util.c revision 18532
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
351590Srgrimesstatic char sccsid[] = "@(#)aux.c	8.1 (Berkeley) 6/6/93";
361590Srgrimes#endif /* not lint */
371590Srgrimes
381590Srgrimes#include "rcv.h"
391590Srgrimes#include "extern.h"
401590Srgrimes
411590Srgrimes/*
421590Srgrimes * Mail -- a mail program
431590Srgrimes *
441590Srgrimes * Auxiliary functions.
451590Srgrimes */
461590Srgrimes
471590Srgrimes/*
481590Srgrimes * Return a pointer to a dynamic copy of the argument.
491590Srgrimes */
501590Srgrimeschar *
511590Srgrimessavestr(str)
521590Srgrimes	char *str;
531590Srgrimes{
541590Srgrimes	char *new;
551590Srgrimes	int size = strlen(str) + 1;
561590Srgrimes
571590Srgrimes	if ((new = salloc(size)) != NOSTR)
581590Srgrimes		bcopy(str, new, size);
591590Srgrimes	return new;
601590Srgrimes}
611590Srgrimes
621590Srgrimes/*
631590Srgrimes * Make a copy of new argument incorporating old one.
641590Srgrimes */
651590Srgrimeschar *
661590Srgrimessave2str(str, old)
671590Srgrimes	char *str, *old;
681590Srgrimes{
691590Srgrimes	char *new;
701590Srgrimes	int newsize = strlen(str) + 1;
711590Srgrimes	int oldsize = old ? strlen(old) + 1 : 0;
721590Srgrimes
731590Srgrimes	if ((new = salloc(newsize + oldsize)) != NOSTR) {
741590Srgrimes		if (oldsize) {
751590Srgrimes			bcopy(old, new, oldsize);
761590Srgrimes			new[oldsize - 1] = ' ';
771590Srgrimes		}
781590Srgrimes		bcopy(str, new + oldsize, newsize);
791590Srgrimes	}
801590Srgrimes	return new;
811590Srgrimes}
821590Srgrimes
831590Srgrimes/*
841590Srgrimes * Announce a fatal error and die.
851590Srgrimes */
861590Srgrimes#if __STDC__
871590Srgrimes#include <stdarg.h>
881590Srgrimes#else
891590Srgrimes#include <varargs.h>
901590Srgrimes#endif
911590Srgrimes
921590Srgrimesvoid
931590Srgrimes#if __STDC__
941590Srgrimespanic(const char *fmt, ...)
951590Srgrimes#else
961590Srgrimespanic(fmt, va_alist)
971590Srgrimes	char *fmt;
981590Srgrimes        va_dcl
991590Srgrimes#endif
1001590Srgrimes{
1011590Srgrimes	va_list ap;
1021590Srgrimes#if __STDC__
1031590Srgrimes	va_start(ap, fmt);
1041590Srgrimes#else
1051590Srgrimes	va_start(ap);
1061590Srgrimes#endif
1071590Srgrimes	(void)fprintf(stderr, "panic: ");
1081590Srgrimes	vfprintf(stderr, fmt, ap);
1091590Srgrimes	va_end(ap);
1101590Srgrimes	(void)fprintf(stderr, "\n");
1111590Srgrimes	fflush(stderr);
1121590Srgrimes	abort();
1131590Srgrimes}
1141590Srgrimes
1151590Srgrimes/*
1161590Srgrimes * Touch the named message by setting its MTOUCH flag.
1171590Srgrimes * Touched messages have the effect of not being sent
1181590Srgrimes * back to the system mailbox on exit.
1191590Srgrimes */
1201590Srgrimesvoid
1211590Srgrimestouch(mp)
1221590Srgrimes	register struct message *mp;
1231590Srgrimes{
1241590Srgrimes
1251590Srgrimes	mp->m_flag |= MTOUCH;
1261590Srgrimes	if ((mp->m_flag & MREAD) == 0)
1271590Srgrimes		mp->m_flag |= MREAD|MSTATUS;
1281590Srgrimes}
1291590Srgrimes
1301590Srgrimes/*
1311590Srgrimes * Test to see if the passed file name is a directory.
1321590Srgrimes * Return true if it is.
1331590Srgrimes */
1341590Srgrimesint
1351590Srgrimesisdir(name)
1361590Srgrimes	char name[];
1371590Srgrimes{
1381590Srgrimes	struct stat sbuf;
1391590Srgrimes
1401590Srgrimes	if (stat(name, &sbuf) < 0)
1411590Srgrimes		return(0);
1421590Srgrimes	return((sbuf.st_mode & S_IFMT) == S_IFDIR);
1431590Srgrimes}
1441590Srgrimes
1451590Srgrimes/*
1461590Srgrimes * Count the number of arguments in the given string raw list.
1471590Srgrimes */
1481590Srgrimesint
1491590Srgrimesargcount(argv)
1501590Srgrimes	char **argv;
1511590Srgrimes{
1521590Srgrimes	register char **ap;
1531590Srgrimes
1541590Srgrimes	for (ap = argv; *ap++ != NOSTR;)
1558874Srgrimes		;
1561590Srgrimes	return ap - argv - 1;
1571590Srgrimes}
1581590Srgrimes
1591590Srgrimes/*
1601590Srgrimes * Return the desired header line from the passed message
1611590Srgrimes * pointer (or NOSTR if the desired header field is not available).
1621590Srgrimes */
1631590Srgrimeschar *
1641590Srgrimeshfield(field, mp)
1651590Srgrimes	char field[];
1661590Srgrimes	struct message *mp;
1671590Srgrimes{
1681590Srgrimes	register FILE *ibuf;
1691590Srgrimes	char linebuf[LINESIZE];
1701590Srgrimes	register int lc;
1711590Srgrimes	register char *hfield;
1721590Srgrimes	char *colon, *oldhfield = NOSTR;
1731590Srgrimes
1741590Srgrimes	ibuf = setinput(mp);
1751590Srgrimes	if ((lc = mp->m_lines - 1) < 0)
1761590Srgrimes		return NOSTR;
1771590Srgrimes	if (readline(ibuf, linebuf, LINESIZE) < 0)
1781590Srgrimes		return NOSTR;
1791590Srgrimes	while (lc > 0) {
1801590Srgrimes		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
1811590Srgrimes			return oldhfield;
1821590Srgrimes		if (hfield = ishfield(linebuf, colon, field))
1831590Srgrimes			oldhfield = save2str(hfield, oldhfield);
1841590Srgrimes	}
1851590Srgrimes	return oldhfield;
1861590Srgrimes}
1871590Srgrimes
1881590Srgrimes/*
1891590Srgrimes * Return the next header field found in the given message.
1901590Srgrimes * Return >= 0 if something found, < 0 elsewise.
1911590Srgrimes * "colon" is set to point to the colon in the header.
1921590Srgrimes * Must deal with \ continuations & other such fraud.
1931590Srgrimes */
1941590Srgrimesint
1951590Srgrimesgethfield(f, linebuf, rem, colon)
1961590Srgrimes	register FILE *f;
1971590Srgrimes	char linebuf[];
1981590Srgrimes	register int rem;
1991590Srgrimes	char **colon;
2001590Srgrimes{
2011590Srgrimes	char line2[LINESIZE];
2021590Srgrimes	register char *cp, *cp2;
2031590Srgrimes	register int c;
2041590Srgrimes
2051590Srgrimes	for (;;) {
2061590Srgrimes		if (--rem < 0)
2071590Srgrimes			return -1;
2081590Srgrimes		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
2091590Srgrimes			return -1;
2101590Srgrimes		for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
2111590Srgrimes		     cp++)
2121590Srgrimes			;
2131590Srgrimes		if (*cp != ':' || cp == linebuf)
2141590Srgrimes			continue;
2151590Srgrimes		/*
2161590Srgrimes		 * I guess we got a headline.
2171590Srgrimes		 * Handle wraparounding
2181590Srgrimes		 */
2191590Srgrimes		*colon = cp;
2201590Srgrimes		cp = linebuf + c;
2211590Srgrimes		for (;;) {
2221590Srgrimes			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
2231590Srgrimes				;
2241590Srgrimes			cp++;
2251590Srgrimes			if (rem <= 0)
2261590Srgrimes				break;
2271590Srgrimes			ungetc(c = getc(f), f);
2281590Srgrimes			if (c != ' ' && c != '\t')
2291590Srgrimes				break;
2301590Srgrimes			if ((c = readline(f, line2, LINESIZE)) < 0)
2311590Srgrimes				break;
2321590Srgrimes			rem--;
2331590Srgrimes			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
2341590Srgrimes				;
2351590Srgrimes			c -= cp2 - line2;
2361590Srgrimes			if (cp + c >= linebuf + LINESIZE - 2)
2371590Srgrimes				break;
2381590Srgrimes			*cp++ = ' ';
2391590Srgrimes			bcopy(cp2, cp, c);
2401590Srgrimes			cp += c;
2411590Srgrimes		}
2421590Srgrimes		*cp = 0;
2431590Srgrimes		return rem;
2441590Srgrimes	}
2451590Srgrimes	/* NOTREACHED */
2461590Srgrimes}
2471590Srgrimes
2481590Srgrimes/*
2491590Srgrimes * Check whether the passed line is a header line of
2501590Srgrimes * the desired breed.  Return the field body, or 0.
2511590Srgrimes */
2521590Srgrimes
2531590Srgrimeschar*
2541590Srgrimesishfield(linebuf, colon, field)
2551590Srgrimes	char linebuf[], field[];
2561590Srgrimes	char *colon;
2571590Srgrimes{
2581590Srgrimes	register char *cp = colon;
2591590Srgrimes
2601590Srgrimes	*cp = 0;
2611590Srgrimes	if (strcasecmp(linebuf, field) != 0) {
2621590Srgrimes		*cp = ':';
2631590Srgrimes		return 0;
2641590Srgrimes	}
2651590Srgrimes	*cp = ':';
2661590Srgrimes	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
2671590Srgrimes		;
2681590Srgrimes	return cp;
2691590Srgrimes}
2701590Srgrimes
2711590Srgrimes/*
2721590Srgrimes * Copy a string, lowercasing it as we go.
2731590Srgrimes */
2741590Srgrimesvoid
2751590Srgrimesistrcpy(dest, src)
2761590Srgrimes	register char *dest, *src;
2771590Srgrimes{
2781590Srgrimes
2791590Srgrimes	do {
2801590Srgrimes		if (isupper(*src))
2811590Srgrimes			*dest++ = tolower(*src);
2821590Srgrimes		else
2831590Srgrimes			*dest++ = *src;
2841590Srgrimes	} while (*src++ != 0);
2851590Srgrimes}
2861590Srgrimes
2871590Srgrimes/*
2881590Srgrimes * The following code deals with input stacking to do source
2891590Srgrimes * commands.  All but the current file pointer are saved on
2901590Srgrimes * the stack.
2911590Srgrimes */
2921590Srgrimes
2931590Srgrimesstatic	int	ssp;			/* Top of file stack */
2941590Srgrimesstruct sstack {
2951590Srgrimes	FILE	*s_file;		/* File we were in. */
2961590Srgrimes	int	s_cond;			/* Saved state of conditionals */
2971590Srgrimes	int	s_loading;		/* Loading .mailrc, etc. */
29818532Sbde};
29918532Sbde#define	SSTACK_SIZE	64		/* XXX was NOFILE. */
30018532Sbdestatic struct sstack sstack[SSTACK_SIZE];
3011590Srgrimes
3021590Srgrimes/*
3031590Srgrimes * Pushdown current input file and switch to a new one.
3041590Srgrimes * Set the global flag "sourcing" so that others will realize
3051590Srgrimes * that they are no longer reading from a tty (in all probability).
3061590Srgrimes */
3071590Srgrimesint
3081590Srgrimessource(arglist)
3091590Srgrimes	char **arglist;
3101590Srgrimes{
3111590Srgrimes	FILE *fi;
3121590Srgrimes	char *cp;
3131590Srgrimes
3141590Srgrimes	if ((cp = expand(*arglist)) == NOSTR)
3151590Srgrimes		return(1);
3161590Srgrimes	if ((fi = Fopen(cp, "r")) == NULL) {
3171590Srgrimes		perror(cp);
3181590Srgrimes		return(1);
3191590Srgrimes	}
32018532Sbde	if (ssp >= SSTACK_SIZE - 1) {
3211590Srgrimes		printf("Too much \"sourcing\" going on.\n");
3221590Srgrimes		Fclose(fi);
3231590Srgrimes		return(1);
3241590Srgrimes	}
3251590Srgrimes	sstack[ssp].s_file = input;
3261590Srgrimes	sstack[ssp].s_cond = cond;
3271590Srgrimes	sstack[ssp].s_loading = loading;
3281590Srgrimes	ssp++;
3291590Srgrimes	loading = 0;
3301590Srgrimes	cond = CANY;
3311590Srgrimes	input = fi;
3321590Srgrimes	sourcing++;
3331590Srgrimes	return(0);
3341590Srgrimes}
3351590Srgrimes
3361590Srgrimes/*
3371590Srgrimes * Pop the current input back to the previous level.
3381590Srgrimes * Update the "sourcing" flag as appropriate.
3391590Srgrimes */
3401590Srgrimesint
3411590Srgrimesunstack()
3421590Srgrimes{
3431590Srgrimes	if (ssp <= 0) {
3441590Srgrimes		printf("\"Source\" stack over-pop.\n");
3451590Srgrimes		sourcing = 0;
3461590Srgrimes		return(1);
3471590Srgrimes	}
3481590Srgrimes	Fclose(input);
3491590Srgrimes	if (cond != CANY)
3501590Srgrimes		printf("Unmatched \"if\"\n");
3511590Srgrimes	ssp--;
3521590Srgrimes	cond = sstack[ssp].s_cond;
3531590Srgrimes	loading = sstack[ssp].s_loading;
3541590Srgrimes	input = sstack[ssp].s_file;
3551590Srgrimes	if (ssp == 0)
3561590Srgrimes		sourcing = loading;
3571590Srgrimes	return(0);
3581590Srgrimes}
3591590Srgrimes
3601590Srgrimes/*
3611590Srgrimes * Touch the indicated file.
3621590Srgrimes * This is nifty for the shell.
3631590Srgrimes */
3641590Srgrimesvoid
3651590Srgrimesalter(name)
3661590Srgrimes	char *name;
3671590Srgrimes{
3681590Srgrimes	struct stat sb;
3691590Srgrimes	struct timeval tv[2];
3701590Srgrimes	time_t time();
3711590Srgrimes
3721590Srgrimes	if (stat(name, &sb))
3731590Srgrimes		return;
3741590Srgrimes	tv[0].tv_sec = time((time_t *)0) + 1;
3751590Srgrimes	tv[1].tv_sec = sb.st_mtime;
3761590Srgrimes	tv[0].tv_usec = tv[1].tv_usec = 0;
3771590Srgrimes	(void)utimes(name, tv);
3781590Srgrimes}
3791590Srgrimes
3801590Srgrimes/*
3811590Srgrimes * Examine the passed line buffer and
3821590Srgrimes * return true if it is all blanks and tabs.
3831590Srgrimes */
3841590Srgrimesint
3851590Srgrimesblankline(linebuf)
3861590Srgrimes	char linebuf[];
3871590Srgrimes{
3881590Srgrimes	register char *cp;
3891590Srgrimes
3901590Srgrimes	for (cp = linebuf; *cp; cp++)
3911590Srgrimes		if (*cp != ' ' && *cp != '\t')
3921590Srgrimes			return(0);
3931590Srgrimes	return(1);
3941590Srgrimes}
3951590Srgrimes
3961590Srgrimes/*
3971590Srgrimes * Get sender's name from this message.  If the message has
3981590Srgrimes * a bunch of arpanet stuff in it, we may have to skin the name
3991590Srgrimes * before returning it.
4001590Srgrimes */
4011590Srgrimeschar *
4021590Srgrimesnameof(mp, reptype)
4031590Srgrimes	register struct message *mp;
4041590Srgrimes	int reptype;
4051590Srgrimes{
4061590Srgrimes	register char *cp, *cp2;
4071590Srgrimes
4081590Srgrimes	cp = skin(name1(mp, reptype));
4091590Srgrimes	if (reptype != 0 || charcount(cp, '!') < 2)
4101590Srgrimes		return(cp);
4111590Srgrimes	cp2 = rindex(cp, '!');
4121590Srgrimes	cp2--;
4131590Srgrimes	while (cp2 > cp && *cp2 != '!')
4141590Srgrimes		cp2--;
4151590Srgrimes	if (*cp2 == '!')
4161590Srgrimes		return(cp2 + 1);
4171590Srgrimes	return(cp);
4181590Srgrimes}
4191590Srgrimes
4201590Srgrimes/*
4211590Srgrimes * Start of a "comment".
4221590Srgrimes * Ignore it.
4231590Srgrimes */
4241590Srgrimeschar *
4251590Srgrimesskip_comment(cp)
4261590Srgrimes	register char *cp;
4271590Srgrimes{
4281590Srgrimes	register nesting = 1;
4291590Srgrimes
4301590Srgrimes	for (; nesting > 0 && *cp; cp++) {
4311590Srgrimes		switch (*cp) {
4321590Srgrimes		case '\\':
4331590Srgrimes			if (cp[1])
4341590Srgrimes				cp++;
4351590Srgrimes			break;
4361590Srgrimes		case '(':
4371590Srgrimes			nesting++;
4381590Srgrimes			break;
4391590Srgrimes		case ')':
4401590Srgrimes			nesting--;
4411590Srgrimes			break;
4421590Srgrimes		}
4431590Srgrimes	}
4441590Srgrimes	return cp;
4451590Srgrimes}
4461590Srgrimes
4471590Srgrimes/*
4481590Srgrimes * Skin an arpa net address according to the RFC 822 interpretation
4491590Srgrimes * of "host-phrase."
4501590Srgrimes */
4511590Srgrimeschar *
4521590Srgrimesskin(name)
4531590Srgrimes	char *name;
4541590Srgrimes{
4551590Srgrimes	register int c;
4561590Srgrimes	register char *cp, *cp2;
4571590Srgrimes	char *bufend;
4581590Srgrimes	int gotlt, lastsp;
4591590Srgrimes	char nbuf[BUFSIZ];
4601590Srgrimes
4611590Srgrimes	if (name == NOSTR)
4621590Srgrimes		return(NOSTR);
4631590Srgrimes	if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
4641590Srgrimes	    && index(name, ' ') == NOSTR)
4651590Srgrimes		return(name);
4661590Srgrimes	gotlt = 0;
4671590Srgrimes	lastsp = 0;
4681590Srgrimes	bufend = nbuf;
4691590Srgrimes	for (cp = name, cp2 = bufend; c = *cp++; ) {
4701590Srgrimes		switch (c) {
4711590Srgrimes		case '(':
4721590Srgrimes			cp = skip_comment(cp);
4731590Srgrimes			lastsp = 0;
4741590Srgrimes			break;
4751590Srgrimes
4761590Srgrimes		case '"':
4771590Srgrimes			/*
4781590Srgrimes			 * Start of a "quoted-string".
4791590Srgrimes			 * Copy it in its entirety.
4801590Srgrimes			 */
4811590Srgrimes			while (c = *cp) {
4821590Srgrimes				cp++;
4831590Srgrimes				if (c == '"')
4841590Srgrimes					break;
4851590Srgrimes				if (c != '\\')
4861590Srgrimes					*cp2++ = c;
4871590Srgrimes				else if (c = *cp) {
4881590Srgrimes					*cp2++ = c;
4891590Srgrimes					cp++;
4901590Srgrimes				}
4911590Srgrimes			}
4921590Srgrimes			lastsp = 0;
4931590Srgrimes			break;
4941590Srgrimes
4951590Srgrimes		case ' ':
4961590Srgrimes			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
4971590Srgrimes				cp += 3, *cp2++ = '@';
4981590Srgrimes			else
4991590Srgrimes			if (cp[0] == '@' && cp[1] == ' ')
5001590Srgrimes				cp += 2, *cp2++ = '@';
5011590Srgrimes			else
5021590Srgrimes				lastsp = 1;
5031590Srgrimes			break;
5041590Srgrimes
5051590Srgrimes		case '<':
5061590Srgrimes			cp2 = bufend;
5071590Srgrimes			gotlt++;
5081590Srgrimes			lastsp = 0;
5091590Srgrimes			break;
5101590Srgrimes
5111590Srgrimes		case '>':
5121590Srgrimes			if (gotlt) {
5131590Srgrimes				gotlt = 0;
5141590Srgrimes				while ((c = *cp) && c != ',') {
5151590Srgrimes					cp++;
5161590Srgrimes					if (c == '(')
5171590Srgrimes						cp = skip_comment(cp);
5181590Srgrimes					else if (c == '"')
5191590Srgrimes						while (c = *cp) {
5201590Srgrimes							cp++;
5211590Srgrimes							if (c == '"')
5221590Srgrimes								break;
5231590Srgrimes							if (c == '\\' && *cp)
5241590Srgrimes								cp++;
5251590Srgrimes						}
5261590Srgrimes				}
5271590Srgrimes				lastsp = 0;
5281590Srgrimes				break;
5291590Srgrimes			}
5301590Srgrimes			/* Fall into . . . */
5311590Srgrimes
5321590Srgrimes		default:
5331590Srgrimes			if (lastsp) {
5341590Srgrimes				lastsp = 0;
5351590Srgrimes				*cp2++ = ' ';
5361590Srgrimes			}
5371590Srgrimes			*cp2++ = c;
5381590Srgrimes			if (c == ',' && !gotlt) {
5391590Srgrimes				*cp2++ = ' ';
5401590Srgrimes				for (; *cp == ' '; cp++)
5411590Srgrimes					;
5421590Srgrimes				lastsp = 0;
5431590Srgrimes				bufend = cp2;
5441590Srgrimes			}
5451590Srgrimes		}
5461590Srgrimes	}
5471590Srgrimes	*cp2 = 0;
5481590Srgrimes
5491590Srgrimes	return(savestr(nbuf));
5501590Srgrimes}
5511590Srgrimes
5521590Srgrimes/*
5531590Srgrimes * Fetch the sender's name from the passed message.
5541590Srgrimes * Reptype can be
5551590Srgrimes *	0 -- get sender's name for display purposes
5561590Srgrimes *	1 -- get sender's name for reply
5571590Srgrimes *	2 -- get sender's name for Reply
5581590Srgrimes */
5591590Srgrimeschar *
5601590Srgrimesname1(mp, reptype)
5611590Srgrimes	register struct message *mp;
5621590Srgrimes	int reptype;
5631590Srgrimes{
5641590Srgrimes	char namebuf[LINESIZE];
5651590Srgrimes	char linebuf[LINESIZE];
5661590Srgrimes	register char *cp, *cp2;
5671590Srgrimes	register FILE *ibuf;
5681590Srgrimes	int first = 1;
5691590Srgrimes
5701590Srgrimes	if ((cp = hfield("from", mp)) != NOSTR)
5711590Srgrimes		return cp;
5721590Srgrimes	if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
5731590Srgrimes		return cp;
5741590Srgrimes	ibuf = setinput(mp);
5751590Srgrimes	namebuf[0] = 0;
5761590Srgrimes	if (readline(ibuf, linebuf, LINESIZE) < 0)
5771590Srgrimes		return(savestr(namebuf));
5781590Srgrimesnewname:
5791590Srgrimes	for (cp = linebuf; *cp && *cp != ' '; cp++)
5801590Srgrimes		;
5811590Srgrimes	for (; *cp == ' ' || *cp == '\t'; cp++)
5821590Srgrimes		;
5831590Srgrimes	for (cp2 = &namebuf[strlen(namebuf)];
5841590Srgrimes	     *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
5851590Srgrimes		*cp2++ = *cp++;
5861590Srgrimes	*cp2 = '\0';
5871590Srgrimes	if (readline(ibuf, linebuf, LINESIZE) < 0)
5881590Srgrimes		return(savestr(namebuf));
5891590Srgrimes	if ((cp = index(linebuf, 'F')) == NULL)
5901590Srgrimes		return(savestr(namebuf));
5911590Srgrimes	if (strncmp(cp, "From", 4) != 0)
5921590Srgrimes		return(savestr(namebuf));
5931590Srgrimes	while ((cp = index(cp, 'r')) != NULL) {
5941590Srgrimes		if (strncmp(cp, "remote", 6) == 0) {
5951590Srgrimes			if ((cp = index(cp, 'f')) == NULL)
5961590Srgrimes				break;
5971590Srgrimes			if (strncmp(cp, "from", 4) != 0)
5981590Srgrimes				break;
5991590Srgrimes			if ((cp = index(cp, ' ')) == NULL)
6001590Srgrimes				break;
6011590Srgrimes			cp++;
6021590Srgrimes			if (first) {
6031590Srgrimes				strcpy(namebuf, cp);
6041590Srgrimes				first = 0;
6051590Srgrimes			} else
6061590Srgrimes				strcpy(rindex(namebuf, '!')+1, cp);
6071590Srgrimes			strcat(namebuf, "!");
6081590Srgrimes			goto newname;
6091590Srgrimes		}
6101590Srgrimes		cp++;
6111590Srgrimes	}
6121590Srgrimes	return(savestr(namebuf));
6131590Srgrimes}
6141590Srgrimes
6151590Srgrimes/*
6161590Srgrimes * Count the occurances of c in str
6171590Srgrimes */
6181590Srgrimesint
6191590Srgrimescharcount(str, c)
6201590Srgrimes	char *str;
6211590Srgrimes	int c;
6221590Srgrimes{
6231590Srgrimes	register char *cp;
6241590Srgrimes	register int i;
6251590Srgrimes
6261590Srgrimes	for (i = 0, cp = str; *cp; cp++)
6271590Srgrimes		if (*cp == c)
6281590Srgrimes			i++;
6291590Srgrimes	return(i);
6301590Srgrimes}
6311590Srgrimes
6321590Srgrimes/*
6331590Srgrimes * Are any of the characters in the two strings the same?
6341590Srgrimes */
6351590Srgrimesint
6361590Srgrimesanyof(s1, s2)
6371590Srgrimes	register char *s1, *s2;
6381590Srgrimes{
6391590Srgrimes
6401590Srgrimes	while (*s1)
6411590Srgrimes		if (index(s2, *s1++))
6421590Srgrimes			return 1;
6431590Srgrimes	return 0;
6441590Srgrimes}
6451590Srgrimes
6461590Srgrimes/*
6471590Srgrimes * Convert c to upper case
6481590Srgrimes */
6491590Srgrimesint
6501590Srgrimesraise(c)
6511590Srgrimes	register int c;
6521590Srgrimes{
6531590Srgrimes
6541590Srgrimes	if (islower(c))
6551590Srgrimes		return toupper(c);
6561590Srgrimes	return c;
6571590Srgrimes}
6581590Srgrimes
6591590Srgrimes/*
6601590Srgrimes * Copy s1 to s2, return pointer to null in s2.
6611590Srgrimes */
6621590Srgrimeschar *
6631590Srgrimescopy(s1, s2)
6641590Srgrimes	register char *s1, *s2;
6651590Srgrimes{
6661590Srgrimes
6671590Srgrimes	while (*s2++ = *s1++)
6681590Srgrimes		;
6691590Srgrimes	return s2 - 1;
6701590Srgrimes}
6711590Srgrimes
6721590Srgrimes/*
6731590Srgrimes * See if the given header field is supposed to be ignored.
6741590Srgrimes */
6751590Srgrimesint
6761590Srgrimesisign(field, ignore)
6771590Srgrimes	char *field;
6781590Srgrimes	struct ignoretab ignore[2];
6791590Srgrimes{
6801590Srgrimes	char realfld[BUFSIZ];
6811590Srgrimes
6821590Srgrimes	if (ignore == ignoreall)
6831590Srgrimes		return 1;
6841590Srgrimes	/*
6851590Srgrimes	 * Lower-case the string, so that "Status" and "status"
6861590Srgrimes	 * will hash to the same place.
6871590Srgrimes	 */
6881590Srgrimes	istrcpy(realfld, field);
6891590Srgrimes	if (ignore[1].i_count > 0)
6901590Srgrimes		return (!member(realfld, ignore + 1));
6911590Srgrimes	else
6921590Srgrimes		return (member(realfld, ignore));
6931590Srgrimes}
6941590Srgrimes
6951590Srgrimesint
6961590Srgrimesmember(realfield, table)
6971590Srgrimes	register char *realfield;
6981590Srgrimes	struct ignoretab *table;
6991590Srgrimes{
7001590Srgrimes	register struct ignore *igp;
7011590Srgrimes
7021590Srgrimes	for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
7031590Srgrimes		if (*igp->i_field == *realfield &&
7041590Srgrimes		    equal(igp->i_field, realfield))
7051590Srgrimes			return (1);
7061590Srgrimes	return (0);
7071590Srgrimes}
708