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