1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23*0Sstevel@tonic-gate /* All Rights Reserved */
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gate
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate * Copyright 1985-2002 Sun Microsystems, Inc. All rights reserved.
28*0Sstevel@tonic-gate * Use is subject to license terms.
29*0Sstevel@tonic-gate */
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate /*
32*0Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
33*0Sstevel@tonic-gate * The Regents of the University of California
34*0Sstevel@tonic-gate * All Rights Reserved
35*0Sstevel@tonic-gate *
36*0Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
37*0Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
38*0Sstevel@tonic-gate * contributors.
39*0Sstevel@tonic-gate */
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate #include "rcv.h"
44*0Sstevel@tonic-gate #include <locale.h>
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gate /*
47*0Sstevel@tonic-gate * mailx -- a modified version of a University of California at Berkeley
48*0Sstevel@tonic-gate * mail program
49*0Sstevel@tonic-gate *
50*0Sstevel@tonic-gate * Auxiliary functions.
51*0Sstevel@tonic-gate */
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate static char *phrase(char *name, int token, int comma);
54*0Sstevel@tonic-gate static char *ripoff(register char *buf);
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate * Return a pointer to a dynamic copy of the argument.
58*0Sstevel@tonic-gate */
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate char *
savestr(char * str)61*0Sstevel@tonic-gate savestr(char *str)
62*0Sstevel@tonic-gate {
63*0Sstevel@tonic-gate register char *cp, *cp2, *top;
64*0Sstevel@tonic-gate
65*0Sstevel@tonic-gate for (cp = str; *cp; cp++)
66*0Sstevel@tonic-gate ;
67*0Sstevel@tonic-gate top = (char *)salloc((unsigned)(cp-str + 1));
68*0Sstevel@tonic-gate if (top == NOSTR)
69*0Sstevel@tonic-gate return(NOSTR);
70*0Sstevel@tonic-gate for (cp = str, cp2 = top; *cp; cp++)
71*0Sstevel@tonic-gate *cp2++ = *cp;
72*0Sstevel@tonic-gate *cp2 = 0;
73*0Sstevel@tonic-gate return(top);
74*0Sstevel@tonic-gate }
75*0Sstevel@tonic-gate
76*0Sstevel@tonic-gate /*
77*0Sstevel@tonic-gate * Announce a fatal error and die.
78*0Sstevel@tonic-gate */
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate void
panic(char * str)81*0Sstevel@tonic-gate panic(char *str)
82*0Sstevel@tonic-gate {
83*0Sstevel@tonic-gate fprintf(stderr, gettext("mailx: Panic - %s\n"), str);
84*0Sstevel@tonic-gate exit(1);
85*0Sstevel@tonic-gate /* NOTREACHED */
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate
88*0Sstevel@tonic-gate /*
89*0Sstevel@tonic-gate * Touch the named message by setting its MTOUCH flag.
90*0Sstevel@tonic-gate * Touched messages have the effect of not being sent
91*0Sstevel@tonic-gate * back to the system mailbox on exit.
92*0Sstevel@tonic-gate */
93*0Sstevel@tonic-gate
94*0Sstevel@tonic-gate void
touch(int mesg)95*0Sstevel@tonic-gate touch(int mesg)
96*0Sstevel@tonic-gate {
97*0Sstevel@tonic-gate register struct message *mp;
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate if (mesg < 1 || mesg > msgCount)
100*0Sstevel@tonic-gate return;
101*0Sstevel@tonic-gate mp = &message[mesg-1];
102*0Sstevel@tonic-gate mp->m_flag |= MTOUCH;
103*0Sstevel@tonic-gate if ((mp->m_flag & MREAD) == 0)
104*0Sstevel@tonic-gate mp->m_flag |= MREAD|MSTATUS;
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate * Test to see if the passed file name is a directory.
109*0Sstevel@tonic-gate * Return true if it is.
110*0Sstevel@tonic-gate */
111*0Sstevel@tonic-gate
112*0Sstevel@tonic-gate int
isdir(char name[])113*0Sstevel@tonic-gate isdir(char name[])
114*0Sstevel@tonic-gate {
115*0Sstevel@tonic-gate struct stat sbuf;
116*0Sstevel@tonic-gate
117*0Sstevel@tonic-gate if (stat(name, &sbuf) < 0)
118*0Sstevel@tonic-gate return(0);
119*0Sstevel@tonic-gate return((sbuf.st_mode & S_IFMT) == S_IFDIR);
120*0Sstevel@tonic-gate }
121*0Sstevel@tonic-gate
122*0Sstevel@tonic-gate /*
123*0Sstevel@tonic-gate * Count the number of arguments in the given string raw list.
124*0Sstevel@tonic-gate */
125*0Sstevel@tonic-gate
126*0Sstevel@tonic-gate int
argcount(char ** argv)127*0Sstevel@tonic-gate argcount(char **argv)
128*0Sstevel@tonic-gate {
129*0Sstevel@tonic-gate register char **ap;
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gate for (ap = argv; *ap != NOSTR; ap++)
132*0Sstevel@tonic-gate ;
133*0Sstevel@tonic-gate return(ap-argv);
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate
136*0Sstevel@tonic-gate /*
137*0Sstevel@tonic-gate * Return the desired header line from the passed message
138*0Sstevel@tonic-gate * pointer (or NOSTR if the desired header field is not available).
139*0Sstevel@tonic-gate * Read all the header lines and concatenate multiple instances of
140*0Sstevel@tonic-gate * the requested header.
141*0Sstevel@tonic-gate */
142*0Sstevel@tonic-gate
143*0Sstevel@tonic-gate char *
hfield(char field[],struct message * mp,char * (* add)(char *,char *))144*0Sstevel@tonic-gate hfield(char field[], struct message *mp, char *(*add)(char *, char *))
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate register FILE *ibuf;
147*0Sstevel@tonic-gate char linebuf[LINESIZE];
148*0Sstevel@tonic-gate register long lc;
149*0Sstevel@tonic-gate char *r = NOSTR;
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate ibuf = setinput(mp);
152*0Sstevel@tonic-gate if ((lc = mp->m_lines) <= 0)
153*0Sstevel@tonic-gate return(NOSTR);
154*0Sstevel@tonic-gate if (readline(ibuf, linebuf) < 0)
155*0Sstevel@tonic-gate return(NOSTR);
156*0Sstevel@tonic-gate lc--;
157*0Sstevel@tonic-gate while ((lc = gethfield(ibuf, linebuf, lc)) >= 0)
158*0Sstevel@tonic-gate if (ishfield(linebuf, field))
159*0Sstevel@tonic-gate r = (*add)(r, hcontents(linebuf));
160*0Sstevel@tonic-gate return r;
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate /*
164*0Sstevel@tonic-gate * Return the next header field found in the given message.
165*0Sstevel@tonic-gate * Return > 0 if something found, <= 0 elsewise.
166*0Sstevel@tonic-gate * Must deal with \ continuations & other such fraud.
167*0Sstevel@tonic-gate */
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate int
gethfield(register FILE * f,char linebuf[],register long rem)170*0Sstevel@tonic-gate gethfield(
171*0Sstevel@tonic-gate register FILE *f,
172*0Sstevel@tonic-gate char linebuf[],
173*0Sstevel@tonic-gate register long rem)
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate char line2[LINESIZE];
176*0Sstevel@tonic-gate register char *cp, *cp2;
177*0Sstevel@tonic-gate register int c;
178*0Sstevel@tonic-gate
179*0Sstevel@tonic-gate for (;;) {
180*0Sstevel@tonic-gate if (rem <= 0)
181*0Sstevel@tonic-gate return(-1);
182*0Sstevel@tonic-gate if (readline(f, linebuf) < 0)
183*0Sstevel@tonic-gate return(-1);
184*0Sstevel@tonic-gate rem--;
185*0Sstevel@tonic-gate if (strlen(linebuf) == 0)
186*0Sstevel@tonic-gate return(-1);
187*0Sstevel@tonic-gate if (isspace(linebuf[0]))
188*0Sstevel@tonic-gate continue;
189*0Sstevel@tonic-gate if (!headerp(linebuf))
190*0Sstevel@tonic-gate return(-1);
191*0Sstevel@tonic-gate
192*0Sstevel@tonic-gate /*
193*0Sstevel@tonic-gate * I guess we got a headline.
194*0Sstevel@tonic-gate * Handle wraparounding
195*0Sstevel@tonic-gate */
196*0Sstevel@tonic-gate
197*0Sstevel@tonic-gate for (;;) {
198*0Sstevel@tonic-gate if (rem <= 0)
199*0Sstevel@tonic-gate break;
200*0Sstevel@tonic-gate c = getc(f);
201*0Sstevel@tonic-gate ungetc(c, f);
202*0Sstevel@tonic-gate if (!isspace(c) || c == '\n')
203*0Sstevel@tonic-gate break;
204*0Sstevel@tonic-gate if (readline(f, line2) < 0)
205*0Sstevel@tonic-gate break;
206*0Sstevel@tonic-gate rem--;
207*0Sstevel@tonic-gate cp2 = line2;
208*0Sstevel@tonic-gate for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
209*0Sstevel@tonic-gate ;
210*0Sstevel@tonic-gate if (strlen(linebuf) + strlen(cp2) >=
211*0Sstevel@tonic-gate (unsigned)LINESIZE-2)
212*0Sstevel@tonic-gate break;
213*0Sstevel@tonic-gate cp = &linebuf[strlen(linebuf)];
214*0Sstevel@tonic-gate while (cp > linebuf &&
215*0Sstevel@tonic-gate (isspace(cp[-1]) || cp[-1] == '\\'))
216*0Sstevel@tonic-gate cp--;
217*0Sstevel@tonic-gate *cp++ = ' ';
218*0Sstevel@tonic-gate for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
219*0Sstevel@tonic-gate ;
220*0Sstevel@tonic-gate nstrcpy(cp, LINESIZE - (cp - linebuf), cp2);
221*0Sstevel@tonic-gate }
222*0Sstevel@tonic-gate if ((c = strlen(linebuf)) > 0) {
223*0Sstevel@tonic-gate cp = &linebuf[c-1];
224*0Sstevel@tonic-gate while (cp > linebuf && isspace(*cp))
225*0Sstevel@tonic-gate cp--;
226*0Sstevel@tonic-gate *++cp = 0;
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate return(rem);
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate /* NOTREACHED */
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate
233*0Sstevel@tonic-gate /*
234*0Sstevel@tonic-gate * Check whether the passed line is a header line of
235*0Sstevel@tonic-gate * the desired breed.
236*0Sstevel@tonic-gate */
237*0Sstevel@tonic-gate
238*0Sstevel@tonic-gate int
ishfield(char linebuf[],char field[])239*0Sstevel@tonic-gate ishfield(char linebuf[], char field[])
240*0Sstevel@tonic-gate {
241*0Sstevel@tonic-gate register char *cp;
242*0Sstevel@tonic-gate
243*0Sstevel@tonic-gate if ((cp = strchr(linebuf, ':')) == NOSTR)
244*0Sstevel@tonic-gate return(0);
245*0Sstevel@tonic-gate if (cp == linebuf)
246*0Sstevel@tonic-gate return(0);
247*0Sstevel@tonic-gate *cp = 0;
248*0Sstevel@tonic-gate if (icequal(linebuf, field)) {
249*0Sstevel@tonic-gate *cp = ':';
250*0Sstevel@tonic-gate return(1);
251*0Sstevel@tonic-gate }
252*0Sstevel@tonic-gate *cp = ':';
253*0Sstevel@tonic-gate return(0);
254*0Sstevel@tonic-gate }
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate /*
257*0Sstevel@tonic-gate * Extract the non label information from the given header field
258*0Sstevel@tonic-gate * and return it.
259*0Sstevel@tonic-gate */
260*0Sstevel@tonic-gate
261*0Sstevel@tonic-gate char *
hcontents(char hfield[])262*0Sstevel@tonic-gate hcontents(char hfield[])
263*0Sstevel@tonic-gate {
264*0Sstevel@tonic-gate register char *cp;
265*0Sstevel@tonic-gate
266*0Sstevel@tonic-gate if ((cp = strchr(hfield, ':')) == NOSTR)
267*0Sstevel@tonic-gate return(NOSTR);
268*0Sstevel@tonic-gate cp++;
269*0Sstevel@tonic-gate while (*cp && isspace(*cp))
270*0Sstevel@tonic-gate cp++;
271*0Sstevel@tonic-gate return(cp);
272*0Sstevel@tonic-gate }
273*0Sstevel@tonic-gate
274*0Sstevel@tonic-gate /*
275*0Sstevel@tonic-gate * Compare two strings, ignoring case.
276*0Sstevel@tonic-gate */
277*0Sstevel@tonic-gate
278*0Sstevel@tonic-gate int
icequal(register char * s1,register char * s2)279*0Sstevel@tonic-gate icequal(register char *s1, register char *s2)
280*0Sstevel@tonic-gate {
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gate while (toupper(*s1++) == toupper(*s2))
283*0Sstevel@tonic-gate if (*s2++ == 0)
284*0Sstevel@tonic-gate return(1);
285*0Sstevel@tonic-gate return(0);
286*0Sstevel@tonic-gate }
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate /*
289*0Sstevel@tonic-gate * Copy a string, lowercasing it as we go. Here dstsize is the size of
290*0Sstevel@tonic-gate * the destination buffer dst.
291*0Sstevel@tonic-gate */
292*0Sstevel@tonic-gate void
istrcpy(char * dst,int dstsize,char * src)293*0Sstevel@tonic-gate istrcpy(char *dst, int dstsize, char *src)
294*0Sstevel@tonic-gate {
295*0Sstevel@tonic-gate register char *cp, *cp2;
296*0Sstevel@tonic-gate
297*0Sstevel@tonic-gate cp2 = dst;
298*0Sstevel@tonic-gate cp = src;
299*0Sstevel@tonic-gate
300*0Sstevel@tonic-gate while (--dstsize > 0 && *cp != '\0')
301*0Sstevel@tonic-gate *cp2++ = tolower(*cp++);
302*0Sstevel@tonic-gate *cp2 = '\0';
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate
305*0Sstevel@tonic-gate /*
306*0Sstevel@tonic-gate * The following code deals with input stacking to do source
307*0Sstevel@tonic-gate * commands. All but the current file pointer are saved on
308*0Sstevel@tonic-gate * the stack.
309*0Sstevel@tonic-gate */
310*0Sstevel@tonic-gate
311*0Sstevel@tonic-gate static int ssp = -1; /* Top of file stack */
312*0Sstevel@tonic-gate static struct sstack {
313*0Sstevel@tonic-gate FILE *s_file; /* File we were in. */
314*0Sstevel@tonic-gate int s_cond; /* Saved state of conditionals */
315*0Sstevel@tonic-gate int s_loading; /* Loading .mailrc, etc. */
316*0Sstevel@tonic-gate } *sstack;
317*0Sstevel@tonic-gate
318*0Sstevel@tonic-gate /*
319*0Sstevel@tonic-gate * Pushdown current input file and switch to a new one.
320*0Sstevel@tonic-gate * Set the global flag "sourcing" so that others will realize
321*0Sstevel@tonic-gate * that they are no longer reading from a tty (in all probability).
322*0Sstevel@tonic-gate */
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate int
source(char name[])325*0Sstevel@tonic-gate source(char name[])
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate register FILE *fi;
328*0Sstevel@tonic-gate register char *cp;
329*0Sstevel@tonic-gate
330*0Sstevel@tonic-gate if ((cp = expand(name)) == NOSTR)
331*0Sstevel@tonic-gate return(1);
332*0Sstevel@tonic-gate if ((fi = fopen(cp, "r")) == NULL) {
333*0Sstevel@tonic-gate printf(gettext("Unable to open %s\n"), cp);
334*0Sstevel@tonic-gate return(1);
335*0Sstevel@tonic-gate }
336*0Sstevel@tonic-gate
337*0Sstevel@tonic-gate if (!maxfiles) {
338*0Sstevel@tonic-gate if ((maxfiles = (int)ulimit(4, 0)) < 0)
339*0Sstevel@tonic-gate #ifndef _NFILE
340*0Sstevel@tonic-gate # define _NFILE 20
341*0Sstevel@tonic-gate #endif
342*0Sstevel@tonic-gate maxfiles = _NFILE;
343*0Sstevel@tonic-gate sstack = (struct sstack *)calloc(maxfiles, sizeof(struct sstack));
344*0Sstevel@tonic-gate if (sstack == NULL) {
345*0Sstevel@tonic-gate printf(gettext(
346*0Sstevel@tonic-gate "Couldn't allocate memory for sourcing stack\n"));
347*0Sstevel@tonic-gate fclose(fi);
348*0Sstevel@tonic-gate return(1);
349*0Sstevel@tonic-gate }
350*0Sstevel@tonic-gate }
351*0Sstevel@tonic-gate
352*0Sstevel@tonic-gate sstack[++ssp].s_file = input;
353*0Sstevel@tonic-gate sstack[ssp].s_cond = cond;
354*0Sstevel@tonic-gate sstack[ssp].s_loading = loading;
355*0Sstevel@tonic-gate loading = 0;
356*0Sstevel@tonic-gate cond = CANY;
357*0Sstevel@tonic-gate input = fi;
358*0Sstevel@tonic-gate sourcing++;
359*0Sstevel@tonic-gate return(0);
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate /*
363*0Sstevel@tonic-gate * Pop the current input back to the previous level.
364*0Sstevel@tonic-gate * Update the "sourcing" flag as appropriate.
365*0Sstevel@tonic-gate */
366*0Sstevel@tonic-gate
367*0Sstevel@tonic-gate int
unstack(void)368*0Sstevel@tonic-gate unstack(void)
369*0Sstevel@tonic-gate {
370*0Sstevel@tonic-gate if (ssp < 0) {
371*0Sstevel@tonic-gate printf(gettext("\"Source\" stack over-pop.\n"));
372*0Sstevel@tonic-gate sourcing = 0;
373*0Sstevel@tonic-gate return(1);
374*0Sstevel@tonic-gate }
375*0Sstevel@tonic-gate fclose(input);
376*0Sstevel@tonic-gate if (cond != CANY)
377*0Sstevel@tonic-gate printf(gettext("Unmatched \"if\"\n"));
378*0Sstevel@tonic-gate cond = sstack[ssp].s_cond;
379*0Sstevel@tonic-gate loading = sstack[ssp].s_loading;
380*0Sstevel@tonic-gate input = sstack[ssp--].s_file;
381*0Sstevel@tonic-gate if (ssp < 0)
382*0Sstevel@tonic-gate sourcing = loading;
383*0Sstevel@tonic-gate return(0);
384*0Sstevel@tonic-gate }
385*0Sstevel@tonic-gate
386*0Sstevel@tonic-gate /*
387*0Sstevel@tonic-gate * Touch the indicated file.
388*0Sstevel@tonic-gate * This is nifty for the shell.
389*0Sstevel@tonic-gate * If we have the utime() system call, this is better served
390*0Sstevel@tonic-gate * by using that, since it will work for empty files.
391*0Sstevel@tonic-gate * On non-utime systems, we must sleep a second, then read.
392*0Sstevel@tonic-gate */
393*0Sstevel@tonic-gate
394*0Sstevel@tonic-gate void
alter(char name[])395*0Sstevel@tonic-gate alter(char name[])
396*0Sstevel@tonic-gate {
397*0Sstevel@tonic-gate int rc = utime(name, utimep);
398*0Sstevel@tonic-gate extern int errno;
399*0Sstevel@tonic-gate
400*0Sstevel@tonic-gate if (rc != 0) {
401*0Sstevel@tonic-gate fprintf(stderr, gettext("Cannot utime %s in aux:alter\n"),
402*0Sstevel@tonic-gate name);
403*0Sstevel@tonic-gate fprintf(stderr, gettext("Errno: %d\n"), errno);
404*0Sstevel@tonic-gate }
405*0Sstevel@tonic-gate }
406*0Sstevel@tonic-gate
407*0Sstevel@tonic-gate /*
408*0Sstevel@tonic-gate * Examine the passed line buffer and
409*0Sstevel@tonic-gate * return true if it is all blanks and tabs.
410*0Sstevel@tonic-gate */
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gate int
blankline(const char linebuf[])413*0Sstevel@tonic-gate blankline(const char linebuf[])
414*0Sstevel@tonic-gate {
415*0Sstevel@tonic-gate register const char *cp;
416*0Sstevel@tonic-gate
417*0Sstevel@tonic-gate for (cp = linebuf; *cp; cp++)
418*0Sstevel@tonic-gate if (!any(*cp, " \t"))
419*0Sstevel@tonic-gate return(0);
420*0Sstevel@tonic-gate return(1);
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate
423*0Sstevel@tonic-gate /*
424*0Sstevel@tonic-gate * Skin an arpa net address according to the RFC 822 interpretation
425*0Sstevel@tonic-gate * of "host-phrase."
426*0Sstevel@tonic-gate */
427*0Sstevel@tonic-gate static char *
phrase(char * name,int token,int comma)428*0Sstevel@tonic-gate phrase(char *name, int token, int comma)
429*0Sstevel@tonic-gate {
430*0Sstevel@tonic-gate register char c;
431*0Sstevel@tonic-gate register char *cp, *cp2;
432*0Sstevel@tonic-gate char *bufend, *nbufp;
433*0Sstevel@tonic-gate int gotlt, lastsp, didq;
434*0Sstevel@tonic-gate char nbuf[LINESIZE];
435*0Sstevel@tonic-gate int nesting;
436*0Sstevel@tonic-gate
437*0Sstevel@tonic-gate if (name == NOSTR)
438*0Sstevel@tonic-gate return(NOSTR);
439*0Sstevel@tonic-gate if (strlen(name) >= (unsigned)LINESIZE)
440*0Sstevel@tonic-gate nbufp = (char *)salloc(strlen(name));
441*0Sstevel@tonic-gate else
442*0Sstevel@tonic-gate nbufp = nbuf;
443*0Sstevel@tonic-gate gotlt = 0;
444*0Sstevel@tonic-gate lastsp = 0;
445*0Sstevel@tonic-gate bufend = nbufp;
446*0Sstevel@tonic-gate for (cp = name, cp2 = bufend; (c = *cp++) != 0;) {
447*0Sstevel@tonic-gate switch (c) {
448*0Sstevel@tonic-gate case '(':
449*0Sstevel@tonic-gate /*
450*0Sstevel@tonic-gate Start of a comment, ignore it.
451*0Sstevel@tonic-gate */
452*0Sstevel@tonic-gate nesting = 1;
453*0Sstevel@tonic-gate while ((c = *cp) != 0) {
454*0Sstevel@tonic-gate cp++;
455*0Sstevel@tonic-gate switch(c) {
456*0Sstevel@tonic-gate case '\\':
457*0Sstevel@tonic-gate if (*cp == 0) goto outcm;
458*0Sstevel@tonic-gate cp++;
459*0Sstevel@tonic-gate break;
460*0Sstevel@tonic-gate case '(':
461*0Sstevel@tonic-gate nesting++;
462*0Sstevel@tonic-gate break;
463*0Sstevel@tonic-gate case ')':
464*0Sstevel@tonic-gate --nesting;
465*0Sstevel@tonic-gate break;
466*0Sstevel@tonic-gate }
467*0Sstevel@tonic-gate if (nesting <= 0) break;
468*0Sstevel@tonic-gate }
469*0Sstevel@tonic-gate outcm:
470*0Sstevel@tonic-gate lastsp = 0;
471*0Sstevel@tonic-gate break;
472*0Sstevel@tonic-gate case '"':
473*0Sstevel@tonic-gate /*
474*0Sstevel@tonic-gate Start a quoted string.
475*0Sstevel@tonic-gate Copy it in its entirety.
476*0Sstevel@tonic-gate */
477*0Sstevel@tonic-gate didq = 0;
478*0Sstevel@tonic-gate while ((c = *cp) != 0) {
479*0Sstevel@tonic-gate cp++;
480*0Sstevel@tonic-gate switch (c) {
481*0Sstevel@tonic-gate case '\\':
482*0Sstevel@tonic-gate if ((c = *cp) == 0) goto outqs;
483*0Sstevel@tonic-gate cp++;
484*0Sstevel@tonic-gate break;
485*0Sstevel@tonic-gate case '"':
486*0Sstevel@tonic-gate goto outqs;
487*0Sstevel@tonic-gate }
488*0Sstevel@tonic-gate if (gotlt == 0 || gotlt == '<') {
489*0Sstevel@tonic-gate if (lastsp) {
490*0Sstevel@tonic-gate lastsp = 0;
491*0Sstevel@tonic-gate *cp2++ = ' ';
492*0Sstevel@tonic-gate }
493*0Sstevel@tonic-gate if (!didq) {
494*0Sstevel@tonic-gate *cp2++ = '"';
495*0Sstevel@tonic-gate didq++;
496*0Sstevel@tonic-gate }
497*0Sstevel@tonic-gate *cp2++ = c;
498*0Sstevel@tonic-gate }
499*0Sstevel@tonic-gate }
500*0Sstevel@tonic-gate outqs:
501*0Sstevel@tonic-gate if (didq)
502*0Sstevel@tonic-gate *cp2++ = '"';
503*0Sstevel@tonic-gate lastsp = 0;
504*0Sstevel@tonic-gate break;
505*0Sstevel@tonic-gate
506*0Sstevel@tonic-gate case ' ':
507*0Sstevel@tonic-gate case '\t':
508*0Sstevel@tonic-gate case '\n':
509*0Sstevel@tonic-gate if (token && (!comma || c == '\n')) {
510*0Sstevel@tonic-gate done:
511*0Sstevel@tonic-gate cp[-1] = 0;
512*0Sstevel@tonic-gate return cp;
513*0Sstevel@tonic-gate }
514*0Sstevel@tonic-gate lastsp = 1;
515*0Sstevel@tonic-gate break;
516*0Sstevel@tonic-gate
517*0Sstevel@tonic-gate case ',':
518*0Sstevel@tonic-gate *cp2++ = c;
519*0Sstevel@tonic-gate if (gotlt != '<') {
520*0Sstevel@tonic-gate if (token)
521*0Sstevel@tonic-gate goto done;
522*0Sstevel@tonic-gate bufend = cp2;
523*0Sstevel@tonic-gate gotlt = 0;
524*0Sstevel@tonic-gate }
525*0Sstevel@tonic-gate break;
526*0Sstevel@tonic-gate
527*0Sstevel@tonic-gate case '<':
528*0Sstevel@tonic-gate cp2 = bufend;
529*0Sstevel@tonic-gate gotlt = c;
530*0Sstevel@tonic-gate lastsp = 0;
531*0Sstevel@tonic-gate break;
532*0Sstevel@tonic-gate
533*0Sstevel@tonic-gate case '>':
534*0Sstevel@tonic-gate if (gotlt == '<') {
535*0Sstevel@tonic-gate gotlt = c;
536*0Sstevel@tonic-gate break;
537*0Sstevel@tonic-gate }
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate /* FALLTHROUGH . . . */
540*0Sstevel@tonic-gate
541*0Sstevel@tonic-gate default:
542*0Sstevel@tonic-gate if (gotlt == 0 || gotlt == '<') {
543*0Sstevel@tonic-gate if (lastsp) {
544*0Sstevel@tonic-gate lastsp = 0;
545*0Sstevel@tonic-gate *cp2++ = ' ';
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate *cp2++ = c;
548*0Sstevel@tonic-gate }
549*0Sstevel@tonic-gate break;
550*0Sstevel@tonic-gate }
551*0Sstevel@tonic-gate }
552*0Sstevel@tonic-gate *cp2 = 0;
553*0Sstevel@tonic-gate return (token ? --cp : equal(name, nbufp) ? name :
554*0Sstevel@tonic-gate nbufp == nbuf ? savestr(nbuf) : nbufp);
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate
557*0Sstevel@tonic-gate char *
skin(char * name)558*0Sstevel@tonic-gate skin(char *name)
559*0Sstevel@tonic-gate {
560*0Sstevel@tonic-gate return phrase(name, 0, 0);
561*0Sstevel@tonic-gate }
562*0Sstevel@tonic-gate
563*0Sstevel@tonic-gate /*
564*0Sstevel@tonic-gate * Here sz is the buffer size of word.
565*0Sstevel@tonic-gate */
566*0Sstevel@tonic-gate char *
yankword(char * name,char * word,int sz,int comma)567*0Sstevel@tonic-gate yankword(char *name, char *word, int sz, int comma)
568*0Sstevel@tonic-gate {
569*0Sstevel@tonic-gate char *cp;
570*0Sstevel@tonic-gate
571*0Sstevel@tonic-gate if (name == 0)
572*0Sstevel@tonic-gate return 0;
573*0Sstevel@tonic-gate while (isspace(*name))
574*0Sstevel@tonic-gate name++;
575*0Sstevel@tonic-gate if (*name == 0)
576*0Sstevel@tonic-gate return 0;
577*0Sstevel@tonic-gate cp = phrase(name, 1, comma);
578*0Sstevel@tonic-gate nstrcpy(word, sz, name);
579*0Sstevel@tonic-gate return cp;
580*0Sstevel@tonic-gate }
581*0Sstevel@tonic-gate
582*0Sstevel@tonic-gate int
docomma(char * s)583*0Sstevel@tonic-gate docomma(char *s)
584*0Sstevel@tonic-gate {
585*0Sstevel@tonic-gate return s && strpbrk(s, "(<,");
586*0Sstevel@tonic-gate }
587*0Sstevel@tonic-gate
588*0Sstevel@tonic-gate /*
589*0Sstevel@tonic-gate * Fetch the sender's name from the passed message.
590*0Sstevel@tonic-gate */
591*0Sstevel@tonic-gate
592*0Sstevel@tonic-gate char *
nameof(register struct message * mp)593*0Sstevel@tonic-gate nameof(register struct message *mp)
594*0Sstevel@tonic-gate {
595*0Sstevel@tonic-gate char namebuf[LINESIZE];
596*0Sstevel@tonic-gate char linebuf[LINESIZE];
597*0Sstevel@tonic-gate register char *cp, *cp2;
598*0Sstevel@tonic-gate register FILE *ibuf;
599*0Sstevel@tonic-gate int first = 1, wint = 0;
600*0Sstevel@tonic-gate char *tmp;
601*0Sstevel@tonic-gate
602*0Sstevel@tonic-gate if (value("from") && (cp = hfield("from", mp, addto)) != NOSTR)
603*0Sstevel@tonic-gate return ripoff(cp);
604*0Sstevel@tonic-gate ibuf = setinput(mp);
605*0Sstevel@tonic-gate copy("", namebuf);
606*0Sstevel@tonic-gate if (readline(ibuf, linebuf) <= 0)
607*0Sstevel@tonic-gate return(savestr(namebuf));
608*0Sstevel@tonic-gate newname:
609*0Sstevel@tonic-gate for (cp = linebuf; *cp != ' '; cp++)
610*0Sstevel@tonic-gate ;
611*0Sstevel@tonic-gate while (any(*cp, " \t"))
612*0Sstevel@tonic-gate cp++;
613*0Sstevel@tonic-gate for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
614*0Sstevel@tonic-gate cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
615*0Sstevel@tonic-gate ;
616*0Sstevel@tonic-gate *cp2 = '\0';
617*0Sstevel@tonic-gate for (;;) {
618*0Sstevel@tonic-gate if (readline(ibuf, linebuf) <= 0)
619*0Sstevel@tonic-gate break;
620*0Sstevel@tonic-gate if (substr(linebuf,"forwarded by ") != -1)
621*0Sstevel@tonic-gate continue;
622*0Sstevel@tonic-gate if (linebuf[0] == 'F')
623*0Sstevel@tonic-gate cp = linebuf;
624*0Sstevel@tonic-gate else if (linebuf[0] == '>')
625*0Sstevel@tonic-gate cp = linebuf + 1;
626*0Sstevel@tonic-gate else
627*0Sstevel@tonic-gate break;
628*0Sstevel@tonic-gate if (strncmp(cp, "From ", 5) != 0)
629*0Sstevel@tonic-gate break;
630*0Sstevel@tonic-gate if ((wint = substr(cp, "remote from ")) != -1) {
631*0Sstevel@tonic-gate cp += wint + 12;
632*0Sstevel@tonic-gate if (first) {
633*0Sstevel@tonic-gate copy(cp, namebuf);
634*0Sstevel@tonic-gate first = 0;
635*0Sstevel@tonic-gate } else {
636*0Sstevel@tonic-gate tmp = strrchr(namebuf, '!') + 1;
637*0Sstevel@tonic-gate nstrcpy(tmp,
638*0Sstevel@tonic-gate sizeof (namebuf) - (tmp - namebuf),
639*0Sstevel@tonic-gate cp);
640*0Sstevel@tonic-gate }
641*0Sstevel@tonic-gate nstrcat(namebuf, sizeof (namebuf), "!");
642*0Sstevel@tonic-gate goto newname;
643*0Sstevel@tonic-gate } else
644*0Sstevel@tonic-gate break;
645*0Sstevel@tonic-gate }
646*0Sstevel@tonic-gate for (cp = namebuf; *cp == '!'; cp++);
647*0Sstevel@tonic-gate while (ishost(host, cp))
648*0Sstevel@tonic-gate cp = strchr(cp, '!') + 1;
649*0Sstevel@tonic-gate if (value("mustbang") && !strchr(cp, '!')) {
650*0Sstevel@tonic-gate snprintf(linebuf, sizeof (linebuf), "%s!%s",
651*0Sstevel@tonic-gate host, cp);
652*0Sstevel@tonic-gate cp = linebuf;
653*0Sstevel@tonic-gate }
654*0Sstevel@tonic-gate if (cp2 = hfield("from", mp, addto))
655*0Sstevel@tonic-gate return(splice(cp, cp2));
656*0Sstevel@tonic-gate else
657*0Sstevel@tonic-gate return(savestr(cp));
658*0Sstevel@tonic-gate }
659*0Sstevel@tonic-gate
660*0Sstevel@tonic-gate /*
661*0Sstevel@tonic-gate * Splice an address into a commented recipient header.
662*0Sstevel@tonic-gate */
663*0Sstevel@tonic-gate char *
splice(char * addr,char * hdr)664*0Sstevel@tonic-gate splice(char *addr, char *hdr)
665*0Sstevel@tonic-gate {
666*0Sstevel@tonic-gate char buf[LINESIZE];
667*0Sstevel@tonic-gate char *cp, *cp2;
668*0Sstevel@tonic-gate
669*0Sstevel@tonic-gate if (cp = strchr(hdr, '<')) {
670*0Sstevel@tonic-gate cp2 = strchr(cp, '>');
671*0Sstevel@tonic-gate if (cp2 == NULL) {
672*0Sstevel@tonic-gate nstrcpy(buf, sizeof (buf), addr);
673*0Sstevel@tonic-gate } else {
674*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), "%.*s%s%s",
675*0Sstevel@tonic-gate cp - hdr + 1, hdr, addr, cp2);
676*0Sstevel@tonic-gate }
677*0Sstevel@tonic-gate } else if (cp = strchr(hdr, '(')) {
678*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), "%s %s",
679*0Sstevel@tonic-gate addr, cp);
680*0Sstevel@tonic-gate } else
681*0Sstevel@tonic-gate nstrcpy(buf, sizeof (buf), addr);
682*0Sstevel@tonic-gate return savestr(ripoff(buf));
683*0Sstevel@tonic-gate }
684*0Sstevel@tonic-gate
685*0Sstevel@tonic-gate static char *
ripoff(register char * buf)686*0Sstevel@tonic-gate ripoff(register char *buf)
687*0Sstevel@tonic-gate {
688*0Sstevel@tonic-gate register char *cp;
689*0Sstevel@tonic-gate
690*0Sstevel@tonic-gate cp = buf + strlen(buf);
691*0Sstevel@tonic-gate while (--cp >= buf && isspace(*cp));
692*0Sstevel@tonic-gate if (cp >= buf && *cp == ',')
693*0Sstevel@tonic-gate cp--;
694*0Sstevel@tonic-gate *++cp = 0;
695*0Sstevel@tonic-gate return buf;
696*0Sstevel@tonic-gate }
697*0Sstevel@tonic-gate
698*0Sstevel@tonic-gate /*
699*0Sstevel@tonic-gate * Are any of the characters in the two strings the same?
700*0Sstevel@tonic-gate */
701*0Sstevel@tonic-gate
702*0Sstevel@tonic-gate int
anyof(register char * s1,register char * s2)703*0Sstevel@tonic-gate anyof(register char *s1, register char *s2)
704*0Sstevel@tonic-gate {
705*0Sstevel@tonic-gate register int c;
706*0Sstevel@tonic-gate
707*0Sstevel@tonic-gate while ((c = *s1++) != 0)
708*0Sstevel@tonic-gate if (any(c, s2))
709*0Sstevel@tonic-gate return(1);
710*0Sstevel@tonic-gate return(0);
711*0Sstevel@tonic-gate }
712*0Sstevel@tonic-gate
713*0Sstevel@tonic-gate /*
714*0Sstevel@tonic-gate * See if the given header field is supposed to be ignored.
715*0Sstevel@tonic-gate * Fields of the form "Content-*" can't be ignored when saving.
716*0Sstevel@tonic-gate */
717*0Sstevel@tonic-gate int
isign(char * field,int saving)718*0Sstevel@tonic-gate isign(char *field, int saving)
719*0Sstevel@tonic-gate {
720*0Sstevel@tonic-gate char realfld[BUFSIZ];
721*0Sstevel@tonic-gate
722*0Sstevel@tonic-gate /*
723*0Sstevel@tonic-gate * Lower-case the string, so that "Status" and "status"
724*0Sstevel@tonic-gate * will hash to the same place.
725*0Sstevel@tonic-gate */
726*0Sstevel@tonic-gate istrcpy(realfld, sizeof (realfld), field);
727*0Sstevel@tonic-gate
728*0Sstevel@tonic-gate if (saving && strncmp(realfld, "content-", 8) == 0)
729*0Sstevel@tonic-gate return (0);
730*0Sstevel@tonic-gate
731*0Sstevel@tonic-gate if (nretained > 0)
732*0Sstevel@tonic-gate return (!member(realfld, retain));
733*0Sstevel@tonic-gate else
734*0Sstevel@tonic-gate return (member(realfld, ignore));
735*0Sstevel@tonic-gate }
736*0Sstevel@tonic-gate
737*0Sstevel@tonic-gate int
member(register char * realfield,register struct ignore ** table)738*0Sstevel@tonic-gate member(register char *realfield, register struct ignore **table)
739*0Sstevel@tonic-gate {
740*0Sstevel@tonic-gate register struct ignore *igp;
741*0Sstevel@tonic-gate
742*0Sstevel@tonic-gate for (igp = table[hash(realfield)]; igp != 0; igp = igp->i_link)
743*0Sstevel@tonic-gate if (equal(igp->i_field, realfield))
744*0Sstevel@tonic-gate return (1);
745*0Sstevel@tonic-gate
746*0Sstevel@tonic-gate return (0);
747*0Sstevel@tonic-gate }
748*0Sstevel@tonic-gate
749*0Sstevel@tonic-gate /*
750*0Sstevel@tonic-gate * This routine looks for string2 in string1.
751*0Sstevel@tonic-gate * If found, it returns the position string2 is found at,
752*0Sstevel@tonic-gate * otherwise it returns a -1.
753*0Sstevel@tonic-gate */
754*0Sstevel@tonic-gate int
substr(char * string1,char * string2)755*0Sstevel@tonic-gate substr(char *string1, char *string2)
756*0Sstevel@tonic-gate {
757*0Sstevel@tonic-gate int i, j, len1, len2;
758*0Sstevel@tonic-gate
759*0Sstevel@tonic-gate len1 = strlen(string1);
760*0Sstevel@tonic-gate len2 = strlen(string2);
761*0Sstevel@tonic-gate for (i = 0; i < len1 - len2 + 1; i++) {
762*0Sstevel@tonic-gate for (j = 0; j < len2 && string1[i+j] == string2[j]; j++)
763*0Sstevel@tonic-gate ;
764*0Sstevel@tonic-gate if (j == len2)
765*0Sstevel@tonic-gate return(i);
766*0Sstevel@tonic-gate }
767*0Sstevel@tonic-gate return(-1);
768*0Sstevel@tonic-gate }
769*0Sstevel@tonic-gate
770*0Sstevel@tonic-gate /*
771*0Sstevel@tonic-gate * Copies src to the dstsize buffer at dst. The copy will never
772*0Sstevel@tonic-gate * overflow the destination buffer and the buffer will always be null
773*0Sstevel@tonic-gate * terminated.
774*0Sstevel@tonic-gate */
775*0Sstevel@tonic-gate char *
nstrcpy(char * dst,int dstsize,char * src)776*0Sstevel@tonic-gate nstrcpy(char *dst, int dstsize, char *src)
777*0Sstevel@tonic-gate {
778*0Sstevel@tonic-gate char *cp, *cp2;
779*0Sstevel@tonic-gate
780*0Sstevel@tonic-gate cp2 = dst;
781*0Sstevel@tonic-gate cp = src;
782*0Sstevel@tonic-gate
783*0Sstevel@tonic-gate while (--dstsize > 0 && *cp != '\0')
784*0Sstevel@tonic-gate *cp2++ = *cp++;
785*0Sstevel@tonic-gate *cp2 = '\0';
786*0Sstevel@tonic-gate return(dst);
787*0Sstevel@tonic-gate }
788*0Sstevel@tonic-gate
789*0Sstevel@tonic-gate /*
790*0Sstevel@tonic-gate * Appends src to the dstsize buffer at dst. The append will never
791*0Sstevel@tonic-gate * overflow the destination buffer and the buffer will always be null
792*0Sstevel@tonic-gate * terminated.
793*0Sstevel@tonic-gate */
794*0Sstevel@tonic-gate char *
nstrcat(char * dst,int dstsize,char * src)795*0Sstevel@tonic-gate nstrcat(char *dst, int dstsize, char *src)
796*0Sstevel@tonic-gate {
797*0Sstevel@tonic-gate char *cp, *cp2;
798*0Sstevel@tonic-gate
799*0Sstevel@tonic-gate cp2 = dst;
800*0Sstevel@tonic-gate cp = src;
801*0Sstevel@tonic-gate
802*0Sstevel@tonic-gate while (*cp2 != '\0') {
803*0Sstevel@tonic-gate cp2++;
804*0Sstevel@tonic-gate dstsize--;
805*0Sstevel@tonic-gate }
806*0Sstevel@tonic-gate while (--dstsize > 0 && *cp != '\0')
807*0Sstevel@tonic-gate *cp2++ = *cp++;
808*0Sstevel@tonic-gate *cp2 = '\0';
809*0Sstevel@tonic-gate return(dst);
810*0Sstevel@tonic-gate }
811