util.c revision 99112
1139823Simp/*
221259Swollman * Copyright (c) 1980, 1993
321259Swollman *	The Regents of the University of California.  All rights reserved.
421259Swollman *
521259Swollman * Redistribution and use in source and binary forms, with or without
621259Swollman * modification, are permitted provided that the following conditions
721259Swollman * are met:
821259Swollman * 1. Redistributions of source code must retain the above copyright
921259Swollman *    notice, this list of conditions and the following disclaimer.
1021259Swollman * 2. Redistributions in binary form must reproduce the above copyright
1121259Swollman *    notice, this list of conditions and the following disclaimer in the
1221259Swollman *    documentation and/or other materials provided with the distribution.
1321259Swollman * 3. All advertising materials mentioning features or use of this software
1421259Swollman *    must display the following acknowledgement:
1521259Swollman *	This product includes software developed by the University of
1621259Swollman *	California, Berkeley and its contributors.
1721259Swollman * 4. Neither the name of the University nor the names of its contributors
1821259Swollman *    may be used to endorse or promote products derived from this software
1921259Swollman *    without specific prior written permission.
2021259Swollman *
2121259Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2221259Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2321259Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2421259Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2521259Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2621259Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2721259Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2821259Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2921259Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3050477Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3121259Swollman * SUCH DAMAGE.
3221259Swollman */
3321259Swollman
3421259Swollman#ifndef lint
3521259Swollman#if 0
3621259Swollmanstatic char sccsid[] = "@(#)aux.c	8.1 (Berkeley) 6/6/93";
3721259Swollman#endif
3821259Swollman#endif /* not lint */
3921259Swollman#include <sys/cdefs.h>
4021259Swollman__FBSDID("$FreeBSD: head/usr.bin/mail/aux.c 99112 2002-06-30 05:25:07Z obrien $");
4121259Swollman
4221259Swollman#include <sys/time.h>
4321259Swollman
4421259Swollman#include "rcv.h"
4521259Swollman#include "extern.h"
4621259Swollman
4721259Swollman/*
4821259Swollman * Mail -- a mail program
4921259Swollman *
5021259Swollman * Auxiliary functions.
51108533Sschweikh */
5221259Swollman
5321259Swollmanstatic char *save2str(char *, char *);
5421259Swollman
5521259Swollman/*
56108533Sschweikh * Return a pointer to a dynamic copy of the argument.
5721259Swollman */
5821259Swollmanchar *
5921259Swollmansavestr(str)
6021259Swollman	char *str;
6121259Swollman{
6221259Swollman	char *new;
6321259Swollman	int size = strlen(str) + 1;
6421259Swollman
6521259Swollman	if ((new = salloc(size)) != NULL)
6683366Sjulian		bcopy(str, new, size);
6721259Swollman	return (new);
6885074Sru}
6921259Swollman
7021259Swollman/*
71142215Sglebius * Make a copy of new argument incorporating old one.
72155051Sglebius */
73191148Skmacychar *
7421259Swollmansave2str(str, old)
7521259Swollman	char *str, *old;
7621259Swollman{
7721259Swollman	char *new;
7869224Sjlemon	int newsize = strlen(str) + 1;
7969152Sjlemon	int oldsize = old ? strlen(old) + 1 : 0;
80126264Smlaier
81186207Skmacy	if ((new = salloc(newsize + oldsize)) != NULL) {
8269224Sjlemon		if (oldsize) {
8374914Sjhb			bcopy(old, new, oldsize);
8474914Sjhb			new[oldsize - 1] = ' ';
85186199Skmacy		}
8683130Sjlemon		bcopy(str, new + oldsize, newsize);
87132712Srwatson	}
8869152Sjlemon	return (new);
89121816Sbrooks}
90121816Sbrooks
91130416Smlaier/*
92130416Smlaier * Touch the named message by setting its MTOUCH flag.
9360938Sjake * Touched messages have the effect of not being sent
9460938Sjake * back to the system mailbox on exit.
9560938Sjake */
9672084Sphkvoid
97159781Smlaiertouch(mp)
9821259Swollman	struct message *mp;
9921259Swollman{
10021259Swollman
10121259Swollman	mp->m_flag |= MTOUCH;
10221259Swollman	if ((mp->m_flag & MREAD) == 0)
10321259Swollman		mp->m_flag |= MREAD|MSTATUS;
10421259Swollman}
10521259Swollman
10621259Swollman/*
10721259Swollman * Test to see if the passed file name is a directory.
10869152Sjlemon * Return true if it is.
10921259Swollman */
11021259Swollmanint
11121259Swollmanisdir(name)
11221259Swollman	char name[];
11321259Swollman{
11421259Swollman	struct stat sbuf;
11521259Swollman
11684380Smjacob	if (stat(name, &sbuf) < 0)
11721259Swollman		return (0);
11821259Swollman	return (S_ISDIR(sbuf.st_mode));
119147256Sbrooks}
120191688Szec
12160938Sjake/*
122121816Sbrooks * Count the number of arguments in the given string raw list.
123121816Sbrooks */
124121816Sbrooksint
125191367Srwatsonargcount(argv)
12621259Swollman	char **argv;
127128291Sluigi{
128128291Sluigi	char **ap;
129128315Sluigi
130128315Sluigi	for (ap = argv; *ap++ != NULL;)
131128315Sluigi		;
132128315Sluigi	return (ap - argv - 1);
133128291Sluigi}
134128315Sluigi
135152315Sru/*
136128291Sluigi * Return the desired header line from the passed message
137133741Sjmg * pointer (or NULL if the desired header field is not available).
13883130Sjlemon */
139142901Sglebiuschar *
14021259Swollmanhfield(field, mp)
14121259Swollman	const char *field;
14221259Swollman	struct message *mp;
143155051Sglebius{
144102052Ssobomax	FILE *ibuf;
145162070Sandre	char linebuf[LINESIZE];
146162070Sandre	int lc;
14721259Swollman	char *hfield;
14821259Swollman	char *colon, *oldhfield = NULL;
14921259Swollman
15021404Swollman	ibuf = setinput(mp);
15121404Swollman	if ((lc = mp->m_lines - 1) < 0)
15221259Swollman		return (NULL);
15321259Swollman	if (readline(ibuf, linebuf, LINESIZE) < 0)
15492725Salfred		return (NULL);
155191148Skmacy	while (lc > 0) {
156106931Ssam		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
157106931Ssam			return (oldhfield);
15821259Swollman		if ((hfield = ishfield(linebuf, colon, field)) != NULL)
15992725Salfred			oldhfield = save2str(hfield, oldhfield);
16021259Swollman	}
16192725Salfred	return (oldhfield);
16221259Swollman}
16392725Salfred
16421259Swollman/*
16592725Salfred * Return the next header field found in the given message.
16621404Swollman * Return >= 0 if something found, < 0 elsewise.
16792725Salfred * "colon" is set to point to the colon in the header.
168189230Srwatson * Must deal with \ continuations & other such fraud.
169189230Srwatson */
170189230Srwatsonint
171189230Srwatsongethfield(f, linebuf, rem, colon)
172152315Sru	FILE *f;
173174388Skmacy	char linebuf[];
174148265Srwatson	int rem;
175130416Smlaier	char **colon;
176123220Simp{
177127828Sluigi	char line2[LINESIZE];
178146986Sthompsa	char *cp, *cp2;
179146986Sthompsa	int c;
180122524Srwatson
181121161Sume	for (;;) {
182127828Sluigi		if (--rem < 0)
183127828Sluigi			return (-1);
184121161Sume		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
185121470Sume			return (-1);
186186199Skmacy		for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
187145320Sglebius		    cp++)
188148640Srwatson			;
189186119Sqingli		if (*cp != ':' || cp == linebuf)
190152209Sthompsa			continue;
191159781Smlaier		/*
192159781Smlaier		 * I guess we got a headline.
193159781Smlaier		 * Handle wraparounding
194168793Sthompsa		 */
195191367Srwatson		*colon = cp;
196189230Srwatson		cp = linebuf + c;
197189230Srwatson		for (;;) {
198189230Srwatson			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
199189230Srwatson				;
200189230Srwatson			cp++;
201189230Srwatson			if (rem <= 0)
202191367Srwatson				break;
203189230Srwatson			ungetc(c = getc(f), f);
204189230Srwatson			if (c != ' ' && c != '\t')
20521259Swollman				break;
20669152Sjlemon			if ((c = readline(f, line2, LINESIZE)) < 0)
20792725Salfred				break;
20821259Swollman			rem--;
209128376Sluigi			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
210128376Sluigi				;
211128376Sluigi			c -= cp2 - line2;
212128376Sluigi			if (cp + c >= linebuf + LINESIZE - 2)
21321259Swollman				break;
21421259Swollman			*cp++ = ' ';
21521259Swollman			bcopy(cp2, cp, c);
21621259Swollman			cp += c;
21721259Swollman		}
21821259Swollman		*cp = 0;
219128871Sandre		return (rem);
22021259Swollman	}
22158698Sjlemon	/* NOTREACHED */
22221259Swollman}
22321259Swollman
22421259Swollman/*
22521259Swollman * Check whether the passed line is a header line of
22621259Swollman * the desired breed.  Return the field body, or 0.
22721259Swollman */
22821259Swollman
22921259Swollmanchar*
23021259Swollmanishfield(linebuf, colon, field)
23121259Swollman	char linebuf[];
23221259Swollman	char *colon;
23321259Swollman	const char *field;
234136950Sjmg{
23521259Swollman	char *cp = colon;
23653541Sshin
23753541Sshin	*cp = 0;
23853541Sshin	if (strcasecmp(linebuf, field) != 0) {
239160981Sbrooks		*cp = ':';
24053541Sshin		return (0);
24121259Swollman	}
242148640Srwatson	*cp = ':';
243148640Srwatson	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
244148640Srwatson		;
245148640Srwatson	return (cp);
246148640Srwatson}
247148640Srwatson
248148640Srwatson/*
249148640Srwatson * Copy a string and lowercase the result.
250148640Srwatson * dsize: space left in buffer (including space for NULL)
251148640Srwatson */
25221259Swollmanvoid
25321259Swollmanistrncpy(dest, src, dsize)
25421259Swollman	char *dest;
25521259Swollman	const char *src;
25621259Swollman	size_t dsize;
25772200Sbmilekic{
25872200Sbmilekic
259130416Smlaier	strlcpy(dest, src, dsize);
26069152Sjlemon	while (*dest)
26169152Sjlemon		*dest++ = tolower((unsigned char)*dest);
26269152Sjlemon}
26321259Swollman
26469152Sjlemon/*
26569152Sjlemon * The following code deals with input stacking to do source
26669152Sjlemon * commands.  All but the current file pointer are saved on
26769152Sjlemon * the stack.
26869152Sjlemon */
26969152Sjlemon
27069152Sjlemonstatic	int	ssp;			/* Top of file stack */
27169152Sjlemonstruct sstack {
27269152Sjlemon	FILE	*s_file;		/* File we were in. */
27369152Sjlemon	int	s_cond;			/* Saved state of conditionals */
27469152Sjlemon	int	s_loading;		/* Loading .mailrc, etc. */
27569152Sjlemon};
27669152Sjlemon#define	SSTACK_SIZE	64		/* XXX was NOFILE. */
27769152Sjlemonstatic struct sstack sstack[SSTACK_SIZE];
27869152Sjlemon
27969152Sjlemon/*
28069152Sjlemon * Pushdown current input file and switch to a new one.
28169152Sjlemon * Set the global flag "sourcing" so that others will realize
28269152Sjlemon * that they are no longer reading from a tty (in all probability).
28369152Sjlemon */
28469152Sjlemonint
28569152Sjlemonsource(arglist)
28669152Sjlemon	char **arglist;
28769152Sjlemon{
28869152Sjlemon	FILE *fi;
28969152Sjlemon	char *cp;
29069152Sjlemon
29169152Sjlemon	if ((cp = expand(*arglist)) == NULL)
29269152Sjlemon		return (1);
29369152Sjlemon	if ((fi = Fopen(cp, "r")) == NULL) {
29469152Sjlemon		warn("%s", cp);
29569152Sjlemon		return (1);
29669152Sjlemon	}
297136950Sjmg	if (ssp >= SSTACK_SIZE - 1) {
29869152Sjlemon		printf("Too much \"sourcing\" going on.\n");
29969152Sjlemon		(void)Fclose(fi);
30069152Sjlemon		return (1);
30169152Sjlemon	}
30269152Sjlemon	sstack[ssp].s_file = input;
30369152Sjlemon	sstack[ssp].s_cond = cond;
30469152Sjlemon	sstack[ssp].s_loading = loading;
30569152Sjlemon	ssp++;
30669152Sjlemon	loading = 0;
30769152Sjlemon	cond = CANY;
30869152Sjlemon	input = fi;
30969152Sjlemon	sourcing++;
310130416Smlaier	return (0);
311130416Smlaier}
312130416Smlaier
313130416Smlaier/*
31469152Sjlemon * Pop the current input back to the previous level.
31569152Sjlemon * Update the "sourcing" flag as appropriate.
31669152Sjlemon */
31769152Sjlemonint
31869152Sjlemonunstack()
31969152Sjlemon{
32069152Sjlemon	if (ssp <= 0) {
32169152Sjlemon		printf("\"Source\" stack over-pop.\n");
32269152Sjlemon		sourcing = 0;
323130416Smlaier		return (1);
324130416Smlaier	}
325130416Smlaier	(void)Fclose(input);
326130416Smlaier	if (cond != CANY)
327130416Smlaier		printf("Unmatched \"if\"\n");
328130416Smlaier	ssp--;
32955205Speter	cond = sstack[ssp].s_cond;
330126264Smlaier	loading = sstack[ssp].s_loading;
331126264Smlaier	input = sstack[ssp].s_file;
332126264Smlaier	if (ssp == 0)
333126264Smlaier		sourcing = loading;
334126264Smlaier	return (0);
335126264Smlaier}
336126264Smlaier
337126264Smlaier/*
338126264Smlaier * Touch the indicated file.
339126264Smlaier * This is nifty for the shell.
340159781Smlaier */
341159781Smlaiervoid
342159781Smlaieralter(name)
343159781Smlaier	char *name;
344159781Smlaier{
345159781Smlaier	struct stat sb;
346159781Smlaier	struct timeval tv[2];
347159781Smlaier
348159781Smlaier	if (stat(name, &sb))
349159781Smlaier		return;
350159781Smlaier	(void)gettimeofday(&tv[0], (struct timezone *)NULL);
351159781Smlaier	tv[0].tv_sec++;
352159781Smlaier	TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
353159781Smlaier	(void)utimes(name, tv);
354159781Smlaier}
355159781Smlaier
356159781Smlaier/*
357159781Smlaier * Get sender's name from this message.  If the message has
358159781Smlaier * a bunch of arpanet stuff in it, we may have to skin the name
359159781Smlaier * before returning it.
360159781Smlaier */
361159781Smlaierchar *
362159781Smlaiernameof(mp, reptype)
363159781Smlaier	struct message *mp;
364159781Smlaier	int reptype;
365159781Smlaier{
366159781Smlaier	char *cp, *cp2;
367159781Smlaier
368159781Smlaier	cp = skin(name1(mp, reptype));
369159781Smlaier	if (reptype != 0 || charcount(cp, '!') < 2)
370159781Smlaier		return (cp);
371121470Sume	cp2 = strrchr(cp, '!');
372186199Skmacy	cp2--;
373121470Sume	while (cp2 > cp && *cp2 != '!')
374186199Skmacy		cp2--;
375186199Skmacy	if (*cp2 == '!')
376186199Skmacy		return (cp2 + 1);
377186199Skmacy	return (cp);
378186199Skmacy}
379186199Skmacy
380186199Skmacy/*
381186199Skmacy * Start of a "comment".
382186119Sqingli * Ignore it.
383186199Skmacy */
384186199Skmacychar *
385186199Skmacyskip_comment(cp)
386137065Srwatson	char *cp;
387137065Srwatson{
388130416Smlaier	int nesting = 1;
389130416Smlaier
390130416Smlaier	for (; nesting > 0 && *cp; cp++) {
391130416Smlaier		switch (*cp) {
39221259Swollman		case '\\':
393132712Srwatson			if (cp[1])
394132712Srwatson				cp++;
395130416Smlaier			break;
396130416Smlaier		case '(':
397130416Smlaier			nesting++;
398130416Smlaier			break;
399130416Smlaier		case ')':
400130416Smlaier			nesting--;
401130416Smlaier			break;
402130416Smlaier		}
403130416Smlaier	}
404130416Smlaier	return (cp);
405130416Smlaier}
406130416Smlaier
407130416Smlaier/*
408130416Smlaier * Skin an arpa net address according to the RFC 822 interpretation
409130416Smlaier * of "host-phrase."
410130416Smlaier */
411130416Smlaierchar *
412130416Smlaierskin(name)
41321259Swollman	char *name;
414130416Smlaier{
415130416Smlaier	char *nbuf, *bufend, *cp, *cp2;
416130416Smlaier	int c, gotlt, lastsp;
417130508Smlaier
418130416Smlaier	if (name == NULL)
419130416Smlaier		return (NULL);
420130416Smlaier	if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
421130416Smlaier	    && strchr(name, ' ') == NULL)
422130416Smlaier		return (name);
423130416Smlaier
424130416Smlaier	/* We assume that length(input) <= length(output) */
425130416Smlaier	if ((nbuf = malloc(strlen(name) + 1)) == NULL)
426130416Smlaier		err(1, "Out of memory");
427130416Smlaier	gotlt = 0;
428130416Smlaier	lastsp = 0;
429130416Smlaier	bufend = nbuf;
430130416Smlaier	for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
431130416Smlaier		switch (c) {
432130416Smlaier		case '(':
433130416Smlaier			cp = skip_comment(cp);
434130508Smlaier			lastsp = 0;
435130416Smlaier			break;
436130416Smlaier
437130416Smlaier		case '"':
438130416Smlaier			/*
439130416Smlaier			 * Start of a "quoted-string".
440130416Smlaier			 * Copy it in its entirety.
441130416Smlaier			 */
442130416Smlaier			while ((c = *cp) != '\0') {
443130416Smlaier				cp++;
444130416Smlaier				if (c == '"')
445130416Smlaier					break;
446130416Smlaier				if (c != '\\')
447130416Smlaier					*cp2++ = c;
448130416Smlaier				else if ((c = *cp) != '\0') {
449130416Smlaier					*cp2++ = c;
450130416Smlaier					cp++;
451130416Smlaier				}
452130416Smlaier			}
453130416Smlaier			lastsp = 0;
454130416Smlaier			break;
455130416Smlaier
456130416Smlaier		case ' ':
457130416Smlaier			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
458130416Smlaier				cp += 3, *cp2++ = '@';
459130416Smlaier			else
460130416Smlaier			if (cp[0] == '@' && cp[1] == ' ')
461130416Smlaier				cp += 2, *cp2++ = '@';
462130416Smlaier			else
463130416Smlaier				lastsp = 1;
464130416Smlaier			break;
465130416Smlaier
466130416Smlaier		case '<':
467130416Smlaier			cp2 = bufend;
468130416Smlaier			gotlt++;
469130416Smlaier			lastsp = 0;
470130416Smlaier			break;
471130416Smlaier
472130416Smlaier		case '>':
473130416Smlaier			if (gotlt) {
474130416Smlaier				gotlt = 0;
475148886Srwatson				while ((c = *cp) != '\0' && c != ',') {
476148886Srwatson					cp++;
477148886Srwatson					if (c == '(')
478148886Srwatson						cp = skip_comment(cp);
479130416Smlaier					else if (c == '"')
480130416Smlaier						while ((c = *cp) != '\0') {
481130416Smlaier							cp++;
482130416Smlaier							if (c == '"')
483130416Smlaier								break;
484130416Smlaier							if (c == '\\' && *cp != '\0')
485130416Smlaier								cp++;
486130416Smlaier						}
487130416Smlaier				}
488130416Smlaier				lastsp = 0;
489130416Smlaier				break;
490130416Smlaier			}
491148886Srwatson			/* Fall into . . . */
492132712Srwatson
493130416Smlaier		default:
494130416Smlaier			if (lastsp) {
495130416Smlaier				lastsp = 0;
496130416Smlaier				*cp2++ = ' ';
497130512Smlaier			}
498130416Smlaier			*cp2++ = c;
499130416Smlaier			if (c == ',' && *cp == ' ' && !gotlt) {
500130416Smlaier				*cp2++ = ' ';
501130416Smlaier				while (*++cp == ' ')
502130416Smlaier					;
503130416Smlaier				lastsp = 0;
504130416Smlaier				bufend = cp2;
505130416Smlaier			}
506130416Smlaier		}
507130416Smlaier	}
508130416Smlaier	*cp2 = '\0';
509130416Smlaier
510130416Smlaier	if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
511130416Smlaier		nbuf = cp;
512130416Smlaier	return (nbuf);
513130416Smlaier}
514130416Smlaier
515130416Smlaier/*
516130416Smlaier * Fetch the sender's name from the passed message.
517130416Smlaier * Reptype can be
518130416Smlaier *	0 -- get sender's name for display purposes
519130416Smlaier *	1 -- get sender's name for reply
520130416Smlaier *	2 -- get sender's name for Reply
521130416Smlaier */
522130416Smlaierchar *
523130416Smlaiername1(mp, reptype)
524130416Smlaier	struct message *mp;
525130416Smlaier	int reptype;
526130416Smlaier{
527130416Smlaier	char namebuf[LINESIZE];
528130416Smlaier	char linebuf[LINESIZE];
529130416Smlaier	char *cp, *cp2;
530132152Smlaier	FILE *ibuf;
531132152Smlaier	int first = 1;
532130416Smlaier
533130416Smlaier	if ((cp = hfield("from", mp)) != NULL)
534130416Smlaier		return (cp);
535130416Smlaier	if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
536130416Smlaier		return (cp);
537130416Smlaier	ibuf = setinput(mp);
538130416Smlaier	namebuf[0] = '\0';
539130416Smlaier	if (readline(ibuf, linebuf, LINESIZE) < 0)
540130416Smlaier		return (savestr(namebuf));
541132152Smlaiernewname:
542132152Smlaier	for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
543132152Smlaier		;
544130416Smlaier	for (; *cp == ' ' || *cp == '\t'; cp++)
545130416Smlaier		;
546130416Smlaier	for (cp2 = &namebuf[strlen(namebuf)];
547130416Smlaier	    *cp != '\0' && *cp != ' ' && *cp != '\t' &&
548130416Smlaier	    cp2 < namebuf + LINESIZE - 1;)
549130416Smlaier		*cp2++ = *cp++;
550130416Smlaier	*cp2 = '\0';
551186207Skmacy	if (readline(ibuf, linebuf, LINESIZE) < 0)
552186213Skmacy		return (savestr(namebuf));
553186213Skmacy	if ((cp = strchr(linebuf, 'F')) == NULL)
554186213Skmacy		return (savestr(namebuf));
555186213Skmacy	if (strncmp(cp, "From", 4) != 0)
556186213Skmacy		return (savestr(namebuf));
557186213Skmacy	while ((cp = strchr(cp, 'r')) != NULL) {
558186213Skmacy		if (strncmp(cp, "remote", 6) == 0) {
559186213Skmacy			if ((cp = strchr(cp, 'f')) == NULL)
560186213Skmacy				break;
561186207Skmacy			if (strncmp(cp, "from", 4) != 0)
562186213Skmacy				break;
563186207Skmacy			if ((cp = strchr(cp, ' ')) == NULL)
564186207Skmacy				break;
565186213Skmacy			cp++;
566186213Skmacy			if (first) {
567186207Skmacy				cp2 = namebuf;
568191033Skmacy				first = 0;
569191033Skmacy			} else
570191033Skmacy				cp2 = strrchr(namebuf, '!') + 1;
571191033Skmacy			strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
572191033Skmacy			strcat(namebuf, "!");
573191033Skmacy			goto newname;
574186207Skmacy		}
575186207Skmacy		cp++;
576186213Skmacy	}
577186207Skmacy	return (savestr(namebuf));
578186213Skmacy}
579186213Skmacy
580186213Skmacy/*
581186207Skmacy * Count the occurances of c in str
582186207Skmacy */
583186207Skmacyint
584186207Skmacycharcount(str, c)
585186207Skmacy	char *str;
586186207Skmacy	int c;
587186207Skmacy{
588186207Skmacy	char *cp;
589186207Skmacy	int i;
590186207Skmacy
591186207Skmacy	for (i = 0, cp = str; *cp != '\0'; cp++)
592186207Skmacy		if (*cp == c)
593186207Skmacy			i++;
594191033Skmacy	return (i);
595191033Skmacy}
596191033Skmacy
597191033Skmacy/*
598191033Skmacy * See if the given header field is supposed to be ignored.
599191033Skmacy */
600191033Skmacyint
601191033Skmacyisign(field, ignore)
602191033Skmacy	const char *field;
603191033Skmacy	struct ignoretab ignore[2];
604191033Skmacy{
605186207Skmacy	char realfld[LINESIZE];
606191033Skmacy
607191033Skmacy	if (ignore == ignoreall)
608186207Skmacy		return (1);
609191033Skmacy	/*
610191033Skmacy	 * Lower-case the string, so that "Status" and "status"
611191033Skmacy	 * will hash to the same place.
612191033Skmacy	 */
613191033Skmacy	istrncpy(realfld, field, sizeof(realfld));
614191033Skmacy	if (ignore[1].i_count > 0)
615191033Skmacy		return (!member(realfld, ignore + 1));
616191033Skmacy	else
617191033Skmacy		return (member(realfld, ignore));
618191033Skmacy}
61949459Sbrian
62049459Sbrianint
62149459Sbrianmember(realfield, table)
62249459Sbrian	char *realfield;
62349459Sbrian	struct ignoretab *table;
62449459Sbrian{
62549459Sbrian	struct ignore *igp;
62655205Speter
62721259Swollman	for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
62821259Swollman		if (*igp->i_field == *realfield &&
62921259Swollman		    equal(igp->i_field, realfield))
63021259Swollman			return (1);
63121259Swollman	return (0);
63221259Swollman}
633128291Sluigi