xref: /freebsd/usr.bin/mail/util.c (revision 5e3934b15a2741b2de6b217e77dc9d798d740804)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro 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 #include <sys/time.h>
330bee4c2cSEd Schouten 
34ae7d5745SJilles Tjoelker #include <fcntl.h>
35ae7d5745SJilles Tjoelker 
360bee4c2cSEd Schouten #include "rcv.h"
370bee4c2cSEd Schouten #include "extern.h"
380bee4c2cSEd Schouten 
390bee4c2cSEd Schouten /*
400bee4c2cSEd Schouten  * Mail -- a mail program
410bee4c2cSEd Schouten  *
420bee4c2cSEd Schouten  * Auxiliary functions.
430bee4c2cSEd Schouten  */
440bee4c2cSEd Schouten 
450bee4c2cSEd Schouten static char *save2str(char *, char *);
460bee4c2cSEd Schouten 
470bee4c2cSEd Schouten /*
480bee4c2cSEd Schouten  * Return a pointer to a dynamic copy of the argument.
490bee4c2cSEd Schouten  */
500bee4c2cSEd Schouten char *
savestr(char * str)516d8484b0SPhilippe Charnier savestr(char *str)
520bee4c2cSEd Schouten {
530bee4c2cSEd Schouten 	char *new;
540bee4c2cSEd Schouten 	int size = strlen(str) + 1;
550bee4c2cSEd Schouten 
560bee4c2cSEd Schouten 	if ((new = salloc(size)) != NULL)
570bee4c2cSEd Schouten 		bcopy(str, new, size);
580bee4c2cSEd Schouten 	return (new);
590bee4c2cSEd Schouten }
600bee4c2cSEd Schouten 
610bee4c2cSEd Schouten /*
620bee4c2cSEd Schouten  * Make a copy of new argument incorporating old one.
630bee4c2cSEd Schouten  */
640bee4c2cSEd Schouten static char *
save2str(char * str,char * old)656d8484b0SPhilippe Charnier save2str(char *str, char *old)
660bee4c2cSEd Schouten {
670bee4c2cSEd Schouten 	char *new;
680bee4c2cSEd Schouten 	int newsize = strlen(str) + 1;
690bee4c2cSEd Schouten 	int oldsize = old ? strlen(old) + 1 : 0;
700bee4c2cSEd Schouten 
710bee4c2cSEd Schouten 	if ((new = salloc(newsize + oldsize)) != NULL) {
720bee4c2cSEd Schouten 		if (oldsize) {
730bee4c2cSEd Schouten 			bcopy(old, new, oldsize);
740bee4c2cSEd Schouten 			new[oldsize - 1] = ' ';
750bee4c2cSEd Schouten 		}
760bee4c2cSEd Schouten 		bcopy(str, new + oldsize, newsize);
770bee4c2cSEd Schouten 	}
780bee4c2cSEd Schouten 	return (new);
790bee4c2cSEd Schouten }
800bee4c2cSEd Schouten 
810bee4c2cSEd Schouten /*
820bee4c2cSEd Schouten  * Touch the named message by setting its MTOUCH flag.
830bee4c2cSEd Schouten  * Touched messages have the effect of not being sent
840bee4c2cSEd Schouten  * back to the system mailbox on exit.
850bee4c2cSEd Schouten  */
860bee4c2cSEd Schouten void
touch(struct message * mp)876d8484b0SPhilippe Charnier touch(struct message *mp)
880bee4c2cSEd Schouten {
890bee4c2cSEd Schouten 
900bee4c2cSEd Schouten 	mp->m_flag |= MTOUCH;
910bee4c2cSEd Schouten 	if ((mp->m_flag & MREAD) == 0)
920bee4c2cSEd Schouten 		mp->m_flag |= MREAD|MSTATUS;
930bee4c2cSEd Schouten }
940bee4c2cSEd Schouten 
950bee4c2cSEd Schouten /*
960bee4c2cSEd Schouten  * Test to see if the passed file name is a directory.
970bee4c2cSEd Schouten  * Return true if it is.
980bee4c2cSEd Schouten  */
990bee4c2cSEd Schouten int
isdir(char name[])1006d8484b0SPhilippe Charnier isdir(char name[])
1010bee4c2cSEd Schouten {
1020bee4c2cSEd Schouten 	struct stat sbuf;
1030bee4c2cSEd Schouten 
1040bee4c2cSEd Schouten 	if (stat(name, &sbuf) < 0)
1050bee4c2cSEd Schouten 		return (0);
1060bee4c2cSEd Schouten 	return (S_ISDIR(sbuf.st_mode));
1070bee4c2cSEd Schouten }
1080bee4c2cSEd Schouten 
1090bee4c2cSEd Schouten /*
1100bee4c2cSEd Schouten  * Count the number of arguments in the given string raw list.
1110bee4c2cSEd Schouten  */
1120bee4c2cSEd Schouten int
argcount(char ** argv)1136d8484b0SPhilippe Charnier argcount(char **argv)
1140bee4c2cSEd Schouten {
1150bee4c2cSEd Schouten 	char **ap;
1160bee4c2cSEd Schouten 
1170bee4c2cSEd Schouten 	for (ap = argv; *ap++ != NULL;)
1180bee4c2cSEd Schouten 		;
1190bee4c2cSEd Schouten 	return (ap - argv - 1);
1200bee4c2cSEd Schouten }
1210bee4c2cSEd Schouten 
1220bee4c2cSEd Schouten /*
1230bee4c2cSEd Schouten  * Return the desired header line from the passed message
1240bee4c2cSEd Schouten  * pointer (or NULL if the desired header field is not available).
1250bee4c2cSEd Schouten  */
1260bee4c2cSEd Schouten char *
hfield(const char * field,struct message * mp)1276d8484b0SPhilippe Charnier hfield(const char *field, struct message *mp)
1280bee4c2cSEd Schouten {
1290bee4c2cSEd Schouten 	FILE *ibuf;
1300bee4c2cSEd Schouten 	char linebuf[LINESIZE];
1310bee4c2cSEd Schouten 	int lc;
1320bee4c2cSEd Schouten 	char *hfield;
1330bee4c2cSEd Schouten 	char *colon, *oldhfield = NULL;
1340bee4c2cSEd Schouten 
1350bee4c2cSEd Schouten 	ibuf = setinput(mp);
1360bee4c2cSEd Schouten 	if ((lc = mp->m_lines - 1) < 0)
1370bee4c2cSEd Schouten 		return (NULL);
1380bee4c2cSEd Schouten 	if (readline(ibuf, linebuf, LINESIZE) < 0)
1390bee4c2cSEd Schouten 		return (NULL);
1400bee4c2cSEd Schouten 	while (lc > 0) {
1410bee4c2cSEd Schouten 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
1420bee4c2cSEd Schouten 			return (oldhfield);
1430bee4c2cSEd Schouten 		if ((hfield = ishfield(linebuf, colon, field)) != NULL)
1440bee4c2cSEd Schouten 			oldhfield = save2str(hfield, oldhfield);
1450bee4c2cSEd Schouten 	}
1460bee4c2cSEd Schouten 	return (oldhfield);
1470bee4c2cSEd Schouten }
1480bee4c2cSEd Schouten 
1490bee4c2cSEd Schouten /*
1500bee4c2cSEd Schouten  * Return the next header field found in the given message.
1510bee4c2cSEd Schouten  * Return >= 0 if something found, < 0 elsewise.
1520bee4c2cSEd Schouten  * "colon" is set to point to the colon in the header.
1530bee4c2cSEd Schouten  * Must deal with \ continuations & other such fraud.
1540bee4c2cSEd Schouten  */
1550bee4c2cSEd Schouten int
gethfield(FILE * f,char linebuf[],int rem,char ** colon)1566d8484b0SPhilippe Charnier gethfield(FILE *f, char linebuf[], int rem, char **colon)
1570bee4c2cSEd Schouten {
1580bee4c2cSEd Schouten 	char line2[LINESIZE];
1590bee4c2cSEd Schouten 	char *cp, *cp2;
1600bee4c2cSEd Schouten 	int c;
1610bee4c2cSEd Schouten 
1620bee4c2cSEd Schouten 	for (;;) {
1630bee4c2cSEd Schouten 		if (--rem < 0)
1640bee4c2cSEd Schouten 			return (-1);
1650bee4c2cSEd Schouten 		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
1660bee4c2cSEd Schouten 			return (-1);
1670bee4c2cSEd Schouten 		for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
1680bee4c2cSEd Schouten 		    cp++)
1690bee4c2cSEd Schouten 			;
1700bee4c2cSEd Schouten 		if (*cp != ':' || cp == linebuf)
1710bee4c2cSEd Schouten 			continue;
1720bee4c2cSEd Schouten 		/*
1730bee4c2cSEd Schouten 		 * I guess we got a headline.
1740bee4c2cSEd Schouten 		 * Handle wraparounding
1750bee4c2cSEd Schouten 		 */
1760bee4c2cSEd Schouten 		*colon = cp;
1770bee4c2cSEd Schouten 		cp = linebuf + c;
1780bee4c2cSEd Schouten 		for (;;) {
1790bee4c2cSEd Schouten 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
1800bee4c2cSEd Schouten 				;
1810bee4c2cSEd Schouten 			cp++;
1820bee4c2cSEd Schouten 			if (rem <= 0)
1830bee4c2cSEd Schouten 				break;
1840bee4c2cSEd Schouten 			ungetc(c = getc(f), f);
1850bee4c2cSEd Schouten 			if (c != ' ' && c != '\t')
1860bee4c2cSEd Schouten 				break;
1870bee4c2cSEd Schouten 			if ((c = readline(f, line2, LINESIZE)) < 0)
1880bee4c2cSEd Schouten 				break;
1890bee4c2cSEd Schouten 			rem--;
1900bee4c2cSEd Schouten 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
1910bee4c2cSEd Schouten 				;
1920bee4c2cSEd Schouten 			c -= cp2 - line2;
1930bee4c2cSEd Schouten 			if (cp + c >= linebuf + LINESIZE - 2)
1940bee4c2cSEd Schouten 				break;
1950bee4c2cSEd Schouten 			*cp++ = ' ';
1960bee4c2cSEd Schouten 			bcopy(cp2, cp, c);
1970bee4c2cSEd Schouten 			cp += c;
1980bee4c2cSEd Schouten 		}
1990bee4c2cSEd Schouten 		*cp = 0;
2000bee4c2cSEd Schouten 		return (rem);
2010bee4c2cSEd Schouten 	}
2020bee4c2cSEd Schouten 	/* NOTREACHED */
2030bee4c2cSEd Schouten }
2040bee4c2cSEd Schouten 
2050bee4c2cSEd Schouten /*
2060bee4c2cSEd Schouten  * Check whether the passed line is a header line of
2070bee4c2cSEd Schouten  * the desired breed.  Return the field body, or 0.
2080bee4c2cSEd Schouten  */
2090bee4c2cSEd Schouten 
2100bee4c2cSEd Schouten char*
ishfield(char * linebuf,char * colon,const char * field)211eeb341a9SPedro F. Giffuni ishfield(char *linebuf, char *colon, const char *field)
2120bee4c2cSEd Schouten {
2130bee4c2cSEd Schouten 	char *cp = colon;
2140bee4c2cSEd Schouten 
2150bee4c2cSEd Schouten 	*cp = 0;
2160bee4c2cSEd Schouten 	if (strcasecmp(linebuf, field) != 0) {
2170bee4c2cSEd Schouten 		*cp = ':';
2180bee4c2cSEd Schouten 		return (0);
2190bee4c2cSEd Schouten 	}
2200bee4c2cSEd Schouten 	*cp = ':';
2210bee4c2cSEd Schouten 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
2220bee4c2cSEd Schouten 		;
2230bee4c2cSEd Schouten 	return (cp);
2240bee4c2cSEd Schouten }
2250bee4c2cSEd Schouten 
2260bee4c2cSEd Schouten /*
2270bee4c2cSEd Schouten  * Copy a string and lowercase the result.
2280bee4c2cSEd Schouten  * dsize: space left in buffer (including space for NULL)
2290bee4c2cSEd Schouten  */
2300bee4c2cSEd Schouten void
istrncpy(char * dest,const char * src,size_t dsize)2316d8484b0SPhilippe Charnier istrncpy(char *dest, const char *src, size_t dsize)
2320bee4c2cSEd Schouten {
2330bee4c2cSEd Schouten 
2340bee4c2cSEd Schouten 	strlcpy(dest, src, dsize);
235ca83b975SDimitry Andric 	for (; *dest; dest++)
236ca83b975SDimitry Andric 		*dest = tolower((unsigned char)*dest);
2370bee4c2cSEd Schouten }
2380bee4c2cSEd Schouten 
2390bee4c2cSEd Schouten /*
2400bee4c2cSEd Schouten  * The following code deals with input stacking to do source
2410bee4c2cSEd Schouten  * commands.  All but the current file pointer are saved on
2420bee4c2cSEd Schouten  * the stack.
2430bee4c2cSEd Schouten  */
2440bee4c2cSEd Schouten 
2450bee4c2cSEd Schouten static	int	ssp;			/* Top of file stack */
2460bee4c2cSEd Schouten struct sstack {
2470bee4c2cSEd Schouten 	FILE	*s_file;		/* File we were in. */
2480bee4c2cSEd Schouten 	int	s_cond;			/* Saved state of conditionals */
2490bee4c2cSEd Schouten 	int	s_loading;		/* Loading .mailrc, etc. */
2500bee4c2cSEd Schouten };
2510bee4c2cSEd Schouten #define	SSTACK_SIZE	64		/* XXX was NOFILE. */
2520bee4c2cSEd Schouten static struct sstack sstack[SSTACK_SIZE];
2530bee4c2cSEd Schouten 
2540bee4c2cSEd Schouten /*
2550bee4c2cSEd Schouten  * Pushdown current input file and switch to a new one.
2560bee4c2cSEd Schouten  * Set the global flag "sourcing" so that others will realize
2570bee4c2cSEd Schouten  * that they are no longer reading from a tty (in all probability).
2580bee4c2cSEd Schouten  */
2590bee4c2cSEd Schouten int
source(void * arg)260*d28a9551SJohn Baldwin source(void *arg)
2610bee4c2cSEd Schouten {
262*d28a9551SJohn Baldwin 	char **arglist = arg;
2630bee4c2cSEd Schouten 	FILE *fi;
2640bee4c2cSEd Schouten 	char *cp;
2650bee4c2cSEd Schouten 
2660bee4c2cSEd Schouten 	if ((cp = expand(*arglist)) == NULL)
2670bee4c2cSEd Schouten 		return (1);
2680bee4c2cSEd Schouten 	if ((fi = Fopen(cp, "r")) == NULL) {
2690bee4c2cSEd Schouten 		warn("%s", cp);
2700bee4c2cSEd Schouten 		return (1);
2710bee4c2cSEd Schouten 	}
2720bee4c2cSEd Schouten 	if (ssp >= SSTACK_SIZE - 1) {
2730bee4c2cSEd Schouten 		printf("Too much \"sourcing\" going on.\n");
2740bee4c2cSEd Schouten 		(void)Fclose(fi);
2750bee4c2cSEd Schouten 		return (1);
2760bee4c2cSEd Schouten 	}
2770bee4c2cSEd Schouten 	sstack[ssp].s_file = input;
2780bee4c2cSEd Schouten 	sstack[ssp].s_cond = cond;
2790bee4c2cSEd Schouten 	sstack[ssp].s_loading = loading;
2800bee4c2cSEd Schouten 	ssp++;
2810bee4c2cSEd Schouten 	loading = 0;
2820bee4c2cSEd Schouten 	cond = CANY;
2830bee4c2cSEd Schouten 	input = fi;
2840bee4c2cSEd Schouten 	sourcing++;
2850bee4c2cSEd Schouten 	return (0);
2860bee4c2cSEd Schouten }
2870bee4c2cSEd Schouten 
2880bee4c2cSEd Schouten /*
2890bee4c2cSEd Schouten  * Pop the current input back to the previous level.
2900bee4c2cSEd Schouten  * Update the "sourcing" flag as appropriate.
2910bee4c2cSEd Schouten  */
2920bee4c2cSEd Schouten int
unstack(void)2936d8484b0SPhilippe Charnier unstack(void)
2940bee4c2cSEd Schouten {
2950bee4c2cSEd Schouten 	if (ssp <= 0) {
2960bee4c2cSEd Schouten 		printf("\"Source\" stack over-pop.\n");
2970bee4c2cSEd Schouten 		sourcing = 0;
2980bee4c2cSEd Schouten 		return (1);
2990bee4c2cSEd Schouten 	}
3000bee4c2cSEd Schouten 	(void)Fclose(input);
3010bee4c2cSEd Schouten 	if (cond != CANY)
3020bee4c2cSEd Schouten 		printf("Unmatched \"if\"\n");
3030bee4c2cSEd Schouten 	ssp--;
3040bee4c2cSEd Schouten 	cond = sstack[ssp].s_cond;
3050bee4c2cSEd Schouten 	loading = sstack[ssp].s_loading;
3060bee4c2cSEd Schouten 	input = sstack[ssp].s_file;
3070bee4c2cSEd Schouten 	if (ssp == 0)
3080bee4c2cSEd Schouten 		sourcing = loading;
3090bee4c2cSEd Schouten 	return (0);
3100bee4c2cSEd Schouten }
3110bee4c2cSEd Schouten 
3120bee4c2cSEd Schouten /*
3130bee4c2cSEd Schouten  * Touch the indicated file.
3140bee4c2cSEd Schouten  * This is nifty for the shell.
3150bee4c2cSEd Schouten  */
3160bee4c2cSEd Schouten void
alter(char * name)3176d8484b0SPhilippe Charnier alter(char *name)
3180bee4c2cSEd Schouten {
319ae7d5745SJilles Tjoelker 	struct timespec ts[2];
3200bee4c2cSEd Schouten 
321ae7d5745SJilles Tjoelker 	(void)clock_gettime(CLOCK_REALTIME, &ts[0]);
322ae7d5745SJilles Tjoelker 	ts[0].tv_sec++;
323ae7d5745SJilles Tjoelker 	ts[1].tv_sec = 0;
324ae7d5745SJilles Tjoelker 	ts[1].tv_nsec = UTIME_OMIT;
325ae7d5745SJilles Tjoelker 	(void)utimensat(AT_FDCWD, name, ts, 0);
3260bee4c2cSEd Schouten }
3270bee4c2cSEd Schouten 
3280bee4c2cSEd Schouten /*
3290bee4c2cSEd Schouten  * Get sender's name from this message.  If the message has
3300bee4c2cSEd Schouten  * a bunch of arpanet stuff in it, we may have to skin the name
3310bee4c2cSEd Schouten  * before returning it.
3320bee4c2cSEd Schouten  */
3330bee4c2cSEd Schouten char *
nameof(struct message * mp,int reptype)3346d8484b0SPhilippe Charnier nameof(struct message *mp, int reptype)
3350bee4c2cSEd Schouten {
3360bee4c2cSEd Schouten 	char *cp, *cp2;
3370bee4c2cSEd Schouten 
3380bee4c2cSEd Schouten 	cp = skin(name1(mp, reptype));
3390bee4c2cSEd Schouten 	if (reptype != 0 || charcount(cp, '!') < 2)
3400bee4c2cSEd Schouten 		return (cp);
3410bee4c2cSEd Schouten 	cp2 = strrchr(cp, '!');
3420bee4c2cSEd Schouten 	cp2--;
3430bee4c2cSEd Schouten 	while (cp2 > cp && *cp2 != '!')
3440bee4c2cSEd Schouten 		cp2--;
3450bee4c2cSEd Schouten 	if (*cp2 == '!')
3460bee4c2cSEd Schouten 		return (cp2 + 1);
3470bee4c2cSEd Schouten 	return (cp);
3480bee4c2cSEd Schouten }
3490bee4c2cSEd Schouten 
3500bee4c2cSEd Schouten /*
3510bee4c2cSEd Schouten  * Start of a "comment".
3520bee4c2cSEd Schouten  * Ignore it.
3530bee4c2cSEd Schouten  */
3540bee4c2cSEd Schouten char *
skip_comment(char * cp)3556d8484b0SPhilippe Charnier skip_comment(char *cp)
3560bee4c2cSEd Schouten {
3570bee4c2cSEd Schouten 	int nesting = 1;
3580bee4c2cSEd Schouten 
3590bee4c2cSEd Schouten 	for (; nesting > 0 && *cp; cp++) {
3600bee4c2cSEd Schouten 		switch (*cp) {
3610bee4c2cSEd Schouten 		case '\\':
3620bee4c2cSEd Schouten 			if (cp[1])
3630bee4c2cSEd Schouten 				cp++;
3640bee4c2cSEd Schouten 			break;
3650bee4c2cSEd Schouten 		case '(':
3660bee4c2cSEd Schouten 			nesting++;
3670bee4c2cSEd Schouten 			break;
3680bee4c2cSEd Schouten 		case ')':
3690bee4c2cSEd Schouten 			nesting--;
3700bee4c2cSEd Schouten 			break;
3710bee4c2cSEd Schouten 		}
3720bee4c2cSEd Schouten 	}
3730bee4c2cSEd Schouten 	return (cp);
3740bee4c2cSEd Schouten }
3750bee4c2cSEd Schouten 
3760bee4c2cSEd Schouten /*
3770bee4c2cSEd Schouten  * Skin an arpa net address according to the RFC 822 interpretation
3780bee4c2cSEd Schouten  * of "host-phrase."
3790bee4c2cSEd Schouten  */
3800bee4c2cSEd Schouten char *
skin(char * name)3816d8484b0SPhilippe Charnier skin(char *name)
3820bee4c2cSEd Schouten {
3830bee4c2cSEd Schouten 	char *nbuf, *bufend, *cp, *cp2;
3840bee4c2cSEd Schouten 	int c, gotlt, lastsp;
3850bee4c2cSEd Schouten 
3860bee4c2cSEd Schouten 	if (name == NULL)
3870bee4c2cSEd Schouten 		return (NULL);
3880bee4c2cSEd Schouten 	if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
3890bee4c2cSEd Schouten 	    && strchr(name, ' ') == NULL)
3900bee4c2cSEd Schouten 		return (name);
3910bee4c2cSEd Schouten 
3920bee4c2cSEd Schouten 	/* We assume that length(input) <= length(output) */
3930bee4c2cSEd Schouten 	if ((nbuf = malloc(strlen(name) + 1)) == NULL)
3940bee4c2cSEd Schouten 		err(1, "Out of memory");
3950bee4c2cSEd Schouten 	gotlt = 0;
3960bee4c2cSEd Schouten 	lastsp = 0;
3970bee4c2cSEd Schouten 	bufend = nbuf;
3980bee4c2cSEd Schouten 	for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
3990bee4c2cSEd Schouten 		switch (c) {
4000bee4c2cSEd Schouten 		case '(':
4010bee4c2cSEd Schouten 			cp = skip_comment(cp);
4020bee4c2cSEd Schouten 			lastsp = 0;
4030bee4c2cSEd Schouten 			break;
4040bee4c2cSEd Schouten 
4050bee4c2cSEd Schouten 		case '"':
4060bee4c2cSEd Schouten 			/*
4070bee4c2cSEd Schouten 			 * Start of a "quoted-string".
4080bee4c2cSEd Schouten 			 * Copy it in its entirety.
4090bee4c2cSEd Schouten 			 */
4100bee4c2cSEd Schouten 			while ((c = *cp) != '\0') {
4110bee4c2cSEd Schouten 				cp++;
4120bee4c2cSEd Schouten 				if (c == '"')
4130bee4c2cSEd Schouten 					break;
4140bee4c2cSEd Schouten 				if (c != '\\')
4150bee4c2cSEd Schouten 					*cp2++ = c;
4160bee4c2cSEd Schouten 				else if ((c = *cp) != '\0') {
4170bee4c2cSEd Schouten 					*cp2++ = c;
4180bee4c2cSEd Schouten 					cp++;
4190bee4c2cSEd Schouten 				}
4200bee4c2cSEd Schouten 			}
4210bee4c2cSEd Schouten 			lastsp = 0;
4220bee4c2cSEd Schouten 			break;
4230bee4c2cSEd Schouten 
4240bee4c2cSEd Schouten 		case ' ':
4250bee4c2cSEd Schouten 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
4260bee4c2cSEd Schouten 				cp += 3, *cp2++ = '@';
4270bee4c2cSEd Schouten 			else
4280bee4c2cSEd Schouten 			if (cp[0] == '@' && cp[1] == ' ')
4290bee4c2cSEd Schouten 				cp += 2, *cp2++ = '@';
4300bee4c2cSEd Schouten 			else
4310bee4c2cSEd Schouten 				lastsp = 1;
4320bee4c2cSEd Schouten 			break;
4330bee4c2cSEd Schouten 
4340bee4c2cSEd Schouten 		case '<':
4350bee4c2cSEd Schouten 			cp2 = bufend;
4360bee4c2cSEd Schouten 			gotlt++;
4370bee4c2cSEd Schouten 			lastsp = 0;
4380bee4c2cSEd Schouten 			break;
4390bee4c2cSEd Schouten 
4400bee4c2cSEd Schouten 		case '>':
4410bee4c2cSEd Schouten 			if (gotlt) {
4420bee4c2cSEd Schouten 				gotlt = 0;
4430bee4c2cSEd Schouten 				while ((c = *cp) != '\0' && c != ',') {
4440bee4c2cSEd Schouten 					cp++;
4450bee4c2cSEd Schouten 					if (c == '(')
4460bee4c2cSEd Schouten 						cp = skip_comment(cp);
4470bee4c2cSEd Schouten 					else if (c == '"')
4480bee4c2cSEd Schouten 						while ((c = *cp) != '\0') {
4490bee4c2cSEd Schouten 							cp++;
4500bee4c2cSEd Schouten 							if (c == '"')
4510bee4c2cSEd Schouten 								break;
4520bee4c2cSEd Schouten 							if (c == '\\' && *cp != '\0')
4530bee4c2cSEd Schouten 								cp++;
4540bee4c2cSEd Schouten 						}
4550bee4c2cSEd Schouten 				}
4560bee4c2cSEd Schouten 				lastsp = 0;
4570bee4c2cSEd Schouten 				break;
4580bee4c2cSEd Schouten 			}
4590bee4c2cSEd Schouten 			/* FALLTHROUGH */
4600bee4c2cSEd Schouten 
4610bee4c2cSEd Schouten 		default:
4620bee4c2cSEd Schouten 			if (lastsp) {
4630bee4c2cSEd Schouten 				lastsp = 0;
4640bee4c2cSEd Schouten 				*cp2++ = ' ';
4650bee4c2cSEd Schouten 			}
4660bee4c2cSEd Schouten 			*cp2++ = c;
467a1d170a0SUlrich Spörlein 			if (c == ',' && !gotlt &&
468a1d170a0SUlrich Spörlein 			    (*cp == ' ' || *cp == '"' || *cp == '<')) {
4690bee4c2cSEd Schouten 				*cp2++ = ' ';
470a1d170a0SUlrich Spörlein 				while (*cp == ' ')
471a1d170a0SUlrich Spörlein 					cp++;
4720bee4c2cSEd Schouten 				lastsp = 0;
4730bee4c2cSEd Schouten 				bufend = cp2;
4740bee4c2cSEd Schouten 			}
4750bee4c2cSEd Schouten 		}
4760bee4c2cSEd Schouten 	}
4770bee4c2cSEd Schouten 	*cp2 = '\0';
4780bee4c2cSEd Schouten 
4790bee4c2cSEd Schouten 	if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
4800bee4c2cSEd Schouten 		nbuf = cp;
4810bee4c2cSEd Schouten 	return (nbuf);
4820bee4c2cSEd Schouten }
4830bee4c2cSEd Schouten 
4840bee4c2cSEd Schouten /*
4850bee4c2cSEd Schouten  * Fetch the sender's name from the passed message.
4860bee4c2cSEd Schouten  * Reptype can be
4870bee4c2cSEd Schouten  *	0 -- get sender's name for display purposes
4880bee4c2cSEd Schouten  *	1 -- get sender's name for reply
4890bee4c2cSEd Schouten  *	2 -- get sender's name for Reply
4900bee4c2cSEd Schouten  */
4910bee4c2cSEd Schouten char *
name1(struct message * mp,int reptype)4926d8484b0SPhilippe Charnier name1(struct message *mp, int reptype)
4930bee4c2cSEd Schouten {
4940bee4c2cSEd Schouten 	char namebuf[LINESIZE];
4950bee4c2cSEd Schouten 	char linebuf[LINESIZE];
4960bee4c2cSEd Schouten 	char *cp, *cp2;
4970bee4c2cSEd Schouten 	FILE *ibuf;
4980bee4c2cSEd Schouten 	int first = 1;
4990bee4c2cSEd Schouten 
5000bee4c2cSEd Schouten 	if ((cp = hfield("from", mp)) != NULL)
5010bee4c2cSEd Schouten 		return (cp);
5020bee4c2cSEd Schouten 	if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
5030bee4c2cSEd Schouten 		return (cp);
5040bee4c2cSEd Schouten 	ibuf = setinput(mp);
5050bee4c2cSEd Schouten 	namebuf[0] = '\0';
5060bee4c2cSEd Schouten 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5070bee4c2cSEd Schouten 		return (savestr(namebuf));
5080bee4c2cSEd Schouten newname:
5090bee4c2cSEd Schouten 	for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
5100bee4c2cSEd Schouten 		;
5110bee4c2cSEd Schouten 	for (; *cp == ' ' || *cp == '\t'; cp++)
5120bee4c2cSEd Schouten 		;
5130bee4c2cSEd Schouten 	for (cp2 = &namebuf[strlen(namebuf)];
5140bee4c2cSEd Schouten 	    *cp != '\0' && *cp != ' ' && *cp != '\t' &&
5150bee4c2cSEd Schouten 	    cp2 < namebuf + LINESIZE - 1;)
5160bee4c2cSEd Schouten 		*cp2++ = *cp++;
5170bee4c2cSEd Schouten 	*cp2 = '\0';
5180bee4c2cSEd Schouten 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5190bee4c2cSEd Schouten 		return (savestr(namebuf));
5200bee4c2cSEd Schouten 	if ((cp = strchr(linebuf, 'F')) == NULL)
5210bee4c2cSEd Schouten 		return (savestr(namebuf));
5220bee4c2cSEd Schouten 	if (strncmp(cp, "From", 4) != 0)
5230bee4c2cSEd Schouten 		return (savestr(namebuf));
5240bee4c2cSEd Schouten 	while ((cp = strchr(cp, 'r')) != NULL) {
5250bee4c2cSEd Schouten 		if (strncmp(cp, "remote", 6) == 0) {
5260bee4c2cSEd Schouten 			if ((cp = strchr(cp, 'f')) == NULL)
5270bee4c2cSEd Schouten 				break;
5280bee4c2cSEd Schouten 			if (strncmp(cp, "from", 4) != 0)
5290bee4c2cSEd Schouten 				break;
5300bee4c2cSEd Schouten 			if ((cp = strchr(cp, ' ')) == NULL)
5310bee4c2cSEd Schouten 				break;
5320bee4c2cSEd Schouten 			cp++;
5330bee4c2cSEd Schouten 			if (first) {
5340bee4c2cSEd Schouten 				cp2 = namebuf;
5350bee4c2cSEd Schouten 				first = 0;
5360bee4c2cSEd Schouten 			} else
5370bee4c2cSEd Schouten 				cp2 = strrchr(namebuf, '!') + 1;
5380bee4c2cSEd Schouten 			strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
5390bee4c2cSEd Schouten 			strcat(namebuf, "!");
5400bee4c2cSEd Schouten 			goto newname;
5410bee4c2cSEd Schouten 		}
5420bee4c2cSEd Schouten 		cp++;
5430bee4c2cSEd Schouten 	}
5440bee4c2cSEd Schouten 	return (savestr(namebuf));
5450bee4c2cSEd Schouten }
5460bee4c2cSEd Schouten 
5470bee4c2cSEd Schouten /*
548389ae6c6SUlrich Spörlein  * Count the occurrences of c in str
5490bee4c2cSEd Schouten  */
5500bee4c2cSEd Schouten int
charcount(char * str,int c)5516d8484b0SPhilippe Charnier charcount(char *str, int c)
5520bee4c2cSEd Schouten {
5530bee4c2cSEd Schouten 	char *cp;
5540bee4c2cSEd Schouten 	int i;
5550bee4c2cSEd Schouten 
5560bee4c2cSEd Schouten 	for (i = 0, cp = str; *cp != '\0'; cp++)
5570bee4c2cSEd Schouten 		if (*cp == c)
5580bee4c2cSEd Schouten 			i++;
5590bee4c2cSEd Schouten 	return (i);
5600bee4c2cSEd Schouten }
5610bee4c2cSEd Schouten 
5620bee4c2cSEd Schouten /*
5630bee4c2cSEd Schouten  * See if the given header field is supposed to be ignored.
5640bee4c2cSEd Schouten  */
5650bee4c2cSEd Schouten int
isign(const char * field,struct ignoretab ignore[2])5666d8484b0SPhilippe Charnier isign(const char *field, struct ignoretab ignore[2])
5670bee4c2cSEd Schouten {
5680bee4c2cSEd Schouten 	char realfld[LINESIZE];
5690bee4c2cSEd Schouten 
5700bee4c2cSEd Schouten 	if (ignore == ignoreall)
5710bee4c2cSEd Schouten 		return (1);
5720bee4c2cSEd Schouten 	/*
5730bee4c2cSEd Schouten 	 * Lower-case the string, so that "Status" and "status"
5740bee4c2cSEd Schouten 	 * will hash to the same place.
5750bee4c2cSEd Schouten 	 */
5760bee4c2cSEd Schouten 	istrncpy(realfld, field, sizeof(realfld));
5770bee4c2cSEd Schouten 	if (ignore[1].i_count > 0)
5780bee4c2cSEd Schouten 		return (!member(realfld, ignore + 1));
5790bee4c2cSEd Schouten 	else
5800bee4c2cSEd Schouten 		return (member(realfld, ignore));
5810bee4c2cSEd Schouten }
5820bee4c2cSEd Schouten 
5830bee4c2cSEd Schouten int
member(char * realfield,struct ignoretab * table)5846d8484b0SPhilippe Charnier member(char *realfield, struct ignoretab *table)
5850bee4c2cSEd Schouten {
5860bee4c2cSEd Schouten 	struct ignore *igp;
5870bee4c2cSEd Schouten 
5880bee4c2cSEd Schouten 	for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
5890bee4c2cSEd Schouten 		if (*igp->i_field == *realfield &&
5900bee4c2cSEd Schouten 		    equal(igp->i_field, realfield))
5910bee4c2cSEd Schouten 			return (1);
5920bee4c2cSEd Schouten 	return (0);
5930bee4c2cSEd Schouten }
594