xref: /csrg-svn/usr.bin/mail/aux.c (revision 7571)
11219Skas #
21219Skas 
31219Skas #include "rcv.h"
41219Skas #include <sys/stat.h>
51219Skas #include <ctype.h>
61219Skas 
71219Skas /*
81219Skas  * Mail -- a mail program
91219Skas  *
101219Skas  * Auxiliary functions.
111219Skas  */
121219Skas 
13*7571Skurt static char *SccsId = "@(#)aux.c	2.6 07/28/82";
141219Skas 
151219Skas /*
161219Skas  * Return a pointer to a dynamic copy of the argument.
171219Skas  */
181219Skas 
191219Skas char *
201219Skas savestr(str)
211219Skas 	char *str;
221219Skas {
231219Skas 	register char *cp, *cp2, *top;
241219Skas 
251219Skas 	for (cp = str; *cp; cp++)
261219Skas 		;
271219Skas 	top = salloc(cp-str + 1);
281219Skas 	if (top == NOSTR)
291219Skas 		return(NOSTR);
301219Skas 	for (cp = str, cp2 = top; *cp; cp++)
311219Skas 		*cp2++ = *cp;
321219Skas 	*cp2 = 0;
331219Skas 	return(top);
341219Skas }
351219Skas 
361219Skas /*
371219Skas  * Copy the name from the passed header line into the passed
381219Skas  * name buffer.  Null pad the name buffer.
391219Skas  */
401219Skas 
411219Skas copyname(linebuf, nbuf)
421219Skas 	char *linebuf, *nbuf;
431219Skas {
441219Skas 	register char *cp, *cp2;
451219Skas 
461219Skas 	for (cp = linebuf + 5, cp2 = nbuf; *cp != ' ' && cp2-nbuf < 8; cp++)
471219Skas 		*cp2++ = *cp;
481219Skas 	while (cp2-nbuf < 8)
491219Skas 		*cp2++ = 0;
501219Skas }
511219Skas 
521219Skas /*
531219Skas  * Announce a fatal error and die.
541219Skas  */
551219Skas 
561219Skas panic(str)
571219Skas 	char *str;
581219Skas {
591219Skas 	prs("panic: ");
601219Skas 	prs(str);
611219Skas 	prs("\n");
621219Skas 	exit(1);
631219Skas }
641219Skas 
651219Skas /*
661219Skas  * Catch stdio errors and report them more nicely.
671219Skas  */
681219Skas 
691219Skas _error(str)
701219Skas 	char *str;
711219Skas {
721219Skas 	prs("Stdio Error: ");
731219Skas 	prs(str);
741219Skas 	prs("\n");
751219Skas 	abort();
761219Skas }
771219Skas 
781219Skas /*
791219Skas  * Print a string on diagnostic output.
801219Skas  */
811219Skas 
821219Skas prs(str)
831219Skas 	char *str;
841219Skas {
851219Skas 	register char *s;
861219Skas 
871219Skas 	for (s = str; *s; s++)
881219Skas 		;
891219Skas 	write(2, str, s-str);
901219Skas }
911219Skas 
921219Skas /*
931219Skas  * Touch the named message by setting its MTOUCH flag.
941219Skas  * Touched messages have the effect of not being sent
951219Skas  * back to the system mailbox on exit.
961219Skas  */
971219Skas 
981219Skas touch(mesg)
991219Skas {
1001479Skas 	register struct message *mp;
1011479Skas 
1021479Skas 	if (mesg < 1 || mesg > msgCount)
1031479Skas 		return;
1041479Skas 	mp = &message[mesg-1];
1051479Skas 	mp->m_flag |= MTOUCH;
1061479Skas 	if ((mp->m_flag & MREAD) == 0)
1071479Skas 		mp->m_flag |= MREAD|MSTATUS;
1081219Skas }
1091219Skas 
1101219Skas /*
1111219Skas  * Test to see if the passed file name is a directory.
1121219Skas  * Return true if it is.
1131219Skas  */
1141219Skas 
1151219Skas isdir(name)
1161219Skas 	char name[];
1171219Skas {
1181219Skas 	struct stat sbuf;
1191219Skas 
1201219Skas 	if (stat(name, &sbuf) < 0)
1211219Skas 		return(0);
1221219Skas 	return((sbuf.st_mode & S_IFMT) == S_IFDIR);
1231219Skas }
1241219Skas 
1251219Skas /*
1261219Skas  * Compute the size in characters of the passed message
1271219Skas  */
1281219Skas 
1291219Skas unsigned int
1301219Skas msize(messp)
1311219Skas 	struct message *messp;
1321219Skas {
1331219Skas 	register struct message *mp;
1341219Skas 
1351219Skas 	mp = messp;
1361219Skas 	return(mp->m_size);
1371219Skas }
1381219Skas 
1391219Skas /*
1401219Skas  * Count the number of arguments in the given string raw list.
1411219Skas  */
1421219Skas 
1431219Skas argcount(argv)
1441219Skas 	char **argv;
1451219Skas {
1461219Skas 	register char **ap;
1471219Skas 
1481219Skas 	for (ap = argv; *ap != NOSTR; ap++)
1491219Skas 		;
1501219Skas 	return(ap-argv);
1511219Skas }
1521219Skas 
1531219Skas /*
1541219Skas  * Given a file address, determine the
1551219Skas  * block number it represents.
1561219Skas  */
1571219Skas 
1581219Skas blockof(off)
1591219Skas 	off_t off;
1601219Skas {
1611219Skas 	off_t a;
1621219Skas 
1631219Skas 	a = off >> 9;
1641219Skas 	a &= 077777;
1651219Skas 	return((int) a);
1661219Skas }
1671219Skas 
1681219Skas /*
1691219Skas  * Take a file address, and determine
1701219Skas  * its offset in the current block.
1711219Skas  */
1721219Skas 
1731219Skas offsetof(off)
1741219Skas 	off_t off;
1751219Skas {
1761219Skas 	off_t a;
1771219Skas 
1781219Skas 	a = off & 0777;
1791219Skas 	return((int) a);
1801219Skas }
1811219Skas 
1821219Skas /*
1831219Skas  * Determine if the passed file is actually a tty, via a call to
1841219Skas  * gtty.  This is not totally reliable, but . . .
1851219Skas  */
1861219Skas 
1871219Skas isatty(f)
1881219Skas {
1891219Skas 	struct sgttyb buf;
1901219Skas 
1911219Skas 	if (gtty(f, &buf) < 0)
1921219Skas 		return(0);
1931219Skas 	return(1);
1941219Skas }
1951219Skas 
1961219Skas /*
1971219Skas  * Return the desired header line from the passed message
1981219Skas  * pointer (or NOSTR if the desired header field is not available).
1991219Skas  */
2001219Skas 
2011219Skas char *
2021219Skas hfield(field, mp)
2031219Skas 	char field[];
2041219Skas 	struct message *mp;
2051219Skas {
2061219Skas 	register FILE *ibuf;
2071219Skas 	char linebuf[LINESIZE];
2081219Skas 	register int lc;
2091219Skas 
2101219Skas 	ibuf = setinput(mp);
2111219Skas 	if ((lc = mp->m_lines) <= 0)
2121219Skas 		return(NOSTR);
2131219Skas 	if (readline(ibuf, linebuf) < 0)
2141219Skas 		return(NOSTR);
2151219Skas 	lc--;
2161219Skas 	do {
2171219Skas 		lc = gethfield(ibuf, linebuf, lc);
2181219Skas 		if (lc == -1)
2191219Skas 			return(NOSTR);
2201219Skas 		if (ishfield(linebuf, field))
2211219Skas 			return(savestr(hcontents(linebuf)));
2221219Skas 	} while (lc > 0);
2231219Skas 	return(NOSTR);
2241219Skas }
2251219Skas 
2261219Skas /*
2271219Skas  * Return the next header field found in the given message.
2281219Skas  * Return > 0 if something found, <= 0 elsewise.
2291219Skas  * Must deal with \ continuations & other such fraud.
2301219Skas  */
2311219Skas 
2321219Skas gethfield(f, linebuf, rem)
2331219Skas 	register FILE *f;
2341219Skas 	char linebuf[];
2351219Skas 	register int rem;
2361219Skas {
2371219Skas 	char line2[LINESIZE];
2381219Skas 	long loc;
2391219Skas 	register char *cp, *cp2;
2401219Skas 	register int c;
2411219Skas 
2421219Skas 
2431219Skas 	for (;;) {
2441219Skas 		if (rem <= 0)
2451219Skas 			return(-1);
2461219Skas 		if (readline(f, linebuf) < 0)
2471219Skas 			return(-1);
2481219Skas 		rem--;
2491219Skas 		if (strlen(linebuf) == 0)
2501219Skas 			return(-1);
2511219Skas 		if (isspace(linebuf[0]))
2521219Skas 			continue;
2531219Skas 		if (linebuf[0] == '>')
2541219Skas 			continue;
2551219Skas 		cp = index(linebuf, ':');
2561219Skas 		if (cp == NOSTR)
2571219Skas 			continue;
2581219Skas 		for (cp2 = linebuf; cp2 < cp; cp2++)
2591219Skas 			if (isdigit(*cp2))
2601219Skas 				continue;
2611219Skas 
2621219Skas 		/*
2631219Skas 		 * I guess we got a headline.
2641219Skas 		 * Handle wraparounding
2651219Skas 		 */
2661219Skas 
2671219Skas 		for (;;) {
2681219Skas 			if (rem <= 0)
2691219Skas 				break;
2701219Skas #ifdef CANTELL
2711219Skas 			loc = ftell(f);
2721219Skas 			if (readline(f, line2) < 0)
2731219Skas 				break;
2741219Skas 			rem--;
2751219Skas 			if (!isspace(line2[0])) {
2761219Skas 				fseek(f, loc, 0);
2771219Skas 				rem++;
2781219Skas 				break;
2791219Skas 			}
2801219Skas #else
2811219Skas 			c = getc(f);
2821219Skas 			ungetc(c, f);
2831219Skas 			if (!isspace(c) || c == '\n')
2841219Skas 				break;
2851219Skas 			if (readline(f, line2) < 0)
2861219Skas 				break;
2871219Skas 			rem--;
2881219Skas #endif
2891219Skas 			cp2 = line2;
2901219Skas 			for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
2911219Skas 				;
2921219Skas 			if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2)
2931219Skas 				break;
2941219Skas 			cp = &linebuf[strlen(linebuf)];
2951219Skas 			while (cp > linebuf &&
2961219Skas 			    (isspace(cp[-1]) || cp[-1] == '\\'))
2971219Skas 				cp--;
2981219Skas 			*cp++ = ' ';
2991219Skas 			for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
3001219Skas 				;
3011219Skas 			strcpy(cp, cp2);
3021219Skas 		}
3031219Skas 		if ((c = strlen(linebuf)) > 0) {
3041219Skas 			cp = &linebuf[c-1];
3051219Skas 			while (cp > linebuf && isspace(*cp))
3061219Skas 				cp--;
3071219Skas 			*++cp = 0;
3081219Skas 		}
3091219Skas 		return(rem);
3101219Skas 	}
3111219Skas 	/* NOTREACHED */
3121219Skas }
3131219Skas 
3141219Skas /*
3151219Skas  * Check whether the passed line is a header line of
3161219Skas  * the desired breed.
3171219Skas  */
3181219Skas 
3191219Skas ishfield(linebuf, field)
3201219Skas 	char linebuf[], field[];
3211219Skas {
3221219Skas 	register char *cp;
3231219Skas 	register int c;
3241219Skas 
3251219Skas 	if ((cp = index(linebuf, ':')) == NOSTR)
3261219Skas 		return(0);
3271219Skas 	if (cp == linebuf)
3281219Skas 		return(0);
3291219Skas 	cp--;
3301219Skas 	while (cp > linebuf && isspace(*cp))
3311219Skas 		cp--;
3321219Skas 	c = *++cp;
3331219Skas 	*cp = 0;
3341219Skas 	if (icequal(linebuf ,field)) {
3351219Skas 		*cp = c;
3361219Skas 		return(1);
3371219Skas 	}
3381219Skas 	*cp = c;
3391219Skas 	return(0);
3401219Skas }
3411219Skas 
3421219Skas /*
3431219Skas  * Extract the non label information from the given header field
3441219Skas  * and return it.
3451219Skas  */
3461219Skas 
3471219Skas char *
3481219Skas hcontents(hfield)
3491219Skas 	char hfield[];
3501219Skas {
3511219Skas 	register char *cp;
3521219Skas 
3531219Skas 	if ((cp = index(hfield, ':')) == NOSTR)
3541219Skas 		return(NOSTR);
3551219Skas 	cp++;
3561219Skas 	while (*cp && isspace(*cp))
3571219Skas 		cp++;
3581219Skas 	return(cp);
3591219Skas }
3601219Skas 
3611219Skas /*
3621219Skas  * Compare two strings, ignoring case.
3631219Skas  */
3641219Skas 
3651219Skas icequal(s1, s2)
3661219Skas 	register char *s1, *s2;
3671219Skas {
3681219Skas 
3691219Skas 	while (raise(*s1++) == raise(*s2))
3701219Skas 		if (*s2++ == 0)
3711219Skas 			return(1);
3721219Skas 	return(0);
3731219Skas }
3741219Skas 
3751219Skas /*
376*7571Skurt  * Copy a string, lowercasing it as we go.
377*7571Skurt  */
378*7571Skurt istrcpy(dest, src)
379*7571Skurt 	char *dest, *src;
380*7571Skurt {
381*7571Skurt 	register char *cp, *cp2;
382*7571Skurt 
383*7571Skurt 	cp2 = dest;
384*7571Skurt 	cp = src;
385*7571Skurt 	do {
386*7571Skurt 		*cp2++ = little(*cp);
387*7571Skurt 	} while (*cp++ != 0);
388*7571Skurt }
389*7571Skurt 
390*7571Skurt /*
3911219Skas  * The following code deals with input stacking to do source
3921219Skas  * commands.  All but the current file pointer are saved on
3931219Skas  * the stack.
3941219Skas  */
3951219Skas 
3961219Skas static	int	ssp = -1;		/* Top of file stack */
3971519Skas struct sstack {
3981519Skas 	FILE	*s_file;		/* File we were in. */
3991519Skas 	int	s_cond;			/* Saved state of conditionals */
4005785Skurt 	int	s_loading;		/* Loading .mailrc, etc. */
4011519Skas } sstack[_NFILE];
4021219Skas 
4031219Skas /*
4041219Skas  * Pushdown current input file and switch to a new one.
4051219Skas  * Set the global flag "sourcing" so that others will realize
4061219Skas  * that they are no longer reading from a tty (in all probability).
4071219Skas  */
4081219Skas 
4091219Skas source(name)
4101219Skas 	char name[];
4111219Skas {
4121219Skas 	register FILE *fi;
4133914Skurt 	register char *cp;
4141219Skas 
4153914Skurt 	if ((cp = expand(name)) == NOSTR)
4161219Skas 		return(1);
4173914Skurt 	if ((fi = fopen(cp, "r")) == NULL) {
4183914Skurt 		perror(cp);
4193914Skurt 		return(1);
4201219Skas 	}
4211219Skas 	if (ssp >= _NFILE-2) {
4221219Skas 		printf("Too much \"sourcing\" going on.\n");
4231219Skas 		fclose(fi);
4241219Skas 		return(1);
4251219Skas 	}
4261519Skas 	sstack[++ssp].s_file = input;
4271519Skas 	sstack[ssp].s_cond = cond;
4285785Skurt 	sstack[ssp].s_loading = loading;
4295785Skurt 	loading = 0;
4301519Skas 	cond = CANY;
4311219Skas 	input = fi;
4321219Skas 	sourcing++;
4331219Skas 	return(0);
4341219Skas }
4351219Skas 
4361219Skas /*
4371219Skas  * Source a file, but do nothing if the file cannot be opened.
4381219Skas  */
4391219Skas 
4401219Skas source1(name)
4411219Skas 	char name[];
4421219Skas {
4431219Skas 	register int f;
4441219Skas 
4451219Skas 	if ((f = open(name, 0)) < 0)
4461219Skas 		return(0);
4471219Skas 	close(f);
4481219Skas 	source(name);
4491219Skas }
4501219Skas 
4511219Skas /*
4521219Skas  * Pop the current input back to the previous level.
4531219Skas  * Update the "sourcing" flag as appropriate.
4541219Skas  */
4551219Skas 
4561219Skas unstack()
4571219Skas {
4581219Skas 	if (ssp < 0) {
4591219Skas 		printf("\"Source\" stack over-pop.\n");
4601219Skas 		sourcing = 0;
4611219Skas 		return(1);
4621219Skas 	}
4631219Skas 	fclose(input);
4641519Skas 	if (cond != CANY)
4651519Skas 		printf("Unmatched \"if\"\n");
4661519Skas 	cond = sstack[ssp].s_cond;
4675785Skurt 	loading = sstack[ssp].s_loading;
4681519Skas 	input = sstack[ssp--].s_file;
4691219Skas 	if (ssp < 0)
4705785Skurt 		sourcing = loading;
4711219Skas 	return(0);
4721219Skas }
4731219Skas 
4741219Skas /*
4751219Skas  * Touch the indicated file.
4761219Skas  * This is nifty for the shell.
4771219Skas  * If we have the utime() system call, this is better served
4781219Skas  * by using that, since it will work for empty files.
4791219Skas  * On non-utime systems, we must sleep a second, then read.
4801219Skas  */
4811219Skas 
4821219Skas alter(name)
4831219Skas 	char name[];
4841219Skas {
4851219Skas #ifdef UTIME
4861219Skas 	struct stat statb;
4871219Skas 	long time();
4881219Skas 	time_t time_p[2];
4891219Skas #else
4901219Skas 	register int pid, f;
4911219Skas 	char w;
4921219Skas #endif UTIME
4931219Skas 
4941219Skas #ifdef UTIME
4951219Skas 	if (stat(name, &statb) < 0)
4961219Skas 		return;
4971219Skas 	time_p[0] = time((long *) 0) + 1;
4981219Skas 	time_p[1] = statb.st_mtime;
4991219Skas 	utime(name, time_p);
5001219Skas #else
5011219Skas 	sleep(1);
5021219Skas 	if ((f = open(name, 0)) < 0)
5034389Skurt 		return;
5041219Skas 	read(f, &w, 1);
5051219Skas 	exit(0);
5061219Skas #endif
5071219Skas }
5081219Skas 
5091219Skas /*
5101219Skas  * Examine the passed line buffer and
5111219Skas  * return true if it is all blanks and tabs.
5121219Skas  */
5131219Skas 
5141219Skas blankline(linebuf)
5151219Skas 	char linebuf[];
5161219Skas {
5171219Skas 	register char *cp;
5181219Skas 
5191219Skas 	for (cp = linebuf; *cp; cp++)
5201219Skas 		if (!any(*cp, " \t"))
5211219Skas 			return(0);
5221219Skas 	return(1);
5231219Skas }
5241219Skas 
5251219Skas /*
5263195Skas  * Get sender's name from this message.  If the message has
5273195Skas  * a bunch of arpanet stuff in it, we may have to skin the name
5283195Skas  * before returning it.
5293195Skas  */
5303195Skas char *
5313195Skas nameof(mp, reptype)
5323195Skas 	register struct message *mp;
5333195Skas {
5345237Skurt 	register char *cp, *cp2;
5353195Skas 
5365237Skurt 	cp = skin(name1(mp, reptype));
5375237Skurt 	if (reptype != 0 || charcount(cp, '!') < 2)
5385237Skurt 		return(cp);
5395237Skurt 	cp2 = rindex(cp, '!');
5405237Skurt 	cp2--;
5415237Skurt 	while (cp2 > cp && *cp2 != '!')
5425237Skurt 		cp2--;
5435237Skurt 	if (*cp2 == '!')
5445237Skurt 		return(cp2 + 1);
5455237Skurt 	return(cp);
5463195Skas }
5473195Skas 
5483195Skas /*
5493195Skas  * Skin an arpa net address according to the RFC 733 interpretation
5503195Skas  * of "host-phrase."
5513195Skas  */
5523195Skas char *
5533195Skas skin(name)
5543195Skas 	char *name;
5553195Skas {
5563195Skas 	register int c;
5573195Skas 	register char *cp, *cp2;
5583195Skas 	int gotlt, lastsp;
5593195Skas 	char nbuf[BUFSIZ];
5603195Skas 
5613195Skas 	if (name == NOSTR)
5623195Skas 		return(NOSTR);
5633195Skas 	if (index(name, '(') == NOSTR && index(name, '<') == NOSTR)
5643195Skas 		return(name);
5653195Skas 	gotlt = 0;
5663195Skas 	lastsp = 0;
5673195Skas 	for (cp = name, cp2 = nbuf, c = *cp++; *cp; c = *cp++) {
5683195Skas 		switch (c) {
5693195Skas 		case '(':
5703195Skas 			while (*cp != ')' && *cp != 0)
5713195Skas 				cp++;
5723195Skas 			if (*cp)
5733195Skas 				cp++;
5743195Skas 			break;
5753195Skas 
5763195Skas 		case ' ':
5773195Skas 			lastsp = 1;
5783195Skas 			break;
5793195Skas 
5803195Skas 		case '<':
5813195Skas 			cp2 = nbuf;
5823195Skas 			gotlt++;
5833195Skas 			lastsp = 0;
5843195Skas 			break;
5853195Skas 
5863195Skas 		case '>':
5873195Skas 			if (gotlt)
5883195Skas 				goto done;
5893195Skas 
5903195Skas 			/* Fall into . . . */
5913195Skas 
5923195Skas 		default:
5933195Skas 			if (lastsp) {
5943195Skas 				lastsp = 0;
5953195Skas 				*cp2++ = ' ';
5963195Skas 			}
5973195Skas 			*cp2++ = c;
5983195Skas 			break;
5993195Skas 		}
6003195Skas 	}
6013195Skas done:
6023195Skas 	*cp2 = 0;
6033195Skas 
6043195Skas 	return(savestr(nbuf));
6053195Skas }
6063195Skas 
6073195Skas /*
6081219Skas  * Fetch the sender's name from the passed message.
6093195Skas  * Reptype can be
6103195Skas  *	0 -- get sender's name for display purposes
6113195Skas  *	1 -- get sender's name for reply
6123195Skas  *	2 -- get sender's name for Reply
6131219Skas  */
6141219Skas 
6151219Skas char *
6163195Skas name1(mp, reptype)
6171219Skas 	register struct message *mp;
6181219Skas {
6191219Skas 	char namebuf[LINESIZE];
6201219Skas 	char linebuf[LINESIZE];
6211219Skas 	register char *cp, *cp2;
6221219Skas 	register FILE *ibuf;
6231219Skas 	int first = 1;
6241219Skas 
6253195Skas #ifndef DELIVERMAIL
6263195Skas 	if ((cp = hfield("from", mp)) != NOSTR)
6273195Skas 		return(cp);
6283195Skas 	if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
6293195Skas 		return(cp);
6303195Skas #endif
6311219Skas 	ibuf = setinput(mp);
6321219Skas 	copy("", namebuf);
6331219Skas 	if (readline(ibuf, linebuf) <= 0)
6341219Skas 		return(savestr(namebuf));
6351219Skas newname:
6361219Skas 	for (cp = linebuf; *cp != ' '; cp++)
6371219Skas 		;
6381219Skas 	while (any(*cp, " \t"))
6391219Skas 		cp++;
6401219Skas 	for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
6411219Skas 	    cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
6421219Skas 		;
6431219Skas 	*cp2 = '\0';
6441219Skas 	if (readline(ibuf, linebuf) <= 0)
6451219Skas 		return(savestr(namebuf));
6461219Skas 	if ((cp = index(linebuf, 'F')) == NULL)
6471219Skas 		return(savestr(namebuf));
6481219Skas 	if (strncmp(cp, "From", 4) != 0)
6491219Skas 		return(savestr(namebuf));
6501219Skas 	while ((cp = index(cp, 'r')) != NULL) {
6511219Skas 		if (strncmp(cp, "remote", 6) == 0) {
6521219Skas 			if ((cp = index(cp, 'f')) == NULL)
6531219Skas 				break;
6541219Skas 			if (strncmp(cp, "from", 4) != 0)
6551219Skas 				break;
6561219Skas 			if ((cp = index(cp, ' ')) == NULL)
6571219Skas 				break;
6581219Skas 			cp++;
6591219Skas 			if (first) {
6601219Skas 				copy(cp, namebuf);
6611219Skas 				first = 0;
6621219Skas 			} else
6631219Skas 				strcpy(rindex(namebuf, '!')+1, cp);
6641219Skas 			strcat(namebuf, "!");
6651219Skas 			goto newname;
6661219Skas 		}
6671219Skas 		cp++;
6681219Skas 	}
6691219Skas 	return(savestr(namebuf));
6701219Skas }
6711219Skas 
6721219Skas /*
6735237Skurt  * Count the occurances of c in str
6745237Skurt  */
6755237Skurt charcount(str, c)
6765237Skurt 	char *str;
6775237Skurt {
6785237Skurt 	register char *cp;
6795237Skurt 	register int i;
6805237Skurt 
6815237Skurt 	for (i = 0, cp = str; *cp; cp++)
6825237Skurt 		if (*cp == c)
6835237Skurt 			i++;
6845237Skurt 	return(i);
6855237Skurt }
6865237Skurt 
6875237Skurt /*
6881219Skas  * Find the rightmost pointer to an instance of the
6891219Skas  * character in the string and return it.
6901219Skas  */
6911219Skas char *
6921219Skas rindex(str, c)
6931219Skas 	char str[];
6941219Skas 	register int c;
6951219Skas {
6961219Skas 	register char *cp, *cp2;
6971219Skas 
6981219Skas 	for (cp = str, cp2 = NOSTR; *cp; cp++)
6991219Skas 		if (c == *cp)
7001219Skas 			cp2 = cp;
7011219Skas 	return(cp2);
7021219Skas }
7031219Skas 
7041219Skas /*
7051219Skas  * See if the string is a number.
7061219Skas  */
7071219Skas 
7081219Skas numeric(str)
7091219Skas 	char str[];
7101219Skas {
7111219Skas 	register char *cp = str;
7121219Skas 
7131219Skas 	while (*cp)
7141219Skas 		if (!isdigit(*cp++))
7151219Skas 			return(0);
7161219Skas 	return(1);
7171219Skas }
7181219Skas 
7191219Skas /*
7201219Skas  * Are any of the characters in the two strings the same?
7211219Skas  */
7221219Skas 
7231219Skas anyof(s1, s2)
7241219Skas 	register char *s1, *s2;
7251219Skas {
7261219Skas 	register int c;
7271219Skas 
7281219Skas 	while (c = *s1++)
7291219Skas 		if (any(c, s2))
7301219Skas 			return(1);
7311219Skas 	return(0);
7321219Skas }
7331219Skas 
7341219Skas /*
7351219Skas  * Determine the leftmost index of the character
7361219Skas  * in the string.
7371219Skas  */
7381219Skas 
7391219Skas char *
7401219Skas index(str, ch)
7411219Skas 	char *str;
7421219Skas {
7431219Skas 	register char *cp;
7441219Skas 	register int c;
7451219Skas 
7461219Skas 	for (c = ch, cp = str; *cp; cp++)
7471219Skas 		if (*cp == c)
7481219Skas 			return(cp);
7491219Skas 	return(NOSTR);
7501219Skas }
7511219Skas 
7521219Skas /*
7531219Skas  * String compare two strings of bounded length.
7541219Skas  */
7551219Skas 
7561219Skas strncmp(as1, as2, an)
7571219Skas 	char *as1, *as2;
7581219Skas {
7591219Skas 	register char *s1, *s2;
7601219Skas 	register int n;
7611219Skas 
7621219Skas 	s1 = as1;
7631219Skas 	s2 = as2;
7641219Skas 	n = an;
7651219Skas 	while (--n >= 0 && *s1 == *s2++)
7661219Skas 		if (*s1++ == '\0')
7671219Skas 			return(0);
7681219Skas 	return(n<0 ? 0 : *s1 - *--s2);
7691219Skas }
7701219Skas 
7717538Skurt #ifndef SIGRETRO
7727538Skurt 
7737538Skurt /*
7747538Skurt  * This routine is used by the sigretro package to
7757538Skurt  * reset held signals to ignored signals.  If you're not
7767538Skurt  * using sigretro, you don't need to do anything, but you DO
7777538Skurt  * need this stub to keep everyone happy.
7787538Skurt  */
7797538Skurt sigchild() {}
7807538Skurt 
7817538Skurt #endif SIGRETRO
782*7571Skurt 
783*7571Skurt /*
784*7571Skurt  * See if the given header field is supposed to be ignored.
785*7571Skurt  */
786*7571Skurt isign(field)
787*7571Skurt 	char *field;
788*7571Skurt {
789*7571Skurt 	char realfld[BUFSIZ];
790*7571Skurt 	register int h;
791*7571Skurt 	register struct ignore *igp;
792*7571Skurt 
793*7571Skurt 	istrcpy(realfld, field);
794*7571Skurt 	h = hash(realfld);
795*7571Skurt 	for (igp = ignore[h]; igp != 0; igp = igp->i_link)
796*7571Skurt 		if (strcmp(igp->i_field, realfld) == 0)
797*7571Skurt 			return(1);
798*7571Skurt 	return(0);
799*7571Skurt }
800