Home | History | Annotate | Line # | Download | only in mail
support.c revision 1.3
      1  1.3  wiz /*	$NetBSD: support.c,v 1.3 2002/03/02 15:27:52 wiz Exp $	*/
      2  1.1   tv 
      3  1.1   tv /*
      4  1.1   tv  * Copyright (c) 1980, 1993
      5  1.1   tv  *	The Regents of the University of California.  All rights reserved.
      6  1.1   tv  *
      7  1.1   tv  * Redistribution and use in source and binary forms, with or without
      8  1.1   tv  * modification, are permitted provided that the following conditions
      9  1.1   tv  * are met:
     10  1.1   tv  * 1. Redistributions of source code must retain the above copyright
     11  1.1   tv  *    notice, this list of conditions and the following disclaimer.
     12  1.1   tv  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1   tv  *    notice, this list of conditions and the following disclaimer in the
     14  1.1   tv  *    documentation and/or other materials provided with the distribution.
     15  1.1   tv  * 3. All advertising materials mentioning features or use of this software
     16  1.1   tv  *    must display the following acknowledgement:
     17  1.1   tv  *	This product includes software developed by the University of
     18  1.1   tv  *	California, Berkeley and its contributors.
     19  1.1   tv  * 4. Neither the name of the University nor the names of its contributors
     20  1.1   tv  *    may be used to endorse or promote products derived from this software
     21  1.1   tv  *    without specific prior written permission.
     22  1.1   tv  *
     23  1.1   tv  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  1.1   tv  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1   tv  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  1.1   tv  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  1.1   tv  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  1.1   tv  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  1.1   tv  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1   tv  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  1.1   tv  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1   tv  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1   tv  * SUCH DAMAGE.
     34  1.1   tv  */
     35  1.1   tv 
     36  1.1   tv #include <sys/cdefs.h>
     37  1.1   tv #ifndef lint
     38  1.1   tv #if 0
     39  1.1   tv static char sccsid[] = "@(#)aux.c	8.1 (Berkeley) 6/6/93";
     40  1.1   tv #else
     41  1.3  wiz __RCSID("$NetBSD: support.c,v 1.3 2002/03/02 15:27:52 wiz Exp $");
     42  1.1   tv #endif
     43  1.1   tv #endif /* not lint */
     44  1.1   tv 
     45  1.1   tv #include "rcv.h"
     46  1.1   tv #include "extern.h"
     47  1.1   tv 
     48  1.1   tv /*
     49  1.1   tv  * Mail -- a mail program
     50  1.1   tv  *
     51  1.1   tv  * Auxiliary functions.
     52  1.1   tv  */
     53  1.2  wiz static char *save2str(char *, char *);
     54  1.1   tv 
     55  1.1   tv /*
     56  1.1   tv  * Return a pointer to a dynamic copy of the argument.
     57  1.1   tv  */
     58  1.1   tv char *
     59  1.2  wiz savestr(const char *str)
     60  1.1   tv {
     61  1.1   tv 	char *new;
     62  1.1   tv 	int size = strlen(str) + 1;
     63  1.1   tv 
     64  1.1   tv 	if ((new = salloc(size)) != NOSTR)
     65  1.1   tv 		memmove(new, str, size);
     66  1.1   tv 	return new;
     67  1.1   tv }
     68  1.1   tv 
     69  1.1   tv /*
     70  1.1   tv  * Make a copy of new argument incorporating old one.
     71  1.1   tv  */
     72  1.1   tv static char *
     73  1.2  wiz save2str(char *str, char *old)
     74  1.1   tv {
     75  1.1   tv 	char *new;
     76  1.1   tv 	int newsize = strlen(str) + 1;
     77  1.1   tv 	int oldsize = old ? strlen(old) + 1 : 0;
     78  1.1   tv 
     79  1.1   tv 	if ((new = salloc(newsize + oldsize)) != NOSTR) {
     80  1.1   tv 		if (oldsize) {
     81  1.1   tv 			memmove(new, old, oldsize);
     82  1.1   tv 			new[oldsize - 1] = ' ';
     83  1.1   tv 		}
     84  1.1   tv 		memmove(new + oldsize, str, newsize);
     85  1.1   tv 	}
     86  1.1   tv 	return new;
     87  1.1   tv }
     88  1.1   tv 
     89  1.1   tv /*
     90  1.1   tv  * Touch the named message by setting its MTOUCH flag.
     91  1.1   tv  * Touched messages have the effect of not being sent
     92  1.1   tv  * back to the system mailbox on exit.
     93  1.1   tv  */
     94  1.1   tv void
     95  1.2  wiz touch(struct message *mp)
     96  1.1   tv {
     97  1.1   tv 
     98  1.1   tv 	mp->m_flag |= MTOUCH;
     99  1.1   tv 	if ((mp->m_flag & MREAD) == 0)
    100  1.1   tv 		mp->m_flag |= MREAD|MSTATUS;
    101  1.1   tv }
    102  1.1   tv 
    103  1.1   tv /*
    104  1.1   tv  * Test to see if the passed file name is a directory.
    105  1.1   tv  * Return true if it is.
    106  1.1   tv  */
    107  1.1   tv int
    108  1.2  wiz isdir(char name[])
    109  1.1   tv {
    110  1.1   tv 	struct stat sbuf;
    111  1.1   tv 
    112  1.1   tv 	if (stat(name, &sbuf) < 0)
    113  1.1   tv 		return(0);
    114  1.1   tv 	return (S_ISDIR(sbuf.st_mode));
    115  1.1   tv }
    116  1.1   tv 
    117  1.1   tv /*
    118  1.1   tv  * Count the number of arguments in the given string raw list.
    119  1.1   tv  */
    120  1.1   tv int
    121  1.2  wiz argcount(char **argv)
    122  1.1   tv {
    123  1.1   tv 	char **ap;
    124  1.1   tv 
    125  1.1   tv 	for (ap = argv; *ap++ != NOSTR;)
    126  1.1   tv 		;
    127  1.1   tv 	return ap - argv - 1;
    128  1.1   tv }
    129  1.1   tv 
    130  1.1   tv /*
    131  1.1   tv  * Return the desired header line from the passed message
    132  1.1   tv  * pointer (or NOSTR if the desired header field is not available).
    133  1.1   tv  */
    134  1.1   tv char *
    135  1.2  wiz hfield(char field[], struct message *mp)
    136  1.1   tv {
    137  1.1   tv 	FILE *ibuf;
    138  1.1   tv 	char linebuf[LINESIZE];
    139  1.1   tv 	int lc;
    140  1.3  wiz 	char *headerfield;
    141  1.1   tv 	char *colon, *oldhfield = NOSTR;
    142  1.1   tv 
    143  1.1   tv 	ibuf = setinput(mp);
    144  1.1   tv 	if ((lc = mp->m_lines - 1) < 0)
    145  1.1   tv 		return NOSTR;
    146  1.1   tv 	if (readline(ibuf, linebuf, LINESIZE) < 0)
    147  1.1   tv 		return NOSTR;
    148  1.1   tv 	while (lc > 0) {
    149  1.1   tv 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
    150  1.1   tv 			return oldhfield;
    151  1.3  wiz 		if ((headerfield = ishfield(linebuf, colon, field)) != NULL)
    152  1.3  wiz 			oldhfield = save2str(headerfield, oldhfield);
    153  1.1   tv 	}
    154  1.1   tv 	return oldhfield;
    155  1.1   tv }
    156  1.1   tv 
    157  1.1   tv /*
    158  1.1   tv  * Return the next header field found in the given message.
    159  1.1   tv  * Return >= 0 if something found, < 0 elsewise.
    160  1.1   tv  * "colon" is set to point to the colon in the header.
    161  1.1   tv  * Must deal with \ continuations & other such fraud.
    162  1.1   tv  */
    163  1.1   tv int
    164  1.2  wiz gethfield(FILE *f, char linebuf[], int rem, char **colon)
    165  1.1   tv {
    166  1.1   tv 	char line2[LINESIZE];
    167  1.1   tv 	char *cp, *cp2;
    168  1.1   tv 	int c;
    169  1.1   tv 
    170  1.1   tv 	for (;;) {
    171  1.1   tv 		if (--rem < 0)
    172  1.1   tv 			return -1;
    173  1.1   tv 		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
    174  1.1   tv 			return -1;
    175  1.1   tv 		for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
    176  1.1   tv 		     cp++)
    177  1.1   tv 			;
    178  1.1   tv 		if (*cp != ':' || cp == linebuf)
    179  1.1   tv 			continue;
    180  1.1   tv 		/*
    181  1.1   tv 		 * I guess we got a headline.
    182  1.1   tv 		 * Handle wraparounding
    183  1.1   tv 		 */
    184  1.1   tv 		*colon = cp;
    185  1.1   tv 		cp = linebuf + c;
    186  1.1   tv 		for (;;) {
    187  1.1   tv 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
    188  1.1   tv 				;
    189  1.1   tv 			cp++;
    190  1.1   tv 			if (rem <= 0)
    191  1.1   tv 				break;
    192  1.1   tv 			ungetc(c = getc(f), f);
    193  1.1   tv 			if (c != ' ' && c != '\t')
    194  1.1   tv 				break;
    195  1.1   tv 			if ((c = readline(f, line2, LINESIZE)) < 0)
    196  1.1   tv 				break;
    197  1.1   tv 			rem--;
    198  1.1   tv 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
    199  1.1   tv 				;
    200  1.1   tv 			c -= cp2 - line2;
    201  1.1   tv 			if (cp + c >= linebuf + LINESIZE - 2)
    202  1.1   tv 				break;
    203  1.1   tv 			*cp++ = ' ';
    204  1.1   tv 			memmove(cp, cp2, c);
    205  1.1   tv 			cp += c;
    206  1.1   tv 		}
    207  1.1   tv 		*cp = 0;
    208  1.1   tv 		return rem;
    209  1.1   tv 	}
    210  1.1   tv 	/* NOTREACHED */
    211  1.1   tv }
    212  1.1   tv 
    213  1.1   tv /*
    214  1.1   tv  * Check whether the passed line is a header line of
    215  1.1   tv  * the desired breed.  Return the field body, or 0.
    216  1.1   tv  */
    217  1.1   tv 
    218  1.1   tv char*
    219  1.1   tv ishfield(linebuf, colon, field)
    220  1.1   tv 	char linebuf[], field[];
    221  1.1   tv 	char *colon;
    222  1.1   tv {
    223  1.1   tv 	char *cp = colon;
    224  1.1   tv 
    225  1.1   tv 	*cp = 0;
    226  1.1   tv 	if (strcasecmp(linebuf, field) != 0) {
    227  1.1   tv 		*cp = ':';
    228  1.1   tv 		return 0;
    229  1.1   tv 	}
    230  1.1   tv 	*cp = ':';
    231  1.1   tv 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
    232  1.1   tv 		;
    233  1.1   tv 	return cp;
    234  1.1   tv }
    235  1.1   tv 
    236  1.1   tv /*
    237  1.1   tv  * Copy a string, lowercasing it as we go.
    238  1.1   tv  */
    239  1.1   tv void
    240  1.2  wiz istrcpy(char *dest, char *src)
    241  1.1   tv {
    242  1.1   tv 
    243  1.1   tv 	do {
    244  1.1   tv 		if (isupper((unsigned char)*src))
    245  1.1   tv 			*dest++ = tolower(*src);
    246  1.1   tv 		else
    247  1.1   tv 			*dest++ = *src;
    248  1.1   tv 	} while (*src++ != 0);
    249  1.1   tv }
    250  1.1   tv 
    251  1.1   tv /*
    252  1.1   tv  * The following code deals with input stacking to do source
    253  1.1   tv  * commands.  All but the current file pointer are saved on
    254  1.1   tv  * the stack.
    255  1.1   tv  */
    256  1.1   tv 
    257  1.1   tv static	int	ssp;			/* Top of file stack */
    258  1.1   tv struct sstack {
    259  1.1   tv 	FILE	*s_file;		/* File we were in. */
    260  1.1   tv 	int	s_cond;			/* Saved state of conditionals */
    261  1.1   tv 	int	s_loading;		/* Loading .mailrc, etc. */
    262  1.1   tv } sstack[NOFILE];
    263  1.1   tv 
    264  1.1   tv /*
    265  1.1   tv  * Pushdown current input file and switch to a new one.
    266  1.1   tv  * Set the global flag "sourcing" so that others will realize
    267  1.1   tv  * that they are no longer reading from a tty (in all probability).
    268  1.1   tv  */
    269  1.1   tv int
    270  1.2  wiz source(void *v)
    271  1.1   tv {
    272  1.1   tv 	char **arglist = v;
    273  1.1   tv 	FILE *fi;
    274  1.1   tv 	char *cp;
    275  1.1   tv 
    276  1.1   tv 	if ((cp = expand(*arglist)) == NOSTR)
    277  1.1   tv 		return(1);
    278  1.1   tv 	if ((fi = Fopen(cp, "r")) == NULL) {
    279  1.1   tv 		perror(cp);
    280  1.1   tv 		return(1);
    281  1.1   tv 	}
    282  1.1   tv 	if (ssp >= NOFILE - 1) {
    283  1.1   tv 		printf("Too much \"sourcing\" going on.\n");
    284  1.1   tv 		Fclose(fi);
    285  1.1   tv 		return(1);
    286  1.1   tv 	}
    287  1.1   tv 	sstack[ssp].s_file = input;
    288  1.1   tv 	sstack[ssp].s_cond = cond;
    289  1.1   tv 	sstack[ssp].s_loading = loading;
    290  1.1   tv 	ssp++;
    291  1.1   tv 	loading = 0;
    292  1.1   tv 	cond = CANY;
    293  1.1   tv 	input = fi;
    294  1.1   tv 	sourcing++;
    295  1.1   tv 	return(0);
    296  1.1   tv }
    297  1.1   tv 
    298  1.1   tv /*
    299  1.1   tv  * Pop the current input back to the previous level.
    300  1.1   tv  * Update the "sourcing" flag as appropriate.
    301  1.1   tv  */
    302  1.1   tv int
    303  1.2  wiz unstack(void)
    304  1.1   tv {
    305  1.1   tv 	if (ssp <= 0) {
    306  1.1   tv 		printf("\"Source\" stack over-pop.\n");
    307  1.1   tv 		sourcing = 0;
    308  1.1   tv 		return(1);
    309  1.1   tv 	}
    310  1.1   tv 	Fclose(input);
    311  1.1   tv 	if (cond != CANY)
    312  1.1   tv 		printf("Unmatched \"if\"\n");
    313  1.1   tv 	ssp--;
    314  1.1   tv 	cond = sstack[ssp].s_cond;
    315  1.1   tv 	loading = sstack[ssp].s_loading;
    316  1.1   tv 	input = sstack[ssp].s_file;
    317  1.1   tv 	if (ssp == 0)
    318  1.1   tv 		sourcing = loading;
    319  1.1   tv 	return(0);
    320  1.1   tv }
    321  1.1   tv 
    322  1.1   tv /*
    323  1.1   tv  * Touch the indicated file.
    324  1.1   tv  * This is nifty for the shell.
    325  1.1   tv  */
    326  1.1   tv void
    327  1.2  wiz alter(char *name)
    328  1.1   tv {
    329  1.1   tv 	struct stat sb;
    330  1.1   tv 	struct timeval tv[2];
    331  1.1   tv 
    332  1.1   tv 	if (stat(name, &sb))
    333  1.1   tv 		return;
    334  1.1   tv 	(void) gettimeofday(&tv[0], (struct timezone *)0);
    335  1.1   tv 	tv[0].tv_sec++;
    336  1.1   tv 	TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
    337  1.1   tv 	(void) utimes(name, tv);
    338  1.1   tv }
    339  1.1   tv 
    340  1.1   tv /*
    341  1.1   tv  * Examine the passed line buffer and
    342  1.1   tv  * return true if it is all blanks and tabs.
    343  1.1   tv  */
    344  1.1   tv int
    345  1.2  wiz blankline(char linebuf[])
    346  1.1   tv {
    347  1.1   tv 	char *cp;
    348  1.1   tv 
    349  1.1   tv 	for (cp = linebuf; *cp; cp++)
    350  1.1   tv 		if (*cp != ' ' && *cp != '\t')
    351  1.1   tv 			return(0);
    352  1.1   tv 	return(1);
    353  1.1   tv }
    354  1.1   tv 
    355  1.1   tv /*
    356  1.1   tv  * Get sender's name from this message.  If the message has
    357  1.1   tv  * a bunch of arpanet stuff in it, we may have to skin the name
    358  1.1   tv  * before returning it.
    359  1.1   tv  */
    360  1.1   tv char *
    361  1.2  wiz nameof(struct message *mp, int reptype)
    362  1.1   tv {
    363  1.1   tv 	char *cp, *cp2;
    364  1.1   tv 
    365  1.1   tv 	cp = skin(name1(mp, reptype));
    366  1.1   tv 	if (reptype != 0 || charcount(cp, '!') < 2)
    367  1.1   tv 		return(cp);
    368  1.1   tv 	cp2 = strrchr(cp, '!');
    369  1.1   tv 	cp2--;
    370  1.1   tv 	while (cp2 > cp && *cp2 != '!')
    371  1.1   tv 		cp2--;
    372  1.1   tv 	if (*cp2 == '!')
    373  1.1   tv 		return(cp2 + 1);
    374  1.1   tv 	return(cp);
    375  1.1   tv }
    376  1.1   tv 
    377  1.1   tv /*
    378  1.1   tv  * Start of a "comment".
    379  1.1   tv  * Ignore it.
    380  1.1   tv  */
    381  1.1   tv char *
    382  1.2  wiz skip_comment(char *cp)
    383  1.1   tv {
    384  1.1   tv 	int nesting = 1;
    385  1.1   tv 
    386  1.1   tv 	for (; nesting > 0 && *cp; cp++) {
    387  1.1   tv 		switch (*cp) {
    388  1.1   tv 		case '\\':
    389  1.1   tv 			if (cp[1])
    390  1.1   tv 				cp++;
    391  1.1   tv 			break;
    392  1.1   tv 		case '(':
    393  1.1   tv 			nesting++;
    394  1.1   tv 			break;
    395  1.1   tv 		case ')':
    396  1.1   tv 			nesting--;
    397  1.1   tv 			break;
    398  1.1   tv 		}
    399  1.1   tv 	}
    400  1.1   tv 	return cp;
    401  1.1   tv }
    402  1.1   tv 
    403  1.1   tv /*
    404  1.1   tv  * Skin an arpa net address according to the RFC 822 interpretation
    405  1.1   tv  * of "host-phrase."
    406  1.1   tv  */
    407  1.1   tv char *
    408  1.2  wiz skin(char *name)
    409  1.1   tv {
    410  1.1   tv 	int c;
    411  1.1   tv 	char *cp, *cp2;
    412  1.1   tv 	char *bufend;
    413  1.1   tv 	int gotlt, lastsp;
    414  1.1   tv 	char nbuf[BUFSIZ];
    415  1.1   tv 
    416  1.1   tv 	if (name == NOSTR)
    417  1.1   tv 		return(NOSTR);
    418  1.1   tv 	if (strchr(name, '(') == NOSTR && strchr(name, '<') == NOSTR
    419  1.1   tv 	    && strchr(name, ' ') == NOSTR)
    420  1.1   tv 		return(name);
    421  1.1   tv 	gotlt = 0;
    422  1.1   tv 	lastsp = 0;
    423  1.1   tv 	bufend = nbuf;
    424  1.1   tv 	for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
    425  1.1   tv 		switch (c) {
    426  1.1   tv 		case '(':
    427  1.1   tv 			cp = skip_comment(cp);
    428  1.1   tv 			lastsp = 0;
    429  1.1   tv 			break;
    430  1.1   tv 
    431  1.1   tv 		case '"':
    432  1.1   tv 			/*
    433  1.1   tv 			 * Start of a "quoted-string".
    434  1.1   tv 			 * Copy it in its entirety.
    435  1.1   tv 			 */
    436  1.1   tv 			while ((c = *cp) != '\0') {
    437  1.1   tv 				cp++;
    438  1.1   tv 				if (c == '"')
    439  1.1   tv 					break;
    440  1.1   tv 				if (c != '\\')
    441  1.1   tv 					*cp2++ = c;
    442  1.1   tv 				else if ((c = *cp) != '\0') {
    443  1.1   tv 					*cp2++ = c;
    444  1.1   tv 					cp++;
    445  1.1   tv 				}
    446  1.1   tv 			}
    447  1.1   tv 			lastsp = 0;
    448  1.1   tv 			break;
    449  1.1   tv 
    450  1.1   tv 		case ' ':
    451  1.1   tv 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
    452  1.1   tv 				cp += 3, *cp2++ = '@';
    453  1.1   tv 			else
    454  1.1   tv 			if (cp[0] == '@' && cp[1] == ' ')
    455  1.1   tv 				cp += 2, *cp2++ = '@';
    456  1.1   tv 			else
    457  1.1   tv 				lastsp = 1;
    458  1.1   tv 			break;
    459  1.1   tv 
    460  1.1   tv 		case '<':
    461  1.1   tv 			cp2 = bufend;
    462  1.1   tv 			gotlt++;
    463  1.1   tv 			lastsp = 0;
    464  1.1   tv 			break;
    465  1.1   tv 
    466  1.1   tv 		case '>':
    467  1.1   tv 			if (gotlt) {
    468  1.1   tv 				gotlt = 0;
    469  1.1   tv 				while ((c = *cp) && c != ',') {
    470  1.1   tv 					cp++;
    471  1.1   tv 					if (c == '(')
    472  1.1   tv 						cp = skip_comment(cp);
    473  1.1   tv 					else if (c == '"')
    474  1.1   tv 						while ((c = *cp) != '\0') {
    475  1.1   tv 							cp++;
    476  1.1   tv 							if (c == '"')
    477  1.1   tv 								break;
    478  1.1   tv 							if (c == '\\' && *cp)
    479  1.1   tv 								cp++;
    480  1.1   tv 						}
    481  1.1   tv 				}
    482  1.1   tv 				lastsp = 0;
    483  1.1   tv 				break;
    484  1.1   tv 			}
    485  1.1   tv 			/* Fall into . . . */
    486  1.1   tv 
    487  1.1   tv 		default:
    488  1.1   tv 			if (lastsp) {
    489  1.1   tv 				lastsp = 0;
    490  1.1   tv 				*cp2++ = ' ';
    491  1.1   tv 			}
    492  1.1   tv 			*cp2++ = c;
    493  1.1   tv 			if (c == ',' && !gotlt) {
    494  1.1   tv 				*cp2++ = ' ';
    495  1.1   tv 				for (; *cp == ' '; cp++)
    496  1.1   tv 					;
    497  1.1   tv 				lastsp = 0;
    498  1.1   tv 				bufend = cp2;
    499  1.1   tv 			}
    500  1.1   tv 		}
    501  1.1   tv 	}
    502  1.1   tv 	*cp2 = 0;
    503  1.1   tv 
    504  1.1   tv 	return(savestr(nbuf));
    505  1.1   tv }
    506  1.1   tv 
    507  1.1   tv /*
    508  1.1   tv  * Fetch the sender's name from the passed message.
    509  1.1   tv  * Reptype can be
    510  1.1   tv  *	0 -- get sender's name for display purposes
    511  1.1   tv  *	1 -- get sender's name for reply
    512  1.1   tv  *	2 -- get sender's name for Reply
    513  1.1   tv  */
    514  1.1   tv char *
    515  1.2  wiz name1(struct message *mp, int reptype)
    516  1.1   tv {
    517  1.1   tv 	char namebuf[LINESIZE];
    518  1.1   tv 	char linebuf[LINESIZE];
    519  1.1   tv 	char *cp, *cp2;
    520  1.1   tv 	FILE *ibuf;
    521  1.3  wiz 	int firstrun = 1;
    522  1.1   tv 
    523  1.1   tv 	if ((cp = hfield("from", mp)) != NOSTR)
    524  1.1   tv 		return cp;
    525  1.1   tv 	if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
    526  1.1   tv 		return cp;
    527  1.1   tv 	ibuf = setinput(mp);
    528  1.1   tv 	namebuf[0] = '\0';
    529  1.1   tv 	if (readline(ibuf, linebuf, LINESIZE) < 0)
    530  1.1   tv 		return(savestr(namebuf));
    531  1.1   tv newname:
    532  1.1   tv 	for (cp = linebuf; *cp && *cp != ' '; cp++)
    533  1.1   tv 		;
    534  1.1   tv 	for (; *cp == ' ' || *cp == '\t'; cp++)
    535  1.1   tv 		;
    536  1.1   tv 	for (cp2 = &namebuf[strlen(namebuf)];
    537  1.1   tv 	     *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
    538  1.1   tv 		*cp2++ = *cp++;
    539  1.1   tv 	*cp2 = '\0';
    540  1.1   tv 	if (readline(ibuf, linebuf, LINESIZE) < 0)
    541  1.1   tv 		return(savestr(namebuf));
    542  1.1   tv 	if ((cp = strchr(linebuf, 'F')) == NULL)
    543  1.1   tv 		return(savestr(namebuf));
    544  1.1   tv 	if (strncmp(cp, "From", 4) != 0)
    545  1.1   tv 		return(savestr(namebuf));
    546  1.1   tv 	while ((cp = strchr(cp, 'r')) != NULL) {
    547  1.1   tv 		if (strncmp(cp, "remote", 6) == 0) {
    548  1.1   tv 			if ((cp = strchr(cp, 'f')) == NULL)
    549  1.1   tv 				break;
    550  1.1   tv 			if (strncmp(cp, "from", 4) != 0)
    551  1.1   tv 				break;
    552  1.1   tv 			if ((cp = strchr(cp, ' ')) == NULL)
    553  1.1   tv 				break;
    554  1.1   tv 			cp++;
    555  1.3  wiz 			if (firstrun) {
    556  1.1   tv 				cp2 = namebuf;
    557  1.3  wiz 				firstrun = 0;
    558  1.1   tv 			} else
    559  1.1   tv 				cp2 = strrchr(namebuf, '!') + 1;
    560  1.1   tv 			while (*cp && cp2 < namebuf + LINESIZE - 1)
    561  1.1   tv 				*cp2++ = *cp++;
    562  1.1   tv 			if (cp2 < namebuf + LINESIZE - 1)
    563  1.1   tv 				*cp2++ = '!';
    564  1.1   tv 			*cp2 = '\0';
    565  1.1   tv 			if (cp2 < namebuf + LINESIZE - 1)
    566  1.1   tv 				goto newname;
    567  1.1   tv 			else
    568  1.1   tv 				break;
    569  1.1   tv 		}
    570  1.1   tv 		cp++;
    571  1.1   tv 	}
    572  1.1   tv 	return(savestr(namebuf));
    573  1.1   tv }
    574  1.1   tv 
    575  1.1   tv /*
    576  1.1   tv  * Count the occurances of c in str
    577  1.1   tv  */
    578  1.1   tv int
    579  1.2  wiz charcount(char *str, int c)
    580  1.1   tv {
    581  1.1   tv 	char *cp;
    582  1.1   tv 	int i;
    583  1.1   tv 
    584  1.1   tv 	for (i = 0, cp = str; *cp; cp++)
    585  1.1   tv 		if (*cp == c)
    586  1.1   tv 			i++;
    587  1.1   tv 	return(i);
    588  1.1   tv }
    589  1.1   tv 
    590  1.1   tv /*
    591  1.1   tv  * Are any of the characters in the two strings the same?
    592  1.1   tv  */
    593  1.1   tv int
    594  1.2  wiz anyof(char *s1, char *s2)
    595  1.1   tv {
    596  1.1   tv 
    597  1.1   tv 	while (*s1)
    598  1.1   tv 		if (strchr(s2, *s1++))
    599  1.1   tv 			return 1;
    600  1.1   tv 	return 0;
    601  1.1   tv }
    602  1.1   tv 
    603  1.1   tv /*
    604  1.1   tv  * Convert c to upper case
    605  1.1   tv  */
    606  1.1   tv int
    607  1.2  wiz upcase(int c)
    608  1.1   tv {
    609  1.1   tv 
    610  1.1   tv 	if (islower(c))
    611  1.1   tv 		return toupper(c);
    612  1.1   tv 	return c;
    613  1.1   tv }
    614  1.1   tv 
    615  1.1   tv /*
    616  1.1   tv  * Copy s1 to s2, return pointer to null in s2.
    617  1.1   tv  */
    618  1.1   tv char *
    619  1.2  wiz copy(char *s1, char *s2)
    620  1.1   tv {
    621  1.1   tv 
    622  1.1   tv 	while ((*s2++ = *s1++) != '\0')
    623  1.1   tv 		;
    624  1.1   tv 	return s2 - 1;
    625  1.1   tv }
    626  1.1   tv 
    627  1.1   tv /*
    628  1.1   tv  * See if the given header field is supposed to be ignored.
    629  1.1   tv  */
    630  1.1   tv int
    631  1.3  wiz isign(char *field, struct ignoretab ignoretabs[2])
    632  1.1   tv {
    633  1.1   tv 	char realfld[LINESIZE];
    634  1.1   tv 
    635  1.3  wiz 	if (ignoretabs == ignoreall)
    636  1.1   tv 		return 1;
    637  1.1   tv 	/*
    638  1.1   tv 	 * Lower-case the string, so that "Status" and "status"
    639  1.1   tv 	 * will hash to the same place.
    640  1.1   tv 	 */
    641  1.1   tv 	istrcpy(realfld, field);
    642  1.3  wiz 	if (ignoretabs[1].i_count > 0)
    643  1.3  wiz 		return (!member(realfld, ignoretabs + 1));
    644  1.1   tv 	else
    645  1.3  wiz 		return (member(realfld, ignoretabs));
    646  1.1   tv }
    647  1.1   tv 
    648  1.1   tv int
    649  1.2  wiz member(char *realfield, struct ignoretab *table)
    650  1.1   tv {
    651  1.1   tv 	struct ignore *igp;
    652  1.1   tv 
    653  1.1   tv 	for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
    654  1.1   tv 		if (*igp->i_field == *realfield &&
    655  1.1   tv 		    equal(igp->i_field, realfield))
    656  1.1   tv 			return (1);
    657  1.1   tv 	return (0);
    658  1.1   tv }
    659