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