xref: /csrg-svn/usr.bin/mail/aux.c (revision 31142)
122444Sdist /*
222444Sdist  * Copyright (c) 1980 Regents of the University of California.
322444Sdist  * All rights reserved.  The Berkeley software License Agreement
422444Sdist  * specifies the terms and conditions for redistribution.
522444Sdist  */
622444Sdist 
714522Ssam #ifndef lint
8*31142Sedward static char *sccsid = "@(#)aux.c	5.6 (Berkeley) 05/18/87";
922444Sdist #endif not lint
101219Skas 
111219Skas #include "rcv.h"
121219Skas #include <sys/stat.h>
131219Skas 
141219Skas /*
151219Skas  * Mail -- a mail program
161219Skas  *
171219Skas  * Auxiliary functions.
181219Skas  */
191219Skas 
201219Skas /*
211219Skas  * Return a pointer to a dynamic copy of the argument.
221219Skas  */
231219Skas 
241219Skas char *
251219Skas savestr(str)
261219Skas 	char *str;
271219Skas {
281219Skas 	register char *cp, *cp2, *top;
291219Skas 
301219Skas 	for (cp = str; *cp; cp++)
311219Skas 		;
321219Skas 	top = salloc(cp-str + 1);
331219Skas 	if (top == NOSTR)
341219Skas 		return(NOSTR);
351219Skas 	for (cp = str, cp2 = top; *cp; cp++)
361219Skas 		*cp2++ = *cp;
371219Skas 	*cp2 = 0;
381219Skas 	return(top);
391219Skas }
401219Skas 
411219Skas /*
421219Skas  * Announce a fatal error and die.
431219Skas  */
441219Skas 
45*31142Sedward /*VARARGS1*/
46*31142Sedward panic(fmt, a, b)
47*31142Sedward 	char *fmt;
481219Skas {
49*31142Sedward 	fprintf(stderr, "panic: ");
50*31142Sedward 	fprintf(stderr, fmt, a, b);
51*31142Sedward 	putc('\n', stderr);
521219Skas 	exit(1);
531219Skas }
541219Skas 
551219Skas /*
561219Skas  * Touch the named message by setting its MTOUCH flag.
571219Skas  * Touched messages have the effect of not being sent
581219Skas  * back to the system mailbox on exit.
591219Skas  */
601219Skas 
611219Skas touch(mesg)
621219Skas {
631479Skas 	register struct message *mp;
641479Skas 
651479Skas 	if (mesg < 1 || mesg > msgCount)
661479Skas 		return;
671479Skas 	mp = &message[mesg-1];
681479Skas 	mp->m_flag |= MTOUCH;
691479Skas 	if ((mp->m_flag & MREAD) == 0)
701479Skas 		mp->m_flag |= MREAD|MSTATUS;
711219Skas }
721219Skas 
731219Skas /*
741219Skas  * Test to see if the passed file name is a directory.
751219Skas  * Return true if it is.
761219Skas  */
771219Skas 
781219Skas isdir(name)
791219Skas 	char name[];
801219Skas {
811219Skas 	struct stat sbuf;
821219Skas 
831219Skas 	if (stat(name, &sbuf) < 0)
841219Skas 		return(0);
851219Skas 	return((sbuf.st_mode & S_IFMT) == S_IFDIR);
861219Skas }
871219Skas 
881219Skas /*
891219Skas  * Count the number of arguments in the given string raw list.
901219Skas  */
911219Skas 
921219Skas argcount(argv)
931219Skas 	char **argv;
941219Skas {
951219Skas 	register char **ap;
961219Skas 
97*31142Sedward 	for (ap = argv; *ap++ != NOSTR;)
981219Skas 		;
99*31142Sedward 	return ap - argv - 1;
1001219Skas }
1011219Skas 
1021219Skas /*
1031219Skas  * Return the desired header line from the passed message
1041219Skas  * pointer (or NOSTR if the desired header field is not available).
1051219Skas  */
1061219Skas 
1071219Skas char *
1081219Skas hfield(field, mp)
1091219Skas 	char field[];
1101219Skas 	struct message *mp;
1111219Skas {
1121219Skas 	register FILE *ibuf;
1131219Skas 	char linebuf[LINESIZE];
1141219Skas 	register int lc;
115*31142Sedward 	register char *hfield;
116*31142Sedward 	char *colon;
1171219Skas 
1181219Skas 	ibuf = setinput(mp);
119*31142Sedward 	if ((lc = mp->m_lines - 1) < 0)
120*31142Sedward 		return NOSTR;
1211219Skas 	if (readline(ibuf, linebuf) < 0)
122*31142Sedward 		return NOSTR;
123*31142Sedward 	while (lc > 0) {
124*31142Sedward 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
125*31142Sedward 			return NOSTR;
126*31142Sedward 		if (hfield = ishfield(linebuf, colon, field))
127*31142Sedward 			return savestr(hfield);
128*31142Sedward 	}
129*31142Sedward 	return NOSTR;
1301219Skas }
1311219Skas 
1321219Skas /*
1331219Skas  * Return the next header field found in the given message.
134*31142Sedward  * Return >= 0 if something found, < 0 elsewise.
135*31142Sedward  * "colon" is set to point to the colon in the header.
1361219Skas  * Must deal with \ continuations & other such fraud.
1371219Skas  */
1381219Skas 
139*31142Sedward gethfield(f, linebuf, rem, colon)
1401219Skas 	register FILE *f;
1411219Skas 	char linebuf[];
1421219Skas 	register int rem;
143*31142Sedward 	char **colon;
1441219Skas {
1451219Skas 	char line2[LINESIZE];
1461219Skas 	register char *cp, *cp2;
1471219Skas 	register int c;
1481219Skas 
1491219Skas 	for (;;) {
150*31142Sedward 		if (--rem < 0)
151*31142Sedward 			return -1;
152*31142Sedward 		if ((c = readline(f, linebuf)) <= 0)
153*31142Sedward 			return -1;
154*31142Sedward 		for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
155*31142Sedward 		     cp++)
156*31142Sedward 			;
157*31142Sedward 		if (*cp != ':' || cp == linebuf)
1581219Skas 			continue;
1591219Skas 		/*
1601219Skas 		 * I guess we got a headline.
1611219Skas 		 * Handle wraparounding
1621219Skas 		 */
163*31142Sedward 		*colon = cp;
164*31142Sedward 		cp = linebuf + c;
1651219Skas 		for (;;) {
166*31142Sedward 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
167*31142Sedward 				;
168*31142Sedward 			cp++;
1691219Skas 			if (rem <= 0)
1701219Skas 				break;
171*31142Sedward 			ungetc(c = getc(f), f);
172*31142Sedward 			if (c != ' ' && c != '\t')
1731219Skas 				break;
174*31142Sedward 			if ((c = readline(f, line2)) < 0)
1751219Skas 				break;
1761219Skas 			rem--;
177*31142Sedward 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
1781219Skas 				;
179*31142Sedward 			c -= cp2 - line2;
180*31142Sedward 			if (cp + c >= linebuf + LINESIZE - 2)
1811219Skas 				break;
1821219Skas 			*cp++ = ' ';
183*31142Sedward 			bcopy(cp2, cp, c);
184*31142Sedward 			cp += c;
1851219Skas 		}
186*31142Sedward 		*cp = 0;
187*31142Sedward 		return rem;
1881219Skas 	}
1891219Skas 	/* NOTREACHED */
1901219Skas }
1911219Skas 
1921219Skas /*
1931219Skas  * Check whether the passed line is a header line of
194*31142Sedward  * the desired breed.  Return the field body, or 0.
1951219Skas  */
1961219Skas 
197*31142Sedward char*
198*31142Sedward ishfield(linebuf, colon, field)
1991219Skas 	char linebuf[], field[];
200*31142Sedward 	char *colon;
2011219Skas {
202*31142Sedward 	register char *cp = colon;
2031219Skas 
2041219Skas 	*cp = 0;
205*31142Sedward 	if (!icequal(linebuf, field)) {
206*31142Sedward 		*cp = ':';
207*31142Sedward 		return 0;
2081219Skas 	}
209*31142Sedward 	*cp = ':';
210*31142Sedward 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
211*31142Sedward 		;
212*31142Sedward 	return cp;
2131219Skas }
2141219Skas 
2151219Skas /*
2161219Skas  * Compare two strings, ignoring case.
2171219Skas  */
2181219Skas 
2191219Skas icequal(s1, s2)
2201219Skas 	register char *s1, *s2;
2211219Skas {
222*31142Sedward 	register c1, c2;
2231219Skas 
224*31142Sedward 	for (;;) {
225*31142Sedward 		if ((c1 = (unsigned char)*s1++) !=
226*31142Sedward 		    (c2 = (unsigned char)*s2++)) {
227*31142Sedward 			if (isupper(c1))
228*31142Sedward 				c1 = tolower(c1);
229*31142Sedward 			if (c1 != c2)
230*31142Sedward 				return 0;
231*31142Sedward 		}
232*31142Sedward 		if (c1 == 0)
233*31142Sedward 			return 1;
234*31142Sedward 	}
235*31142Sedward 	/*NOTREACHED*/
2361219Skas }
2371219Skas 
2381219Skas /*
2397571Skurt  * Copy a string, lowercasing it as we go.
2407571Skurt  */
2417571Skurt istrcpy(dest, src)
242*31142Sedward 	register char *dest, *src;
2437571Skurt {
2447571Skurt 
2457571Skurt 	do {
246*31142Sedward 		if (isupper(*src))
247*31142Sedward 			*dest++ = tolower(*src);
248*31142Sedward 		else
249*31142Sedward 			*dest++ = *src;
250*31142Sedward 	} while (*src++ != 0);
2517571Skurt }
2527571Skurt 
2537571Skurt /*
2541219Skas  * The following code deals with input stacking to do source
2551219Skas  * commands.  All but the current file pointer are saved on
2561219Skas  * the stack.
2571219Skas  */
2581219Skas 
2591219Skas static	int	ssp = -1;		/* Top of file stack */
2601519Skas struct sstack {
2611519Skas 	FILE	*s_file;		/* File we were in. */
2621519Skas 	int	s_cond;			/* Saved state of conditionals */
2635785Skurt 	int	s_loading;		/* Loading .mailrc, etc. */
26418661Sserge } sstack[NOFILE];
2651219Skas 
2661219Skas /*
2671219Skas  * Pushdown current input file and switch to a new one.
2681219Skas  * Set the global flag "sourcing" so that others will realize
2691219Skas  * that they are no longer reading from a tty (in all probability).
2701219Skas  */
2711219Skas 
2721219Skas source(name)
2731219Skas 	char name[];
2741219Skas {
2751219Skas 	register FILE *fi;
2763914Skurt 	register char *cp;
2771219Skas 
2783914Skurt 	if ((cp = expand(name)) == NOSTR)
2791219Skas 		return(1);
2803914Skurt 	if ((fi = fopen(cp, "r")) == NULL) {
2813914Skurt 		perror(cp);
2823914Skurt 		return(1);
2831219Skas 	}
28418661Sserge 	if (ssp >= NOFILE - 2) {
2851219Skas 		printf("Too much \"sourcing\" going on.\n");
2861219Skas 		fclose(fi);
2871219Skas 		return(1);
2881219Skas 	}
2891519Skas 	sstack[++ssp].s_file = input;
2901519Skas 	sstack[ssp].s_cond = cond;
2915785Skurt 	sstack[ssp].s_loading = loading;
2925785Skurt 	loading = 0;
2931519Skas 	cond = CANY;
2941219Skas 	input = fi;
2951219Skas 	sourcing++;
2961219Skas 	return(0);
2971219Skas }
2981219Skas 
2991219Skas /*
3001219Skas  * Pop the current input back to the previous level.
3011219Skas  * Update the "sourcing" flag as appropriate.
3021219Skas  */
3031219Skas 
3041219Skas unstack()
3051219Skas {
3061219Skas 	if (ssp < 0) {
3071219Skas 		printf("\"Source\" stack over-pop.\n");
3081219Skas 		sourcing = 0;
3091219Skas 		return(1);
3101219Skas 	}
3111219Skas 	fclose(input);
3121519Skas 	if (cond != CANY)
3131519Skas 		printf("Unmatched \"if\"\n");
3141519Skas 	cond = sstack[ssp].s_cond;
3155785Skurt 	loading = sstack[ssp].s_loading;
3161519Skas 	input = sstack[ssp--].s_file;
3171219Skas 	if (ssp < 0)
3185785Skurt 		sourcing = loading;
3191219Skas 	return(0);
3201219Skas }
3211219Skas 
3221219Skas /*
3231219Skas  * Touch the indicated file.
3241219Skas  * This is nifty for the shell.
3251219Skas  * If we have the utime() system call, this is better served
3261219Skas  * by using that, since it will work for empty files.
3271219Skas  * On non-utime systems, we must sleep a second, then read.
3281219Skas  */
3291219Skas 
3301219Skas alter(name)
3311219Skas 	char name[];
3321219Skas {
3331219Skas #ifdef UTIME
3341219Skas 	struct stat statb;
3351219Skas 	long time();
3361219Skas 	time_t time_p[2];
3371219Skas #else
3381219Skas 	register int pid, f;
3391219Skas 	char w;
3401219Skas #endif UTIME
3411219Skas 
3421219Skas #ifdef UTIME
3431219Skas 	if (stat(name, &statb) < 0)
3441219Skas 		return;
3451219Skas 	time_p[0] = time((long *) 0) + 1;
3461219Skas 	time_p[1] = statb.st_mtime;
3471219Skas 	utime(name, time_p);
3481219Skas #else
3491219Skas 	sleep(1);
3501219Skas 	if ((f = open(name, 0)) < 0)
3514389Skurt 		return;
3521219Skas 	read(f, &w, 1);
3531219Skas 	exit(0);
3541219Skas #endif
3551219Skas }
3561219Skas 
3571219Skas /*
3581219Skas  * Examine the passed line buffer and
3591219Skas  * return true if it is all blanks and tabs.
3601219Skas  */
3611219Skas 
3621219Skas blankline(linebuf)
3631219Skas 	char linebuf[];
3641219Skas {
3651219Skas 	register char *cp;
3661219Skas 
3671219Skas 	for (cp = linebuf; *cp; cp++)
36818661Sserge 		if (*cp != ' ' && *cp != '\t')
3691219Skas 			return(0);
3701219Skas 	return(1);
3711219Skas }
3721219Skas 
3731219Skas /*
3743195Skas  * Get sender's name from this message.  If the message has
3753195Skas  * a bunch of arpanet stuff in it, we may have to skin the name
3763195Skas  * before returning it.
3773195Skas  */
3783195Skas char *
3793195Skas nameof(mp, reptype)
3803195Skas 	register struct message *mp;
3813195Skas {
3825237Skurt 	register char *cp, *cp2;
3833195Skas 
3845237Skurt 	cp = skin(name1(mp, reptype));
3855237Skurt 	if (reptype != 0 || charcount(cp, '!') < 2)
3865237Skurt 		return(cp);
3875237Skurt 	cp2 = rindex(cp, '!');
3885237Skurt 	cp2--;
3895237Skurt 	while (cp2 > cp && *cp2 != '!')
3905237Skurt 		cp2--;
3915237Skurt 	if (*cp2 == '!')
3925237Skurt 		return(cp2 + 1);
3935237Skurt 	return(cp);
3943195Skas }
3953195Skas 
3963195Skas /*
39725912Smckusick  * Skin an arpa net address according to the RFC 822 interpretation
3983195Skas  * of "host-phrase."
3993195Skas  */
4003195Skas char *
4013195Skas skin(name)
4023195Skas 	char *name;
4033195Skas {
4043195Skas 	register int c;
4053195Skas 	register char *cp, *cp2;
40625912Smckusick 	char *bufend;
4073195Skas 	int gotlt, lastsp;
4083195Skas 	char nbuf[BUFSIZ];
40918661Sserge 	int nesting;
4103195Skas 
4113195Skas 	if (name == NOSTR)
4123195Skas 		return(NOSTR);
41312819Sleres 	if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
414*31142Sedward 	    && index(name, ' ') == NOSTR)
4153195Skas 		return(name);
4163195Skas 	gotlt = 0;
4173195Skas 	lastsp = 0;
41825912Smckusick 	bufend = nbuf;
41925912Smckusick 	for (cp = name, cp2 = bufend; c = *cp++; ) {
4203195Skas 		switch (c) {
4213195Skas 		case '(':
42225912Smckusick 			/*
42325912Smckusick 			 * Start of a "comment".
42425912Smckusick 			 * Ignore it.
42525912Smckusick 			 */
42618661Sserge 			nesting = 1;
42725912Smckusick 			while ((c = *cp) != 0) {
42825912Smckusick 				cp++;
42925912Smckusick 				switch (c) {
43025912Smckusick 				case '\\':
43125912Smckusick 					if (*cp == 0)
43225912Smckusick 						goto outcm;
43325912Smckusick 					cp++;
43425912Smckusick 					break;
43518661Sserge 				case '(':
43618661Sserge 					nesting++;
43718661Sserge 					break;
43818661Sserge 
43918661Sserge 				case ')':
44018661Sserge 					--nesting;
44118661Sserge 					break;
44218661Sserge 				}
44318661Sserge 
44418661Sserge 				if (nesting <= 0)
44518661Sserge 					break;
44618661Sserge 			}
44725912Smckusick 		outcm:
44812819Sleres 			lastsp = 0;
4493195Skas 			break;
4503195Skas 
45125912Smckusick 		case '"':
45225912Smckusick 			/*
45325912Smckusick 			 * Start of a "quoted-string".
45425912Smckusick 			 * Copy it in its entirety.
45525912Smckusick 			 */
45625912Smckusick 			while ((c = *cp) != 0) {
45725912Smckusick 				cp++;
45825912Smckusick 				switch (c) {
45925912Smckusick 				case '\\':
46025912Smckusick 					if ((c = *cp) == 0)
46125912Smckusick 						goto outqs;
46225912Smckusick 					cp++;
46325912Smckusick 					break;
46425912Smckusick 				case '"':
46525912Smckusick 					goto outqs;
46625912Smckusick 				}
46725912Smckusick 				*cp2++ = c;
46825912Smckusick 			}
46925912Smckusick 		outqs:
47025912Smckusick 			lastsp = 0;
47125912Smckusick 			break;
47225912Smckusick 
4733195Skas 		case ' ':
47412819Sleres 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
47512819Sleres 				cp += 3, *cp2++ = '@';
47612819Sleres 			else
47712819Sleres 			if (cp[0] == '@' && cp[1] == ' ')
47812819Sleres 				cp += 2, *cp2++ = '@';
47912819Sleres 			else
48012819Sleres 				lastsp = 1;
4813195Skas 			break;
4823195Skas 
4833195Skas 		case '<':
48425912Smckusick 			cp2 = bufend;
4853195Skas 			gotlt++;
4863195Skas 			lastsp = 0;
4873195Skas 			break;
4883195Skas 
4893195Skas 		case '>':
49025912Smckusick 			if (gotlt) {
49125912Smckusick 				gotlt = 0;
49225912Smckusick 				while (*cp != ',' && *cp != 0)
49325912Smckusick 					cp++;
49425912Smckusick 				if (*cp == 0 )
49525912Smckusick 					goto done;
49625912Smckusick 				*cp2++ = ',';
49725912Smckusick 				*cp2++ = ' ';
49825912Smckusick 				bufend = cp2;
49925912Smckusick 				break;
50025912Smckusick 			}
5013195Skas 
5023195Skas 			/* Fall into . . . */
5033195Skas 
5043195Skas 		default:
5053195Skas 			if (lastsp) {
5063195Skas 				lastsp = 0;
5073195Skas 				*cp2++ = ' ';
5083195Skas 			}
5093195Skas 			*cp2++ = c;
5103195Skas 			break;
5113195Skas 		}
5123195Skas 	}
5133195Skas done:
5143195Skas 	*cp2 = 0;
5153195Skas 
5163195Skas 	return(savestr(nbuf));
5173195Skas }
5183195Skas 
5193195Skas /*
5201219Skas  * Fetch the sender's name from the passed message.
5213195Skas  * Reptype can be
5223195Skas  *	0 -- get sender's name for display purposes
5233195Skas  *	1 -- get sender's name for reply
5243195Skas  *	2 -- get sender's name for Reply
5251219Skas  */
5261219Skas 
5271219Skas char *
5283195Skas name1(mp, reptype)
5291219Skas 	register struct message *mp;
5301219Skas {
5311219Skas 	char namebuf[LINESIZE];
5321219Skas 	char linebuf[LINESIZE];
5331219Skas 	register char *cp, *cp2;
5341219Skas 	register FILE *ibuf;
5351219Skas 	int first = 1;
5361219Skas 
5373195Skas 	if ((cp = hfield("from", mp)) != NOSTR)
538*31142Sedward 		return cp;
5393195Skas 	if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
540*31142Sedward 		return cp;
5411219Skas 	ibuf = setinput(mp);
542*31142Sedward 	namebuf[0] = 0;
543*31142Sedward 	if (readline(ibuf, linebuf) < 0)
5441219Skas 		return(savestr(namebuf));
5451219Skas newname:
546*31142Sedward 	for (cp = linebuf; *cp && *cp != ' '; cp++)
5471219Skas 		;
548*31142Sedward 	for (; *cp == ' ' || *cp == '\t'; cp++)
5491219Skas 		;
550*31142Sedward 	for (cp2 = &namebuf[strlen(namebuf)];
551*31142Sedward 	     *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
552*31142Sedward 		*cp2++ = *cp++;
5531219Skas 	*cp2 = '\0';
554*31142Sedward 	if (readline(ibuf, linebuf) < 0)
5551219Skas 		return(savestr(namebuf));
5561219Skas 	if ((cp = index(linebuf, 'F')) == NULL)
5571219Skas 		return(savestr(namebuf));
5581219Skas 	if (strncmp(cp, "From", 4) != 0)
5591219Skas 		return(savestr(namebuf));
5601219Skas 	while ((cp = index(cp, 'r')) != NULL) {
5611219Skas 		if (strncmp(cp, "remote", 6) == 0) {
5621219Skas 			if ((cp = index(cp, 'f')) == NULL)
5631219Skas 				break;
5641219Skas 			if (strncmp(cp, "from", 4) != 0)
5651219Skas 				break;
5661219Skas 			if ((cp = index(cp, ' ')) == NULL)
5671219Skas 				break;
5681219Skas 			cp++;
5691219Skas 			if (first) {
570*31142Sedward 				strcpy(namebuf, cp);
5711219Skas 				first = 0;
5721219Skas 			} else
5731219Skas 				strcpy(rindex(namebuf, '!')+1, cp);
5741219Skas 			strcat(namebuf, "!");
5751219Skas 			goto newname;
5761219Skas 		}
5771219Skas 		cp++;
5781219Skas 	}
5791219Skas 	return(savestr(namebuf));
5801219Skas }
5811219Skas 
5821219Skas /*
5835237Skurt  * Count the occurances of c in str
5845237Skurt  */
5855237Skurt charcount(str, c)
5865237Skurt 	char *str;
5875237Skurt {
5885237Skurt 	register char *cp;
5895237Skurt 	register int i;
5905237Skurt 
5915237Skurt 	for (i = 0, cp = str; *cp; cp++)
5925237Skurt 		if (*cp == c)
5935237Skurt 			i++;
5945237Skurt 	return(i);
5955237Skurt }
5965237Skurt 
5975237Skurt /*
598*31142Sedward  * Are any of the characters in the two strings the same?
5991219Skas  */
6001219Skas 
601*31142Sedward anyof(s1, s2)
602*31142Sedward 	register char *s1, *s2;
6031219Skas {
6041219Skas 
605*31142Sedward 	while (*s1)
606*31142Sedward 		if (index(s2, *s1++))
607*31142Sedward 			return 1;
608*31142Sedward 	return 0;
6091219Skas }
6101219Skas 
6111219Skas /*
612*31142Sedward  * Convert c to upper case
6131219Skas  */
6141219Skas 
615*31142Sedward raise(c)
616*31142Sedward 	register c;
617*31142Sedward {
618*31142Sedward 
619*31142Sedward 	if (islower(c))
620*31142Sedward 		return toupper(c);
621*31142Sedward 	return c;
622*31142Sedward }
623*31142Sedward 
624*31142Sedward /*
625*31142Sedward  * Copy s1 to s2, return pointer to null in s2.
626*31142Sedward  */
627*31142Sedward 
628*31142Sedward char *
629*31142Sedward copy(s1, s2)
6301219Skas 	register char *s1, *s2;
6311219Skas {
6321219Skas 
633*31142Sedward 	while (*s2++ = *s1++)
634*31142Sedward 		;
635*31142Sedward 	return s2 - 1;
6361219Skas }
6371219Skas 
6381219Skas /*
639*31142Sedward  * Add a single character onto a string.
640*31142Sedward  */
641*31142Sedward 
642*31142Sedward stradd(str, c)
643*31142Sedward 	register char *str;
644*31142Sedward {
645*31142Sedward 
646*31142Sedward 	while (*str++)
647*31142Sedward 		;
648*31142Sedward 	str[-1] = c;
649*31142Sedward 	*str = 0;
650*31142Sedward }
651*31142Sedward 
652*31142Sedward /*
6537571Skurt  * See if the given header field is supposed to be ignored.
6547571Skurt  */
6557571Skurt isign(field)
6567571Skurt 	char *field;
6577571Skurt {
6587571Skurt 	char realfld[BUFSIZ];
6597571Skurt 
66018661Sserge 	/*
66118661Sserge 	 * Lower-case the string, so that "Status" and "status"
66218661Sserge 	 * will hash to the same place.
66318661Sserge 	 */
6647571Skurt 	istrcpy(realfld, field);
66518661Sserge 	if (nretained > 0)
66618661Sserge 		return (!member(realfld, retain));
66718661Sserge 	else
66818661Sserge 		return (member(realfld, ignore));
6697571Skurt }
67018661Sserge 
67118661Sserge member(realfield, table)
67218661Sserge 	register char *realfield;
673*31142Sedward 	struct ignore **table;
67418661Sserge {
67518661Sserge 	register struct ignore *igp;
67618661Sserge 
67718661Sserge 	for (igp = table[hash(realfield)]; igp != 0; igp = igp->i_link)
678*31142Sedward 		if (*igp->i_field == *realfield &&
679*31142Sedward 		    equal(igp->i_field, realfield))
68018661Sserge 			return (1);
68118661Sserge 	return (0);
68218661Sserge }
683