xref: /titanic_53/usr/src/cmd/mailx/names.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1985-2001 by Sun Microsystems, Inc.
28*7c478bd9Sstevel@tonic-gate  * All rights reserved.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /*
32*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
33*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
34*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
37*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
38*7c478bd9Sstevel@tonic-gate  * contributors.
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate /*
44*7c478bd9Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
45*7c478bd9Sstevel@tonic-gate  *	mail program
46*7c478bd9Sstevel@tonic-gate  *
47*7c478bd9Sstevel@tonic-gate  * Handle name lists.
48*7c478bd9Sstevel@tonic-gate  */
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #include "rcv.h"
51*7c478bd9Sstevel@tonic-gate #include <locale.h>
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate static struct name	*nalloc(char str[]);
54*7c478bd9Sstevel@tonic-gate static int		isfileaddr(char *name);
55*7c478bd9Sstevel@tonic-gate static int		lengthof(struct name *name);
56*7c478bd9Sstevel@tonic-gate static struct name	*gexpand(struct name *nlist, struct grouphead *gh, int metoo, int arg_ntype);
57*7c478bd9Sstevel@tonic-gate static char		*norm(register char *user, register char *ubuf, int nbangs);
58*7c478bd9Sstevel@tonic-gate static struct name	*put(struct name *list, struct name *node);
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  * Allocate a single element of a name list,
62*7c478bd9Sstevel@tonic-gate  * initialize its name field to the passed
63*7c478bd9Sstevel@tonic-gate  * name and return it.
64*7c478bd9Sstevel@tonic-gate  */
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate static struct name *
67*7c478bd9Sstevel@tonic-gate nalloc(char str[])
68*7c478bd9Sstevel@tonic-gate {
69*7c478bd9Sstevel@tonic-gate 	register struct name *np;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	np = (struct name *) salloc(sizeof *np);
72*7c478bd9Sstevel@tonic-gate 	np->n_flink = NIL;
73*7c478bd9Sstevel@tonic-gate 	np->n_blink = NIL;
74*7c478bd9Sstevel@tonic-gate 	np->n_type = -1;
75*7c478bd9Sstevel@tonic-gate 	np->n_full = savestr(str);
76*7c478bd9Sstevel@tonic-gate 	np->n_name = skin(np->n_full);
77*7c478bd9Sstevel@tonic-gate 	return(np);
78*7c478bd9Sstevel@tonic-gate }
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /*
81*7c478bd9Sstevel@tonic-gate  * Find the tail of a list and return it.
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate struct name *
85*7c478bd9Sstevel@tonic-gate tailof(struct name *name)
86*7c478bd9Sstevel@tonic-gate {
87*7c478bd9Sstevel@tonic-gate 	register struct name *np;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	np = name;
90*7c478bd9Sstevel@tonic-gate 	if (np == NIL)
91*7c478bd9Sstevel@tonic-gate 		return(NIL);
92*7c478bd9Sstevel@tonic-gate 	while (np->n_flink != NIL)
93*7c478bd9Sstevel@tonic-gate 		np = np->n_flink;
94*7c478bd9Sstevel@tonic-gate 	return(np);
95*7c478bd9Sstevel@tonic-gate }
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /*
98*7c478bd9Sstevel@tonic-gate  * Extract a list of names from a line,
99*7c478bd9Sstevel@tonic-gate  * and make a list of names from it.
100*7c478bd9Sstevel@tonic-gate  * Return the list or NIL if none found.
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate struct name *
104*7c478bd9Sstevel@tonic-gate extract(char line[], int arg_ntype)
105*7c478bd9Sstevel@tonic-gate {
106*7c478bd9Sstevel@tonic-gate 	short ntype = (short)arg_ntype;
107*7c478bd9Sstevel@tonic-gate 	register char *cp;
108*7c478bd9Sstevel@tonic-gate 	register struct name *top, *np, *t;
109*7c478bd9Sstevel@tonic-gate 	char nbuf[BUFSIZ], abuf[BUFSIZ];
110*7c478bd9Sstevel@tonic-gate 	int comma;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	if (line == NOSTR || strlen(line) == 0)
113*7c478bd9Sstevel@tonic-gate 		return(NIL);
114*7c478bd9Sstevel@tonic-gate 	comma = docomma(line);
115*7c478bd9Sstevel@tonic-gate 	top = NIL;
116*7c478bd9Sstevel@tonic-gate 	np = NIL;
117*7c478bd9Sstevel@tonic-gate 	cp = line;
118*7c478bd9Sstevel@tonic-gate 	while ((cp = yankword(cp, nbuf, sizeof (nbuf), comma)) != NOSTR) {
119*7c478bd9Sstevel@tonic-gate 		if (np != NIL && equal(nbuf, "at")) {
120*7c478bd9Sstevel@tonic-gate 			nstrcpy(abuf, sizeof (abuf), nbuf);
121*7c478bd9Sstevel@tonic-gate 			if ((cp = yankword(cp, nbuf, sizeof (nbuf),
122*7c478bd9Sstevel@tonic-gate 				comma)) == NOSTR) {
123*7c478bd9Sstevel@tonic-gate 				nstrcpy(nbuf, sizeof (nbuf), abuf);
124*7c478bd9Sstevel@tonic-gate 				goto normal;
125*7c478bd9Sstevel@tonic-gate 			}
126*7c478bd9Sstevel@tonic-gate 			snprintf(abuf, sizeof (abuf), "%s@%s", np->n_name,
127*7c478bd9Sstevel@tonic-gate 				nbuf);
128*7c478bd9Sstevel@tonic-gate 			np->n_name = savestr(abuf);
129*7c478bd9Sstevel@tonic-gate 			continue;
130*7c478bd9Sstevel@tonic-gate 		}
131*7c478bd9Sstevel@tonic-gate normal:
132*7c478bd9Sstevel@tonic-gate 		t = nalloc(nbuf);
133*7c478bd9Sstevel@tonic-gate 		t->n_type = ntype;
134*7c478bd9Sstevel@tonic-gate 		if (top == NIL)
135*7c478bd9Sstevel@tonic-gate 			top = t;
136*7c478bd9Sstevel@tonic-gate 		else
137*7c478bd9Sstevel@tonic-gate 			np->n_flink = t;
138*7c478bd9Sstevel@tonic-gate 		t->n_blink = np;
139*7c478bd9Sstevel@tonic-gate 		np = t;
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 	return(top);
142*7c478bd9Sstevel@tonic-gate }
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate /*
145*7c478bd9Sstevel@tonic-gate  * Turn a list of names into a string of the same names.
146*7c478bd9Sstevel@tonic-gate  */
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate char *
149*7c478bd9Sstevel@tonic-gate detract(register struct name *np, int ntype)
150*7c478bd9Sstevel@tonic-gate {
151*7c478bd9Sstevel@tonic-gate 	register int s;
152*7c478bd9Sstevel@tonic-gate 	register char *cp, *top;
153*7c478bd9Sstevel@tonic-gate 	register struct name *p;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	if (np == NIL)
156*7c478bd9Sstevel@tonic-gate 		return(NOSTR);
157*7c478bd9Sstevel@tonic-gate 	s = 0;
158*7c478bd9Sstevel@tonic-gate 	for (p = np; p != NIL; p = p->n_flink) {
159*7c478bd9Sstevel@tonic-gate 		if ((ntype && (p->n_type & GMASK) != ntype)
160*7c478bd9Sstevel@tonic-gate 		 || (p->n_type & GDEL))
161*7c478bd9Sstevel@tonic-gate 			continue;
162*7c478bd9Sstevel@tonic-gate 		s += strlen(p->n_full) + 2;
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 	if (s == 0)
165*7c478bd9Sstevel@tonic-gate 		return(NOSTR);
166*7c478bd9Sstevel@tonic-gate 	top = (char *)salloc((unsigned)(++s));
167*7c478bd9Sstevel@tonic-gate 	cp = top;
168*7c478bd9Sstevel@tonic-gate 	for (p = np; p != NIL; p = p->n_flink) {
169*7c478bd9Sstevel@tonic-gate 		if ((ntype && (p->n_type & GMASK) != ntype)
170*7c478bd9Sstevel@tonic-gate 		 || (p->n_type & GDEL))
171*7c478bd9Sstevel@tonic-gate 			continue;
172*7c478bd9Sstevel@tonic-gate 		cp = copy(p->n_full, cp);
173*7c478bd9Sstevel@tonic-gate 		*cp++ = ',';
174*7c478bd9Sstevel@tonic-gate 		*cp++ = ' ';
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 	*cp = 0;
177*7c478bd9Sstevel@tonic-gate 	return(top);
178*7c478bd9Sstevel@tonic-gate }
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate struct name *
181*7c478bd9Sstevel@tonic-gate outpre(struct name *to)
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate 	register struct name *np;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	for (np = to; np; np = np->n_flink)
186*7c478bd9Sstevel@tonic-gate 		if (isfileaddr(np->n_name))
187*7c478bd9Sstevel@tonic-gate 			np->n_type |= GDEL;
188*7c478bd9Sstevel@tonic-gate 	return to;
189*7c478bd9Sstevel@tonic-gate }
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /*
192*7c478bd9Sstevel@tonic-gate  * For each recipient in the passed name list with a /
193*7c478bd9Sstevel@tonic-gate  * in the name, append the message to the end of the named file
194*7c478bd9Sstevel@tonic-gate  * and remove him from the recipient list.
195*7c478bd9Sstevel@tonic-gate  *
196*7c478bd9Sstevel@tonic-gate  * Recipients whose name begins with | are piped through the given
197*7c478bd9Sstevel@tonic-gate  * program and removed.
198*7c478bd9Sstevel@tonic-gate  */
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate int
201*7c478bd9Sstevel@tonic-gate outof(struct name *names, FILE *fo)
202*7c478bd9Sstevel@tonic-gate {
203*7c478bd9Sstevel@tonic-gate 	register int c;
204*7c478bd9Sstevel@tonic-gate 	register struct name *np;
205*7c478bd9Sstevel@tonic-gate 	time_t now;
206*7c478bd9Sstevel@tonic-gate 	char *date, *fname, *shell;
207*7c478bd9Sstevel@tonic-gate 	FILE *fout, *fin;
208*7c478bd9Sstevel@tonic-gate 	int ispipe;
209*7c478bd9Sstevel@tonic-gate 	int nout = 0;
210*7c478bd9Sstevel@tonic-gate 	int fd = 0;
211*7c478bd9Sstevel@tonic-gate #ifdef preSVr4
212*7c478bd9Sstevel@tonic-gate 	char line[BUFSIZ];
213*7c478bd9Sstevel@tonic-gate #endif
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	for (np = names; np != NIL; np = np->n_flink) {
216*7c478bd9Sstevel@tonic-gate 		if (!isfileaddr(np->n_name) && np->n_name[0] != '|')
217*7c478bd9Sstevel@tonic-gate 			continue;
218*7c478bd9Sstevel@tonic-gate 		nout++;
219*7c478bd9Sstevel@tonic-gate 		ispipe = np->n_name[0] == '|';
220*7c478bd9Sstevel@tonic-gate 		if (ispipe)
221*7c478bd9Sstevel@tonic-gate 			fname = np->n_name+1;
222*7c478bd9Sstevel@tonic-gate 		else
223*7c478bd9Sstevel@tonic-gate 			fname = safeexpand(np->n_name);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 		/*
226*7c478bd9Sstevel@tonic-gate 		 * See if we have copied the complete message out yet.
227*7c478bd9Sstevel@tonic-gate 		 * If not, do so.
228*7c478bd9Sstevel@tonic-gate 		 */
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 		if (image < 0) {
231*7c478bd9Sstevel@tonic-gate 			fd = open(tempEdit, O_CREAT|O_EXCL|O_APPEND|O_WRONLY,
232*7c478bd9Sstevel@tonic-gate 					0600);
233*7c478bd9Sstevel@tonic-gate 			if ((fd  < 0) && (errno == EEXIST)) {
234*7c478bd9Sstevel@tonic-gate 				if ((fd = open(tempEdit, O_APPEND|O_WRONLY,
235*7c478bd9Sstevel@tonic-gate 						0600)) < 0) {
236*7c478bd9Sstevel@tonic-gate 					perror(tempEdit);
237*7c478bd9Sstevel@tonic-gate 					senderr++;
238*7c478bd9Sstevel@tonic-gate 					goto cant;
239*7c478bd9Sstevel@tonic-gate 				}
240*7c478bd9Sstevel@tonic-gate 			}
241*7c478bd9Sstevel@tonic-gate 			if ((fout = fdopen(fd, "a")) == NULL) {
242*7c478bd9Sstevel@tonic-gate 				perror(tempEdit);
243*7c478bd9Sstevel@tonic-gate 				senderr++;
244*7c478bd9Sstevel@tonic-gate 				goto cant;
245*7c478bd9Sstevel@tonic-gate 			}
246*7c478bd9Sstevel@tonic-gate 			image = open(tempEdit, O_RDWR);
247*7c478bd9Sstevel@tonic-gate 			unlink(tempEdit);
248*7c478bd9Sstevel@tonic-gate 			if (image < 0) {
249*7c478bd9Sstevel@tonic-gate 				perror(tempEdit);
250*7c478bd9Sstevel@tonic-gate 				senderr++;
251*7c478bd9Sstevel@tonic-gate 				goto cant;
252*7c478bd9Sstevel@tonic-gate 			} else {
253*7c478bd9Sstevel@tonic-gate 				rewind(fo);
254*7c478bd9Sstevel@tonic-gate 				time(&now);
255*7c478bd9Sstevel@tonic-gate 				date = ctime(&now);
256*7c478bd9Sstevel@tonic-gate 				fprintf(fout, "From %s %s", myname, date);
257*7c478bd9Sstevel@tonic-gate 				while ((c = getc(fo)) != EOF)
258*7c478bd9Sstevel@tonic-gate 					putc(c, fout);
259*7c478bd9Sstevel@tonic-gate 				rewind(fo);
260*7c478bd9Sstevel@tonic-gate 				fflush(fout);
261*7c478bd9Sstevel@tonic-gate 				if (fferror(fout))
262*7c478bd9Sstevel@tonic-gate 					perror(tempEdit);
263*7c478bd9Sstevel@tonic-gate 				fclose(fout);
264*7c478bd9Sstevel@tonic-gate 			}
265*7c478bd9Sstevel@tonic-gate 		}
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 		/*
268*7c478bd9Sstevel@tonic-gate 		 * Now either copy "image" to the desired file
269*7c478bd9Sstevel@tonic-gate 		 * or give it as the standard input to the desired
270*7c478bd9Sstevel@tonic-gate 		 * program as appropriate.
271*7c478bd9Sstevel@tonic-gate 		 */
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		if (ispipe) {
274*7c478bd9Sstevel@tonic-gate 			wait((int *)NULL);
275*7c478bd9Sstevel@tonic-gate 			switch (fork()) {
276*7c478bd9Sstevel@tonic-gate 			case 0:
277*7c478bd9Sstevel@tonic-gate 				sigchild();
278*7c478bd9Sstevel@tonic-gate 				sigset(SIGHUP, SIG_IGN);
279*7c478bd9Sstevel@tonic-gate 				sigset(SIGINT, SIG_IGN);
280*7c478bd9Sstevel@tonic-gate 				sigset(SIGQUIT, SIG_IGN);
281*7c478bd9Sstevel@tonic-gate 				close(0);
282*7c478bd9Sstevel@tonic-gate 				dup(image);
283*7c478bd9Sstevel@tonic-gate 				close(image);
284*7c478bd9Sstevel@tonic-gate 				lseek(0, 0L, 0);
285*7c478bd9Sstevel@tonic-gate 				if ((shell = value("SHELL")) == NOSTR || *shell=='\0')
286*7c478bd9Sstevel@tonic-gate 					shell = SHELL;
287*7c478bd9Sstevel@tonic-gate 				(void) execlp(shell, shell, "-c", fname, (char *)0);
288*7c478bd9Sstevel@tonic-gate 				perror(shell);
289*7c478bd9Sstevel@tonic-gate 				exit(1);
290*7c478bd9Sstevel@tonic-gate 				break;
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 			case (pid_t)-1:
293*7c478bd9Sstevel@tonic-gate 				perror("fork");
294*7c478bd9Sstevel@tonic-gate 				senderr++;
295*7c478bd9Sstevel@tonic-gate 				goto cant;
296*7c478bd9Sstevel@tonic-gate 			}
297*7c478bd9Sstevel@tonic-gate 		}
298*7c478bd9Sstevel@tonic-gate 		else {
299*7c478bd9Sstevel@tonic-gate 			if ((fout = fopen(fname, "a")) == NULL) {
300*7c478bd9Sstevel@tonic-gate 				perror(fname);
301*7c478bd9Sstevel@tonic-gate 				senderr++;
302*7c478bd9Sstevel@tonic-gate 				goto cant;
303*7c478bd9Sstevel@tonic-gate 			}
304*7c478bd9Sstevel@tonic-gate 			fin = Fdopen(image, "r");
305*7c478bd9Sstevel@tonic-gate 			if (fin == NULL) {
306*7c478bd9Sstevel@tonic-gate 				fprintf(stderr,
307*7c478bd9Sstevel@tonic-gate 				    gettext("Can't reopen image\n"));
308*7c478bd9Sstevel@tonic-gate 				fclose(fout);
309*7c478bd9Sstevel@tonic-gate 				senderr++;
310*7c478bd9Sstevel@tonic-gate 				goto cant;
311*7c478bd9Sstevel@tonic-gate 			}
312*7c478bd9Sstevel@tonic-gate 			rewind(fin);
313*7c478bd9Sstevel@tonic-gate #ifdef preSVr4
314*7c478bd9Sstevel@tonic-gate 			putc(getc(fin), fout);
315*7c478bd9Sstevel@tonic-gate 			while (fgets(line, sizeof line, fin)) {
316*7c478bd9Sstevel@tonic-gate 				if (!strncmp(line, "From ", 5))
317*7c478bd9Sstevel@tonic-gate 					putc('>', fout);
318*7c478bd9Sstevel@tonic-gate 				fputs(line, fout);
319*7c478bd9Sstevel@tonic-gate 			}
320*7c478bd9Sstevel@tonic-gate #else
321*7c478bd9Sstevel@tonic-gate 			while ((c = getc(fin)) != EOF)
322*7c478bd9Sstevel@tonic-gate 				putc(c, fout);
323*7c478bd9Sstevel@tonic-gate #endif
324*7c478bd9Sstevel@tonic-gate 			putc('\n', fout);
325*7c478bd9Sstevel@tonic-gate 			fflush(fout);
326*7c478bd9Sstevel@tonic-gate 			if (fferror(fout))
327*7c478bd9Sstevel@tonic-gate 				senderr++, perror(fname);
328*7c478bd9Sstevel@tonic-gate 			fclose(fout);
329*7c478bd9Sstevel@tonic-gate 			fclose(fin);
330*7c478bd9Sstevel@tonic-gate 		}
331*7c478bd9Sstevel@tonic-gate cant:
332*7c478bd9Sstevel@tonic-gate 		/*
333*7c478bd9Sstevel@tonic-gate 		 * In days of old we removed the entry from the
334*7c478bd9Sstevel@tonic-gate 		 * the list; now for sake of header expansion
335*7c478bd9Sstevel@tonic-gate 		 * we leave it in and mark it as deleted.
336*7c478bd9Sstevel@tonic-gate 		 */
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate #ifdef CRAZYWOW
339*7c478bd9Sstevel@tonic-gate 		{
340*7c478bd9Sstevel@tonic-gate 		register struct name *t, *x;
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 		if (np == top) {
343*7c478bd9Sstevel@tonic-gate 			top = np->n_flink;
344*7c478bd9Sstevel@tonic-gate 			if (top != NIL)
345*7c478bd9Sstevel@tonic-gate 				top->n_blink = NIL;
346*7c478bd9Sstevel@tonic-gate 			np = top;
347*7c478bd9Sstevel@tonic-gate 			continue;
348*7c478bd9Sstevel@tonic-gate 		}
349*7c478bd9Sstevel@tonic-gate 		x = np->n_blink;
350*7c478bd9Sstevel@tonic-gate 		t = np->n_flink;
351*7c478bd9Sstevel@tonic-gate 		x->n_flink = t;
352*7c478bd9Sstevel@tonic-gate 		if (t != NIL)
353*7c478bd9Sstevel@tonic-gate 			t->n_blink = x;
354*7c478bd9Sstevel@tonic-gate 		np = t;
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate #endif
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 		np->n_type |= GDEL;
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 	if (image >= 0) {
361*7c478bd9Sstevel@tonic-gate 		close(image);
362*7c478bd9Sstevel@tonic-gate 		image = -1;
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 	return(nout);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * Determine if the passed address is a local "send to file" address.
369*7c478bd9Sstevel@tonic-gate  * If any of the network metacharacters precedes any slashes, it can't
370*7c478bd9Sstevel@tonic-gate  * be a filename.  We cheat with .'s to allow path names like ./...
371*7c478bd9Sstevel@tonic-gate  * If "fcc" has been unset, then short-circuit those tests, but not
372*7c478bd9Sstevel@tonic-gate  * the +... test.
373*7c478bd9Sstevel@tonic-gate  */
374*7c478bd9Sstevel@tonic-gate static int
375*7c478bd9Sstevel@tonic-gate isfileaddr(char *name)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	register char *cp;
378*7c478bd9Sstevel@tonic-gate 	char *fcc = value("fcc");
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	if (any('@', name))
381*7c478bd9Sstevel@tonic-gate 		return(0);
382*7c478bd9Sstevel@tonic-gate 	if (*name == '+')
383*7c478bd9Sstevel@tonic-gate 		return(1);
384*7c478bd9Sstevel@tonic-gate 	if (fcc == NOSTR)
385*7c478bd9Sstevel@tonic-gate 		return(0);
386*7c478bd9Sstevel@tonic-gate 	for (cp = name; *cp; cp++) {
387*7c478bd9Sstevel@tonic-gate 		if (*cp == '.')
388*7c478bd9Sstevel@tonic-gate 			continue;
389*7c478bd9Sstevel@tonic-gate 		if (any(*cp, metanet))
390*7c478bd9Sstevel@tonic-gate 			return(0);
391*7c478bd9Sstevel@tonic-gate 		if (*cp == '/')
392*7c478bd9Sstevel@tonic-gate 			return(1);
393*7c478bd9Sstevel@tonic-gate 	}
394*7c478bd9Sstevel@tonic-gate 	return(0);
395*7c478bd9Sstevel@tonic-gate }
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate /*
398*7c478bd9Sstevel@tonic-gate  * Map all of the aliased users in the invoker's mailrc
399*7c478bd9Sstevel@tonic-gate  * file and insert them into the list.
400*7c478bd9Sstevel@tonic-gate  * Changed after all these months of service to recursively
401*7c478bd9Sstevel@tonic-gate  * expand names (2/14/80).
402*7c478bd9Sstevel@tonic-gate  */
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate struct name *
405*7c478bd9Sstevel@tonic-gate usermap(struct name *names)
406*7c478bd9Sstevel@tonic-gate {
407*7c478bd9Sstevel@tonic-gate 	register struct name *newnames, *np, *cp;
408*7c478bd9Sstevel@tonic-gate 	struct grouphead *gh;
409*7c478bd9Sstevel@tonic-gate 	register int metoo;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	newnames = NIL;
412*7c478bd9Sstevel@tonic-gate 	np = names;
413*7c478bd9Sstevel@tonic-gate 	metoo = (value("metoo") != NOSTR);
414*7c478bd9Sstevel@tonic-gate 	while (np != NIL) {
415*7c478bd9Sstevel@tonic-gate 		if (np->n_name[0] == '\\') {
416*7c478bd9Sstevel@tonic-gate 			cp = np->n_flink;
417*7c478bd9Sstevel@tonic-gate 			newnames = put(newnames, np);
418*7c478bd9Sstevel@tonic-gate 			np = cp;
419*7c478bd9Sstevel@tonic-gate 			continue;
420*7c478bd9Sstevel@tonic-gate 		}
421*7c478bd9Sstevel@tonic-gate 		gh = findgroup(np->n_name);
422*7c478bd9Sstevel@tonic-gate 		cp = np->n_flink;
423*7c478bd9Sstevel@tonic-gate 		if (gh != NOGRP)
424*7c478bd9Sstevel@tonic-gate 			newnames = gexpand(newnames, gh, metoo, np->n_type);
425*7c478bd9Sstevel@tonic-gate 		else
426*7c478bd9Sstevel@tonic-gate 			newnames = put(newnames, np);
427*7c478bd9Sstevel@tonic-gate 		np = cp;
428*7c478bd9Sstevel@tonic-gate 	}
429*7c478bd9Sstevel@tonic-gate 	return(newnames);
430*7c478bd9Sstevel@tonic-gate }
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate /*
433*7c478bd9Sstevel@tonic-gate  * Recursively expand a group name.  We limit the expansion to some
434*7c478bd9Sstevel@tonic-gate  * fixed level to keep things from going haywire.
435*7c478bd9Sstevel@tonic-gate  * Direct recursion is not expanded for convenience.
436*7c478bd9Sstevel@tonic-gate  */
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate static struct name *
439*7c478bd9Sstevel@tonic-gate gexpand(struct name *nlist, struct grouphead *gh, int metoo, int arg_ntype)
440*7c478bd9Sstevel@tonic-gate {
441*7c478bd9Sstevel@tonic-gate 	short ntype = (short)arg_ntype;
442*7c478bd9Sstevel@tonic-gate 	struct mgroup *gp;
443*7c478bd9Sstevel@tonic-gate 	struct grouphead *ngh;
444*7c478bd9Sstevel@tonic-gate 	struct name *np;
445*7c478bd9Sstevel@tonic-gate 	static int depth;
446*7c478bd9Sstevel@tonic-gate 	register char *cp;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	if (depth > MAXEXP) {
449*7c478bd9Sstevel@tonic-gate 		printf(gettext("Expanding alias to depth larger than %d\n"),
450*7c478bd9Sstevel@tonic-gate 		    MAXEXP);
451*7c478bd9Sstevel@tonic-gate 		return(nlist);
452*7c478bd9Sstevel@tonic-gate 	}
453*7c478bd9Sstevel@tonic-gate 	depth++;
454*7c478bd9Sstevel@tonic-gate 	for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) {
455*7c478bd9Sstevel@tonic-gate 		cp = gp->ge_name;
456*7c478bd9Sstevel@tonic-gate 		if (*cp == '\\')
457*7c478bd9Sstevel@tonic-gate 			goto quote;
458*7c478bd9Sstevel@tonic-gate 		if (strcmp(cp, gh->g_name) == 0)
459*7c478bd9Sstevel@tonic-gate 			goto quote;
460*7c478bd9Sstevel@tonic-gate 		if ((ngh = findgroup(cp)) != NOGRP) {
461*7c478bd9Sstevel@tonic-gate 			nlist = gexpand(nlist, ngh, metoo, ntype);
462*7c478bd9Sstevel@tonic-gate 			continue;
463*7c478bd9Sstevel@tonic-gate 		}
464*7c478bd9Sstevel@tonic-gate quote:
465*7c478bd9Sstevel@tonic-gate 		np = nalloc(cp);
466*7c478bd9Sstevel@tonic-gate 		np->n_type = ntype;
467*7c478bd9Sstevel@tonic-gate 		/*
468*7c478bd9Sstevel@tonic-gate 		 * At this point should allow to expand
469*7c478bd9Sstevel@tonic-gate 		 * to self if only person in group
470*7c478bd9Sstevel@tonic-gate 		 */
471*7c478bd9Sstevel@tonic-gate 		if (gp == gh->g_list && gp->ge_link == NOGE)
472*7c478bd9Sstevel@tonic-gate 			goto skip;
473*7c478bd9Sstevel@tonic-gate 		if (!metoo && samebody(myname, gp->ge_name, FALSE))
474*7c478bd9Sstevel@tonic-gate 			np->n_type |= GDEL;
475*7c478bd9Sstevel@tonic-gate skip:
476*7c478bd9Sstevel@tonic-gate 		nlist = put(nlist, np);
477*7c478bd9Sstevel@tonic-gate 	}
478*7c478bd9Sstevel@tonic-gate 	depth--;
479*7c478bd9Sstevel@tonic-gate 	return(nlist);
480*7c478bd9Sstevel@tonic-gate }
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate /*
483*7c478bd9Sstevel@tonic-gate  * Normalize a network name for comparison purposes.
484*7c478bd9Sstevel@tonic-gate  */
485*7c478bd9Sstevel@tonic-gate static char *
486*7c478bd9Sstevel@tonic-gate norm(register char *user, register char *ubuf, int nbangs)
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	register char *cp;
489*7c478bd9Sstevel@tonic-gate 	int inubuf = 0;
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	while (*user++ == '!');
492*7c478bd9Sstevel@tonic-gate 	user--;
493*7c478bd9Sstevel@tonic-gate 	if (!strchr(user, '!')) {
494*7c478bd9Sstevel@tonic-gate 		snprintf(ubuf, BUFSIZ, "%s!%s", host, user);
495*7c478bd9Sstevel@tonic-gate 		user = ubuf;
496*7c478bd9Sstevel@tonic-gate 		inubuf++;
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 	if (nbangs) {
499*7c478bd9Sstevel@tonic-gate 		cp = user + strlen(user);
500*7c478bd9Sstevel@tonic-gate 		while (nbangs--)
501*7c478bd9Sstevel@tonic-gate 			while (cp > user && *--cp != '!');
502*7c478bd9Sstevel@tonic-gate 		user = (cp > user) ? ++cp : cp;
503*7c478bd9Sstevel@tonic-gate 		/*
504*7c478bd9Sstevel@tonic-gate 		 * Now strip off all Internet-type
505*7c478bd9Sstevel@tonic-gate 		 * hosts.
506*7c478bd9Sstevel@tonic-gate 		 */
507*7c478bd9Sstevel@tonic-gate 		if ((cp = strchr(user, '%')) == NOSTR)
508*7c478bd9Sstevel@tonic-gate 			cp = strchr(user, '@');
509*7c478bd9Sstevel@tonic-gate 		if (cp != NOSTR) {
510*7c478bd9Sstevel@tonic-gate 			if (!inubuf) {
511*7c478bd9Sstevel@tonic-gate 				strncpy(ubuf, user, cp - user);
512*7c478bd9Sstevel@tonic-gate 				ubuf[cp - user] = '\0';
513*7c478bd9Sstevel@tonic-gate 				user = ubuf;
514*7c478bd9Sstevel@tonic-gate 			} else
515*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
516*7c478bd9Sstevel@tonic-gate 		}
517*7c478bd9Sstevel@tonic-gate 	}
518*7c478bd9Sstevel@tonic-gate 	return user;
519*7c478bd9Sstevel@tonic-gate }
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate /*
522*7c478bd9Sstevel@tonic-gate  * Implement allnet options.
523*7c478bd9Sstevel@tonic-gate  */
524*7c478bd9Sstevel@tonic-gate int
525*7c478bd9Sstevel@tonic-gate samebody(register char *user, register char *addr, int fuzzy)
526*7c478bd9Sstevel@tonic-gate {
527*7c478bd9Sstevel@tonic-gate 	char ubuf[BUFSIZ], abuf[BUFSIZ];
528*7c478bd9Sstevel@tonic-gate 	char *allnet = value("allnet");
529*7c478bd9Sstevel@tonic-gate 	int nbangs = allnet ? !strcmp(allnet, "uucp") ? 2 : 1 : 0;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	if (fuzzy && value("fuzzymatch")) {
532*7c478bd9Sstevel@tonic-gate 		int i;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(ubuf, user, BUFSIZ);
535*7c478bd9Sstevel@tonic-gate 		for (i = 0; ubuf[i]; i++)
536*7c478bd9Sstevel@tonic-gate 			ubuf[i] = tolower(ubuf[i]);
537*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(abuf, addr, BUFSIZ);
538*7c478bd9Sstevel@tonic-gate 		for (i = 0; abuf[i]; i++)
539*7c478bd9Sstevel@tonic-gate 			abuf[i] = tolower(abuf[i]);
540*7c478bd9Sstevel@tonic-gate 		return (strstr(abuf, ubuf) != NOSTR);
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate 	user = norm(user, ubuf, nbangs);
543*7c478bd9Sstevel@tonic-gate 	addr = norm(addr, abuf, nbangs);
544*7c478bd9Sstevel@tonic-gate 	return strcmp(user, addr) == 0;
545*7c478bd9Sstevel@tonic-gate }
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate /*
548*7c478bd9Sstevel@tonic-gate  * Compute the length of the passed name list and
549*7c478bd9Sstevel@tonic-gate  * return it.
550*7c478bd9Sstevel@tonic-gate  */
551*7c478bd9Sstevel@tonic-gate static int
552*7c478bd9Sstevel@tonic-gate lengthof(struct name *name)
553*7c478bd9Sstevel@tonic-gate {
554*7c478bd9Sstevel@tonic-gate 	register struct name *np;
555*7c478bd9Sstevel@tonic-gate 	register int c;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	for (c = 0, np = name; np != NIL; c++, np = np->n_flink)
558*7c478bd9Sstevel@tonic-gate 		;
559*7c478bd9Sstevel@tonic-gate 	return(c);
560*7c478bd9Sstevel@tonic-gate }
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate /*
563*7c478bd9Sstevel@tonic-gate  * Concatenate the two passed name lists, return the result.
564*7c478bd9Sstevel@tonic-gate  */
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate struct name *
567*7c478bd9Sstevel@tonic-gate cat(struct name *n1, struct name *n2)
568*7c478bd9Sstevel@tonic-gate {
569*7c478bd9Sstevel@tonic-gate 	register struct name *tail;
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	if (n1 == NIL)
572*7c478bd9Sstevel@tonic-gate 		return(n2);
573*7c478bd9Sstevel@tonic-gate 	if (n2 == NIL)
574*7c478bd9Sstevel@tonic-gate 		return(n1);
575*7c478bd9Sstevel@tonic-gate 	tail = tailof(n1);
576*7c478bd9Sstevel@tonic-gate 	tail->n_flink = n2;
577*7c478bd9Sstevel@tonic-gate 	n2->n_blink = tail;
578*7c478bd9Sstevel@tonic-gate 	return(n1);
579*7c478bd9Sstevel@tonic-gate }
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate /*
582*7c478bd9Sstevel@tonic-gate  * Unpack the name list onto a vector of strings.
583*7c478bd9Sstevel@tonic-gate  * Return an error if the name list won't fit.
584*7c478bd9Sstevel@tonic-gate  */
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate char **
587*7c478bd9Sstevel@tonic-gate unpack(struct name *np)
588*7c478bd9Sstevel@tonic-gate {
589*7c478bd9Sstevel@tonic-gate 	register char **ap, **top;
590*7c478bd9Sstevel@tonic-gate 	register struct name *n;
591*7c478bd9Sstevel@tonic-gate 	char hbuf[10];
592*7c478bd9Sstevel@tonic-gate 	int t, extra, metoo, verbose;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	n = np;
595*7c478bd9Sstevel@tonic-gate 	if ((t = lengthof(n)) == 0)
596*7c478bd9Sstevel@tonic-gate 		panic("No names to unpack");
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	/*
599*7c478bd9Sstevel@tonic-gate 	 * Compute the number of extra arguments we will need.
600*7c478bd9Sstevel@tonic-gate 	 * We need at least 2 extra -- one for "mail" and one for
601*7c478bd9Sstevel@tonic-gate 	 * the terminating 0 pointer.
602*7c478bd9Sstevel@tonic-gate 	 * Additional spots may be needed to pass along -r and -f to
603*7c478bd9Sstevel@tonic-gate 	 * the host mailer.
604*7c478bd9Sstevel@tonic-gate 	 */
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	extra = 2;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	if (rflag != NOSTR)
609*7c478bd9Sstevel@tonic-gate 		extra += 2;
610*7c478bd9Sstevel@tonic-gate #ifdef SENDMAIL
611*7c478bd9Sstevel@tonic-gate 	extra++;
612*7c478bd9Sstevel@tonic-gate 	metoo = value("metoo") != NOSTR;
613*7c478bd9Sstevel@tonic-gate 	if (metoo)
614*7c478bd9Sstevel@tonic-gate 		extra++;
615*7c478bd9Sstevel@tonic-gate 	verbose = value("verbose") != NOSTR;
616*7c478bd9Sstevel@tonic-gate 	if (verbose)
617*7c478bd9Sstevel@tonic-gate 		extra++;
618*7c478bd9Sstevel@tonic-gate 	if (hflag)
619*7c478bd9Sstevel@tonic-gate 		extra += 2;
620*7c478bd9Sstevel@tonic-gate #endif SENDMAIL
621*7c478bd9Sstevel@tonic-gate 	top = (char **) salloc((t + extra) * sizeof (char *));
622*7c478bd9Sstevel@tonic-gate 	ap = top;
623*7c478bd9Sstevel@tonic-gate 	*ap++ = "mail";
624*7c478bd9Sstevel@tonic-gate 	if (rflag != NOSTR) {
625*7c478bd9Sstevel@tonic-gate 		*ap++ = "-r";
626*7c478bd9Sstevel@tonic-gate 		*ap++ = rflag;
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate #ifdef SENDMAIL
629*7c478bd9Sstevel@tonic-gate 	*ap++ = "-i";
630*7c478bd9Sstevel@tonic-gate 	if (metoo)
631*7c478bd9Sstevel@tonic-gate 		*ap++ = "-m";
632*7c478bd9Sstevel@tonic-gate 	if (verbose)
633*7c478bd9Sstevel@tonic-gate 		*ap++ = "-v";
634*7c478bd9Sstevel@tonic-gate 	if (hflag) {
635*7c478bd9Sstevel@tonic-gate 		*ap++ = "-h";
636*7c478bd9Sstevel@tonic-gate 		snprintf(hbuf, sizeof (hbuf), "%d", hflag);
637*7c478bd9Sstevel@tonic-gate 		*ap++ = savestr(hbuf);
638*7c478bd9Sstevel@tonic-gate 	}
639*7c478bd9Sstevel@tonic-gate #endif SENDMAIL
640*7c478bd9Sstevel@tonic-gate 	while (n != NIL) {
641*7c478bd9Sstevel@tonic-gate 		if (n->n_type & GDEL) {
642*7c478bd9Sstevel@tonic-gate 			n = n->n_flink;
643*7c478bd9Sstevel@tonic-gate 			continue;
644*7c478bd9Sstevel@tonic-gate 		}
645*7c478bd9Sstevel@tonic-gate 		*ap++ = n->n_name;
646*7c478bd9Sstevel@tonic-gate 		n = n->n_flink;
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate 	*ap = NOSTR;
649*7c478bd9Sstevel@tonic-gate 	return(top);
650*7c478bd9Sstevel@tonic-gate }
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate /*
653*7c478bd9Sstevel@tonic-gate  * See if the user named himself as a destination
654*7c478bd9Sstevel@tonic-gate  * for outgoing mail.  If so, set the global flag
655*7c478bd9Sstevel@tonic-gate  * selfsent so that we avoid removing his mailbox.
656*7c478bd9Sstevel@tonic-gate  */
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate void
659*7c478bd9Sstevel@tonic-gate mechk(struct name *names)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate 	register struct name *np;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	for (np = names; np != NIL; np = np->n_flink)
664*7c478bd9Sstevel@tonic-gate 		if ((np->n_type & GDEL) == 0 &&
665*7c478bd9Sstevel@tonic-gate 		    samebody(np->n_name, myname, FALSE)) {
666*7c478bd9Sstevel@tonic-gate 			selfsent++;
667*7c478bd9Sstevel@tonic-gate 			return;
668*7c478bd9Sstevel@tonic-gate 		}
669*7c478bd9Sstevel@tonic-gate }
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate /*
672*7c478bd9Sstevel@tonic-gate  * Remove all of the duplicates from the passed name list by
673*7c478bd9Sstevel@tonic-gate  * insertion sorting them, then checking for dups.
674*7c478bd9Sstevel@tonic-gate  * Return the head of the new list.
675*7c478bd9Sstevel@tonic-gate  */
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate struct name *
678*7c478bd9Sstevel@tonic-gate elide(struct name *names)
679*7c478bd9Sstevel@tonic-gate {
680*7c478bd9Sstevel@tonic-gate 	register struct name *np, *t, *newnames;
681*7c478bd9Sstevel@tonic-gate 	struct name *x;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	if (names == NIL)
684*7c478bd9Sstevel@tonic-gate 		return(NIL);
685*7c478bd9Sstevel@tonic-gate 	newnames = names;
686*7c478bd9Sstevel@tonic-gate 	np = names;
687*7c478bd9Sstevel@tonic-gate 	np = np->n_flink;
688*7c478bd9Sstevel@tonic-gate 	if (np != NIL)
689*7c478bd9Sstevel@tonic-gate 		np->n_blink = NIL;
690*7c478bd9Sstevel@tonic-gate 	newnames->n_flink = NIL;
691*7c478bd9Sstevel@tonic-gate 	while (np != NIL) {
692*7c478bd9Sstevel@tonic-gate 		t = newnames;
693*7c478bd9Sstevel@tonic-gate 		while (strcmp(t->n_name, np->n_name) < 0) {
694*7c478bd9Sstevel@tonic-gate 			if (t->n_flink == NIL)
695*7c478bd9Sstevel@tonic-gate 				break;
696*7c478bd9Sstevel@tonic-gate 			t = t->n_flink;
697*7c478bd9Sstevel@tonic-gate 		}
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 		/*
700*7c478bd9Sstevel@tonic-gate 		 * If we ran out of t's, put the new entry after
701*7c478bd9Sstevel@tonic-gate 		 * the current value of t.
702*7c478bd9Sstevel@tonic-gate 		 */
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 		if (strcmp(t->n_name, np->n_name) < 0) {
705*7c478bd9Sstevel@tonic-gate 			t->n_flink = np;
706*7c478bd9Sstevel@tonic-gate 			np->n_blink = t;
707*7c478bd9Sstevel@tonic-gate 			t = np;
708*7c478bd9Sstevel@tonic-gate 			np = np->n_flink;
709*7c478bd9Sstevel@tonic-gate 			t->n_flink = NIL;
710*7c478bd9Sstevel@tonic-gate 			continue;
711*7c478bd9Sstevel@tonic-gate 		}
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 		/*
714*7c478bd9Sstevel@tonic-gate 		 * Otherwise, put the new entry in front of the
715*7c478bd9Sstevel@tonic-gate 		 * current t.  If at the front of the list,
716*7c478bd9Sstevel@tonic-gate 		 * the new guy becomes the new head of the list.
717*7c478bd9Sstevel@tonic-gate 		 */
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		if (t == newnames) {
720*7c478bd9Sstevel@tonic-gate 			t = np;
721*7c478bd9Sstevel@tonic-gate 			np = np->n_flink;
722*7c478bd9Sstevel@tonic-gate 			t->n_flink = newnames;
723*7c478bd9Sstevel@tonic-gate 			newnames->n_blink = t;
724*7c478bd9Sstevel@tonic-gate 			t->n_blink = NIL;
725*7c478bd9Sstevel@tonic-gate 			newnames = t;
726*7c478bd9Sstevel@tonic-gate 			continue;
727*7c478bd9Sstevel@tonic-gate 		}
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 		/*
730*7c478bd9Sstevel@tonic-gate 		 * The normal case -- we are inserting into the
731*7c478bd9Sstevel@tonic-gate 		 * middle of the list.
732*7c478bd9Sstevel@tonic-gate 		 */
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 		x = np;
735*7c478bd9Sstevel@tonic-gate 		np = np->n_flink;
736*7c478bd9Sstevel@tonic-gate 		x->n_flink = t;
737*7c478bd9Sstevel@tonic-gate 		x->n_blink = t->n_blink;
738*7c478bd9Sstevel@tonic-gate 		t->n_blink->n_flink = x;
739*7c478bd9Sstevel@tonic-gate 		t->n_blink = x;
740*7c478bd9Sstevel@tonic-gate 	}
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	/*
743*7c478bd9Sstevel@tonic-gate 	 * Now the list headed up by new is sorted.
744*7c478bd9Sstevel@tonic-gate 	 * Go through it and remove duplicates.
745*7c478bd9Sstevel@tonic-gate 	 * Remember the best "type" among all the
746*7c478bd9Sstevel@tonic-gate 	 * duplicates of a name.
747*7c478bd9Sstevel@tonic-gate 	 */
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	np = newnames;
750*7c478bd9Sstevel@tonic-gate 	while (np != NIL) {
751*7c478bd9Sstevel@tonic-gate 		int type;
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 		t = np;
754*7c478bd9Sstevel@tonic-gate 		type = np->n_type;
755*7c478bd9Sstevel@tonic-gate 		while (t->n_flink!=NIL &&
756*7c478bd9Sstevel@tonic-gate 		    strcmp(np->n_name, t->n_flink->n_name) == 0) {
757*7c478bd9Sstevel@tonic-gate 			t = t->n_flink;
758*7c478bd9Sstevel@tonic-gate 			/* "To" before "Cc" before "Bcc" */
759*7c478bd9Sstevel@tonic-gate 			if (t->n_type < type)
760*7c478bd9Sstevel@tonic-gate 				type = t->n_type;
761*7c478bd9Sstevel@tonic-gate 		}
762*7c478bd9Sstevel@tonic-gate 		if (t == np || t == NIL) {
763*7c478bd9Sstevel@tonic-gate 			np = np->n_flink;
764*7c478bd9Sstevel@tonic-gate 			continue;
765*7c478bd9Sstevel@tonic-gate 		}
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 		/*
768*7c478bd9Sstevel@tonic-gate 		 * Now t points to the last entry with the same name
769*7c478bd9Sstevel@tonic-gate 		 * as np.  Make np point beyond t.
770*7c478bd9Sstevel@tonic-gate 		 */
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 		np->n_flink = t->n_flink;
773*7c478bd9Sstevel@tonic-gate 		if (t->n_flink != NIL)
774*7c478bd9Sstevel@tonic-gate 			t->n_flink->n_blink = np;
775*7c478bd9Sstevel@tonic-gate 		np->n_type = type;
776*7c478bd9Sstevel@tonic-gate 		np = np->n_flink;
777*7c478bd9Sstevel@tonic-gate 	}
778*7c478bd9Sstevel@tonic-gate 	return(newnames);
779*7c478bd9Sstevel@tonic-gate }
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate /*
782*7c478bd9Sstevel@tonic-gate  * Put another node onto a list of names and return
783*7c478bd9Sstevel@tonic-gate  * the list.
784*7c478bd9Sstevel@tonic-gate  */
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate static struct name *
787*7c478bd9Sstevel@tonic-gate put(struct name *list, struct name *node)
788*7c478bd9Sstevel@tonic-gate {
789*7c478bd9Sstevel@tonic-gate 	node->n_flink = list;
790*7c478bd9Sstevel@tonic-gate 	node->n_blink = NIL;
791*7c478bd9Sstevel@tonic-gate 	if (list != NIL)
792*7c478bd9Sstevel@tonic-gate 		list->n_blink = node;
793*7c478bd9Sstevel@tonic-gate 	return(node);
794*7c478bd9Sstevel@tonic-gate }
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate /*
798*7c478bd9Sstevel@tonic-gate  * Delete the given name from a namelist.
799*7c478bd9Sstevel@tonic-gate  */
800*7c478bd9Sstevel@tonic-gate struct name *
801*7c478bd9Sstevel@tonic-gate delname(register struct name *np, char name[])
802*7c478bd9Sstevel@tonic-gate {
803*7c478bd9Sstevel@tonic-gate 	register struct name *p;
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	for (p = np; p != NIL; p = p->n_flink)
806*7c478bd9Sstevel@tonic-gate 		if (samebody(name, p->n_name, FALSE)) {
807*7c478bd9Sstevel@tonic-gate 			if (p->n_blink == NIL) {
808*7c478bd9Sstevel@tonic-gate 				if (p->n_flink != NIL)
809*7c478bd9Sstevel@tonic-gate 					p->n_flink->n_blink = NIL;
810*7c478bd9Sstevel@tonic-gate 				np = p->n_flink;
811*7c478bd9Sstevel@tonic-gate 				continue;
812*7c478bd9Sstevel@tonic-gate 			}
813*7c478bd9Sstevel@tonic-gate 			if (p->n_flink == NIL) {
814*7c478bd9Sstevel@tonic-gate 				if (p->n_blink != NIL)
815*7c478bd9Sstevel@tonic-gate 					p->n_blink->n_flink = NIL;
816*7c478bd9Sstevel@tonic-gate 				continue;
817*7c478bd9Sstevel@tonic-gate 			}
818*7c478bd9Sstevel@tonic-gate 			p->n_blink->n_flink = p->n_flink;
819*7c478bd9Sstevel@tonic-gate 			p->n_flink->n_blink = p->n_blink;
820*7c478bd9Sstevel@tonic-gate 		}
821*7c478bd9Sstevel@tonic-gate 	return(np);
822*7c478bd9Sstevel@tonic-gate }
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate /*
825*7c478bd9Sstevel@tonic-gate  * Call the given routine on each element of the name
826*7c478bd9Sstevel@tonic-gate  * list, replacing said value if need be.
827*7c478bd9Sstevel@tonic-gate  */
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate void
830*7c478bd9Sstevel@tonic-gate mapf(register struct name *np, char *from)
831*7c478bd9Sstevel@tonic-gate {
832*7c478bd9Sstevel@tonic-gate 	register struct name *p;
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	if (debug) fprintf(stderr, "mapf %lx, %s\n", (long)np, from);
835*7c478bd9Sstevel@tonic-gate 	for (p = np; p != NIL; p = p->n_flink)
836*7c478bd9Sstevel@tonic-gate 		if ((p->n_type & GDEL) == 0) {
837*7c478bd9Sstevel@tonic-gate 			p->n_name = netmap(p->n_name, from);
838*7c478bd9Sstevel@tonic-gate 			p->n_full = splice(p->n_name, p->n_full);
839*7c478bd9Sstevel@tonic-gate 		}
840*7c478bd9Sstevel@tonic-gate 	if (debug) fprintf(stderr, "mapf %s done\n", from);
841*7c478bd9Sstevel@tonic-gate }
842