Home | History | Annotate | Line # | Download | only in mail
support.c revision 1.6
      1  1.6  wiz /*	$NetBSD: support.c,v 1.6 2002/03/05 19:26:42 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.6  wiz __RCSID("$NetBSD: support.c,v 1.6 2002/03/05 19:26:42 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.4  wiz 	if ((new = salloc(size)) != NULL)
     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.4  wiz 	if ((new = salloc(newsize + oldsize)) != NULL) {
     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.4  wiz 	for (ap = argv; *ap++ != NULL;)
    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.4  wiz  * pointer (or NULL 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.4  wiz 	char *colon, *oldhfield = NULL;
    142  1.1   tv 
    143  1.1   tv 	ibuf = setinput(mp);
    144  1.1   tv 	if ((lc = mp->m_lines - 1) < 0)
    145  1.4  wiz 		return NULL;
    146  1.1   tv 	if (readline(ibuf, linebuf, LINESIZE) < 0)
    147  1.4  wiz 		return NULL;
    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.6  wiz ishfield(char linebuf[], char *colon, char field[])
    220  1.1   tv {
    221  1.1   tv 	char *cp = colon;
    222  1.1   tv 
    223  1.1   tv 	*cp = 0;
    224  1.1   tv 	if (strcasecmp(linebuf, field) != 0) {
    225  1.1   tv 		*cp = ':';
    226  1.1   tv 		return 0;
    227  1.1   tv 	}
    228  1.1   tv 	*cp = ':';
    229  1.1   tv 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
    230  1.1   tv 		;
    231  1.1   tv 	return cp;
    232  1.1   tv }
    233  1.1   tv 
    234  1.1   tv /*
    235  1.1   tv  * Copy a string, lowercasing it as we go.
    236  1.1   tv  */
    237  1.1   tv void
    238  1.2  wiz istrcpy(char *dest, char *src)
    239  1.1   tv {
    240  1.1   tv 
    241  1.1   tv 	do {
    242  1.1   tv 		if (isupper((unsigned char)*src))
    243  1.1   tv 			*dest++ = tolower(*src);
    244  1.1   tv 		else
    245  1.1   tv 			*dest++ = *src;
    246  1.1   tv 	} while (*src++ != 0);
    247  1.1   tv }
    248  1.1   tv 
    249  1.1   tv /*
    250  1.1   tv  * The following code deals with input stacking to do source
    251  1.1   tv  * commands.  All but the current file pointer are saved on
    252  1.1   tv  * the stack.
    253  1.1   tv  */
    254  1.1   tv 
    255  1.1   tv static	int	ssp;			/* Top of file stack */
    256  1.1   tv struct sstack {
    257  1.1   tv 	FILE	*s_file;		/* File we were in. */
    258  1.1   tv 	int	s_cond;			/* Saved state of conditionals */
    259  1.1   tv 	int	s_loading;		/* Loading .mailrc, etc. */
    260  1.1   tv } sstack[NOFILE];
    261  1.1   tv 
    262  1.1   tv /*
    263  1.1   tv  * Pushdown current input file and switch to a new one.
    264  1.1   tv  * Set the global flag "sourcing" so that others will realize
    265  1.1   tv  * that they are no longer reading from a tty (in all probability).
    266  1.1   tv  */
    267  1.1   tv int
    268  1.2  wiz source(void *v)
    269  1.1   tv {
    270  1.1   tv 	char **arglist = v;
    271  1.1   tv 	FILE *fi;
    272  1.1   tv 	char *cp;
    273  1.1   tv 
    274  1.4  wiz 	if ((cp = expand(*arglist)) == NULL)
    275  1.1   tv 		return(1);
    276  1.1   tv 	if ((fi = Fopen(cp, "r")) == NULL) {
    277  1.1   tv 		perror(cp);
    278  1.1   tv 		return(1);
    279  1.1   tv 	}
    280  1.1   tv 	if (ssp >= NOFILE - 1) {
    281  1.1   tv 		printf("Too much \"sourcing\" going on.\n");
    282  1.1   tv 		Fclose(fi);
    283  1.1   tv 		return(1);
    284  1.1   tv 	}
    285  1.1   tv 	sstack[ssp].s_file = input;
    286  1.1   tv 	sstack[ssp].s_cond = cond;
    287  1.1   tv 	sstack[ssp].s_loading = loading;
    288  1.1   tv 	ssp++;
    289  1.1   tv 	loading = 0;
    290  1.1   tv 	cond = CANY;
    291  1.1   tv 	input = fi;
    292  1.1   tv 	sourcing++;
    293  1.1   tv 	return(0);
    294  1.1   tv }
    295  1.1   tv 
    296  1.1   tv /*
    297  1.1   tv  * Pop the current input back to the previous level.
    298  1.1   tv  * Update the "sourcing" flag as appropriate.
    299  1.1   tv  */
    300  1.1   tv int
    301  1.2  wiz unstack(void)
    302  1.1   tv {
    303  1.1   tv 	if (ssp <= 0) {
    304  1.1   tv 		printf("\"Source\" stack over-pop.\n");
    305  1.1   tv 		sourcing = 0;
    306  1.1   tv 		return(1);
    307  1.1   tv 	}
    308  1.1   tv 	Fclose(input);
    309  1.1   tv 	if (cond != CANY)
    310  1.1   tv 		printf("Unmatched \"if\"\n");
    311  1.1   tv 	ssp--;
    312  1.1   tv 	cond = sstack[ssp].s_cond;
    313  1.1   tv 	loading = sstack[ssp].s_loading;
    314  1.1   tv 	input = sstack[ssp].s_file;
    315  1.1   tv 	if (ssp == 0)
    316  1.1   tv 		sourcing = loading;
    317  1.1   tv 	return(0);
    318  1.1   tv }
    319  1.1   tv 
    320  1.1   tv /*
    321  1.1   tv  * Touch the indicated file.
    322  1.1   tv  * This is nifty for the shell.
    323  1.1   tv  */
    324  1.1   tv void
    325  1.2  wiz alter(char *name)
    326  1.1   tv {
    327  1.1   tv 	struct stat sb;
    328  1.1   tv 	struct timeval tv[2];
    329  1.1   tv 
    330  1.1   tv 	if (stat(name, &sb))
    331  1.1   tv 		return;
    332  1.1   tv 	(void) gettimeofday(&tv[0], (struct timezone *)0);
    333  1.1   tv 	tv[0].tv_sec++;
    334  1.1   tv 	TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
    335  1.1   tv 	(void) utimes(name, tv);
    336  1.1   tv }
    337  1.1   tv 
    338  1.1   tv /*
    339  1.1   tv  * Examine the passed line buffer and
    340  1.1   tv  * return true if it is all blanks and tabs.
    341  1.1   tv  */
    342  1.1   tv int
    343  1.2  wiz blankline(char linebuf[])
    344  1.1   tv {
    345  1.1   tv 	char *cp;
    346  1.1   tv 
    347  1.1   tv 	for (cp = linebuf; *cp; cp++)
    348  1.1   tv 		if (*cp != ' ' && *cp != '\t')
    349  1.1   tv 			return(0);
    350  1.1   tv 	return(1);
    351  1.1   tv }
    352  1.1   tv 
    353  1.1   tv /*
    354  1.1   tv  * Get sender's name from this message.  If the message has
    355  1.1   tv  * a bunch of arpanet stuff in it, we may have to skin the name
    356  1.1   tv  * before returning it.
    357  1.1   tv  */
    358  1.1   tv char *
    359  1.2  wiz nameof(struct message *mp, int reptype)
    360  1.1   tv {
    361  1.1   tv 	char *cp, *cp2;
    362  1.1   tv 
    363  1.1   tv 	cp = skin(name1(mp, reptype));
    364  1.1   tv 	if (reptype != 0 || charcount(cp, '!') < 2)
    365  1.1   tv 		return(cp);
    366  1.1   tv 	cp2 = strrchr(cp, '!');
    367  1.1   tv 	cp2--;
    368  1.1   tv 	while (cp2 > cp && *cp2 != '!')
    369  1.1   tv 		cp2--;
    370  1.1   tv 	if (*cp2 == '!')
    371  1.1   tv 		return(cp2 + 1);
    372  1.1   tv 	return(cp);
    373  1.1   tv }
    374  1.1   tv 
    375  1.1   tv /*
    376  1.1   tv  * Start of a "comment".
    377  1.1   tv  * Ignore it.
    378  1.1   tv  */
    379  1.1   tv char *
    380  1.2  wiz skip_comment(char *cp)
    381  1.1   tv {
    382  1.1   tv 	int nesting = 1;
    383  1.1   tv 
    384  1.1   tv 	for (; nesting > 0 && *cp; cp++) {
    385  1.1   tv 		switch (*cp) {
    386  1.1   tv 		case '\\':
    387  1.1   tv 			if (cp[1])
    388  1.1   tv 				cp++;
    389  1.1   tv 			break;
    390  1.1   tv 		case '(':
    391  1.1   tv 			nesting++;
    392  1.1   tv 			break;
    393  1.1   tv 		case ')':
    394  1.1   tv 			nesting--;
    395  1.1   tv 			break;
    396  1.1   tv 		}
    397  1.1   tv 	}
    398  1.1   tv 	return cp;
    399  1.1   tv }
    400  1.1   tv 
    401  1.1   tv /*
    402  1.1   tv  * Skin an arpa net address according to the RFC 822 interpretation
    403  1.1   tv  * of "host-phrase."
    404  1.1   tv  */
    405  1.1   tv char *
    406  1.2  wiz skin(char *name)
    407  1.1   tv {
    408  1.1   tv 	int c;
    409  1.1   tv 	char *cp, *cp2;
    410  1.1   tv 	char *bufend;
    411  1.1   tv 	int gotlt, lastsp;
    412  1.1   tv 	char nbuf[BUFSIZ];
    413  1.1   tv 
    414  1.4  wiz 	if (name == NULL)
    415  1.4  wiz 		return(NULL);
    416  1.4  wiz 	if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
    417  1.4  wiz 	    && strchr(name, ' ') == NULL)
    418  1.1   tv 		return(name);
    419  1.1   tv 	gotlt = 0;
    420  1.1   tv 	lastsp = 0;
    421  1.1   tv 	bufend = nbuf;
    422  1.1   tv 	for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
    423  1.1   tv 		switch (c) {
    424  1.1   tv 		case '(':
    425  1.1   tv 			cp = skip_comment(cp);
    426  1.1   tv 			lastsp = 0;
    427  1.1   tv 			break;
    428  1.1   tv 
    429  1.1   tv 		case '"':
    430  1.1   tv 			/*
    431  1.1   tv 			 * Start of a "quoted-string".
    432  1.1   tv 			 * Copy it in its entirety.
    433  1.1   tv 			 */
    434  1.1   tv 			while ((c = *cp) != '\0') {
    435  1.1   tv 				cp++;
    436  1.1   tv 				if (c == '"')
    437  1.1   tv 					break;
    438  1.1   tv 				if (c != '\\')
    439  1.1   tv 					*cp2++ = c;
    440  1.1   tv 				else if ((c = *cp) != '\0') {
    441  1.1   tv 					*cp2++ = c;
    442  1.1   tv 					cp++;
    443  1.1   tv 				}
    444  1.1   tv 			}
    445  1.1   tv 			lastsp = 0;
    446  1.1   tv 			break;
    447  1.1   tv 
    448  1.1   tv 		case ' ':
    449  1.1   tv 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
    450  1.1   tv 				cp += 3, *cp2++ = '@';
    451  1.1   tv 			else
    452  1.1   tv 			if (cp[0] == '@' && cp[1] == ' ')
    453  1.1   tv 				cp += 2, *cp2++ = '@';
    454  1.1   tv 			else
    455  1.1   tv 				lastsp = 1;
    456  1.1   tv 			break;
    457  1.1   tv 
    458  1.1   tv 		case '<':
    459  1.1   tv 			cp2 = bufend;
    460  1.1   tv 			gotlt++;
    461  1.1   tv 			lastsp = 0;
    462  1.1   tv 			break;
    463  1.1   tv 
    464  1.1   tv 		case '>':
    465  1.1   tv 			if (gotlt) {
    466  1.1   tv 				gotlt = 0;
    467  1.1   tv 				while ((c = *cp) && c != ',') {
    468  1.1   tv 					cp++;
    469  1.1   tv 					if (c == '(')
    470  1.1   tv 						cp = skip_comment(cp);
    471  1.1   tv 					else if (c == '"')
    472  1.1   tv 						while ((c = *cp) != '\0') {
    473  1.1   tv 							cp++;
    474  1.1   tv 							if (c == '"')
    475  1.1   tv 								break;
    476  1.1   tv 							if (c == '\\' && *cp)
    477  1.1   tv 								cp++;
    478  1.1   tv 						}
    479  1.1   tv 				}
    480  1.1   tv 				lastsp = 0;
    481  1.1   tv 				break;
    482  1.1   tv 			}
    483  1.1   tv 			/* Fall into . . . */
    484  1.1   tv 
    485  1.1   tv 		default:
    486  1.1   tv 			if (lastsp) {
    487  1.1   tv 				lastsp = 0;
    488  1.1   tv 				*cp2++ = ' ';
    489  1.1   tv 			}
    490  1.1   tv 			*cp2++ = c;
    491  1.1   tv 			if (c == ',' && !gotlt) {
    492  1.1   tv 				*cp2++ = ' ';
    493  1.1   tv 				for (; *cp == ' '; cp++)
    494  1.1   tv 					;
    495  1.1   tv 				lastsp = 0;
    496  1.1   tv 				bufend = cp2;
    497  1.1   tv 			}
    498  1.1   tv 		}
    499  1.1   tv 	}
    500  1.1   tv 	*cp2 = 0;
    501  1.1   tv 
    502  1.1   tv 	return(savestr(nbuf));
    503  1.1   tv }
    504  1.1   tv 
    505  1.1   tv /*
    506  1.1   tv  * Fetch the sender's name from the passed message.
    507  1.1   tv  * Reptype can be
    508  1.1   tv  *	0 -- get sender's name for display purposes
    509  1.1   tv  *	1 -- get sender's name for reply
    510  1.1   tv  *	2 -- get sender's name for Reply
    511  1.1   tv  */
    512  1.1   tv char *
    513  1.2  wiz name1(struct message *mp, int reptype)
    514  1.1   tv {
    515  1.1   tv 	char namebuf[LINESIZE];
    516  1.1   tv 	char linebuf[LINESIZE];
    517  1.1   tv 	char *cp, *cp2;
    518  1.1   tv 	FILE *ibuf;
    519  1.3  wiz 	int firstrun = 1;
    520  1.1   tv 
    521  1.4  wiz 	if ((cp = hfield("from", mp)) != NULL)
    522  1.1   tv 		return cp;
    523  1.4  wiz 	if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
    524  1.1   tv 		return cp;
    525  1.1   tv 	ibuf = setinput(mp);
    526  1.1   tv 	namebuf[0] = '\0';
    527  1.1   tv 	if (readline(ibuf, linebuf, LINESIZE) < 0)
    528  1.1   tv 		return(savestr(namebuf));
    529  1.1   tv newname:
    530  1.1   tv 	for (cp = linebuf; *cp && *cp != ' '; cp++)
    531  1.1   tv 		;
    532  1.1   tv 	for (; *cp == ' ' || *cp == '\t'; cp++)
    533  1.1   tv 		;
    534  1.1   tv 	for (cp2 = &namebuf[strlen(namebuf)];
    535  1.1   tv 	     *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
    536  1.1   tv 		*cp2++ = *cp++;
    537  1.1   tv 	*cp2 = '\0';
    538  1.1   tv 	if (readline(ibuf, linebuf, LINESIZE) < 0)
    539  1.1   tv 		return(savestr(namebuf));
    540  1.1   tv 	if ((cp = strchr(linebuf, 'F')) == NULL)
    541  1.1   tv 		return(savestr(namebuf));
    542  1.1   tv 	if (strncmp(cp, "From", 4) != 0)
    543  1.1   tv 		return(savestr(namebuf));
    544  1.1   tv 	while ((cp = strchr(cp, 'r')) != NULL) {
    545  1.1   tv 		if (strncmp(cp, "remote", 6) == 0) {
    546  1.1   tv 			if ((cp = strchr(cp, 'f')) == NULL)
    547  1.1   tv 				break;
    548  1.1   tv 			if (strncmp(cp, "from", 4) != 0)
    549  1.1   tv 				break;
    550  1.1   tv 			if ((cp = strchr(cp, ' ')) == NULL)
    551  1.1   tv 				break;
    552  1.1   tv 			cp++;
    553  1.3  wiz 			if (firstrun) {
    554  1.1   tv 				cp2 = namebuf;
    555  1.3  wiz 				firstrun = 0;
    556  1.1   tv 			} else
    557  1.1   tv 				cp2 = strrchr(namebuf, '!') + 1;
    558  1.1   tv 			while (*cp && cp2 < namebuf + LINESIZE - 1)
    559  1.1   tv 				*cp2++ = *cp++;
    560  1.1   tv 			if (cp2 < namebuf + LINESIZE - 1)
    561  1.1   tv 				*cp2++ = '!';
    562  1.1   tv 			*cp2 = '\0';
    563  1.1   tv 			if (cp2 < namebuf + LINESIZE - 1)
    564  1.1   tv 				goto newname;
    565  1.1   tv 			else
    566  1.1   tv 				break;
    567  1.1   tv 		}
    568  1.1   tv 		cp++;
    569  1.1   tv 	}
    570  1.1   tv 	return(savestr(namebuf));
    571  1.1   tv }
    572  1.1   tv 
    573  1.1   tv /*
    574  1.1   tv  * Count the occurances of c in str
    575  1.1   tv  */
    576  1.1   tv int
    577  1.2  wiz charcount(char *str, int c)
    578  1.1   tv {
    579  1.1   tv 	char *cp;
    580  1.1   tv 	int i;
    581  1.1   tv 
    582  1.1   tv 	for (i = 0, cp = str; *cp; cp++)
    583  1.1   tv 		if (*cp == c)
    584  1.1   tv 			i++;
    585  1.1   tv 	return(i);
    586  1.1   tv }
    587  1.1   tv 
    588  1.1   tv /*
    589  1.1   tv  * Convert c to upper case
    590  1.1   tv  */
    591  1.1   tv int
    592  1.2  wiz upcase(int c)
    593  1.1   tv {
    594  1.1   tv 
    595  1.1   tv 	if (islower(c))
    596  1.1   tv 		return toupper(c);
    597  1.1   tv 	return c;
    598  1.1   tv }
    599  1.1   tv 
    600  1.1   tv /*
    601  1.1   tv  * Copy s1 to s2, return pointer to null in s2.
    602  1.1   tv  */
    603  1.1   tv char *
    604  1.2  wiz copy(char *s1, char *s2)
    605  1.1   tv {
    606  1.1   tv 
    607  1.1   tv 	while ((*s2++ = *s1++) != '\0')
    608  1.1   tv 		;
    609  1.1   tv 	return s2 - 1;
    610  1.1   tv }
    611  1.1   tv 
    612  1.1   tv /*
    613  1.1   tv  * See if the given header field is supposed to be ignored.
    614  1.1   tv  */
    615  1.1   tv int
    616  1.3  wiz isign(char *field, struct ignoretab ignoretabs[2])
    617  1.1   tv {
    618  1.1   tv 	char realfld[LINESIZE];
    619  1.1   tv 
    620  1.3  wiz 	if (ignoretabs == ignoreall)
    621  1.1   tv 		return 1;
    622  1.1   tv 	/*
    623  1.1   tv 	 * Lower-case the string, so that "Status" and "status"
    624  1.1   tv 	 * will hash to the same place.
    625  1.1   tv 	 */
    626  1.1   tv 	istrcpy(realfld, field);
    627  1.3  wiz 	if (ignoretabs[1].i_count > 0)
    628  1.3  wiz 		return (!member(realfld, ignoretabs + 1));
    629  1.1   tv 	else
    630  1.3  wiz 		return (member(realfld, ignoretabs));
    631  1.1   tv }
    632  1.1   tv 
    633  1.1   tv int
    634  1.2  wiz member(char *realfield, struct ignoretab *table)
    635  1.1   tv {
    636  1.1   tv 	struct ignore *igp;
    637  1.1   tv 
    638  1.1   tv 	for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
    639  1.1   tv 		if (*igp->i_field == *realfield &&
    640  1.1   tv 		    equal(igp->i_field, realfield))
    641  1.1   tv 			return (1);
    642  1.1   tv 	return (0);
    643  1.1   tv }
    644