xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 59709)
122717Sdist /*
242833Sbostic  * Copyright (c) 1983 Eric P. Allman
333731Sbostic  * Copyright (c) 1988 Regents of the University of California.
433731Sbostic  * All rights reserved.
533731Sbostic  *
642833Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822717Sdist 
922717Sdist #ifndef lint
10*59709Seric static char sccsid[] = "@(#)util.c	6.17 (Berkeley) 05/03/93";
1133731Sbostic #endif /* not lint */
1222717Sdist 
1358332Seric # include "sendmail.h"
14298Seric # include <sysexits.h>
1557135Seric /*
16298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
17298Seric **
18298Seric **	Runs through a string and strips off unquoted quote
19298Seric **	characters and quote bits.  This is done in place.
20298Seric **
21298Seric **	Parameters:
22298Seric **		s -- the string to strip.
23298Seric **
24298Seric **	Returns:
25298Seric **		none.
26298Seric **
27298Seric **	Side Effects:
28298Seric **		none.
29298Seric **
30298Seric **	Called By:
31298Seric **		deliver
32298Seric */
33298Seric 
3454983Seric stripquotes(s)
35298Seric 	char *s;
36298Seric {
37298Seric 	register char *p;
38298Seric 	register char *q;
39298Seric 	register char c;
40298Seric 
414101Seric 	if (s == NULL)
424101Seric 		return;
434101Seric 
4454983Seric 	p = q = s;
4554983Seric 	do
46298Seric 	{
4754983Seric 		c = *p++;
4854983Seric 		if (c == '\\')
4954983Seric 			c = *p++;
5054983Seric 		else if (c == '"')
5154983Seric 			continue;
5254983Seric 		*q++ = c;
5354983Seric 	} while (c != '\0');
54298Seric }
55298Seric /*
56298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
57298Seric **
58298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
59298Seric **	error -- but after all, what can we do?
60298Seric **
61298Seric **	Parameters:
62298Seric **		sz -- size of area to allocate.
63298Seric **
64298Seric **	Returns:
65298Seric **		pointer to data region.
66298Seric **
67298Seric **	Side Effects:
68298Seric **		Memory is allocated.
69298Seric */
70298Seric 
71298Seric char *
72298Seric xalloc(sz)
737007Seric 	register int sz;
74298Seric {
75298Seric 	register char *p;
76298Seric 
7723121Seric 	p = malloc((unsigned) sz);
78298Seric 	if (p == NULL)
79298Seric 	{
80298Seric 		syserr("Out of memory!!");
8110685Seric 		abort();
8210685Seric 		/* exit(EX_UNAVAILABLE); */
83298Seric 	}
84298Seric 	return (p);
85298Seric }
86298Seric /*
873151Seric **  COPYPLIST -- copy list of pointers.
883151Seric **
893151Seric **	This routine is the equivalent of newstr for lists of
903151Seric **	pointers.
913151Seric **
923151Seric **	Parameters:
933151Seric **		list -- list of pointers to copy.
943151Seric **			Must be NULL terminated.
953151Seric **		copycont -- if TRUE, copy the contents of the vector
963151Seric **			(which must be a string) also.
973151Seric **
983151Seric **	Returns:
993151Seric **		a copy of 'list'.
1003151Seric **
1013151Seric **	Side Effects:
1023151Seric **		none.
1033151Seric */
1043151Seric 
1053151Seric char **
1063151Seric copyplist(list, copycont)
1073151Seric 	char **list;
1083151Seric 	bool copycont;
1093151Seric {
1103151Seric 	register char **vp;
1113151Seric 	register char **newvp;
1123151Seric 
1133151Seric 	for (vp = list; *vp != NULL; vp++)
1143151Seric 		continue;
1153151Seric 
1163151Seric 	vp++;
1173151Seric 
11816897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
11916897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1203151Seric 
1213151Seric 	if (copycont)
1223151Seric 	{
1233151Seric 		for (vp = newvp; *vp != NULL; vp++)
1243151Seric 			*vp = newstr(*vp);
1253151Seric 	}
1263151Seric 
1273151Seric 	return (newvp);
1283151Seric }
1293151Seric /*
13058170Seric **  COPYQUEUE -- copy address queue.
13158170Seric **
13258170Seric **	This routine is the equivalent of newstr for address queues
13358170Seric **	addresses marked with QDONTSEND aren't copied
13458170Seric **
13558170Seric **	Parameters:
13658170Seric **		addr -- list of address structures to copy.
13758170Seric **
13858170Seric **	Returns:
13958170Seric **		a copy of 'addr'.
14058170Seric **
14158170Seric **	Side Effects:
14258170Seric **		none.
14358170Seric */
14458170Seric 
14558170Seric ADDRESS *
14658170Seric copyqueue(addr)
14758170Seric 	ADDRESS *addr;
14858170Seric {
14958170Seric 	register ADDRESS *newaddr;
15058170Seric 	ADDRESS *ret;
15158170Seric 	register ADDRESS **tail = &ret;
15258170Seric 
15358170Seric 	while (addr != NULL)
15458170Seric 	{
15558170Seric 		if (!bitset(QDONTSEND, addr->q_flags))
15658170Seric 		{
15758170Seric 			newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));
15858170Seric 			STRUCTCOPY(*addr, *newaddr);
15958170Seric 			*tail = newaddr;
16058170Seric 			tail = &newaddr->q_next;
16158170Seric 		}
16258170Seric 		addr = addr->q_next;
16358170Seric 	}
16458170Seric 	*tail = NULL;
16558170Seric 
16658170Seric 	return ret;
16758170Seric }
16858170Seric /*
1693151Seric **  PRINTAV -- print argument vector.
1703151Seric **
1713151Seric **	Parameters:
1723151Seric **		av -- argument vector.
1733151Seric **
1743151Seric **	Returns:
1753151Seric **		none.
1763151Seric **
1773151Seric **	Side Effects:
1783151Seric **		prints av.
1793151Seric */
1803151Seric 
1813151Seric printav(av)
1823151Seric 	register char **av;
1833151Seric {
1843151Seric 	while (*av != NULL)
1853151Seric 	{
1868063Seric 		if (tTd(0, 44))
1878063Seric 			printf("\n\t%08x=", *av);
1888063Seric 		else
18923105Seric 			(void) putchar(' ');
1903151Seric 		xputs(*av++);
1913151Seric 	}
19223105Seric 	(void) putchar('\n');
1933151Seric }
1943151Seric /*
1953151Seric **  LOWER -- turn letter into lower case.
1963151Seric **
1973151Seric **	Parameters:
1983151Seric **		c -- character to turn into lower case.
1993151Seric **
2003151Seric **	Returns:
2013151Seric **		c, in lower case.
2023151Seric **
2033151Seric **	Side Effects:
2043151Seric **		none.
2053151Seric */
2063151Seric 
2073151Seric char
2083151Seric lower(c)
2093151Seric 	register char c;
2103151Seric {
21158050Seric 	return((isascii(c) && isupper(c)) ? tolower(c) : c);
2123151Seric }
2133151Seric /*
2143151Seric **  XPUTS -- put string doing control escapes.
2153151Seric **
2163151Seric **	Parameters:
2173151Seric **		s -- string to put.
2183151Seric **
2193151Seric **	Returns:
2203151Seric **		none.
2213151Seric **
2223151Seric **	Side Effects:
2233151Seric **		output to stdout
2243151Seric */
2253151Seric 
2263151Seric xputs(s)
2273151Seric 	register char *s;
2283151Seric {
22958050Seric 	register int c;
23051781Seric 	register struct metamac *mp;
23151781Seric 	extern struct metamac MetaMacros[];
2323151Seric 
2338055Seric 	if (s == NULL)
2348055Seric 	{
2358055Seric 		printf("<null>");
2368055Seric 		return;
2378055Seric 	}
23858050Seric 	while ((c = (*s++ & 0377)) != '\0')
2393151Seric 	{
2403151Seric 		if (!isascii(c))
2413151Seric 		{
24258050Seric 			if (c == MATCHREPL || c == MACROEXPAND)
24358050Seric 			{
24458050Seric 				putchar('$');
24558050Seric 				continue;
24658050Seric 			}
24758050Seric 			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
24858050Seric 			{
24958050Seric 				if ((mp->metaval & 0377) == c)
25058050Seric 				{
25158050Seric 					printf("$%c", mp->metaname);
25258050Seric 					break;
25358050Seric 				}
25458050Seric 			}
25558050Seric 			if (mp->metaname != '\0')
25658050Seric 				continue;
25723105Seric 			(void) putchar('\\');
2583151Seric 			c &= 0177;
2593151Seric 		}
26057589Seric 		if (isprint(c))
2613151Seric 		{
26257589Seric 			putchar(c);
26357589Seric 			continue;
26457589Seric 		}
26552050Seric 
26657589Seric 		/* wasn't a meta-macro -- find another way to print it */
26757589Seric 		switch (c)
26857589Seric 		{
26957589Seric 		  case '\0':
27057589Seric 			continue;
27152050Seric 
27257589Seric 		  case '\n':
27357589Seric 			c = 'n';
27457589Seric 			break;
27552050Seric 
27657589Seric 		  case '\r':
27757589Seric 			c = 'r';
27857589Seric 			break;
27952637Seric 
28057589Seric 		  case '\t':
28157589Seric 			c = 't';
28257589Seric 			break;
28357589Seric 
28457589Seric 		  default:
28557589Seric 			(void) putchar('^');
28657589Seric 			(void) putchar(c ^ 0100);
28757589Seric 			continue;
2883151Seric 		}
2893151Seric 	}
2904086Seric 	(void) fflush(stdout);
2913151Seric }
2923151Seric /*
2933151Seric **  MAKELOWER -- Translate a line into lower case
2943151Seric **
2953151Seric **	Parameters:
2963151Seric **		p -- the string to translate.  If NULL, return is
2973151Seric **			immediate.
2983151Seric **
2993151Seric **	Returns:
3003151Seric **		none.
3013151Seric **
3023151Seric **	Side Effects:
3033151Seric **		String pointed to by p is translated to lower case.
3043151Seric **
3053151Seric **	Called By:
3063151Seric **		parse
3073151Seric */
3083151Seric 
3093151Seric makelower(p)
3103151Seric 	register char *p;
3113151Seric {
3123151Seric 	register char c;
3133151Seric 
3143151Seric 	if (p == NULL)
3153151Seric 		return;
3163151Seric 	for (; (c = *p) != '\0'; p++)
3173151Seric 		if (isascii(c) && isupper(c))
31833724Sbostic 			*p = tolower(c);
3193151Seric }
3204059Seric /*
3215196Seric **  BUILDFNAME -- build full name from gecos style entry.
3224375Seric **
3235196Seric **	This routine interprets the strange entry that would appear
3245196Seric **	in the GECOS field of the password file.
3255196Seric **
3264375Seric **	Parameters:
3275196Seric **		p -- name to build.
3285196Seric **		login -- the login name of this user (for &).
3295196Seric **		buf -- place to put the result.
3304375Seric **
3314375Seric **	Returns:
3324375Seric **		none.
3334375Seric **
3344375Seric **	Side Effects:
3354375Seric **		none.
3364375Seric */
3374375Seric 
33854984Seric buildfname(gecos, login, buf)
33954984Seric 	register char *gecos;
3405196Seric 	char *login;
3414375Seric 	char *buf;
3424375Seric {
34354984Seric 	register char *p;
3444375Seric 	register char *bp = buf;
34554984Seric 	int l;
3464375Seric 
34754984Seric 	if (*gecos == '*')
34854984Seric 		gecos++;
34954984Seric 
35057123Seric 	/* find length of final string */
35154984Seric 	l = 0;
35254984Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
35354984Seric 	{
35454984Seric 		if (*p == '&')
35554984Seric 			l += strlen(login);
35654984Seric 		else
35754984Seric 			l++;
35854984Seric 	}
35954984Seric 
36054984Seric 	/* now fill in buf */
36155193Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
3624375Seric 	{
3634375Seric 		if (*p == '&')
3644375Seric 		{
3655196Seric 			(void) strcpy(bp, login);
3664375Seric 			*bp = toupper(*bp);
3674375Seric 			while (*bp != '\0')
3684375Seric 				bp++;
3694375Seric 		}
3704375Seric 		else
37155193Seric 			*bp++ = *p;
3724375Seric 	}
3734375Seric 	*bp = '\0';
3744375Seric }
3754375Seric /*
3764538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3774538Seric **
3784538Seric **	Parameters:
3794538Seric **		fn -- filename to check.
3804538Seric **		uid -- uid to compare against.
3814538Seric **		mode -- mode bits that must match.
3824538Seric **
3834538Seric **	Returns:
38458247Seric **		0 if fn exists, is owned by uid, and matches mode.
38558247Seric **		An errno otherwise.  The actual errno is cleared.
3864538Seric **
3874538Seric **	Side Effects:
3884538Seric **		none.
3894538Seric */
3904538Seric 
39158247Seric int
3924538Seric safefile(fn, uid, mode)
3934538Seric 	char *fn;
39455372Seric 	uid_t uid;
3954538Seric 	int mode;
3964538Seric {
3974538Seric 	struct stat stbuf;
3984538Seric 
39958247Seric 	if (stat(fn, &stbuf) < 0)
40058247Seric 	{
40158247Seric 		int ret = errno;
40258247Seric 
40358247Seric 		errno = 0;
40458247Seric 		return ret;
40558247Seric 	}
40658247Seric 	if (stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode)
40758247Seric 		return 0;
40858247Seric 	return EPERM;
4094538Seric }
4104538Seric /*
4114557Seric **  FIXCRLF -- fix <CR><LF> in line.
4124557Seric **
4134557Seric **	Looks for the <CR><LF> combination and turns it into the
4144557Seric **	UNIX canonical <NL> character.  It only takes one line,
4154557Seric **	i.e., it is assumed that the first <NL> found is the end
4164557Seric **	of the line.
4174557Seric **
4184557Seric **	Parameters:
4194557Seric **		line -- the line to fix.
4204557Seric **		stripnl -- if true, strip the newline also.
4214557Seric **
4224557Seric **	Returns:
4234557Seric **		none.
4244557Seric **
4254557Seric **	Side Effects:
4264557Seric **		line is changed in place.
4274557Seric */
4284557Seric 
4294557Seric fixcrlf(line, stripnl)
4304557Seric 	char *line;
4314557Seric 	bool stripnl;
4324557Seric {
4334557Seric 	register char *p;
4344557Seric 
43556795Seric 	p = strchr(line, '\n');
4364557Seric 	if (p == NULL)
4374557Seric 		return;
43836291Sbostic 	if (p > line && p[-1] == '\r')
4394557Seric 		p--;
4404557Seric 	if (!stripnl)
4414557Seric 		*p++ = '\n';
4424557Seric 	*p = '\0';
4434557Seric }
4444557Seric /*
4456890Seric **  DFOPEN -- determined file open
4466890Seric **
4476890Seric **	This routine has the semantics of fopen, except that it will
4486890Seric **	keep trying a few times to make this happen.  The idea is that
4496890Seric **	on very loaded systems, we may run out of resources (inodes,
4506890Seric **	whatever), so this tries to get around it.
4516890Seric */
4526890Seric 
4536890Seric FILE *
4546890Seric dfopen(filename, mode)
4556890Seric 	char *filename;
4566890Seric 	char *mode;
4576890Seric {
4586890Seric 	register int tries;
4596890Seric 	register FILE *fp;
46059431Seric 	struct stat st;
4616890Seric 
4626890Seric 	for (tries = 0; tries < 10; tries++)
4636890Seric 	{
46425618Seric 		sleep((unsigned) (10 * tries));
4656890Seric 		errno = 0;
4666890Seric 		fp = fopen(filename, mode);
4679376Seric 		if (fp != NULL)
4686890Seric 			break;
4699376Seric 		if (errno != ENFILE && errno != EINTR)
4709376Seric 			break;
4716890Seric 	}
47259431Seric 	if (fp != NULL && fstat(fileno(fp), &st) >= 0 && S_ISREG(st.st_mode))
47356328Seric 	{
47456328Seric 		int locktype;
47558689Seric 		extern bool lockfile();
47656328Seric 
47756328Seric 		/* lock the file to avoid accidental conflicts */
47856328Seric 		if (*mode == 'w' || *mode == 'a')
47956328Seric 			locktype = LOCK_EX;
48056328Seric 		else
48156328Seric 			locktype = LOCK_SH;
48258689Seric 		(void) lockfile(fileno(fp), filename, locktype);
48356328Seric 		errno = 0;
48456328Seric 	}
4856890Seric 	return (fp);
4866890Seric }
4877124Seric /*
4887124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
4897124Seric **
4907753Seric **	This routine always guarantees outputing a newline (or CRLF,
4917753Seric **	as appropriate) at the end of the string.
4927753Seric **
4937124Seric **	Parameters:
4947124Seric **		l -- line to put.
4957124Seric **		fp -- file to put it onto.
49610172Seric **		m -- the mailer used to control output.
4977124Seric **
4987124Seric **	Returns:
4997124Seric **		none
5007124Seric **
5017124Seric **	Side Effects:
5027124Seric **		output of l to fp.
5037124Seric */
5047124Seric 
50510172Seric putline(l, fp, m)
5067753Seric 	register char *l;
5077124Seric 	FILE *fp;
50810172Seric 	MAILER *m;
5097124Seric {
5107124Seric 	register char *p;
51147157Sbostic 	register char svchar;
5127124Seric 
51311275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
51452106Seric 	if (bitnset(M_7BITS, m->m_flags))
51511275Seric 	{
51647157Sbostic 		for (p = l; svchar = *p; ++p)
51747157Sbostic 			if (svchar & 0200)
51847157Sbostic 				*p = svchar &~ 0200;
51911275Seric 	}
52011275Seric 
5217753Seric 	do
5227124Seric 	{
5237753Seric 		/* find the end of the line */
52456795Seric 		p = strchr(l, '\n');
5257753Seric 		if (p == NULL)
5267753Seric 			p = &l[strlen(l)];
5277124Seric 
5287753Seric 		/* check for line overflow */
52952106Seric 		while (m->m_linelimit > 0 && (p - l) > m->m_linelimit)
5307753Seric 		{
53152106Seric 			register char *q = &l[m->m_linelimit - 1];
5327124Seric 
5337753Seric 			svchar = *q;
5347753Seric 			*q = '\0';
53510685Seric 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
53623105Seric 				(void) putc('.', fp);
5377753Seric 			fputs(l, fp);
53823105Seric 			(void) putc('!', fp);
53910326Seric 			fputs(m->m_eol, fp);
5407753Seric 			*q = svchar;
5417753Seric 			l = q;
5427753Seric 		}
5437124Seric 
5447753Seric 		/* output last part */
54510685Seric 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
54623105Seric 			(void) putc('.', fp);
54747157Sbostic 		for ( ; l < p; ++l)
54847157Sbostic 			(void) putc(*l, fp);
54910326Seric 		fputs(m->m_eol, fp);
5507753Seric 		if (*l == '\n')
55147157Sbostic 			++l;
5527753Seric 	} while (l[0] != '\0');
5537124Seric }
5547676Seric /*
5557676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5567676Seric **
5577676Seric **	Parameters:
5587676Seric **		f -- name of file to unlink.
5597676Seric **
5607676Seric **	Returns:
5617676Seric **		none.
5627676Seric **
5637676Seric **	Side Effects:
5647676Seric **		f is unlinked.
5657676Seric */
5667676Seric 
5677676Seric xunlink(f)
5687676Seric 	char *f;
5697676Seric {
5707676Seric 	register int i;
5717676Seric 
5727676Seric # ifdef LOG
57358020Seric 	if (LogLevel > 98)
57458020Seric 		syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f);
57556795Seric # endif /* LOG */
5767676Seric 
5777676Seric 	i = unlink(f);
5787676Seric # ifdef LOG
57958020Seric 	if (i < 0 && LogLevel > 97)
5807942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
58156795Seric # endif /* LOG */
5827676Seric }
5837685Seric /*
58458680Seric **  XFCLOSE -- close a file, doing logging as appropriate.
58558680Seric **
58658680Seric **	Parameters:
58758680Seric **		fp -- file pointer for the file to close
58858680Seric **		a, b -- miscellaneous crud to print for debugging
58958680Seric **
59058680Seric **	Returns:
59158680Seric **		none.
59258680Seric **
59358680Seric **	Side Effects:
59458680Seric **		fp is closed.
59558680Seric */
59658680Seric 
59758680Seric xfclose(fp, a, b)
59858680Seric 	FILE *fp;
59958680Seric 	char *a, *b;
60058680Seric {
60158796Seric 	if (tTd(53, 99))
60258680Seric 		printf("xfclose(%x) %s %s\n", fp, a, b);
60358796Seric 	if (fclose(fp) < 0 && tTd(53, 99))
60458680Seric 		printf("xfclose FAILURE: %s\n", errstring(errno));
60558680Seric }
60658680Seric /*
60714885Seric **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
6087685Seric **
6097685Seric **	Parameters:
6107685Seric **		buf -- place to put the input line.
6117685Seric **		siz -- size of buf.
6127685Seric **		fp -- file to read from.
61357384Seric **		timeout -- the timeout before error occurs.
6147685Seric **
6157685Seric **	Returns:
61615533Seric **		NULL on error (including timeout).  This will also leave
61715533Seric **			buf containing a null string.
6187685Seric **		buf otherwise.
6197685Seric **
6207685Seric **	Side Effects:
6217685Seric **		none.
6227685Seric */
6237685Seric 
62414885Seric static jmp_buf	CtxReadTimeout;
6257685Seric 
6267685Seric char *
62757384Seric sfgets(buf, siz, fp, timeout)
6287685Seric 	char *buf;
6297685Seric 	int siz;
6307685Seric 	FILE *fp;
63157384Seric 	time_t timeout;
6327685Seric {
6337942Seric 	register EVENT *ev = NULL;
6347685Seric 	register char *p;
63546928Sbostic 	static int readtimeout();
6367685Seric 
63714885Seric 	/* set the timeout */
63857384Seric 	if (timeout != 0)
63914885Seric 	{
64014885Seric 		if (setjmp(CtxReadTimeout) != 0)
64114885Seric 		{
64236233Skarels # ifdef LOG
64336230Skarels 			syslog(LOG_NOTICE,
64436230Skarels 			    "timeout waiting for input from %s\n",
64557642Seric 			    CurHostName? CurHostName: "local");
64636233Skarels # endif
64736230Skarels 			errno = 0;
64840964Sbostic 			usrerr("451 timeout waiting for input");
64919037Seric 			buf[0] = '\0';
65014885Seric 			return (NULL);
65114885Seric 		}
65257384Seric 		ev = setevent(timeout, readtimeout, 0);
65314885Seric 	}
65414885Seric 
65514885Seric 	/* try to read */
65615533Seric 	p = NULL;
65715533Seric 	while (p == NULL && !feof(fp) && !ferror(fp))
6587942Seric 	{
6597942Seric 		errno = 0;
6607942Seric 		p = fgets(buf, siz, fp);
66115533Seric 		if (errno == EINTR)
66215533Seric 			clearerr(fp);
66315533Seric 	}
66414885Seric 
66514885Seric 	/* clear the event if it has not sprung */
6667685Seric 	clrevent(ev);
66714885Seric 
66814885Seric 	/* clean up the books and exit */
6698055Seric 	LineNumber++;
67015533Seric 	if (p == NULL)
67116880Seric 	{
67215533Seric 		buf[0] = '\0';
67316880Seric 		return (NULL);
67416880Seric 	}
675*59709Seric 	if (SevenBit)
67652106Seric 		for (p = buf; *p != '\0'; p++)
67752106Seric 			*p &= ~0200;
67816880Seric 	return (buf);
6797685Seric }
6807685Seric 
6817685Seric static
6827685Seric readtimeout()
6837685Seric {
68414885Seric 	longjmp(CtxReadTimeout, 1);
6857685Seric }
6867786Seric /*
6877786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
6887786Seric **
6897786Seric **	Parameters:
6907786Seric **		buf -- place to put result.
6917786Seric **		n -- bytes available.
6927786Seric **		f -- file to read from.
6937786Seric **
6947786Seric **	Returns:
69557135Seric **		input line(s) on success, NULL on error or EOF.
69657135Seric **		This will normally be buf -- unless the line is too
69757135Seric **			long, when it will be xalloc()ed.
6987786Seric **
6997786Seric **	Side Effects:
7007786Seric **		buf gets lines from f, with continuation lines (lines
7017786Seric **		with leading white space) appended.  CRLF's are mapped
7027786Seric **		into single newlines.  Any trailing NL is stripped.
7037786Seric */
7047786Seric 
7057786Seric char *
7067786Seric fgetfolded(buf, n, f)
7077786Seric 	char *buf;
7087786Seric 	register int n;
7097786Seric 	FILE *f;
7107786Seric {
7117786Seric 	register char *p = buf;
71257135Seric 	char *bp = buf;
7137786Seric 	register int i;
7147786Seric 
7157786Seric 	n--;
71617350Seric 	while ((i = getc(f)) != EOF)
7177786Seric 	{
71817350Seric 		if (i == '\r')
71917350Seric 		{
72017350Seric 			i = getc(f);
72117350Seric 			if (i != '\n')
72217350Seric 			{
72317350Seric 				if (i != EOF)
72423105Seric 					(void) ungetc(i, f);
72517350Seric 				i = '\r';
72617350Seric 			}
72717350Seric 		}
72857135Seric 		if (--n <= 0)
72957135Seric 		{
73057135Seric 			/* allocate new space */
73157135Seric 			char *nbp;
73257135Seric 			int nn;
73357135Seric 
73457135Seric 			nn = (p - bp);
73557232Seric 			if (nn < MEMCHUNKSIZE)
73657135Seric 				nn *= 2;
73757135Seric 			else
73857232Seric 				nn += MEMCHUNKSIZE;
73957135Seric 			nbp = xalloc(nn);
74057135Seric 			bcopy(bp, nbp, p - bp);
74157135Seric 			p = &nbp[p - bp];
74257135Seric 			if (bp != buf)
74357135Seric 				free(bp);
74457135Seric 			bp = nbp;
74557135Seric 			n = nn - (p - bp);
74657135Seric 		}
74757135Seric 		*p++ = i;
74817350Seric 		if (i == '\n')
74917350Seric 		{
75017350Seric 			LineNumber++;
75117350Seric 			i = getc(f);
75217350Seric 			if (i != EOF)
75323105Seric 				(void) ungetc(i, f);
75417350Seric 			if (i != ' ' && i != '\t')
75552647Seric 				break;
75617350Seric 		}
7577786Seric 	}
75857135Seric 	if (p == bp)
75952647Seric 		return (NULL);
76052647Seric 	*--p = '\0';
76157135Seric 	return (bp);
7627786Seric }
7637860Seric /*
7647886Seric **  CURTIME -- return current time.
7657886Seric **
7667886Seric **	Parameters:
7677886Seric **		none.
7687886Seric **
7697886Seric **	Returns:
7707886Seric **		the current time.
7717886Seric **
7727886Seric **	Side Effects:
7737886Seric **		none.
7747886Seric */
7757886Seric 
7767886Seric time_t
7777886Seric curtime()
7787886Seric {
7797886Seric 	auto time_t t;
7807886Seric 
7817886Seric 	(void) time(&t);
7827886Seric 	return (t);
7837886Seric }
7848264Seric /*
7858264Seric **  ATOBOOL -- convert a string representation to boolean.
7868264Seric **
7878264Seric **	Defaults to "TRUE"
7888264Seric **
7898264Seric **	Parameters:
7908264Seric **		s -- string to convert.  Takes "tTyY" as true,
7918264Seric **			others as false.
7928264Seric **
7938264Seric **	Returns:
7948264Seric **		A boolean representation of the string.
7958264Seric **
7968264Seric **	Side Effects:
7978264Seric **		none.
7988264Seric */
7998264Seric 
8008264Seric bool
8018264Seric atobool(s)
8028264Seric 	register char *s;
8038264Seric {
80456795Seric 	if (*s == '\0' || strchr("tTyY", *s) != NULL)
8058264Seric 		return (TRUE);
8068264Seric 	return (FALSE);
8078264Seric }
8089048Seric /*
8099048Seric **  ATOOCT -- convert a string representation to octal.
8109048Seric **
8119048Seric **	Parameters:
8129048Seric **		s -- string to convert.
8139048Seric **
8149048Seric **	Returns:
8159048Seric **		An integer representing the string interpreted as an
8169048Seric **		octal number.
8179048Seric **
8189048Seric **	Side Effects:
8199048Seric **		none.
8209048Seric */
8219048Seric 
8229048Seric atooct(s)
8239048Seric 	register char *s;
8249048Seric {
8259048Seric 	register int i = 0;
8269048Seric 
8279048Seric 	while (*s >= '0' && *s <= '7')
8289048Seric 		i = (i << 3) | (*s++ - '0');
8299048Seric 	return (i);
8309048Seric }
8319376Seric /*
8329376Seric **  WAITFOR -- wait for a particular process id.
8339376Seric **
8349376Seric **	Parameters:
8359376Seric **		pid -- process id to wait for.
8369376Seric **
8379376Seric **	Returns:
8389376Seric **		status of pid.
8399376Seric **		-1 if pid never shows up.
8409376Seric **
8419376Seric **	Side Effects:
8429376Seric **		none.
8439376Seric */
8449376Seric 
8459376Seric waitfor(pid)
8469376Seric 	int pid;
8479376Seric {
8489376Seric 	auto int st;
8499376Seric 	int i;
8509376Seric 
8519376Seric 	do
8529376Seric 	{
8539376Seric 		errno = 0;
8549376Seric 		i = wait(&st);
8559376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
8569376Seric 	if (i < 0)
8579376Seric 		st = -1;
8589376Seric 	return (st);
8599376Seric }
8609376Seric /*
86110685Seric **  BITINTERSECT -- tell if two bitmaps intersect
86210685Seric **
86310685Seric **	Parameters:
86410685Seric **		a, b -- the bitmaps in question
86510685Seric **
86610685Seric **	Returns:
86710685Seric **		TRUE if they have a non-null intersection
86810685Seric **		FALSE otherwise
86910685Seric **
87010685Seric **	Side Effects:
87110685Seric **		none.
87210685Seric */
87310685Seric 
87410685Seric bool
87510685Seric bitintersect(a, b)
87610685Seric 	BITMAP a;
87710685Seric 	BITMAP b;
87810685Seric {
87910685Seric 	int i;
88010685Seric 
88110685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
88210685Seric 		if ((a[i] & b[i]) != 0)
88310685Seric 			return (TRUE);
88410685Seric 	return (FALSE);
88510685Seric }
88610685Seric /*
88710685Seric **  BITZEROP -- tell if a bitmap is all zero
88810685Seric **
88910685Seric **	Parameters:
89010685Seric **		map -- the bit map to check
89110685Seric **
89210685Seric **	Returns:
89310685Seric **		TRUE if map is all zero.
89410685Seric **		FALSE if there are any bits set in map.
89510685Seric **
89610685Seric **	Side Effects:
89710685Seric **		none.
89810685Seric */
89910685Seric 
90010685Seric bool
90110685Seric bitzerop(map)
90210685Seric 	BITMAP map;
90310685Seric {
90410685Seric 	int i;
90510685Seric 
90610685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
90710685Seric 		if (map[i] != 0)
90810685Seric 			return (FALSE);
90910685Seric 	return (TRUE);
91010685Seric }
91158247Seric /*
91258318Seric **  STRCONTAINEDIN -- tell if one string is contained in another
91358318Seric **
91458318Seric **	Parameters:
91558318Seric **		a -- possible substring.
91658318Seric **		b -- possible superstring.
91758318Seric **
91858318Seric **	Returns:
91958318Seric **		TRUE if a is contained in b.
92058318Seric **		FALSE otherwise.
92158318Seric */
92258318Seric 
92358318Seric bool
92458318Seric strcontainedin(a, b)
92558318Seric 	register char *a;
92658318Seric 	register char *b;
92758318Seric {
92858318Seric 	int l;
92958318Seric 
93058318Seric 	l = strlen(a);
93158318Seric 	for (;;)
93258318Seric 	{
93358318Seric 		b = strchr(b, a[0]);
93458318Seric 		if (b == NULL)
93558318Seric 			return FALSE;
93658318Seric 		if (strncmp(a, b, l) == 0)
93758318Seric 			return TRUE;
93858318Seric 		b++;
93958318Seric 	}
94058318Seric }
941