xref: /csrg-svn/usr.bin/mail/aux.c (revision 34692)
122444Sdist /*
222444Sdist  * Copyright (c) 1980 Regents of the University of California.
333499Sbostic  * All rights reserved.
433499Sbostic  *
533499Sbostic  * Redistribution and use in source and binary forms are permitted
633499Sbostic  * provided that this notice is preserved and that due credit is given
733499Sbostic  * to the University of California at Berkeley. The name of the University
833499Sbostic  * may not be used to endorse or promote products derived from this
933499Sbostic  * software without specific prior written permission. This software
1033499Sbostic  * is provided ``as is'' without express or implied warranty.
1122444Sdist  */
1222444Sdist 
1333499Sbostic #ifdef notdef
14*34692Sedward static char sccsid[] = "@(#)aux.c	5.8 (Berkeley) 06/09/88";
1533499Sbostic #endif /* notdef */
161219Skas 
171219Skas #include "rcv.h"
181219Skas #include <sys/stat.h>
191219Skas 
201219Skas /*
211219Skas  * Mail -- a mail program
221219Skas  *
231219Skas  * Auxiliary functions.
241219Skas  */
251219Skas 
261219Skas /*
271219Skas  * Return a pointer to a dynamic copy of the argument.
281219Skas  */
291219Skas 
301219Skas char *
311219Skas savestr(str)
321219Skas 	char *str;
331219Skas {
341219Skas 	register char *cp, *cp2, *top;
351219Skas 
361219Skas 	for (cp = str; *cp; cp++)
371219Skas 		;
381219Skas 	top = salloc(cp-str + 1);
391219Skas 	if (top == NOSTR)
401219Skas 		return(NOSTR);
411219Skas 	for (cp = str, cp2 = top; *cp; cp++)
421219Skas 		*cp2++ = *cp;
431219Skas 	*cp2 = 0;
441219Skas 	return(top);
451219Skas }
461219Skas 
471219Skas /*
481219Skas  * Announce a fatal error and die.
491219Skas  */
501219Skas 
5131142Sedward /*VARARGS1*/
5231142Sedward panic(fmt, a, b)
5331142Sedward 	char *fmt;
541219Skas {
5531142Sedward 	fprintf(stderr, "panic: ");
5631142Sedward 	fprintf(stderr, fmt, a, b);
5731142Sedward 	putc('\n', stderr);
581219Skas 	exit(1);
591219Skas }
601219Skas 
611219Skas /*
621219Skas  * Touch the named message by setting its MTOUCH flag.
631219Skas  * Touched messages have the effect of not being sent
641219Skas  * back to the system mailbox on exit.
651219Skas  */
661219Skas 
671219Skas touch(mesg)
681219Skas {
691479Skas 	register struct message *mp;
701479Skas 
711479Skas 	if (mesg < 1 || mesg > msgCount)
721479Skas 		return;
731479Skas 	mp = &message[mesg-1];
741479Skas 	mp->m_flag |= MTOUCH;
751479Skas 	if ((mp->m_flag & MREAD) == 0)
761479Skas 		mp->m_flag |= MREAD|MSTATUS;
771219Skas }
781219Skas 
791219Skas /*
801219Skas  * Test to see if the passed file name is a directory.
811219Skas  * Return true if it is.
821219Skas  */
831219Skas 
841219Skas isdir(name)
851219Skas 	char name[];
861219Skas {
871219Skas 	struct stat sbuf;
881219Skas 
891219Skas 	if (stat(name, &sbuf) < 0)
901219Skas 		return(0);
911219Skas 	return((sbuf.st_mode & S_IFMT) == S_IFDIR);
921219Skas }
931219Skas 
941219Skas /*
951219Skas  * Count the number of arguments in the given string raw list.
961219Skas  */
971219Skas 
981219Skas argcount(argv)
991219Skas 	char **argv;
1001219Skas {
1011219Skas 	register char **ap;
1021219Skas 
10331142Sedward 	for (ap = argv; *ap++ != NOSTR;)
1041219Skas 		;
10531142Sedward 	return ap - argv - 1;
1061219Skas }
1071219Skas 
1081219Skas /*
1091219Skas  * Return the desired header line from the passed message
1101219Skas  * pointer (or NOSTR if the desired header field is not available).
1111219Skas  */
1121219Skas 
1131219Skas char *
1141219Skas hfield(field, mp)
1151219Skas 	char field[];
1161219Skas 	struct message *mp;
1171219Skas {
1181219Skas 	register FILE *ibuf;
1191219Skas 	char linebuf[LINESIZE];
1201219Skas 	register int lc;
12131142Sedward 	register char *hfield;
12231142Sedward 	char *colon;
1231219Skas 
1241219Skas 	ibuf = setinput(mp);
12531142Sedward 	if ((lc = mp->m_lines - 1) < 0)
12631142Sedward 		return NOSTR;
1271219Skas 	if (readline(ibuf, linebuf) < 0)
12831142Sedward 		return NOSTR;
12931142Sedward 	while (lc > 0) {
13031142Sedward 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
13131142Sedward 			return NOSTR;
13231142Sedward 		if (hfield = ishfield(linebuf, colon, field))
13331142Sedward 			return savestr(hfield);
13431142Sedward 	}
13531142Sedward 	return NOSTR;
1361219Skas }
1371219Skas 
1381219Skas /*
1391219Skas  * Return the next header field found in the given message.
14031142Sedward  * Return >= 0 if something found, < 0 elsewise.
14131142Sedward  * "colon" is set to point to the colon in the header.
1421219Skas  * Must deal with \ continuations & other such fraud.
1431219Skas  */
1441219Skas 
14531142Sedward gethfield(f, linebuf, rem, colon)
1461219Skas 	register FILE *f;
1471219Skas 	char linebuf[];
1481219Skas 	register int rem;
14931142Sedward 	char **colon;
1501219Skas {
1511219Skas 	char line2[LINESIZE];
1521219Skas 	register char *cp, *cp2;
1531219Skas 	register int c;
1541219Skas 
1551219Skas 	for (;;) {
15631142Sedward 		if (--rem < 0)
15731142Sedward 			return -1;
15831142Sedward 		if ((c = readline(f, linebuf)) <= 0)
15931142Sedward 			return -1;
16031142Sedward 		for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
16131142Sedward 		     cp++)
16231142Sedward 			;
16331142Sedward 		if (*cp != ':' || cp == linebuf)
1641219Skas 			continue;
1651219Skas 		/*
1661219Skas 		 * I guess we got a headline.
1671219Skas 		 * Handle wraparounding
1681219Skas 		 */
16931142Sedward 		*colon = cp;
17031142Sedward 		cp = linebuf + c;
1711219Skas 		for (;;) {
17231142Sedward 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
17331142Sedward 				;
17431142Sedward 			cp++;
1751219Skas 			if (rem <= 0)
1761219Skas 				break;
17731142Sedward 			ungetc(c = getc(f), f);
17831142Sedward 			if (c != ' ' && c != '\t')
1791219Skas 				break;
18031142Sedward 			if ((c = readline(f, line2)) < 0)
1811219Skas 				break;
1821219Skas 			rem--;
18331142Sedward 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
1841219Skas 				;
18531142Sedward 			c -= cp2 - line2;
18631142Sedward 			if (cp + c >= linebuf + LINESIZE - 2)
1871219Skas 				break;
1881219Skas 			*cp++ = ' ';
18931142Sedward 			bcopy(cp2, cp, c);
19031142Sedward 			cp += c;
1911219Skas 		}
19231142Sedward 		*cp = 0;
19331142Sedward 		return rem;
1941219Skas 	}
1951219Skas 	/* NOTREACHED */
1961219Skas }
1971219Skas 
1981219Skas /*
1991219Skas  * Check whether the passed line is a header line of
20031142Sedward  * the desired breed.  Return the field body, or 0.
2011219Skas  */
2021219Skas 
20331142Sedward char*
20431142Sedward ishfield(linebuf, colon, field)
2051219Skas 	char linebuf[], field[];
20631142Sedward 	char *colon;
2071219Skas {
20831142Sedward 	register char *cp = colon;
2091219Skas 
2101219Skas 	*cp = 0;
21131142Sedward 	if (!icequal(linebuf, field)) {
21231142Sedward 		*cp = ':';
21331142Sedward 		return 0;
2141219Skas 	}
21531142Sedward 	*cp = ':';
21631142Sedward 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
21731142Sedward 		;
21831142Sedward 	return cp;
2191219Skas }
2201219Skas 
2211219Skas /*
2221219Skas  * Compare two strings, ignoring case.
2231219Skas  */
2241219Skas 
2251219Skas icequal(s1, s2)
2261219Skas 	register char *s1, *s2;
2271219Skas {
22831142Sedward 	register c1, c2;
2291219Skas 
23031142Sedward 	for (;;) {
23131142Sedward 		if ((c1 = (unsigned char)*s1++) !=
23231142Sedward 		    (c2 = (unsigned char)*s2++)) {
23331142Sedward 			if (isupper(c1))
23431142Sedward 				c1 = tolower(c1);
23531142Sedward 			if (c1 != c2)
23631142Sedward 				return 0;
23731142Sedward 		}
23831142Sedward 		if (c1 == 0)
23931142Sedward 			return 1;
24031142Sedward 	}
24131142Sedward 	/*NOTREACHED*/
2421219Skas }
2431219Skas 
2441219Skas /*
2457571Skurt  * Copy a string, lowercasing it as we go.
2467571Skurt  */
2477571Skurt istrcpy(dest, src)
24831142Sedward 	register char *dest, *src;
2497571Skurt {
2507571Skurt 
2517571Skurt 	do {
25231142Sedward 		if (isupper(*src))
25331142Sedward 			*dest++ = tolower(*src);
25431142Sedward 		else
25531142Sedward 			*dest++ = *src;
25631142Sedward 	} while (*src++ != 0);
2577571Skurt }
2587571Skurt 
2597571Skurt /*
2601219Skas  * The following code deals with input stacking to do source
2611219Skas  * commands.  All but the current file pointer are saved on
2621219Skas  * the stack.
2631219Skas  */
2641219Skas 
2651219Skas static	int	ssp = -1;		/* Top of file stack */
2661519Skas struct sstack {
2671519Skas 	FILE	*s_file;		/* File we were in. */
2681519Skas 	int	s_cond;			/* Saved state of conditionals */
2695785Skurt 	int	s_loading;		/* Loading .mailrc, etc. */
27018661Sserge } sstack[NOFILE];
2711219Skas 
2721219Skas /*
2731219Skas  * Pushdown current input file and switch to a new one.
2741219Skas  * Set the global flag "sourcing" so that others will realize
2751219Skas  * that they are no longer reading from a tty (in all probability).
2761219Skas  */
2771219Skas 
2781219Skas source(name)
2791219Skas 	char name[];
2801219Skas {
2811219Skas 	register FILE *fi;
2823914Skurt 	register char *cp;
2831219Skas 
2843914Skurt 	if ((cp = expand(name)) == NOSTR)
2851219Skas 		return(1);
2863914Skurt 	if ((fi = fopen(cp, "r")) == NULL) {
2873914Skurt 		perror(cp);
2883914Skurt 		return(1);
2891219Skas 	}
29018661Sserge 	if (ssp >= NOFILE - 2) {
2911219Skas 		printf("Too much \"sourcing\" going on.\n");
2921219Skas 		fclose(fi);
2931219Skas 		return(1);
2941219Skas 	}
2951519Skas 	sstack[++ssp].s_file = input;
2961519Skas 	sstack[ssp].s_cond = cond;
2975785Skurt 	sstack[ssp].s_loading = loading;
2985785Skurt 	loading = 0;
2991519Skas 	cond = CANY;
3001219Skas 	input = fi;
3011219Skas 	sourcing++;
3021219Skas 	return(0);
3031219Skas }
3041219Skas 
3051219Skas /*
3061219Skas  * Pop the current input back to the previous level.
3071219Skas  * Update the "sourcing" flag as appropriate.
3081219Skas  */
3091219Skas 
3101219Skas unstack()
3111219Skas {
3121219Skas 	if (ssp < 0) {
3131219Skas 		printf("\"Source\" stack over-pop.\n");
3141219Skas 		sourcing = 0;
3151219Skas 		return(1);
3161219Skas 	}
3171219Skas 	fclose(input);
3181519Skas 	if (cond != CANY)
3191519Skas 		printf("Unmatched \"if\"\n");
3201519Skas 	cond = sstack[ssp].s_cond;
3215785Skurt 	loading = sstack[ssp].s_loading;
3221519Skas 	input = sstack[ssp--].s_file;
3231219Skas 	if (ssp < 0)
3245785Skurt 		sourcing = loading;
3251219Skas 	return(0);
3261219Skas }
3271219Skas 
3281219Skas /*
3291219Skas  * Touch the indicated file.
3301219Skas  * This is nifty for the shell.
3311219Skas  * If we have the utime() system call, this is better served
3321219Skas  * by using that, since it will work for empty files.
3331219Skas  * On non-utime systems, we must sleep a second, then read.
3341219Skas  */
3351219Skas 
3361219Skas alter(name)
3371219Skas 	char name[];
3381219Skas {
3391219Skas #ifdef UTIME
3401219Skas 	struct stat statb;
3411219Skas 	long time();
3421219Skas 	time_t time_p[2];
3431219Skas #else
3441219Skas 	register int pid, f;
3451219Skas 	char w;
3461219Skas #endif UTIME
3471219Skas 
3481219Skas #ifdef UTIME
3491219Skas 	if (stat(name, &statb) < 0)
3501219Skas 		return;
3511219Skas 	time_p[0] = time((long *) 0) + 1;
3521219Skas 	time_p[1] = statb.st_mtime;
3531219Skas 	utime(name, time_p);
3541219Skas #else
3551219Skas 	sleep(1);
3561219Skas 	if ((f = open(name, 0)) < 0)
3574389Skurt 		return;
3581219Skas 	read(f, &w, 1);
3591219Skas 	exit(0);
3601219Skas #endif
3611219Skas }
3621219Skas 
3631219Skas /*
3641219Skas  * Examine the passed line buffer and
3651219Skas  * return true if it is all blanks and tabs.
3661219Skas  */
3671219Skas 
3681219Skas blankline(linebuf)
3691219Skas 	char linebuf[];
3701219Skas {
3711219Skas 	register char *cp;
3721219Skas 
3731219Skas 	for (cp = linebuf; *cp; cp++)
37418661Sserge 		if (*cp != ' ' && *cp != '\t')
3751219Skas 			return(0);
3761219Skas 	return(1);
3771219Skas }
3781219Skas 
3791219Skas /*
3803195Skas  * Get sender's name from this message.  If the message has
3813195Skas  * a bunch of arpanet stuff in it, we may have to skin the name
3823195Skas  * before returning it.
3833195Skas  */
3843195Skas char *
3853195Skas nameof(mp, reptype)
3863195Skas 	register struct message *mp;
3873195Skas {
3885237Skurt 	register char *cp, *cp2;
3893195Skas 
3905237Skurt 	cp = skin(name1(mp, reptype));
3915237Skurt 	if (reptype != 0 || charcount(cp, '!') < 2)
3925237Skurt 		return(cp);
3935237Skurt 	cp2 = rindex(cp, '!');
3945237Skurt 	cp2--;
3955237Skurt 	while (cp2 > cp && *cp2 != '!')
3965237Skurt 		cp2--;
3975237Skurt 	if (*cp2 == '!')
3985237Skurt 		return(cp2 + 1);
3995237Skurt 	return(cp);
4003195Skas }
4013195Skas 
4023195Skas /*
40325912Smckusick  * Skin an arpa net address according to the RFC 822 interpretation
4043195Skas  * of "host-phrase."
4053195Skas  */
4063195Skas char *
4073195Skas skin(name)
4083195Skas 	char *name;
4093195Skas {
4103195Skas 	register int c;
4113195Skas 	register char *cp, *cp2;
41225912Smckusick 	char *bufend;
4133195Skas 	int gotlt, lastsp;
4143195Skas 	char nbuf[BUFSIZ];
41518661Sserge 	int nesting;
4163195Skas 
4173195Skas 	if (name == NOSTR)
4183195Skas 		return(NOSTR);
41912819Sleres 	if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
42031142Sedward 	    && index(name, ' ') == NOSTR)
4213195Skas 		return(name);
4223195Skas 	gotlt = 0;
4233195Skas 	lastsp = 0;
42425912Smckusick 	bufend = nbuf;
42525912Smckusick 	for (cp = name, cp2 = bufend; c = *cp++; ) {
4263195Skas 		switch (c) {
4273195Skas 		case '(':
42825912Smckusick 			/*
42925912Smckusick 			 * Start of a "comment".
43025912Smckusick 			 * Ignore it.
43125912Smckusick 			 */
43218661Sserge 			nesting = 1;
43325912Smckusick 			while ((c = *cp) != 0) {
43425912Smckusick 				cp++;
43525912Smckusick 				switch (c) {
43625912Smckusick 				case '\\':
43725912Smckusick 					if (*cp == 0)
43825912Smckusick 						goto outcm;
43925912Smckusick 					cp++;
44025912Smckusick 					break;
44118661Sserge 				case '(':
44218661Sserge 					nesting++;
44318661Sserge 					break;
44418661Sserge 
44518661Sserge 				case ')':
44618661Sserge 					--nesting;
44718661Sserge 					break;
44818661Sserge 				}
44918661Sserge 
45018661Sserge 				if (nesting <= 0)
45118661Sserge 					break;
45218661Sserge 			}
45325912Smckusick 		outcm:
45412819Sleres 			lastsp = 0;
4553195Skas 			break;
4563195Skas 
45725912Smckusick 		case '"':
45825912Smckusick 			/*
45925912Smckusick 			 * Start of a "quoted-string".
46025912Smckusick 			 * Copy it in its entirety.
46125912Smckusick 			 */
46225912Smckusick 			while ((c = *cp) != 0) {
46325912Smckusick 				cp++;
46425912Smckusick 				switch (c) {
46525912Smckusick 				case '\\':
46625912Smckusick 					if ((c = *cp) == 0)
46725912Smckusick 						goto outqs;
46825912Smckusick 					cp++;
46925912Smckusick 					break;
47025912Smckusick 				case '"':
47125912Smckusick 					goto outqs;
47225912Smckusick 				}
47325912Smckusick 				*cp2++ = c;
47425912Smckusick 			}
47525912Smckusick 		outqs:
47625912Smckusick 			lastsp = 0;
47725912Smckusick 			break;
47825912Smckusick 
4793195Skas 		case ' ':
48012819Sleres 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
48112819Sleres 				cp += 3, *cp2++ = '@';
48212819Sleres 			else
48312819Sleres 			if (cp[0] == '@' && cp[1] == ' ')
48412819Sleres 				cp += 2, *cp2++ = '@';
48512819Sleres 			else
48612819Sleres 				lastsp = 1;
4873195Skas 			break;
4883195Skas 
4893195Skas 		case '<':
49025912Smckusick 			cp2 = bufend;
4913195Skas 			gotlt++;
4923195Skas 			lastsp = 0;
4933195Skas 			break;
4943195Skas 
4953195Skas 		case '>':
49625912Smckusick 			if (gotlt) {
49725912Smckusick 				gotlt = 0;
49825912Smckusick 				while (*cp != ',' && *cp != 0)
49925912Smckusick 					cp++;
50025912Smckusick 				if (*cp == 0 )
50125912Smckusick 					goto done;
50225912Smckusick 				*cp2++ = ',';
50325912Smckusick 				*cp2++ = ' ';
50425912Smckusick 				bufend = cp2;
50525912Smckusick 				break;
50625912Smckusick 			}
5073195Skas 
5083195Skas 			/* Fall into . . . */
5093195Skas 
5103195Skas 		default:
5113195Skas 			if (lastsp) {
5123195Skas 				lastsp = 0;
5133195Skas 				*cp2++ = ' ';
5143195Skas 			}
5153195Skas 			*cp2++ = c;
5163195Skas 			break;
5173195Skas 		}
5183195Skas 	}
5193195Skas done:
5203195Skas 	*cp2 = 0;
5213195Skas 
5223195Skas 	return(savestr(nbuf));
5233195Skas }
5243195Skas 
5253195Skas /*
5261219Skas  * Fetch the sender's name from the passed message.
5273195Skas  * Reptype can be
5283195Skas  *	0 -- get sender's name for display purposes
5293195Skas  *	1 -- get sender's name for reply
5303195Skas  *	2 -- get sender's name for Reply
5311219Skas  */
5321219Skas 
5331219Skas char *
5343195Skas name1(mp, reptype)
5351219Skas 	register struct message *mp;
5361219Skas {
5371219Skas 	char namebuf[LINESIZE];
5381219Skas 	char linebuf[LINESIZE];
5391219Skas 	register char *cp, *cp2;
5401219Skas 	register FILE *ibuf;
5411219Skas 	int first = 1;
5421219Skas 
5433195Skas 	if ((cp = hfield("from", mp)) != NOSTR)
54431142Sedward 		return cp;
5453195Skas 	if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
54631142Sedward 		return cp;
5471219Skas 	ibuf = setinput(mp);
54831142Sedward 	namebuf[0] = 0;
54931142Sedward 	if (readline(ibuf, linebuf) < 0)
5501219Skas 		return(savestr(namebuf));
5511219Skas newname:
55231142Sedward 	for (cp = linebuf; *cp && *cp != ' '; cp++)
5531219Skas 		;
55431142Sedward 	for (; *cp == ' ' || *cp == '\t'; cp++)
5551219Skas 		;
55631142Sedward 	for (cp2 = &namebuf[strlen(namebuf)];
55731142Sedward 	     *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
55831142Sedward 		*cp2++ = *cp++;
5591219Skas 	*cp2 = '\0';
56031142Sedward 	if (readline(ibuf, linebuf) < 0)
5611219Skas 		return(savestr(namebuf));
5621219Skas 	if ((cp = index(linebuf, 'F')) == NULL)
5631219Skas 		return(savestr(namebuf));
5641219Skas 	if (strncmp(cp, "From", 4) != 0)
5651219Skas 		return(savestr(namebuf));
5661219Skas 	while ((cp = index(cp, 'r')) != NULL) {
5671219Skas 		if (strncmp(cp, "remote", 6) == 0) {
5681219Skas 			if ((cp = index(cp, 'f')) == NULL)
5691219Skas 				break;
5701219Skas 			if (strncmp(cp, "from", 4) != 0)
5711219Skas 				break;
5721219Skas 			if ((cp = index(cp, ' ')) == NULL)
5731219Skas 				break;
5741219Skas 			cp++;
5751219Skas 			if (first) {
57631142Sedward 				strcpy(namebuf, cp);
5771219Skas 				first = 0;
5781219Skas 			} else
5791219Skas 				strcpy(rindex(namebuf, '!')+1, cp);
5801219Skas 			strcat(namebuf, "!");
5811219Skas 			goto newname;
5821219Skas 		}
5831219Skas 		cp++;
5841219Skas 	}
5851219Skas 	return(savestr(namebuf));
5861219Skas }
5871219Skas 
5881219Skas /*
5895237Skurt  * Count the occurances of c in str
5905237Skurt  */
5915237Skurt charcount(str, c)
5925237Skurt 	char *str;
5935237Skurt {
5945237Skurt 	register char *cp;
5955237Skurt 	register int i;
5965237Skurt 
5975237Skurt 	for (i = 0, cp = str; *cp; cp++)
5985237Skurt 		if (*cp == c)
5995237Skurt 			i++;
6005237Skurt 	return(i);
6015237Skurt }
6025237Skurt 
6035237Skurt /*
60431142Sedward  * Are any of the characters in the two strings the same?
6051219Skas  */
6061219Skas 
60731142Sedward anyof(s1, s2)
60831142Sedward 	register char *s1, *s2;
6091219Skas {
6101219Skas 
61131142Sedward 	while (*s1)
61231142Sedward 		if (index(s2, *s1++))
61331142Sedward 			return 1;
61431142Sedward 	return 0;
6151219Skas }
6161219Skas 
6171219Skas /*
61831142Sedward  * Convert c to upper case
6191219Skas  */
6201219Skas 
62131142Sedward raise(c)
62231142Sedward 	register c;
62331142Sedward {
62431142Sedward 
62531142Sedward 	if (islower(c))
62631142Sedward 		return toupper(c);
62731142Sedward 	return c;
62831142Sedward }
62931142Sedward 
63031142Sedward /*
63131142Sedward  * Copy s1 to s2, return pointer to null in s2.
63231142Sedward  */
63331142Sedward 
63431142Sedward char *
63531142Sedward copy(s1, s2)
6361219Skas 	register char *s1, *s2;
6371219Skas {
6381219Skas 
63931142Sedward 	while (*s2++ = *s1++)
64031142Sedward 		;
64131142Sedward 	return s2 - 1;
6421219Skas }
6431219Skas 
6441219Skas /*
64531142Sedward  * Add a single character onto a string.
64631142Sedward  */
64731142Sedward 
64831142Sedward stradd(str, c)
64931142Sedward 	register char *str;
65031142Sedward {
65131142Sedward 
65231142Sedward 	while (*str++)
65331142Sedward 		;
65431142Sedward 	str[-1] = c;
65531142Sedward 	*str = 0;
65631142Sedward }
65731142Sedward 
65831142Sedward /*
6597571Skurt  * See if the given header field is supposed to be ignored.
6607571Skurt  */
661*34692Sedward isign(field, ignore)
6627571Skurt 	char *field;
663*34692Sedward 	struct ignoretab ignore[2];
6647571Skurt {
6657571Skurt 	char realfld[BUFSIZ];
6667571Skurt 
66718661Sserge 	/*
66818661Sserge 	 * Lower-case the string, so that "Status" and "status"
66918661Sserge 	 * will hash to the same place.
67018661Sserge 	 */
6717571Skurt 	istrcpy(realfld, field);
672*34692Sedward 	if (ignore[1].i_count > 0)
673*34692Sedward 		return (!member(realfld, ignore + 1));
67418661Sserge 	else
67518661Sserge 		return (member(realfld, ignore));
6767571Skurt }
67718661Sserge 
67818661Sserge member(realfield, table)
67918661Sserge 	register char *realfield;
680*34692Sedward 	struct ignoretab *table;
68118661Sserge {
68218661Sserge 	register struct ignore *igp;
68318661Sserge 
684*34692Sedward 	for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
68531142Sedward 		if (*igp->i_field == *realfield &&
68631142Sedward 		    equal(igp->i_field, realfield))
68718661Sserge 			return (1);
68818661Sserge 	return (0);
68918661Sserge }
690