xref: /dflybsd-src/usr.bin/mail/util.c (revision 058e90e202de283fd948d417b00be8171ef37cfa)
1937f07e0SSascha Wildner /*
2937f07e0SSascha Wildner  * Copyright (c) 1980, 1993
3937f07e0SSascha Wildner  *	The Regents of the University of California.  All rights reserved.
4937f07e0SSascha Wildner  *
5937f07e0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6937f07e0SSascha Wildner  * modification, are permitted provided that the following conditions
7937f07e0SSascha Wildner  * are met:
8937f07e0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9937f07e0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10937f07e0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11937f07e0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12937f07e0SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13dc71b7abSJustin C. Sherrill  * 3. Neither the name of the University nor the names of its contributors
14937f07e0SSascha Wildner  *    may be used to endorse or promote products derived from this software
15937f07e0SSascha Wildner  *    without specific prior written permission.
16937f07e0SSascha Wildner  *
17937f07e0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18937f07e0SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19937f07e0SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20937f07e0SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21937f07e0SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22937f07e0SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23937f07e0SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24937f07e0SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25937f07e0SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26937f07e0SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27937f07e0SSascha Wildner  * SUCH DAMAGE.
28937f07e0SSascha Wildner  *
29937f07e0SSascha Wildner  * @(#)aux.c	8.1 (Berkeley) 6/6/93
30937f07e0SSascha Wildner  * $FreeBSD: src/usr.bin/mail/aux.c,v 1.4.6.4 2003/01/06 05:46:03 mikeh Exp $
31937f07e0SSascha Wildner  */
32937f07e0SSascha Wildner 
33937f07e0SSascha Wildner #include <sys/time.h>
34937f07e0SSascha Wildner 
35937f07e0SSascha Wildner #include "rcv.h"
36937f07e0SSascha Wildner #include "extern.h"
37937f07e0SSascha Wildner 
38937f07e0SSascha Wildner /*
39937f07e0SSascha Wildner  * Mail -- a mail program
40937f07e0SSascha Wildner  *
41937f07e0SSascha Wildner  * Auxiliary functions.
42937f07e0SSascha Wildner  */
43937f07e0SSascha Wildner 
44937f07e0SSascha Wildner static char *save2str(char *, char *);
45937f07e0SSascha Wildner 
46937f07e0SSascha Wildner /*
47937f07e0SSascha Wildner  * Return a pointer to a dynamic copy of the argument.
48937f07e0SSascha Wildner  */
49937f07e0SSascha Wildner char *
savestr(char * str)50937f07e0SSascha Wildner savestr(char *str)
51937f07e0SSascha Wildner {
52937f07e0SSascha Wildner 	char *new;
53937f07e0SSascha Wildner 	int size = strlen(str) + 1;
54937f07e0SSascha Wildner 
55937f07e0SSascha Wildner 	if ((new = salloc(size)) != NULL)
56937f07e0SSascha Wildner 		bcopy(str, new, size);
57937f07e0SSascha Wildner 	return (new);
58937f07e0SSascha Wildner }
59937f07e0SSascha Wildner 
60937f07e0SSascha Wildner /*
61937f07e0SSascha Wildner  * Make a copy of new argument incorporating old one.
62937f07e0SSascha Wildner  */
63937f07e0SSascha Wildner char *
save2str(char * str,char * old)64937f07e0SSascha Wildner save2str(char *str, char *old)
65937f07e0SSascha Wildner {
66937f07e0SSascha Wildner 	char *new;
67937f07e0SSascha Wildner 	int newsize = strlen(str) + 1;
68937f07e0SSascha Wildner 	int oldsize = old ? strlen(old) + 1 : 0;
69937f07e0SSascha Wildner 
70937f07e0SSascha Wildner 	if ((new = salloc(newsize + oldsize)) != NULL) {
71937f07e0SSascha Wildner 		if (oldsize) {
72937f07e0SSascha Wildner 			bcopy(old, new, oldsize);
73937f07e0SSascha Wildner 			new[oldsize - 1] = ' ';
74937f07e0SSascha Wildner 		}
75937f07e0SSascha Wildner 		bcopy(str, new + oldsize, newsize);
76937f07e0SSascha Wildner 	}
77937f07e0SSascha Wildner 	return (new);
78937f07e0SSascha Wildner }
79937f07e0SSascha Wildner 
80937f07e0SSascha Wildner /*
81937f07e0SSascha Wildner  * Touch the named message by setting its MTOUCH flag.
82937f07e0SSascha Wildner  * Touched messages have the effect of not being sent
83937f07e0SSascha Wildner  * back to the system mailbox on exit.
84937f07e0SSascha Wildner  */
85937f07e0SSascha Wildner void
touch(struct message * mp)86937f07e0SSascha Wildner touch(struct message *mp)
87937f07e0SSascha Wildner {
88937f07e0SSascha Wildner 	mp->m_flag |= MTOUCH;
89937f07e0SSascha Wildner 	if ((mp->m_flag & MREAD) == 0)
90937f07e0SSascha Wildner 		mp->m_flag |= MREAD|MSTATUS;
91937f07e0SSascha Wildner }
92937f07e0SSascha Wildner 
93937f07e0SSascha Wildner /*
94937f07e0SSascha Wildner  * Test to see if the passed file name is a directory.
95937f07e0SSascha Wildner  * Return true if it is.
96937f07e0SSascha Wildner  */
97937f07e0SSascha Wildner int
isdir(char * name)98937f07e0SSascha Wildner isdir(char *name)
99937f07e0SSascha Wildner {
100937f07e0SSascha Wildner 	struct stat sbuf;
101937f07e0SSascha Wildner 
102937f07e0SSascha Wildner 	if (stat(name, &sbuf) < 0)
103937f07e0SSascha Wildner 		return (0);
104937f07e0SSascha Wildner 	return (S_ISDIR(sbuf.st_mode));
105937f07e0SSascha Wildner }
106937f07e0SSascha Wildner 
107937f07e0SSascha Wildner /*
108937f07e0SSascha Wildner  * Count the number of arguments in the given string raw list.
109937f07e0SSascha Wildner  */
110937f07e0SSascha Wildner int
argcount(char ** argv)111937f07e0SSascha Wildner argcount(char **argv)
112937f07e0SSascha Wildner {
113937f07e0SSascha Wildner 	char **ap;
114937f07e0SSascha Wildner 
115937f07e0SSascha Wildner 	for (ap = argv; *ap++ != NULL;)
116937f07e0SSascha Wildner 		;
117937f07e0SSascha Wildner 	return (ap - argv - 1);
118937f07e0SSascha Wildner }
119937f07e0SSascha Wildner 
120937f07e0SSascha Wildner /*
121937f07e0SSascha Wildner  * Return the desired header line from the passed message
122937f07e0SSascha Wildner  * pointer (or NULL if the desired header field is not available).
123937f07e0SSascha Wildner  */
124937f07e0SSascha Wildner char *
hfield(const char * field,struct message * mp)125937f07e0SSascha Wildner hfield(const char *field, struct message *mp)
126937f07e0SSascha Wildner {
127937f07e0SSascha Wildner 	FILE *ibuf;
128937f07e0SSascha Wildner 	char linebuf[LINESIZE];
129937f07e0SSascha Wildner 	int lc;
130937f07e0SSascha Wildner 	char *hfield;
131937f07e0SSascha Wildner 	char *colon, *oldhfield = NULL;
132937f07e0SSascha Wildner 
133937f07e0SSascha Wildner 	ibuf = setinput(mp);
134937f07e0SSascha Wildner 	if ((lc = mp->m_lines - 1) < 0)
135937f07e0SSascha Wildner 		return (NULL);
136937f07e0SSascha Wildner 	if (readline(ibuf, linebuf, LINESIZE) < 0)
137937f07e0SSascha Wildner 		return (NULL);
138937f07e0SSascha Wildner 	while (lc > 0) {
139937f07e0SSascha Wildner 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
140937f07e0SSascha Wildner 			return (oldhfield);
141937f07e0SSascha Wildner 		if ((hfield = ishfield(linebuf, colon, field)) != NULL)
142937f07e0SSascha Wildner 			oldhfield = save2str(hfield, oldhfield);
143937f07e0SSascha Wildner 	}
144937f07e0SSascha Wildner 	return (oldhfield);
145937f07e0SSascha Wildner }
146937f07e0SSascha Wildner 
147937f07e0SSascha Wildner /*
148937f07e0SSascha Wildner  * Return the next header field found in the given message.
149937f07e0SSascha Wildner  * Return >= 0 if something found, < 0 elsewise.
150937f07e0SSascha Wildner  * "colon" is set to point to the colon in the header.
151937f07e0SSascha Wildner  * Must deal with \ continuations & other such fraud.
152937f07e0SSascha Wildner  */
153937f07e0SSascha Wildner int
gethfield(FILE * f,char * linebuf,int rem,char ** colon)154937f07e0SSascha Wildner gethfield(FILE *f, char *linebuf, int rem, char **colon)
155937f07e0SSascha Wildner {
156937f07e0SSascha Wildner 	char line2[LINESIZE];
157937f07e0SSascha Wildner 	char *cp, *cp2;
158937f07e0SSascha Wildner 	int c;
159937f07e0SSascha Wildner 
160937f07e0SSascha Wildner 	for (;;) {
161937f07e0SSascha Wildner 		if (--rem < 0)
162937f07e0SSascha Wildner 			return (-1);
163937f07e0SSascha Wildner 		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
164937f07e0SSascha Wildner 			return (-1);
165937f07e0SSascha Wildner 		for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
166937f07e0SSascha Wildner 		    cp++)
167937f07e0SSascha Wildner 			;
168937f07e0SSascha Wildner 		if (*cp != ':' || cp == linebuf)
169937f07e0SSascha Wildner 			continue;
170937f07e0SSascha Wildner 		/*
171937f07e0SSascha Wildner 		 * I guess we got a headline.
172937f07e0SSascha Wildner 		 * Handle wraparounding
173937f07e0SSascha Wildner 		 */
174937f07e0SSascha Wildner 		*colon = cp;
175937f07e0SSascha Wildner 		cp = linebuf + c;
176937f07e0SSascha Wildner 		for (;;) {
177937f07e0SSascha Wildner 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
178937f07e0SSascha Wildner 				;
179937f07e0SSascha Wildner 			cp++;
180937f07e0SSascha Wildner 			if (rem <= 0)
181937f07e0SSascha Wildner 				break;
182937f07e0SSascha Wildner 			ungetc(c = getc(f), f);
183937f07e0SSascha Wildner 			if (c != ' ' && c != '\t')
184937f07e0SSascha Wildner 				break;
185937f07e0SSascha Wildner 			if ((c = readline(f, line2, LINESIZE)) < 0)
186937f07e0SSascha Wildner 				break;
187937f07e0SSascha Wildner 			rem--;
188937f07e0SSascha Wildner 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
189937f07e0SSascha Wildner 				;
190937f07e0SSascha Wildner 			c -= cp2 - line2;
191937f07e0SSascha Wildner 			if (cp + c >= linebuf + LINESIZE - 2)
192937f07e0SSascha Wildner 				break;
193937f07e0SSascha Wildner 			*cp++ = ' ';
194937f07e0SSascha Wildner 			bcopy(cp2, cp, c);
195937f07e0SSascha Wildner 			cp += c;
196937f07e0SSascha Wildner 		}
197937f07e0SSascha Wildner 		*cp = 0;
198937f07e0SSascha Wildner 		return (rem);
199937f07e0SSascha Wildner 	}
200937f07e0SSascha Wildner 	/* NOTREACHED */
201937f07e0SSascha Wildner }
202937f07e0SSascha Wildner 
203937f07e0SSascha Wildner /*
204937f07e0SSascha Wildner  * Check whether the passed line is a header line of
205937f07e0SSascha Wildner  * the desired breed.  Return the field body, or 0.
206937f07e0SSascha Wildner  */
207937f07e0SSascha Wildner 
208937f07e0SSascha Wildner char*
ishfield(char * linebuf,char * colon,const char * field)209937f07e0SSascha Wildner ishfield(char *linebuf, char *colon, const char *field)
210937f07e0SSascha Wildner {
211937f07e0SSascha Wildner 	char *cp = colon;
212937f07e0SSascha Wildner 
213937f07e0SSascha Wildner 	*cp = 0;
214937f07e0SSascha Wildner 	if (strcasecmp(linebuf, field) != 0) {
215937f07e0SSascha Wildner 		*cp = ':';
216937f07e0SSascha Wildner 		return (0);
217937f07e0SSascha Wildner 	}
218937f07e0SSascha Wildner 	*cp = ':';
219937f07e0SSascha Wildner 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
220937f07e0SSascha Wildner 		;
221937f07e0SSascha Wildner 	return (cp);
222937f07e0SSascha Wildner }
223937f07e0SSascha Wildner 
224937f07e0SSascha Wildner /*
225937f07e0SSascha Wildner  * Copy a string and lowercase the result.
226937f07e0SSascha Wildner  * dsize: space left in buffer (including space for NULL)
227937f07e0SSascha Wildner  */
228937f07e0SSascha Wildner void
istrncpy(char * dest,const char * src,size_t dsize)229937f07e0SSascha Wildner istrncpy(char *dest, const char *src, size_t dsize)
230937f07e0SSascha Wildner {
231937f07e0SSascha Wildner 	strlcpy(dest, src, dsize);
232*058e90e2SSascha Wildner 	for (; *dest; dest++)
233*058e90e2SSascha Wildner 		*dest = tolower((unsigned char)*dest);
234937f07e0SSascha Wildner }
235937f07e0SSascha Wildner 
236937f07e0SSascha Wildner /*
237937f07e0SSascha Wildner  * The following code deals with input stacking to do source
238937f07e0SSascha Wildner  * commands.  All but the current file pointer are saved on
239937f07e0SSascha Wildner  * the stack.
240937f07e0SSascha Wildner  */
241937f07e0SSascha Wildner 
242937f07e0SSascha Wildner static	int	ssp;			/* Top of file stack */
243937f07e0SSascha Wildner struct sstack {
244937f07e0SSascha Wildner 	FILE	*s_file;		/* File we were in. */
245937f07e0SSascha Wildner 	int	s_cond;			/* Saved state of conditionals */
246937f07e0SSascha Wildner 	int	s_loading;		/* Loading .mailrc, etc. */
247937f07e0SSascha Wildner };
248937f07e0SSascha Wildner #define	SSTACK_SIZE	64		/* XXX was NOFILE. */
249937f07e0SSascha Wildner static struct sstack sstack[SSTACK_SIZE];
250937f07e0SSascha Wildner 
251937f07e0SSascha Wildner /*
252937f07e0SSascha Wildner  * Pushdown current input file and switch to a new one.
253937f07e0SSascha Wildner  * Set the global flag "sourcing" so that others will realize
254937f07e0SSascha Wildner  * that they are no longer reading from a tty (in all probability).
255937f07e0SSascha Wildner  */
256937f07e0SSascha Wildner int
source(char ** arglist)257937f07e0SSascha Wildner source(char **arglist)
258937f07e0SSascha Wildner {
259937f07e0SSascha Wildner 	FILE *fi;
260937f07e0SSascha Wildner 	char *cp;
261937f07e0SSascha Wildner 
262937f07e0SSascha Wildner 	if ((cp = expand(*arglist)) == NULL)
263937f07e0SSascha Wildner 		return (1);
264937f07e0SSascha Wildner 	if ((fi = Fopen(cp, "r")) == NULL) {
265937f07e0SSascha Wildner 		warn("%s", cp);
266937f07e0SSascha Wildner 		return (1);
267937f07e0SSascha Wildner 	}
268937f07e0SSascha Wildner 	if (ssp >= SSTACK_SIZE - 1) {
269937f07e0SSascha Wildner 		printf("Too much \"sourcing\" going on.\n");
270937f07e0SSascha Wildner 		Fclose(fi);
271937f07e0SSascha Wildner 		return (1);
272937f07e0SSascha Wildner 	}
273937f07e0SSascha Wildner 	sstack[ssp].s_file = input;
274937f07e0SSascha Wildner 	sstack[ssp].s_cond = cond;
275937f07e0SSascha Wildner 	sstack[ssp].s_loading = loading;
276937f07e0SSascha Wildner 	ssp++;
277937f07e0SSascha Wildner 	loading = 0;
278937f07e0SSascha Wildner 	cond = CANY;
279937f07e0SSascha Wildner 	input = fi;
280937f07e0SSascha Wildner 	sourcing++;
281937f07e0SSascha Wildner 	return (0);
282937f07e0SSascha Wildner }
283937f07e0SSascha Wildner 
284937f07e0SSascha Wildner /*
285937f07e0SSascha Wildner  * Pop the current input back to the previous level.
286937f07e0SSascha Wildner  * Update the "sourcing" flag as appropriate.
287937f07e0SSascha Wildner  */
288937f07e0SSascha Wildner int
unstack(void)289937f07e0SSascha Wildner unstack(void)
290937f07e0SSascha Wildner {
291937f07e0SSascha Wildner 	if (ssp <= 0) {
292937f07e0SSascha Wildner 		printf("\"Source\" stack over-pop.\n");
293937f07e0SSascha Wildner 		sourcing = 0;
294937f07e0SSascha Wildner 		return (1);
295937f07e0SSascha Wildner 	}
296937f07e0SSascha Wildner 	Fclose(input);
297937f07e0SSascha Wildner 	if (cond != CANY)
298937f07e0SSascha Wildner 		printf("Unmatched \"if\"\n");
299937f07e0SSascha Wildner 	ssp--;
300937f07e0SSascha Wildner 	cond = sstack[ssp].s_cond;
301937f07e0SSascha Wildner 	loading = sstack[ssp].s_loading;
302937f07e0SSascha Wildner 	input = sstack[ssp].s_file;
303937f07e0SSascha Wildner 	if (ssp == 0)
304937f07e0SSascha Wildner 		sourcing = loading;
305937f07e0SSascha Wildner 	return (0);
306937f07e0SSascha Wildner }
307937f07e0SSascha Wildner 
308937f07e0SSascha Wildner /*
309937f07e0SSascha Wildner  * Touch the indicated file.
310937f07e0SSascha Wildner  * This is nifty for the shell.
311937f07e0SSascha Wildner  */
312937f07e0SSascha Wildner void
alter(char * name)313937f07e0SSascha Wildner alter(char *name)
314937f07e0SSascha Wildner {
315937f07e0SSascha Wildner 	struct stat sb;
316937f07e0SSascha Wildner 	struct timeval tv[2];
317937f07e0SSascha Wildner 
318937f07e0SSascha Wildner 	if (stat(name, &sb))
319937f07e0SSascha Wildner 		return;
320937f07e0SSascha Wildner 	gettimeofday(&tv[0], NULL);
321937f07e0SSascha Wildner 	tv[0].tv_sec++;
322937f07e0SSascha Wildner 	TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
323937f07e0SSascha Wildner 	utimes(name, tv);
324937f07e0SSascha Wildner }
325937f07e0SSascha Wildner 
326937f07e0SSascha Wildner /*
327937f07e0SSascha Wildner  * Get sender's name from this message.  If the message has
328937f07e0SSascha Wildner  * a bunch of arpanet stuff in it, we may have to skin the name
329937f07e0SSascha Wildner  * before returning it.
330937f07e0SSascha Wildner  */
331937f07e0SSascha Wildner char *
nameof(struct message * mp,int reptype)332937f07e0SSascha Wildner nameof(struct message *mp, int reptype)
333937f07e0SSascha Wildner {
334937f07e0SSascha Wildner 	char *cp, *cp2;
335937f07e0SSascha Wildner 
336937f07e0SSascha Wildner 	cp = skin(name1(mp, reptype));
337937f07e0SSascha Wildner 	if (reptype != 0 || charcount(cp, '!') < 2)
338937f07e0SSascha Wildner 		return (cp);
339937f07e0SSascha Wildner 	cp2 = strrchr(cp, '!');
340937f07e0SSascha Wildner 	cp2--;
341937f07e0SSascha Wildner 	while (cp2 > cp && *cp2 != '!')
342937f07e0SSascha Wildner 		cp2--;
343937f07e0SSascha Wildner 	if (*cp2 == '!')
344937f07e0SSascha Wildner 		return (cp2 + 1);
345937f07e0SSascha Wildner 	return (cp);
346937f07e0SSascha Wildner }
347937f07e0SSascha Wildner 
348937f07e0SSascha Wildner /*
349937f07e0SSascha Wildner  * Start of a "comment".
350937f07e0SSascha Wildner  * Ignore it.
351937f07e0SSascha Wildner  */
352937f07e0SSascha Wildner char *
skip_comment(char * cp)353937f07e0SSascha Wildner skip_comment(char *cp)
354937f07e0SSascha Wildner {
355937f07e0SSascha Wildner 	int nesting = 1;
356937f07e0SSascha Wildner 
357937f07e0SSascha Wildner 	for (; nesting > 0 && *cp; cp++) {
358937f07e0SSascha Wildner 		switch (*cp) {
359937f07e0SSascha Wildner 		case '\\':
360937f07e0SSascha Wildner 			if (cp[1])
361937f07e0SSascha Wildner 				cp++;
362937f07e0SSascha Wildner 			break;
363937f07e0SSascha Wildner 		case '(':
364937f07e0SSascha Wildner 			nesting++;
365937f07e0SSascha Wildner 			break;
366937f07e0SSascha Wildner 		case ')':
367937f07e0SSascha Wildner 			nesting--;
368937f07e0SSascha Wildner 			break;
369937f07e0SSascha Wildner 		}
370937f07e0SSascha Wildner 	}
371937f07e0SSascha Wildner 	return (cp);
372937f07e0SSascha Wildner }
373937f07e0SSascha Wildner 
374937f07e0SSascha Wildner /*
375937f07e0SSascha Wildner  * Skin an arpa net address according to the RFC 822 interpretation
376937f07e0SSascha Wildner  * of "host-phrase."
377937f07e0SSascha Wildner  */
378937f07e0SSascha Wildner char *
skin(char * name)379937f07e0SSascha Wildner skin(char *name)
380937f07e0SSascha Wildner {
381937f07e0SSascha Wildner 	char *nbuf, *bufend, *cp, *cp2;
382937f07e0SSascha Wildner 	int c, gotlt, lastsp;
383937f07e0SSascha Wildner 
384937f07e0SSascha Wildner 	if (name == NULL)
385937f07e0SSascha Wildner 		return (NULL);
386937f07e0SSascha Wildner 	if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
387937f07e0SSascha Wildner 	    && strchr(name, ' ') == NULL)
388937f07e0SSascha Wildner 		return (name);
389937f07e0SSascha Wildner 
390937f07e0SSascha Wildner 	/* We assume that length(input) <= length(output) */
391937f07e0SSascha Wildner 	if ((nbuf = malloc(strlen(name) + 1)) == NULL)
392937f07e0SSascha Wildner 		err(1, "Out of memory");
393937f07e0SSascha Wildner 	gotlt = 0;
394937f07e0SSascha Wildner 	lastsp = 0;
395937f07e0SSascha Wildner 	bufend = nbuf;
396937f07e0SSascha Wildner 	for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
397937f07e0SSascha Wildner 		switch (c) {
398937f07e0SSascha Wildner 		case '(':
399937f07e0SSascha Wildner 			cp = skip_comment(cp);
400937f07e0SSascha Wildner 			lastsp = 0;
401937f07e0SSascha Wildner 			break;
402937f07e0SSascha Wildner 
403937f07e0SSascha Wildner 		case '"':
404937f07e0SSascha Wildner 			/*
405937f07e0SSascha Wildner 			 * Start of a "quoted-string".
406937f07e0SSascha Wildner 			 * Copy it in its entirety.
407937f07e0SSascha Wildner 			 */
408937f07e0SSascha Wildner 			while ((c = *cp) != '\0') {
409937f07e0SSascha Wildner 				cp++;
410937f07e0SSascha Wildner 				if (c == '"')
411937f07e0SSascha Wildner 					break;
412937f07e0SSascha Wildner 				if (c != '\\')
413937f07e0SSascha Wildner 					*cp2++ = c;
414937f07e0SSascha Wildner 				else if ((c = *cp) != '\0') {
415937f07e0SSascha Wildner 					*cp2++ = c;
416937f07e0SSascha Wildner 					cp++;
417937f07e0SSascha Wildner 				}
418937f07e0SSascha Wildner 			}
419937f07e0SSascha Wildner 			lastsp = 0;
420937f07e0SSascha Wildner 			break;
421937f07e0SSascha Wildner 
422937f07e0SSascha Wildner 		case ' ':
423937f07e0SSascha Wildner 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
424937f07e0SSascha Wildner 				cp += 3, *cp2++ = '@';
425937f07e0SSascha Wildner 			else
426937f07e0SSascha Wildner 			if (cp[0] == '@' && cp[1] == ' ')
427937f07e0SSascha Wildner 				cp += 2, *cp2++ = '@';
428937f07e0SSascha Wildner 			else
429937f07e0SSascha Wildner 				lastsp = 1;
430937f07e0SSascha Wildner 			break;
431937f07e0SSascha Wildner 
432937f07e0SSascha Wildner 		case '<':
433937f07e0SSascha Wildner 			cp2 = bufend;
434937f07e0SSascha Wildner 			gotlt++;
435937f07e0SSascha Wildner 			lastsp = 0;
436937f07e0SSascha Wildner 			break;
437937f07e0SSascha Wildner 
438937f07e0SSascha Wildner 		case '>':
439937f07e0SSascha Wildner 			if (gotlt) {
440937f07e0SSascha Wildner 				gotlt = 0;
441937f07e0SSascha Wildner 				while ((c = *cp) != '\0' && c != ',') {
442937f07e0SSascha Wildner 					cp++;
443937f07e0SSascha Wildner 					if (c == '(')
444937f07e0SSascha Wildner 						cp = skip_comment(cp);
445937f07e0SSascha Wildner 					else if (c == '"')
446937f07e0SSascha Wildner 						while ((c = *cp) != '\0') {
447937f07e0SSascha Wildner 							cp++;
448937f07e0SSascha Wildner 							if (c == '"')
449937f07e0SSascha Wildner 								break;
450937f07e0SSascha Wildner 							if (c == '\\' && *cp != '\0')
451937f07e0SSascha Wildner 								cp++;
452937f07e0SSascha Wildner 						}
453937f07e0SSascha Wildner 				}
454937f07e0SSascha Wildner 				lastsp = 0;
455937f07e0SSascha Wildner 				break;
456937f07e0SSascha Wildner 			}
457937f07e0SSascha Wildner 			/* FALLTHROUGH */
458937f07e0SSascha Wildner 
459937f07e0SSascha Wildner 		default:
460937f07e0SSascha Wildner 			if (lastsp) {
461937f07e0SSascha Wildner 				lastsp = 0;
462937f07e0SSascha Wildner 				*cp2++ = ' ';
463937f07e0SSascha Wildner 			}
464937f07e0SSascha Wildner 			*cp2++ = c;
465937f07e0SSascha Wildner 			if (c == ',' && *cp == ' ' && !gotlt) {
466937f07e0SSascha Wildner 				*cp2++ = ' ';
467937f07e0SSascha Wildner 				while (*++cp == ' ')
468937f07e0SSascha Wildner 					;
469937f07e0SSascha Wildner 				lastsp = 0;
470937f07e0SSascha Wildner 				bufend = cp2;
471937f07e0SSascha Wildner 			}
472937f07e0SSascha Wildner 		}
473937f07e0SSascha Wildner 	}
474937f07e0SSascha Wildner 	*cp2 = '\0';
475937f07e0SSascha Wildner 
476937f07e0SSascha Wildner 	if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
477937f07e0SSascha Wildner 		nbuf = cp;
478937f07e0SSascha Wildner 	return (nbuf);
479937f07e0SSascha Wildner }
480937f07e0SSascha Wildner 
481937f07e0SSascha Wildner /*
482937f07e0SSascha Wildner  * Fetch the sender's name from the passed message.
483937f07e0SSascha Wildner  * Reptype can be
484937f07e0SSascha Wildner  *	0 -- get sender's name for display purposes
485937f07e0SSascha Wildner  *	1 -- get sender's name for reply
486937f07e0SSascha Wildner  *	2 -- get sender's name for Reply
487937f07e0SSascha Wildner  */
488937f07e0SSascha Wildner char *
name1(struct message * mp,int reptype)489937f07e0SSascha Wildner name1(struct message *mp, int reptype)
490937f07e0SSascha Wildner {
491937f07e0SSascha Wildner 	char namebuf[LINESIZE];
492937f07e0SSascha Wildner 	char linebuf[LINESIZE];
493937f07e0SSascha Wildner 	char *cp, *cp2;
494937f07e0SSascha Wildner 	FILE *ibuf;
495937f07e0SSascha Wildner 	int first = 1;
496937f07e0SSascha Wildner 
497937f07e0SSascha Wildner 	if ((cp = hfield("from", mp)) != NULL)
498937f07e0SSascha Wildner 		return (cp);
499937f07e0SSascha Wildner 	if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
500937f07e0SSascha Wildner 		return (cp);
501937f07e0SSascha Wildner 	ibuf = setinput(mp);
502937f07e0SSascha Wildner 	namebuf[0] = '\0';
503937f07e0SSascha Wildner 	if (readline(ibuf, linebuf, LINESIZE) < 0)
504937f07e0SSascha Wildner 		return (savestr(namebuf));
505937f07e0SSascha Wildner newname:
506937f07e0SSascha Wildner 	for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
507937f07e0SSascha Wildner 		;
508937f07e0SSascha Wildner 	for (; *cp == ' ' || *cp == '\t'; cp++)
509937f07e0SSascha Wildner 		;
510937f07e0SSascha Wildner 	for (cp2 = &namebuf[strlen(namebuf)];
511937f07e0SSascha Wildner 	    *cp != '\0' && *cp != ' ' && *cp != '\t' &&
512937f07e0SSascha Wildner 	    cp2 < namebuf + LINESIZE - 1;)
513937f07e0SSascha Wildner 		*cp2++ = *cp++;
514937f07e0SSascha Wildner 	*cp2 = '\0';
515937f07e0SSascha Wildner 	if (readline(ibuf, linebuf, LINESIZE) < 0)
516937f07e0SSascha Wildner 		return (savestr(namebuf));
517937f07e0SSascha Wildner 	if ((cp = strchr(linebuf, 'F')) == NULL)
518937f07e0SSascha Wildner 		return (savestr(namebuf));
519937f07e0SSascha Wildner 	if (strncmp(cp, "From", 4) != 0)
520937f07e0SSascha Wildner 		return (savestr(namebuf));
521937f07e0SSascha Wildner 	while ((cp = strchr(cp, 'r')) != NULL) {
522937f07e0SSascha Wildner 		if (strncmp(cp, "remote", 6) == 0) {
523937f07e0SSascha Wildner 			if ((cp = strchr(cp, 'f')) == NULL)
524937f07e0SSascha Wildner 				break;
525937f07e0SSascha Wildner 			if (strncmp(cp, "from", 4) != 0)
526937f07e0SSascha Wildner 				break;
527937f07e0SSascha Wildner 			if ((cp = strchr(cp, ' ')) == NULL)
528937f07e0SSascha Wildner 				break;
529937f07e0SSascha Wildner 			cp++;
530937f07e0SSascha Wildner 			if (first) {
531937f07e0SSascha Wildner 				cp2 = namebuf;
532937f07e0SSascha Wildner 				first = 0;
533937f07e0SSascha Wildner 			} else
534937f07e0SSascha Wildner 				cp2 = strrchr(namebuf, '!') + 1;
535937f07e0SSascha Wildner 			strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
536937f07e0SSascha Wildner 			strcat(namebuf, "!");
537937f07e0SSascha Wildner 			goto newname;
538937f07e0SSascha Wildner 		}
539937f07e0SSascha Wildner 		cp++;
540937f07e0SSascha Wildner 	}
541937f07e0SSascha Wildner 	return (savestr(namebuf));
542937f07e0SSascha Wildner }
543937f07e0SSascha Wildner 
544937f07e0SSascha Wildner /*
545937f07e0SSascha Wildner  * Count the occurances of c in str
546937f07e0SSascha Wildner  */
547937f07e0SSascha Wildner int
charcount(char * str,int c)548937f07e0SSascha Wildner charcount(char *str, int c)
549937f07e0SSascha Wildner {
550937f07e0SSascha Wildner 	char *cp;
551937f07e0SSascha Wildner 	int i;
552937f07e0SSascha Wildner 
553937f07e0SSascha Wildner 	for (i = 0, cp = str; *cp != '\0'; cp++)
554937f07e0SSascha Wildner 		if (*cp == c)
555937f07e0SSascha Wildner 			i++;
556937f07e0SSascha Wildner 	return (i);
557937f07e0SSascha Wildner }
558937f07e0SSascha Wildner 
559937f07e0SSascha Wildner /*
560937f07e0SSascha Wildner  * See if the given header field is supposed to be ignored.
561937f07e0SSascha Wildner  */
562937f07e0SSascha Wildner int
isign(const char * field,struct ignoretab ignore[2])563937f07e0SSascha Wildner isign(const char *field, struct ignoretab ignore[2])
564937f07e0SSascha Wildner {
565937f07e0SSascha Wildner 	char realfld[LINESIZE];
566937f07e0SSascha Wildner 
567937f07e0SSascha Wildner 	if (ignore == ignoreall)
568937f07e0SSascha Wildner 		return (1);
569937f07e0SSascha Wildner 	/*
570937f07e0SSascha Wildner 	 * Lower-case the string, so that "Status" and "status"
571937f07e0SSascha Wildner 	 * will hash to the same place.
572937f07e0SSascha Wildner 	 */
573937f07e0SSascha Wildner 	istrncpy(realfld, field, sizeof(realfld));
574937f07e0SSascha Wildner 	if (ignore[1].i_count > 0)
575937f07e0SSascha Wildner 		return (!member(realfld, ignore + 1));
576937f07e0SSascha Wildner 	else
577937f07e0SSascha Wildner 		return (member(realfld, ignore));
578937f07e0SSascha Wildner }
579937f07e0SSascha Wildner 
580937f07e0SSascha Wildner int
member(char * realfield,struct ignoretab * table)581937f07e0SSascha Wildner member(char *realfield, struct ignoretab *table)
582937f07e0SSascha Wildner {
583937f07e0SSascha Wildner 	struct ignore *igp;
584937f07e0SSascha Wildner 
585937f07e0SSascha Wildner 	for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
586937f07e0SSascha Wildner 		if (*igp->i_field == *realfield &&
587937f07e0SSascha Wildner 		    equal(igp->i_field, realfield))
588937f07e0SSascha Wildner 			return (1);
589937f07e0SSascha Wildner 	return (0);
590937f07e0SSascha Wildner }
591