1872b698pfg/*-
2872b698pfg * SPDX-License-Identifier: BSD-3-Clause
3872b698pfg *
4f9ab90drgrimes * Copyright (c) 1980, 1993
5f9ab90drgrimes *	The Regents of the University of California.  All rights reserved.
6f9ab90drgrimes *
7f9ab90drgrimes * Redistribution and use in source and binary forms, with or without
8f9ab90drgrimes * modification, are permitted provided that the following conditions
9f9ab90drgrimes * are met:
10f9ab90drgrimes * 1. Redistributions of source code must retain the above copyright
11f9ab90drgrimes *    notice, this list of conditions and the following disclaimer.
12f9ab90drgrimes * 2. Redistributions in binary form must reproduce the above copyright
13f9ab90drgrimes *    notice, this list of conditions and the following disclaimer in the
14f9ab90drgrimes *    documentation and/or other materials provided with the distribution.
157e6cabdimp * 3. Neither the name of the University nor the names of its contributors
16f9ab90drgrimes *    may be used to endorse or promote products derived from this software
17f9ab90drgrimes *    without specific prior written permission.
18f9ab90drgrimes *
19f9ab90drgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20f9ab90drgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21f9ab90drgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22f9ab90drgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23f9ab90drgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24f9ab90drgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25f9ab90drgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26f9ab90drgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27f9ab90drgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28f9ab90drgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29f9ab90drgrimes * SUCH DAMAGE.
30f9ab90drgrimes */
31f9ab90drgrimes
32f9ab90drgrimes#ifndef lint
33e51e7e0mikeh#if 0
34f9ab90drgrimesstatic char sccsid[] = "@(#)aux.c	8.1 (Berkeley) 6/6/93";
35e51e7e0mikeh#endif
36f9ab90drgrimes#endif /* not lint */
37bc61fc9obrien#include <sys/cdefs.h>
38bc61fc9obrien__FBSDID("$FreeBSD$");
39f9ab90drgrimes
401108cb5bde#include <sys/time.h>
411108cb5bde
428156bf7jilles#include <fcntl.h>
438156bf7jilles
44f9ab90drgrimes#include "rcv.h"
45f9ab90drgrimes#include "extern.h"
46f9ab90drgrimes
47f9ab90drgrimes/*
48f9ab90drgrimes * Mail -- a mail program
49f9ab90drgrimes *
50f9ab90drgrimes * Auxiliary functions.
51f9ab90drgrimes */
52f9ab90drgrimes
531698cb2impstatic char *save2str(char *, char *);
54aa40e2emikeh
55f9ab90drgrimes/*
56f9ab90drgrimes * Return a pointer to a dynamic copy of the argument.
57f9ab90drgrimes */
58f9ab90drgrimeschar *
59f4859becharniersavestr(char *str)
60f9ab90drgrimes{
61f9ab90drgrimes	char *new;
62f9ab90drgrimes	int size = strlen(str) + 1;
63f9ab90drgrimes
64aa40e2emikeh	if ((new = salloc(size)) != NULL)
65f9ab90drgrimes		bcopy(str, new, size);
66aa40e2emikeh	return (new);
67f9ab90drgrimes}
68f9ab90drgrimes
69f9ab90drgrimes/*
70f9ab90drgrimes * Make a copy of new argument incorporating old one.
71f9ab90drgrimes */
72bb2ff10ddsstatic char *
73f4859becharniersave2str(char *str, char *old)
74f9ab90drgrimes{
75f9ab90drgrimes	char *new;
76f9ab90drgrimes	int newsize = strlen(str) + 1;
77f9ab90drgrimes	int oldsize = old ? strlen(old) + 1 : 0;
78f9ab90drgrimes
79aa40e2emikeh	if ((new = salloc(newsize + oldsize)) != NULL) {
80f9ab90drgrimes		if (oldsize) {
81f9ab90drgrimes			bcopy(old, new, oldsize);
82f9ab90drgrimes			new[oldsize - 1] = ' ';
83f9ab90drgrimes		}
84f9ab90drgrimes		bcopy(str, new + oldsize, newsize);
85f9ab90drgrimes	}
86aa40e2emikeh	return (new);
87f9ab90drgrimes}
88f9ab90drgrimes
89f9ab90drgrimes/*
90f9ab90drgrimes * Touch the named message by setting its MTOUCH flag.
91f9ab90drgrimes * Touched messages have the effect of not being sent
92f9ab90drgrimes * back to the system mailbox on exit.
93f9ab90drgrimes */
94f9ab90drgrimesvoid
95f4859becharniertouch(struct message *mp)
96f9ab90drgrimes{
97f9ab90drgrimes
98f9ab90drgrimes	mp->m_flag |= MTOUCH;
99f9ab90drgrimes	if ((mp->m_flag & MREAD) == 0)
100f9ab90drgrimes		mp->m_flag |= MREAD|MSTATUS;
101f9ab90drgrimes}
102f9ab90drgrimes
103f9ab90drgrimes/*
104f9ab90drgrimes * Test to see if the passed file name is a directory.
105f9ab90drgrimes * Return true if it is.
106f9ab90drgrimes */
107f9ab90drgrimesint
108f4859becharnierisdir(char name[])
109f9ab90drgrimes{
110f9ab90drgrimes	struct stat sbuf;
111f9ab90drgrimes
112f9ab90drgrimes	if (stat(name, &sbuf) < 0)
113aa40e2emikeh		return (0);
114aa40e2emikeh	return (S_ISDIR(sbuf.st_mode));
115f9ab90drgrimes}
116f9ab90drgrimes
117f9ab90drgrimes/*
118f9ab90drgrimes * Count the number of arguments in the given string raw list.
119f9ab90drgrimes */
120f9ab90drgrimesint
121f4859becharnierargcount(char **argv)
122f9ab90drgrimes{
123aa40e2emikeh	char **ap;
124f9ab90drgrimes
125aa40e2emikeh	for (ap = argv; *ap++ != NULL;)
126a14d555rgrimes		;
127aa40e2emikeh	return (ap - argv - 1);
128f9ab90drgrimes}
129f9ab90drgrimes
130f9ab90drgrimes/*
131f9ab90drgrimes * Return the desired header line from the passed message
132aa40e2emikeh * pointer (or NULL if the desired header field is not available).
133f9ab90drgrimes */
134f9ab90drgrimeschar *
135f4859becharnierhfield(const char *field, struct message *mp)
136f9ab90drgrimes{
137aa40e2emikeh	FILE *ibuf;
138f9ab90drgrimes	char linebuf[LINESIZE];
139aa40e2emikeh	int lc;
140aa40e2emikeh	char *hfield;
141aa40e2emikeh	char *colon, *oldhfield = NULL;
142f9ab90drgrimes
143f9ab90drgrimes	ibuf = setinput(mp);
144f9ab90drgrimes	if ((lc = mp->m_lines - 1) < 0)
145aa40e2emikeh		return (NULL);
146f9ab90drgrimes	if (readline(ibuf, linebuf, LINESIZE) < 0)
147aa40e2emikeh		return (NULL);
148f9ab90drgrimes	while (lc > 0) {
149f9ab90drgrimes		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
150aa40e2emikeh			return (oldhfield);
1512df2878charnier		if ((hfield = ishfield(linebuf, colon, field)) != NULL)
152f9ab90drgrimes			oldhfield = save2str(hfield, oldhfield);
153f9ab90drgrimes	}
154aa40e2emikeh	return (oldhfield);
155f9ab90drgrimes}
156f9ab90drgrimes
157f9ab90drgrimes/*
158f9ab90drgrimes * Return the next header field found in the given message.
159f9ab90drgrimes * Return >= 0 if something found, < 0 elsewise.
160f9ab90drgrimes * "colon" is set to point to the colon in the header.
161f9ab90drgrimes * Must deal with \ continuations & other such fraud.
162f9ab90drgrimes */
163f9ab90drgrimesint
164f4859becharniergethfield(FILE *f, char linebuf[], int rem, char **colon)
165f9ab90drgrimes{
166f9ab90drgrimes	char line2[LINESIZE];
167aa40e2emikeh	char *cp, *cp2;
168aa40e2emikeh	int c;
169f9ab90drgrimes
170f9ab90drgrimes	for (;;) {
171f9ab90drgrimes		if (--rem < 0)
172aa40e2emikeh			return (-1);
173f9ab90drgrimes		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
174aa40e2emikeh			return (-1);
1758d59503ache		for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
176aa40e2emikeh		    cp++)
177f9ab90drgrimes			;
178f9ab90drgrimes		if (*cp != ':' || cp == linebuf)
179f9ab90drgrimes			continue;
180f9ab90drgrimes		/*
181f9ab90drgrimes		 * I guess we got a headline.
182f9ab90drgrimes		 * Handle wraparounding
183f9ab90drgrimes		 */
184f9ab90drgrimes		*colon = cp;
185f9ab90drgrimes		cp = linebuf + c;
186f9ab90drgrimes		for (;;) {
187f9ab90drgrimes			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
188f9ab90drgrimes				;
189f9ab90drgrimes			cp++;
190f9ab90drgrimes			if (rem <= 0)
191f9ab90drgrimes				break;
192f9ab90drgrimes			ungetc(c = getc(f), f);
193f9ab90drgrimes			if (c != ' ' && c != '\t')
194f9ab90drgrimes				break;
195f9ab90drgrimes			if ((c = readline(f, line2, LINESIZE)) < 0)
196f9ab90drgrimes				break;
197f9ab90drgrimes			rem--;
198f9ab90drgrimes			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
199f9ab90drgrimes				;
200f9ab90drgrimes			c -= cp2 - line2;
201f9ab90drgrimes			if (cp + c >= linebuf + LINESIZE - 2)
202f9ab90drgrimes				break;
203f9ab90drgrimes			*cp++ = ' ';
204f9ab90drgrimes			bcopy(cp2, cp, c);
205f9ab90drgrimes			cp += c;
206f9ab90drgrimes		}
207f9ab90drgrimes		*cp = 0;
208aa40e2emikeh		return (rem);
209f9ab90drgrimes	}
210f9ab90drgrimes	/* NOTREACHED */
211f9ab90drgrimes}
212f9ab90drgrimes
213f9ab90drgrimes/*
214f9ab90drgrimes * Check whether the passed line is a header line of
215f9ab90drgrimes * the desired breed.  Return the field body, or 0.
216f9ab90drgrimes */
217f9ab90drgrimes
218f9ab90drgrimeschar*
2192e191bepfgishfield(char *linebuf, char *colon, const char *field)
220f9ab90drgrimes{
221aa40e2emikeh	char *cp = colon;
222f9ab90drgrimes
223f9ab90drgrimes	*cp = 0;
224f9ab90drgrimes	if (strcasecmp(linebuf, field) != 0) {
225f9ab90drgrimes		*cp = ':';
226aa40e2emikeh		return (0);
227f9ab90drgrimes	}
228f9ab90drgrimes	*cp = ':';
229f9ab90drgrimes	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
230f9ab90drgrimes		;
231aa40e2emikeh	return (cp);
232f9ab90drgrimes}
233f9ab90drgrimes
234f9ab90drgrimes/*
235e51e7e0mikeh * Copy a string and lowercase the result.
236e51e7e0mikeh * dsize: space left in buffer (including space for NULL)
237f9ab90drgrimes */
238f9ab90drgrimesvoid
239f4859becharnieristrncpy(char *dest, const char *src, size_t dsize)
240f9ab90drgrimes{
241f9ab90drgrimes
242e51e7e0mikeh	strlcpy(dest, src, dsize);
243f4e7f0adim	for (; *dest; dest++)
244f4e7f0adim		*dest = tolower((unsigned char)*dest);
245f9ab90drgrimes}
246f9ab90drgrimes
247f9ab90drgrimes/*
248f9ab90drgrimes * The following code deals with input stacking to do source
249f9ab90drgrimes * commands.  All but the current file pointer are saved on
250f9ab90drgrimes * the stack.
251f9ab90drgrimes */
252f9ab90drgrimes
253f9ab90drgrimesstatic	int	ssp;			/* Top of file stack */
254f9ab90drgrimesstruct sstack {
255f9ab90drgrimes	FILE	*s_file;		/* File we were in. */
256f9ab90drgrimes	int	s_cond;			/* Saved state of conditionals */
257f9ab90drgrimes	int	s_loading;		/* Loading .mailrc, etc. */
2588dd1904bde};
2598dd1904bde#define	SSTACK_SIZE	64		/* XXX was NOFILE. */
2608dd1904bdestatic struct sstack sstack[SSTACK_SIZE];
261f9ab90drgrimes
262f9ab90drgrimes/*
263f9ab90drgrimes * Pushdown current input file and switch to a new one.
264f9ab90drgrimes * Set the global flag "sourcing" so that others will realize
265f9ab90drgrimes * that they are no longer reading from a tty (in all probability).
266f9ab90drgrimes */
267f9ab90drgrimesint
268f4859becharniersource(char **arglist)
269f9ab90drgrimes{
270f9ab90drgrimes	FILE *fi;
271f9ab90drgrimes	char *cp;
272f9ab90drgrimes
273aa40e2emikeh	if ((cp = expand(*arglist)) == NULL)
274aa40e2emikeh		return (1);
275f9ab90drgrimes	if ((fi = Fopen(cp, "r")) == NULL) {
276e51e7e0mikeh		warn("%s", cp);
277aa40e2emikeh		return (1);
278f9ab90drgrimes	}
2798dd1904bde	if (ssp >= SSTACK_SIZE - 1) {
280f9ab90drgrimes		printf("Too much \"sourcing\" going on.\n");
281aa40e2emikeh		(void)Fclose(fi);
282aa40e2emikeh		return (1);
283f9ab90drgrimes	}
284f9ab90drgrimes	sstack[ssp].s_file = input;
285f9ab90drgrimes	sstack[ssp].s_cond = cond;
286f9ab90drgrimes	sstack[ssp].s_loading = loading;
287f9ab90drgrimes	ssp++;
288f9ab90drgrimes	loading = 0;
289f9ab90drgrimes	cond = CANY;
290f9ab90drgrimes	input = fi;
291f9ab90drgrimes	sourcing++;
292aa40e2emikeh	return (0);
293f9ab90drgrimes}
294f9ab90drgrimes
295f9ab90drgrimes/*
296f9ab90drgrimes * Pop the current input back to the previous level.
297f9ab90drgrimes * Update the "sourcing" flag as appropriate.
298f9ab90drgrimes */
299f9ab90drgrimesint
300f4859becharnierunstack(void)
301f9ab90drgrimes{
302f9ab90drgrimes	if (ssp <= 0) {
303f9ab90drgrimes		printf("\"Source\" stack over-pop.\n");
304f9ab90drgrimes		sourcing = 0;
305aa40e2emikeh		return (1);
306f9ab90drgrimes	}
307aa40e2emikeh	(void)Fclose(input);
308f9ab90drgrimes	if (cond != CANY)
309f9ab90drgrimes		printf("Unmatched \"if\"\n");
310f9ab90drgrimes	ssp--;
311f9ab90drgrimes	cond = sstack[ssp].s_cond;
312f9ab90drgrimes	loading = sstack[ssp].s_loading;
313f9ab90drgrimes	input = sstack[ssp].s_file;
314f9ab90drgrimes	if (ssp == 0)
315f9ab90drgrimes		sourcing = loading;
316aa40e2emikeh	return (0);
317f9ab90drgrimes}
318f9ab90drgrimes
319f9ab90drgrimes/*
320f9ab90drgrimes * Touch the indicated file.
321f9ab90drgrimes * This is nifty for the shell.
322f9ab90drgrimes */
323f9ab90drgrimesvoid
324f4859becharnieralter(char *name)
325f9ab90drgrimes{
3268156bf7jilles	struct timespec ts[2];
3278156bf7jilles
3288156bf7jilles	(void)clock_gettime(CLOCK_REALTIME, &ts[0]);
3298156bf7jilles	ts[0].tv_sec++;
3308156bf7jilles	ts[1].tv_sec = 0;
3318156bf7jilles	ts[1].tv_nsec = UTIME_OMIT;
3328156bf7jilles	(void)utimensat(AT_FDCWD, name, ts, 0);
333f9ab90drgrimes}
334f9ab90drgrimes
335f9ab90drgrimes/*
336f9ab90drgrimes * Get sender's name from this message.  If the message has
337f9ab90drgrimes * a bunch of arpanet stuff in it, we may have to skin the name
338f9ab90drgrimes * before returning it.
339f9ab90drgrimes */
340f9ab90drgrimeschar *
341f4859becharniernameof(struct message *mp, int reptype)
342f9ab90drgrimes{
343aa40e2emikeh	char *cp, *cp2;
344f9ab90drgrimes
345f9ab90drgrimes	cp = skin(name1(mp, reptype));
346f9ab90drgrimes	if (reptype != 0 || charcount(cp, '!') < 2)
347aa40e2emikeh		return (cp);
348e51e7e0mikeh	cp2 = strrchr(cp, '!');
349f9ab90drgrimes	cp2--;
350f9ab90drgrimes	while (cp2 > cp && *cp2 != '!')
351f9ab90drgrimes		cp2--;
352f9ab90drgrimes	if (*cp2 == '!')
353aa40e2emikeh		return (cp2 + 1);
354aa40e2emikeh	return (cp);
355f9ab90drgrimes}
356f9ab90drgrimes
357f9ab90drgrimes/*
358f9ab90drgrimes * Start of a "comment".
359f9ab90drgrimes * Ignore it.
360f9ab90drgrimes */
361f9ab90drgrimeschar *
362f4859becharnierskip_comment(char *cp)
363f9ab90drgrimes{
364aa40e2emikeh	int nesting = 1;
365f9ab90drgrimes
366f9ab90drgrimes	for (; nesting > 0 && *cp; cp++) {
367f9ab90drgrimes		switch (*cp) {
368f9ab90drgrimes		case '\\':
369f9ab90drgrimes			if (cp[1])
370f9ab90drgrimes				cp++;
371f9ab90drgrimes			break;
372f9ab90drgrimes		case '(':
373f9ab90drgrimes			nesting++;
374f9ab90drgrimes			break;
375f9ab90drgrimes		case ')':
376f9ab90drgrimes			nesting--;
377f9ab90drgrimes			break;
378f9ab90drgrimes		}
379f9ab90drgrimes	}
380aa40e2emikeh	return (cp);
381f9ab90drgrimes}
382f9ab90drgrimes
383f9ab90drgrimes/*
384f9ab90drgrimes * Skin an arpa net address according to the RFC 822 interpretation
385f9ab90drgrimes * of "host-phrase."
386f9ab90drgrimes */
387f9ab90drgrimeschar *
388f4859becharnierskin(char *name)
389f9ab90drgrimes{
390aa40e2emikeh	char *nbuf, *bufend, *cp, *cp2;
391aa40e2emikeh	int c, gotlt, lastsp;
392f9ab90drgrimes
393aa40e2emikeh	if (name == NULL)
394aa40e2emikeh		return (NULL);
395aa40e2emikeh	if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
396aa40e2emikeh	    && strchr(name, ' ') == NULL)
397aa40e2emikeh		return (name);
398e51e7e0mikeh
399e51e7e0mikeh	/* We assume that length(input) <= length(output) */
400aa40e2emikeh	if ((nbuf = malloc(strlen(name) + 1)) == NULL)
401e51e7e0mikeh		err(1, "Out of memory");
402f9ab90drgrimes	gotlt = 0;
403f9ab90drgrimes	lastsp = 0;
404f9ab90drgrimes	bufend = nbuf;
405aa40e2emikeh	for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
406f9ab90drgrimes		switch (c) {
407f9ab90drgrimes		case '(':
408f9ab90drgrimes			cp = skip_comment(cp);
409f9ab90drgrimes			lastsp = 0;
410f9ab90drgrimes			break;
411f9ab90drgrimes
412f9ab90drgrimes		case '"':
413f9ab90drgrimes			/*
414f9ab90drgrimes			 * Start of a "quoted-string".
415f9ab90drgrimes			 * Copy it in its entirety.
416f9ab90drgrimes			 */
417aa40e2emikeh			while ((c = *cp) != '\0') {
418f9ab90drgrimes				cp++;
419f9ab90drgrimes				if (c == '"')
420f9ab90drgrimes					break;
421f9ab90drgrimes				if (c != '\\')
422f9ab90drgrimes					*cp2++ = c;
423aa40e2emikeh				else if ((c = *cp) != '\0') {
424f9ab90drgrimes					*cp2++ = c;
425f9ab90drgrimes					cp++;
426f9ab90drgrimes				}
427f9ab90drgrimes			}
428f9ab90drgrimes			lastsp = 0;
429f9ab90drgrimes			break;
430f9ab90drgrimes
431f9ab90drgrimes		case ' ':
432f9ab90drgrimes			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
433f9ab90drgrimes				cp += 3, *cp2++ = '@';
434f9ab90drgrimes			else
435f9ab90drgrimes			if (cp[0] == '@' && cp[1] == ' ')
436f9ab90drgrimes				cp += 2, *cp2++ = '@';
437f9ab90drgrimes			else
438f9ab90drgrimes				lastsp = 1;
439f9ab90drgrimes			break;
440f9ab90drgrimes
441f9ab90drgrimes		case '<':
442f9ab90drgrimes			cp2 = bufend;
443f9ab90drgrimes			gotlt++;
444f9ab90drgrimes			lastsp = 0;
445f9ab90drgrimes			break;
446f9ab90drgrimes
447f9ab90drgrimes		case '>':
448f9ab90drgrimes			if (gotlt) {
449f9ab90drgrimes				gotlt = 0;
450aa40e2emikeh				while ((c = *cp) != '\0' && c != ',') {
451f9ab90drgrimes					cp++;
452f9ab90drgrimes					if (c == '(')
453f9ab90drgrimes						cp = skip_comment(cp);
454f9ab90drgrimes					else if (c == '"')
455aa40e2emikeh						while ((c = *cp) != '\0') {
456f9ab90drgrimes							cp++;
457f9ab90drgrimes							if (c == '"')
458f9ab90drgrimes								break;
459aa40e2emikeh							if (c == '\\' && *cp != '\0')
460f9ab90drgrimes								cp++;
461f9ab90drgrimes						}
462f9ab90drgrimes				}
463f9ab90drgrimes				lastsp = 0;
464f9ab90drgrimes				break;
465f9ab90drgrimes			}
4667dd9d47charnier			/* FALLTHROUGH */
467f9ab90drgrimes
468f9ab90drgrimes		default:
469f9ab90drgrimes			if (lastsp) {
470f9ab90drgrimes				lastsp = 0;
471f9ab90drgrimes				*cp2++ = ' ';
472f9ab90drgrimes			}
473f9ab90drgrimes			*cp2++ = c;
4742053f03uqs			if (c == ',' && !gotlt &&
4752053f03uqs			    (*cp == ' ' || *cp == '"' || *cp == '<')) {
476f9ab90drgrimes				*cp2++ = ' ';
4772053f03uqs				while (*cp == ' ')
4782053f03uqs					cp++;
479f9ab90drgrimes				lastsp = 0;
480f9ab90drgrimes				bufend = cp2;
481f9ab90drgrimes			}
482f9ab90drgrimes		}
483f9ab90drgrimes	}
484aa40e2emikeh	*cp2 = '\0';
485f9ab90drgrimes
486ff0ca8amikeh	if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
487ff0ca8amikeh		nbuf = cp;
488aa40e2emikeh	return (nbuf);
489f9ab90drgrimes}
490f9ab90drgrimes
491f9ab90drgrimes/*
492f9ab90drgrimes * Fetch the sender's name from the passed message.
493f9ab90drgrimes * Reptype can be
494f9ab90drgrimes *	0 -- get sender's name for display purposes
495f9ab90drgrimes *	1 -- get sender's name for reply
496f9ab90drgrimes *	2 -- get sender's name for Reply
497f9ab90drgrimes */
498f9ab90drgrimeschar *
499f4859becharniername1(struct message *mp, int reptype)
500f9ab90drgrimes{
501f9ab90drgrimes	char namebuf[LINESIZE];
502f9ab90drgrimes	char linebuf[LINESIZE];
503aa40e2emikeh	char *cp, *cp2;
504aa40e2emikeh	FILE *ibuf;
505f9ab90drgrimes	int first = 1;
506f9ab90drgrimes
507aa40e2emikeh	if ((cp = hfield("from", mp)) != NULL)
508aa40e2emikeh		return (cp);
509aa40e2emikeh	if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
510aa40e2emikeh		return (cp);
511f9ab90drgrimes	ibuf = setinput(mp);
5122df2878charnier	namebuf[0] = '\0';
513f9ab90drgrimes	if (readline(ibuf, linebuf, LINESIZE) < 0)
514aa40e2emikeh		return (savestr(namebuf));
515f9ab90drgrimesnewname:
516aa40e2emikeh	for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
517f9ab90drgrimes		;
518f9ab90drgrimes	for (; *cp == ' ' || *cp == '\t'; cp++)
519f9ab90drgrimes		;
520f9ab90drgrimes	for (cp2 = &namebuf[strlen(namebuf)];
521aa40e2emikeh	    *cp != '\0' && *cp != ' ' && *cp != '\t' &&
522aa40e2emikeh	    cp2 < namebuf + LINESIZE - 1;)
523f9ab90drgrimes		*cp2++ = *cp++;
524f9ab90drgrimes	*cp2 = '\0';
525f9ab90drgrimes	if (readline(ibuf, linebuf, LINESIZE) < 0)
526aa40e2emikeh		return (savestr(namebuf));
527e51e7e0mikeh	if ((cp = strchr(linebuf, 'F')) == NULL)
528aa40e2emikeh		return (savestr(namebuf));
529f9ab90drgrimes	if (strncmp(cp, "From", 4) != 0)
530aa40e2emikeh		return (savestr(namebuf));
531e51e7e0mikeh	while ((cp = strchr(cp, 'r')) != NULL) {
532f9ab90drgrimes		if (strncmp(cp, "remote", 6) == 0) {
533e51e7e0mikeh			if ((cp = strchr(cp, 'f')) == NULL)
534f9ab90drgrimes				break;
535f9ab90drgrimes			if (strncmp(cp, "from", 4) != 0)
536f9ab90drgrimes				break;
537e51e7e0mikeh			if ((cp = strchr(cp, ' ')) == NULL)
538f9ab90drgrimes				break;
539f9ab90drgrimes			cp++;
540f9ab90drgrimes			if (first) {
541e51e7e0mikeh				cp2 = namebuf;
542f9ab90drgrimes				first = 0;
543f9ab90drgrimes			} else
544e51e7e0mikeh				cp2 = strrchr(namebuf, '!') + 1;
545e51e7e0mikeh			strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
546f9ab90drgrimes			strcat(namebuf, "!");
547f9ab90drgrimes			goto newname;
548f9ab90drgrimes		}
549f9ab90drgrimes		cp++;
550f9ab90drgrimes	}
551aa40e2emikeh	return (savestr(namebuf));
552f9ab90drgrimes}
553f9ab90drgrimes
554f9ab90drgrimes/*
5552b302aauqs * Count the occurrences of c in str
556f9ab90drgrimes */
557f9ab90drgrimesint
558f4859becharniercharcount(char *str, int c)
559f9ab90drgrimes{
560aa40e2emikeh	char *cp;
561aa40e2emikeh	int i;
562f9ab90drgrimes
563aa40e2emikeh	for (i = 0, cp = str; *cp != '\0'; cp++)
564f9ab90drgrimes		if (*cp == c)
565f9ab90drgrimes			i++;
566aa40e2emikeh	return (i);
567f9ab90drgrimes}
568f9ab90drgrimes
569f9ab90drgrimes/*
570f9ab90drgrimes * See if the given header field is supposed to be ignored.
571f9ab90drgrimes */
572f9ab90drgrimesint
573f4859becharnierisign(const char *field, struct ignoretab ignore[2])
574f9ab90drgrimes{
575e51e7e0mikeh	char realfld[LINESIZE];
576f9ab90drgrimes
577f9ab90drgrimes	if (ignore == ignoreall)
578aa40e2emikeh		return (1);
579f9ab90drgrimes	/*
580f9ab90drgrimes	 * Lower-case the string, so that "Status" and "status"
581f9ab90drgrimes	 * will hash to the same place.
582f9ab90drgrimes	 */
583e51e7e0mikeh	istrncpy(realfld, field, sizeof(realfld));
584f9ab90drgrimes	if (ignore[1].i_count > 0)
585f9ab90drgrimes		return (!member(realfld, ignore + 1));
586f9ab90drgrimes	else
587f9ab90drgrimes		return (member(realfld, ignore));
588f9ab90drgrimes}
589f9ab90drgrimes
590f9ab90drgrimesint
591f4859becharniermember(char *realfield, struct ignoretab *table)
592f9ab90drgrimes{
593aa40e2emikeh	struct ignore *igp;
594f9ab90drgrimes
595aa40e2emikeh	for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
596f9ab90drgrimes		if (*igp->i_field == *realfield &&
597f9ab90drgrimes		    equal(igp->i_field, realfield))
598f9ab90drgrimes			return (1);
599f9ab90drgrimes	return (0);
600f9ab90drgrimes}
601