xref: /freebsd/usr.bin/mail/util.c (revision a1d170a0b61aa2bf5fb5f73f294f29dda17442f4)
10bee4c2cSEd Schouten /*
20bee4c2cSEd Schouten  * Copyright (c) 1980, 1993
30bee4c2cSEd Schouten  *	The Regents of the University of California.  All rights reserved.
40bee4c2cSEd Schouten  *
50bee4c2cSEd Schouten  * Redistribution and use in source and binary forms, with or without
60bee4c2cSEd Schouten  * modification, are permitted provided that the following conditions
70bee4c2cSEd Schouten  * are met:
80bee4c2cSEd Schouten  * 1. Redistributions of source code must retain the above copyright
90bee4c2cSEd Schouten  *    notice, this list of conditions and the following disclaimer.
100bee4c2cSEd Schouten  * 2. Redistributions in binary form must reproduce the above copyright
110bee4c2cSEd Schouten  *    notice, this list of conditions and the following disclaimer in the
120bee4c2cSEd Schouten  *    documentation and/or other materials provided with the distribution.
130bee4c2cSEd Schouten  * 3. All advertising materials mentioning features or use of this software
140bee4c2cSEd Schouten  *    must display the following acknowledgement:
150bee4c2cSEd Schouten  *	This product includes software developed by the University of
160bee4c2cSEd Schouten  *	California, Berkeley and its contributors.
170bee4c2cSEd Schouten  * 4. Neither the name of the University nor the names of its contributors
180bee4c2cSEd Schouten  *    may be used to endorse or promote products derived from this software
190bee4c2cSEd Schouten  *    without specific prior written permission.
200bee4c2cSEd Schouten  *
210bee4c2cSEd Schouten  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
220bee4c2cSEd Schouten  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
230bee4c2cSEd Schouten  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
240bee4c2cSEd Schouten  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
250bee4c2cSEd Schouten  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
260bee4c2cSEd Schouten  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
270bee4c2cSEd Schouten  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
280bee4c2cSEd Schouten  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
290bee4c2cSEd Schouten  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
300bee4c2cSEd Schouten  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
310bee4c2cSEd Schouten  * SUCH DAMAGE.
320bee4c2cSEd Schouten  */
330bee4c2cSEd Schouten 
340bee4c2cSEd Schouten #ifndef lint
350bee4c2cSEd Schouten #if 0
360bee4c2cSEd Schouten static char sccsid[] = "@(#)aux.c	8.1 (Berkeley) 6/6/93";
370bee4c2cSEd Schouten #endif
380bee4c2cSEd Schouten #endif /* not lint */
390bee4c2cSEd Schouten #include <sys/cdefs.h>
400bee4c2cSEd Schouten __FBSDID("$FreeBSD$");
410bee4c2cSEd Schouten 
420bee4c2cSEd Schouten #include <sys/time.h>
430bee4c2cSEd Schouten 
440bee4c2cSEd Schouten #include "rcv.h"
450bee4c2cSEd Schouten #include "extern.h"
460bee4c2cSEd Schouten 
470bee4c2cSEd Schouten /*
480bee4c2cSEd Schouten  * Mail -- a mail program
490bee4c2cSEd Schouten  *
500bee4c2cSEd Schouten  * Auxiliary functions.
510bee4c2cSEd Schouten  */
520bee4c2cSEd Schouten 
530bee4c2cSEd Schouten static char *save2str(char *, char *);
540bee4c2cSEd Schouten 
550bee4c2cSEd Schouten /*
560bee4c2cSEd Schouten  * Return a pointer to a dynamic copy of the argument.
570bee4c2cSEd Schouten  */
580bee4c2cSEd Schouten char *
590bee4c2cSEd Schouten savestr(str)
600bee4c2cSEd Schouten 	char *str;
610bee4c2cSEd Schouten {
620bee4c2cSEd Schouten 	char *new;
630bee4c2cSEd Schouten 	int size = strlen(str) + 1;
640bee4c2cSEd Schouten 
650bee4c2cSEd Schouten 	if ((new = salloc(size)) != NULL)
660bee4c2cSEd Schouten 		bcopy(str, new, size);
670bee4c2cSEd Schouten 	return (new);
680bee4c2cSEd Schouten }
690bee4c2cSEd Schouten 
700bee4c2cSEd Schouten /*
710bee4c2cSEd Schouten  * Make a copy of new argument incorporating old one.
720bee4c2cSEd Schouten  */
730bee4c2cSEd Schouten static char *
740bee4c2cSEd Schouten save2str(str, old)
750bee4c2cSEd Schouten 	char *str, *old;
760bee4c2cSEd Schouten {
770bee4c2cSEd Schouten 	char *new;
780bee4c2cSEd Schouten 	int newsize = strlen(str) + 1;
790bee4c2cSEd Schouten 	int oldsize = old ? strlen(old) + 1 : 0;
800bee4c2cSEd Schouten 
810bee4c2cSEd Schouten 	if ((new = salloc(newsize + oldsize)) != NULL) {
820bee4c2cSEd Schouten 		if (oldsize) {
830bee4c2cSEd Schouten 			bcopy(old, new, oldsize);
840bee4c2cSEd Schouten 			new[oldsize - 1] = ' ';
850bee4c2cSEd Schouten 		}
860bee4c2cSEd Schouten 		bcopy(str, new + oldsize, newsize);
870bee4c2cSEd Schouten 	}
880bee4c2cSEd Schouten 	return (new);
890bee4c2cSEd Schouten }
900bee4c2cSEd Schouten 
910bee4c2cSEd Schouten /*
920bee4c2cSEd Schouten  * Touch the named message by setting its MTOUCH flag.
930bee4c2cSEd Schouten  * Touched messages have the effect of not being sent
940bee4c2cSEd Schouten  * back to the system mailbox on exit.
950bee4c2cSEd Schouten  */
960bee4c2cSEd Schouten void
970bee4c2cSEd Schouten touch(mp)
980bee4c2cSEd Schouten 	struct message *mp;
990bee4c2cSEd Schouten {
1000bee4c2cSEd Schouten 
1010bee4c2cSEd Schouten 	mp->m_flag |= MTOUCH;
1020bee4c2cSEd Schouten 	if ((mp->m_flag & MREAD) == 0)
1030bee4c2cSEd Schouten 		mp->m_flag |= MREAD|MSTATUS;
1040bee4c2cSEd Schouten }
1050bee4c2cSEd Schouten 
1060bee4c2cSEd Schouten /*
1070bee4c2cSEd Schouten  * Test to see if the passed file name is a directory.
1080bee4c2cSEd Schouten  * Return true if it is.
1090bee4c2cSEd Schouten  */
1100bee4c2cSEd Schouten int
1110bee4c2cSEd Schouten isdir(name)
1120bee4c2cSEd Schouten 	char name[];
1130bee4c2cSEd Schouten {
1140bee4c2cSEd Schouten 	struct stat sbuf;
1150bee4c2cSEd Schouten 
1160bee4c2cSEd Schouten 	if (stat(name, &sbuf) < 0)
1170bee4c2cSEd Schouten 		return (0);
1180bee4c2cSEd Schouten 	return (S_ISDIR(sbuf.st_mode));
1190bee4c2cSEd Schouten }
1200bee4c2cSEd Schouten 
1210bee4c2cSEd Schouten /*
1220bee4c2cSEd Schouten  * Count the number of arguments in the given string raw list.
1230bee4c2cSEd Schouten  */
1240bee4c2cSEd Schouten int
1250bee4c2cSEd Schouten argcount(argv)
1260bee4c2cSEd Schouten 	char **argv;
1270bee4c2cSEd Schouten {
1280bee4c2cSEd Schouten 	char **ap;
1290bee4c2cSEd Schouten 
1300bee4c2cSEd Schouten 	for (ap = argv; *ap++ != NULL;)
1310bee4c2cSEd Schouten 		;
1320bee4c2cSEd Schouten 	return (ap - argv - 1);
1330bee4c2cSEd Schouten }
1340bee4c2cSEd Schouten 
1350bee4c2cSEd Schouten /*
1360bee4c2cSEd Schouten  * Return the desired header line from the passed message
1370bee4c2cSEd Schouten  * pointer (or NULL if the desired header field is not available).
1380bee4c2cSEd Schouten  */
1390bee4c2cSEd Schouten char *
1400bee4c2cSEd Schouten hfield(field, mp)
1410bee4c2cSEd Schouten 	const char *field;
1420bee4c2cSEd Schouten 	struct message *mp;
1430bee4c2cSEd Schouten {
1440bee4c2cSEd Schouten 	FILE *ibuf;
1450bee4c2cSEd Schouten 	char linebuf[LINESIZE];
1460bee4c2cSEd Schouten 	int lc;
1470bee4c2cSEd Schouten 	char *hfield;
1480bee4c2cSEd Schouten 	char *colon, *oldhfield = NULL;
1490bee4c2cSEd Schouten 
1500bee4c2cSEd Schouten 	ibuf = setinput(mp);
1510bee4c2cSEd Schouten 	if ((lc = mp->m_lines - 1) < 0)
1520bee4c2cSEd Schouten 		return (NULL);
1530bee4c2cSEd Schouten 	if (readline(ibuf, linebuf, LINESIZE) < 0)
1540bee4c2cSEd Schouten 		return (NULL);
1550bee4c2cSEd Schouten 	while (lc > 0) {
1560bee4c2cSEd Schouten 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
1570bee4c2cSEd Schouten 			return (oldhfield);
1580bee4c2cSEd Schouten 		if ((hfield = ishfield(linebuf, colon, field)) != NULL)
1590bee4c2cSEd Schouten 			oldhfield = save2str(hfield, oldhfield);
1600bee4c2cSEd Schouten 	}
1610bee4c2cSEd Schouten 	return (oldhfield);
1620bee4c2cSEd Schouten }
1630bee4c2cSEd Schouten 
1640bee4c2cSEd Schouten /*
1650bee4c2cSEd Schouten  * Return the next header field found in the given message.
1660bee4c2cSEd Schouten  * Return >= 0 if something found, < 0 elsewise.
1670bee4c2cSEd Schouten  * "colon" is set to point to the colon in the header.
1680bee4c2cSEd Schouten  * Must deal with \ continuations & other such fraud.
1690bee4c2cSEd Schouten  */
1700bee4c2cSEd Schouten int
1710bee4c2cSEd Schouten gethfield(f, linebuf, rem, colon)
1720bee4c2cSEd Schouten 	FILE *f;
1730bee4c2cSEd Schouten 	char linebuf[];
1740bee4c2cSEd Schouten 	int rem;
1750bee4c2cSEd Schouten 	char **colon;
1760bee4c2cSEd Schouten {
1770bee4c2cSEd Schouten 	char line2[LINESIZE];
1780bee4c2cSEd Schouten 	char *cp, *cp2;
1790bee4c2cSEd Schouten 	int c;
1800bee4c2cSEd Schouten 
1810bee4c2cSEd Schouten 	for (;;) {
1820bee4c2cSEd Schouten 		if (--rem < 0)
1830bee4c2cSEd Schouten 			return (-1);
1840bee4c2cSEd Schouten 		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
1850bee4c2cSEd Schouten 			return (-1);
1860bee4c2cSEd Schouten 		for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
1870bee4c2cSEd Schouten 		    cp++)
1880bee4c2cSEd Schouten 			;
1890bee4c2cSEd Schouten 		if (*cp != ':' || cp == linebuf)
1900bee4c2cSEd Schouten 			continue;
1910bee4c2cSEd Schouten 		/*
1920bee4c2cSEd Schouten 		 * I guess we got a headline.
1930bee4c2cSEd Schouten 		 * Handle wraparounding
1940bee4c2cSEd Schouten 		 */
1950bee4c2cSEd Schouten 		*colon = cp;
1960bee4c2cSEd Schouten 		cp = linebuf + c;
1970bee4c2cSEd Schouten 		for (;;) {
1980bee4c2cSEd Schouten 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
1990bee4c2cSEd Schouten 				;
2000bee4c2cSEd Schouten 			cp++;
2010bee4c2cSEd Schouten 			if (rem <= 0)
2020bee4c2cSEd Schouten 				break;
2030bee4c2cSEd Schouten 			ungetc(c = getc(f), f);
2040bee4c2cSEd Schouten 			if (c != ' ' && c != '\t')
2050bee4c2cSEd Schouten 				break;
2060bee4c2cSEd Schouten 			if ((c = readline(f, line2, LINESIZE)) < 0)
2070bee4c2cSEd Schouten 				break;
2080bee4c2cSEd Schouten 			rem--;
2090bee4c2cSEd Schouten 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
2100bee4c2cSEd Schouten 				;
2110bee4c2cSEd Schouten 			c -= cp2 - line2;
2120bee4c2cSEd Schouten 			if (cp + c >= linebuf + LINESIZE - 2)
2130bee4c2cSEd Schouten 				break;
2140bee4c2cSEd Schouten 			*cp++ = ' ';
2150bee4c2cSEd Schouten 			bcopy(cp2, cp, c);
2160bee4c2cSEd Schouten 			cp += c;
2170bee4c2cSEd Schouten 		}
2180bee4c2cSEd Schouten 		*cp = 0;
2190bee4c2cSEd Schouten 		return (rem);
2200bee4c2cSEd Schouten 	}
2210bee4c2cSEd Schouten 	/* NOTREACHED */
2220bee4c2cSEd Schouten }
2230bee4c2cSEd Schouten 
2240bee4c2cSEd Schouten /*
2250bee4c2cSEd Schouten  * Check whether the passed line is a header line of
2260bee4c2cSEd Schouten  * the desired breed.  Return the field body, or 0.
2270bee4c2cSEd Schouten  */
2280bee4c2cSEd Schouten 
2290bee4c2cSEd Schouten char*
2300bee4c2cSEd Schouten ishfield(linebuf, colon, field)
2310bee4c2cSEd Schouten 	char linebuf[];
2320bee4c2cSEd Schouten 	char *colon;
2330bee4c2cSEd Schouten 	const char *field;
2340bee4c2cSEd Schouten {
2350bee4c2cSEd Schouten 	char *cp = colon;
2360bee4c2cSEd Schouten 
2370bee4c2cSEd Schouten 	*cp = 0;
2380bee4c2cSEd Schouten 	if (strcasecmp(linebuf, field) != 0) {
2390bee4c2cSEd Schouten 		*cp = ':';
2400bee4c2cSEd Schouten 		return (0);
2410bee4c2cSEd Schouten 	}
2420bee4c2cSEd Schouten 	*cp = ':';
2430bee4c2cSEd Schouten 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
2440bee4c2cSEd Schouten 		;
2450bee4c2cSEd Schouten 	return (cp);
2460bee4c2cSEd Schouten }
2470bee4c2cSEd Schouten 
2480bee4c2cSEd Schouten /*
2490bee4c2cSEd Schouten  * Copy a string and lowercase the result.
2500bee4c2cSEd Schouten  * dsize: space left in buffer (including space for NULL)
2510bee4c2cSEd Schouten  */
2520bee4c2cSEd Schouten void
2530bee4c2cSEd Schouten istrncpy(dest, src, dsize)
2540bee4c2cSEd Schouten 	char *dest;
2550bee4c2cSEd Schouten 	const char *src;
2560bee4c2cSEd Schouten 	size_t dsize;
2570bee4c2cSEd Schouten {
2580bee4c2cSEd Schouten 
2590bee4c2cSEd Schouten 	strlcpy(dest, src, dsize);
2600bee4c2cSEd Schouten 	while (*dest)
2610bee4c2cSEd Schouten 		*dest++ = tolower((unsigned char)*dest);
2620bee4c2cSEd Schouten }
2630bee4c2cSEd Schouten 
2640bee4c2cSEd Schouten /*
2650bee4c2cSEd Schouten  * The following code deals with input stacking to do source
2660bee4c2cSEd Schouten  * commands.  All but the current file pointer are saved on
2670bee4c2cSEd Schouten  * the stack.
2680bee4c2cSEd Schouten  */
2690bee4c2cSEd Schouten 
2700bee4c2cSEd Schouten static	int	ssp;			/* Top of file stack */
2710bee4c2cSEd Schouten struct sstack {
2720bee4c2cSEd Schouten 	FILE	*s_file;		/* File we were in. */
2730bee4c2cSEd Schouten 	int	s_cond;			/* Saved state of conditionals */
2740bee4c2cSEd Schouten 	int	s_loading;		/* Loading .mailrc, etc. */
2750bee4c2cSEd Schouten };
2760bee4c2cSEd Schouten #define	SSTACK_SIZE	64		/* XXX was NOFILE. */
2770bee4c2cSEd Schouten static struct sstack sstack[SSTACK_SIZE];
2780bee4c2cSEd Schouten 
2790bee4c2cSEd Schouten /*
2800bee4c2cSEd Schouten  * Pushdown current input file and switch to a new one.
2810bee4c2cSEd Schouten  * Set the global flag "sourcing" so that others will realize
2820bee4c2cSEd Schouten  * that they are no longer reading from a tty (in all probability).
2830bee4c2cSEd Schouten  */
2840bee4c2cSEd Schouten int
2850bee4c2cSEd Schouten source(arglist)
2860bee4c2cSEd Schouten 	char **arglist;
2870bee4c2cSEd Schouten {
2880bee4c2cSEd Schouten 	FILE *fi;
2890bee4c2cSEd Schouten 	char *cp;
2900bee4c2cSEd Schouten 
2910bee4c2cSEd Schouten 	if ((cp = expand(*arglist)) == NULL)
2920bee4c2cSEd Schouten 		return (1);
2930bee4c2cSEd Schouten 	if ((fi = Fopen(cp, "r")) == NULL) {
2940bee4c2cSEd Schouten 		warn("%s", cp);
2950bee4c2cSEd Schouten 		return (1);
2960bee4c2cSEd Schouten 	}
2970bee4c2cSEd Schouten 	if (ssp >= SSTACK_SIZE - 1) {
2980bee4c2cSEd Schouten 		printf("Too much \"sourcing\" going on.\n");
2990bee4c2cSEd Schouten 		(void)Fclose(fi);
3000bee4c2cSEd Schouten 		return (1);
3010bee4c2cSEd Schouten 	}
3020bee4c2cSEd Schouten 	sstack[ssp].s_file = input;
3030bee4c2cSEd Schouten 	sstack[ssp].s_cond = cond;
3040bee4c2cSEd Schouten 	sstack[ssp].s_loading = loading;
3050bee4c2cSEd Schouten 	ssp++;
3060bee4c2cSEd Schouten 	loading = 0;
3070bee4c2cSEd Schouten 	cond = CANY;
3080bee4c2cSEd Schouten 	input = fi;
3090bee4c2cSEd Schouten 	sourcing++;
3100bee4c2cSEd Schouten 	return (0);
3110bee4c2cSEd Schouten }
3120bee4c2cSEd Schouten 
3130bee4c2cSEd Schouten /*
3140bee4c2cSEd Schouten  * Pop the current input back to the previous level.
3150bee4c2cSEd Schouten  * Update the "sourcing" flag as appropriate.
3160bee4c2cSEd Schouten  */
3170bee4c2cSEd Schouten int
3180bee4c2cSEd Schouten unstack()
3190bee4c2cSEd Schouten {
3200bee4c2cSEd Schouten 	if (ssp <= 0) {
3210bee4c2cSEd Schouten 		printf("\"Source\" stack over-pop.\n");
3220bee4c2cSEd Schouten 		sourcing = 0;
3230bee4c2cSEd Schouten 		return (1);
3240bee4c2cSEd Schouten 	}
3250bee4c2cSEd Schouten 	(void)Fclose(input);
3260bee4c2cSEd Schouten 	if (cond != CANY)
3270bee4c2cSEd Schouten 		printf("Unmatched \"if\"\n");
3280bee4c2cSEd Schouten 	ssp--;
3290bee4c2cSEd Schouten 	cond = sstack[ssp].s_cond;
3300bee4c2cSEd Schouten 	loading = sstack[ssp].s_loading;
3310bee4c2cSEd Schouten 	input = sstack[ssp].s_file;
3320bee4c2cSEd Schouten 	if (ssp == 0)
3330bee4c2cSEd Schouten 		sourcing = loading;
3340bee4c2cSEd Schouten 	return (0);
3350bee4c2cSEd Schouten }
3360bee4c2cSEd Schouten 
3370bee4c2cSEd Schouten /*
3380bee4c2cSEd Schouten  * Touch the indicated file.
3390bee4c2cSEd Schouten  * This is nifty for the shell.
3400bee4c2cSEd Schouten  */
3410bee4c2cSEd Schouten void
3420bee4c2cSEd Schouten alter(name)
3430bee4c2cSEd Schouten 	char *name;
3440bee4c2cSEd Schouten {
3450bee4c2cSEd Schouten 	struct stat sb;
3460bee4c2cSEd Schouten 	struct timeval tv[2];
3470bee4c2cSEd Schouten 
3480bee4c2cSEd Schouten 	if (stat(name, &sb))
3490bee4c2cSEd Schouten 		return;
3500bee4c2cSEd Schouten 	(void)gettimeofday(&tv[0], (struct timezone *)NULL);
3510bee4c2cSEd Schouten 	tv[0].tv_sec++;
35299742a23SEd Schouten 	TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtim);
3530bee4c2cSEd Schouten 	(void)utimes(name, tv);
3540bee4c2cSEd Schouten }
3550bee4c2cSEd Schouten 
3560bee4c2cSEd Schouten /*
3570bee4c2cSEd Schouten  * Get sender's name from this message.  If the message has
3580bee4c2cSEd Schouten  * a bunch of arpanet stuff in it, we may have to skin the name
3590bee4c2cSEd Schouten  * before returning it.
3600bee4c2cSEd Schouten  */
3610bee4c2cSEd Schouten char *
3620bee4c2cSEd Schouten nameof(mp, reptype)
3630bee4c2cSEd Schouten 	struct message *mp;
3640bee4c2cSEd Schouten 	int reptype;
3650bee4c2cSEd Schouten {
3660bee4c2cSEd Schouten 	char *cp, *cp2;
3670bee4c2cSEd Schouten 
3680bee4c2cSEd Schouten 	cp = skin(name1(mp, reptype));
3690bee4c2cSEd Schouten 	if (reptype != 0 || charcount(cp, '!') < 2)
3700bee4c2cSEd Schouten 		return (cp);
3710bee4c2cSEd Schouten 	cp2 = strrchr(cp, '!');
3720bee4c2cSEd Schouten 	cp2--;
3730bee4c2cSEd Schouten 	while (cp2 > cp && *cp2 != '!')
3740bee4c2cSEd Schouten 		cp2--;
3750bee4c2cSEd Schouten 	if (*cp2 == '!')
3760bee4c2cSEd Schouten 		return (cp2 + 1);
3770bee4c2cSEd Schouten 	return (cp);
3780bee4c2cSEd Schouten }
3790bee4c2cSEd Schouten 
3800bee4c2cSEd Schouten /*
3810bee4c2cSEd Schouten  * Start of a "comment".
3820bee4c2cSEd Schouten  * Ignore it.
3830bee4c2cSEd Schouten  */
3840bee4c2cSEd Schouten char *
3850bee4c2cSEd Schouten skip_comment(cp)
3860bee4c2cSEd Schouten 	char *cp;
3870bee4c2cSEd Schouten {
3880bee4c2cSEd Schouten 	int nesting = 1;
3890bee4c2cSEd Schouten 
3900bee4c2cSEd Schouten 	for (; nesting > 0 && *cp; cp++) {
3910bee4c2cSEd Schouten 		switch (*cp) {
3920bee4c2cSEd Schouten 		case '\\':
3930bee4c2cSEd Schouten 			if (cp[1])
3940bee4c2cSEd Schouten 				cp++;
3950bee4c2cSEd Schouten 			break;
3960bee4c2cSEd Schouten 		case '(':
3970bee4c2cSEd Schouten 			nesting++;
3980bee4c2cSEd Schouten 			break;
3990bee4c2cSEd Schouten 		case ')':
4000bee4c2cSEd Schouten 			nesting--;
4010bee4c2cSEd Schouten 			break;
4020bee4c2cSEd Schouten 		}
4030bee4c2cSEd Schouten 	}
4040bee4c2cSEd Schouten 	return (cp);
4050bee4c2cSEd Schouten }
4060bee4c2cSEd Schouten 
4070bee4c2cSEd Schouten /*
4080bee4c2cSEd Schouten  * Skin an arpa net address according to the RFC 822 interpretation
4090bee4c2cSEd Schouten  * of "host-phrase."
4100bee4c2cSEd Schouten  */
4110bee4c2cSEd Schouten char *
4120bee4c2cSEd Schouten skin(name)
4130bee4c2cSEd Schouten 	char *name;
4140bee4c2cSEd Schouten {
4150bee4c2cSEd Schouten 	char *nbuf, *bufend, *cp, *cp2;
4160bee4c2cSEd Schouten 	int c, gotlt, lastsp;
4170bee4c2cSEd Schouten 
4180bee4c2cSEd Schouten 	if (name == NULL)
4190bee4c2cSEd Schouten 		return (NULL);
4200bee4c2cSEd Schouten 	if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
4210bee4c2cSEd Schouten 	    && strchr(name, ' ') == NULL)
4220bee4c2cSEd Schouten 		return (name);
4230bee4c2cSEd Schouten 
4240bee4c2cSEd Schouten 	/* We assume that length(input) <= length(output) */
4250bee4c2cSEd Schouten 	if ((nbuf = malloc(strlen(name) + 1)) == NULL)
4260bee4c2cSEd Schouten 		err(1, "Out of memory");
4270bee4c2cSEd Schouten 	gotlt = 0;
4280bee4c2cSEd Schouten 	lastsp = 0;
4290bee4c2cSEd Schouten 	bufend = nbuf;
4300bee4c2cSEd Schouten 	for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
4310bee4c2cSEd Schouten 		switch (c) {
4320bee4c2cSEd Schouten 		case '(':
4330bee4c2cSEd Schouten 			cp = skip_comment(cp);
4340bee4c2cSEd Schouten 			lastsp = 0;
4350bee4c2cSEd Schouten 			break;
4360bee4c2cSEd Schouten 
4370bee4c2cSEd Schouten 		case '"':
4380bee4c2cSEd Schouten 			/*
4390bee4c2cSEd Schouten 			 * Start of a "quoted-string".
4400bee4c2cSEd Schouten 			 * Copy it in its entirety.
4410bee4c2cSEd Schouten 			 */
4420bee4c2cSEd Schouten 			while ((c = *cp) != '\0') {
4430bee4c2cSEd Schouten 				cp++;
4440bee4c2cSEd Schouten 				if (c == '"')
4450bee4c2cSEd Schouten 					break;
4460bee4c2cSEd Schouten 				if (c != '\\')
4470bee4c2cSEd Schouten 					*cp2++ = c;
4480bee4c2cSEd Schouten 				else if ((c = *cp) != '\0') {
4490bee4c2cSEd Schouten 					*cp2++ = c;
4500bee4c2cSEd Schouten 					cp++;
4510bee4c2cSEd Schouten 				}
4520bee4c2cSEd Schouten 			}
4530bee4c2cSEd Schouten 			lastsp = 0;
4540bee4c2cSEd Schouten 			break;
4550bee4c2cSEd Schouten 
4560bee4c2cSEd Schouten 		case ' ':
4570bee4c2cSEd Schouten 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
4580bee4c2cSEd Schouten 				cp += 3, *cp2++ = '@';
4590bee4c2cSEd Schouten 			else
4600bee4c2cSEd Schouten 			if (cp[0] == '@' && cp[1] == ' ')
4610bee4c2cSEd Schouten 				cp += 2, *cp2++ = '@';
4620bee4c2cSEd Schouten 			else
4630bee4c2cSEd Schouten 				lastsp = 1;
4640bee4c2cSEd Schouten 			break;
4650bee4c2cSEd Schouten 
4660bee4c2cSEd Schouten 		case '<':
4670bee4c2cSEd Schouten 			cp2 = bufend;
4680bee4c2cSEd Schouten 			gotlt++;
4690bee4c2cSEd Schouten 			lastsp = 0;
4700bee4c2cSEd Schouten 			break;
4710bee4c2cSEd Schouten 
4720bee4c2cSEd Schouten 		case '>':
4730bee4c2cSEd Schouten 			if (gotlt) {
4740bee4c2cSEd Schouten 				gotlt = 0;
4750bee4c2cSEd Schouten 				while ((c = *cp) != '\0' && c != ',') {
4760bee4c2cSEd Schouten 					cp++;
4770bee4c2cSEd Schouten 					if (c == '(')
4780bee4c2cSEd Schouten 						cp = skip_comment(cp);
4790bee4c2cSEd Schouten 					else if (c == '"')
4800bee4c2cSEd Schouten 						while ((c = *cp) != '\0') {
4810bee4c2cSEd Schouten 							cp++;
4820bee4c2cSEd Schouten 							if (c == '"')
4830bee4c2cSEd Schouten 								break;
4840bee4c2cSEd Schouten 							if (c == '\\' && *cp != '\0')
4850bee4c2cSEd Schouten 								cp++;
4860bee4c2cSEd Schouten 						}
4870bee4c2cSEd Schouten 				}
4880bee4c2cSEd Schouten 				lastsp = 0;
4890bee4c2cSEd Schouten 				break;
4900bee4c2cSEd Schouten 			}
4910bee4c2cSEd Schouten 			/* FALLTHROUGH */
4920bee4c2cSEd Schouten 
4930bee4c2cSEd Schouten 		default:
4940bee4c2cSEd Schouten 			if (lastsp) {
4950bee4c2cSEd Schouten 				lastsp = 0;
4960bee4c2cSEd Schouten 				*cp2++ = ' ';
4970bee4c2cSEd Schouten 			}
4980bee4c2cSEd Schouten 			*cp2++ = c;
499*a1d170a0SUlrich Spörlein 			if (c == ',' && !gotlt &&
500*a1d170a0SUlrich Spörlein 			    (*cp == ' ' || *cp == '"' || *cp == '<')) {
5010bee4c2cSEd Schouten 				*cp2++ = ' ';
502*a1d170a0SUlrich Spörlein 				while (*cp == ' ')
503*a1d170a0SUlrich Spörlein 					cp++;
5040bee4c2cSEd Schouten 				lastsp = 0;
5050bee4c2cSEd Schouten 				bufend = cp2;
5060bee4c2cSEd Schouten 			}
5070bee4c2cSEd Schouten 		}
5080bee4c2cSEd Schouten 	}
5090bee4c2cSEd Schouten 	*cp2 = '\0';
5100bee4c2cSEd Schouten 
5110bee4c2cSEd Schouten 	if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
5120bee4c2cSEd Schouten 		nbuf = cp;
5130bee4c2cSEd Schouten 	return (nbuf);
5140bee4c2cSEd Schouten }
5150bee4c2cSEd Schouten 
5160bee4c2cSEd Schouten /*
5170bee4c2cSEd Schouten  * Fetch the sender's name from the passed message.
5180bee4c2cSEd Schouten  * Reptype can be
5190bee4c2cSEd Schouten  *	0 -- get sender's name for display purposes
5200bee4c2cSEd Schouten  *	1 -- get sender's name for reply
5210bee4c2cSEd Schouten  *	2 -- get sender's name for Reply
5220bee4c2cSEd Schouten  */
5230bee4c2cSEd Schouten char *
5240bee4c2cSEd Schouten name1(mp, reptype)
5250bee4c2cSEd Schouten 	struct message *mp;
5260bee4c2cSEd Schouten 	int reptype;
5270bee4c2cSEd Schouten {
5280bee4c2cSEd Schouten 	char namebuf[LINESIZE];
5290bee4c2cSEd Schouten 	char linebuf[LINESIZE];
5300bee4c2cSEd Schouten 	char *cp, *cp2;
5310bee4c2cSEd Schouten 	FILE *ibuf;
5320bee4c2cSEd Schouten 	int first = 1;
5330bee4c2cSEd Schouten 
5340bee4c2cSEd Schouten 	if ((cp = hfield("from", mp)) != NULL)
5350bee4c2cSEd Schouten 		return (cp);
5360bee4c2cSEd Schouten 	if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
5370bee4c2cSEd Schouten 		return (cp);
5380bee4c2cSEd Schouten 	ibuf = setinput(mp);
5390bee4c2cSEd Schouten 	namebuf[0] = '\0';
5400bee4c2cSEd Schouten 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5410bee4c2cSEd Schouten 		return (savestr(namebuf));
5420bee4c2cSEd Schouten newname:
5430bee4c2cSEd Schouten 	for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
5440bee4c2cSEd Schouten 		;
5450bee4c2cSEd Schouten 	for (; *cp == ' ' || *cp == '\t'; cp++)
5460bee4c2cSEd Schouten 		;
5470bee4c2cSEd Schouten 	for (cp2 = &namebuf[strlen(namebuf)];
5480bee4c2cSEd Schouten 	    *cp != '\0' && *cp != ' ' && *cp != '\t' &&
5490bee4c2cSEd Schouten 	    cp2 < namebuf + LINESIZE - 1;)
5500bee4c2cSEd Schouten 		*cp2++ = *cp++;
5510bee4c2cSEd Schouten 	*cp2 = '\0';
5520bee4c2cSEd Schouten 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5530bee4c2cSEd Schouten 		return (savestr(namebuf));
5540bee4c2cSEd Schouten 	if ((cp = strchr(linebuf, 'F')) == NULL)
5550bee4c2cSEd Schouten 		return (savestr(namebuf));
5560bee4c2cSEd Schouten 	if (strncmp(cp, "From", 4) != 0)
5570bee4c2cSEd Schouten 		return (savestr(namebuf));
5580bee4c2cSEd Schouten 	while ((cp = strchr(cp, 'r')) != NULL) {
5590bee4c2cSEd Schouten 		if (strncmp(cp, "remote", 6) == 0) {
5600bee4c2cSEd Schouten 			if ((cp = strchr(cp, 'f')) == NULL)
5610bee4c2cSEd Schouten 				break;
5620bee4c2cSEd Schouten 			if (strncmp(cp, "from", 4) != 0)
5630bee4c2cSEd Schouten 				break;
5640bee4c2cSEd Schouten 			if ((cp = strchr(cp, ' ')) == NULL)
5650bee4c2cSEd Schouten 				break;
5660bee4c2cSEd Schouten 			cp++;
5670bee4c2cSEd Schouten 			if (first) {
5680bee4c2cSEd Schouten 				cp2 = namebuf;
5690bee4c2cSEd Schouten 				first = 0;
5700bee4c2cSEd Schouten 			} else
5710bee4c2cSEd Schouten 				cp2 = strrchr(namebuf, '!') + 1;
5720bee4c2cSEd Schouten 			strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
5730bee4c2cSEd Schouten 			strcat(namebuf, "!");
5740bee4c2cSEd Schouten 			goto newname;
5750bee4c2cSEd Schouten 		}
5760bee4c2cSEd Schouten 		cp++;
5770bee4c2cSEd Schouten 	}
5780bee4c2cSEd Schouten 	return (savestr(namebuf));
5790bee4c2cSEd Schouten }
5800bee4c2cSEd Schouten 
5810bee4c2cSEd Schouten /*
5820bee4c2cSEd Schouten  * Count the occurances of c in str
5830bee4c2cSEd Schouten  */
5840bee4c2cSEd Schouten int
5850bee4c2cSEd Schouten charcount(str, c)
5860bee4c2cSEd Schouten 	char *str;
5870bee4c2cSEd Schouten 	int c;
5880bee4c2cSEd Schouten {
5890bee4c2cSEd Schouten 	char *cp;
5900bee4c2cSEd Schouten 	int i;
5910bee4c2cSEd Schouten 
5920bee4c2cSEd Schouten 	for (i = 0, cp = str; *cp != '\0'; cp++)
5930bee4c2cSEd Schouten 		if (*cp == c)
5940bee4c2cSEd Schouten 			i++;
5950bee4c2cSEd Schouten 	return (i);
5960bee4c2cSEd Schouten }
5970bee4c2cSEd Schouten 
5980bee4c2cSEd Schouten /*
5990bee4c2cSEd Schouten  * See if the given header field is supposed to be ignored.
6000bee4c2cSEd Schouten  */
6010bee4c2cSEd Schouten int
6020bee4c2cSEd Schouten isign(field, ignore)
6030bee4c2cSEd Schouten 	const char *field;
6040bee4c2cSEd Schouten 	struct ignoretab ignore[2];
6050bee4c2cSEd Schouten {
6060bee4c2cSEd Schouten 	char realfld[LINESIZE];
6070bee4c2cSEd Schouten 
6080bee4c2cSEd Schouten 	if (ignore == ignoreall)
6090bee4c2cSEd Schouten 		return (1);
6100bee4c2cSEd Schouten 	/*
6110bee4c2cSEd Schouten 	 * Lower-case the string, so that "Status" and "status"
6120bee4c2cSEd Schouten 	 * will hash to the same place.
6130bee4c2cSEd Schouten 	 */
6140bee4c2cSEd Schouten 	istrncpy(realfld, field, sizeof(realfld));
6150bee4c2cSEd Schouten 	if (ignore[1].i_count > 0)
6160bee4c2cSEd Schouten 		return (!member(realfld, ignore + 1));
6170bee4c2cSEd Schouten 	else
6180bee4c2cSEd Schouten 		return (member(realfld, ignore));
6190bee4c2cSEd Schouten }
6200bee4c2cSEd Schouten 
6210bee4c2cSEd Schouten int
6220bee4c2cSEd Schouten member(realfield, table)
6230bee4c2cSEd Schouten 	char *realfield;
6240bee4c2cSEd Schouten 	struct ignoretab *table;
6250bee4c2cSEd Schouten {
6260bee4c2cSEd Schouten 	struct ignore *igp;
6270bee4c2cSEd Schouten 
6280bee4c2cSEd Schouten 	for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
6290bee4c2cSEd Schouten 		if (*igp->i_field == *realfield &&
6300bee4c2cSEd Schouten 		    equal(igp->i_field, realfield))
6310bee4c2cSEd Schouten 			return (1);
6320bee4c2cSEd Schouten 	return (0);
6330bee4c2cSEd Schouten }
634