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