17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate 237c478bd9Sstevel@tonic-gate /* 24*6c83d09fSrobbin * Copyright 2001 Sun Microsystems, Inc. All rights reserved. 25*6c83d09fSrobbin * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 28*6c83d09fSrobbin /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29*6c83d09fSrobbin /* All Rights Reserved */ 30*6c83d09fSrobbin 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 337c478bd9Sstevel@tonic-gate * The Regents of the University of California 347c478bd9Sstevel@tonic-gate * All Rights Reserved 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 377c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 387c478bd9Sstevel@tonic-gate * contributors. 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* 447c478bd9Sstevel@tonic-gate * mailx -- a modified version of a University of California at Berkeley 457c478bd9Sstevel@tonic-gate * mail program 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate * Handle name lists. 487c478bd9Sstevel@tonic-gate */ 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include "rcv.h" 517c478bd9Sstevel@tonic-gate #include <locale.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static struct name *nalloc(char str[]); 547c478bd9Sstevel@tonic-gate static int isfileaddr(char *name); 557c478bd9Sstevel@tonic-gate static int lengthof(struct name *name); 567c478bd9Sstevel@tonic-gate static struct name *gexpand(struct name *nlist, struct grouphead *gh, int metoo, int arg_ntype); 577c478bd9Sstevel@tonic-gate static char *norm(register char *user, register char *ubuf, int nbangs); 587c478bd9Sstevel@tonic-gate static struct name *put(struct name *list, struct name *node); 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate /* 617c478bd9Sstevel@tonic-gate * Allocate a single element of a name list, 627c478bd9Sstevel@tonic-gate * initialize its name field to the passed 637c478bd9Sstevel@tonic-gate * name and return it. 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static struct name * 677c478bd9Sstevel@tonic-gate nalloc(char str[]) 687c478bd9Sstevel@tonic-gate { 697c478bd9Sstevel@tonic-gate register struct name *np; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate np = (struct name *) salloc(sizeof *np); 727c478bd9Sstevel@tonic-gate np->n_flink = NIL; 737c478bd9Sstevel@tonic-gate np->n_blink = NIL; 747c478bd9Sstevel@tonic-gate np->n_type = -1; 757c478bd9Sstevel@tonic-gate np->n_full = savestr(str); 767c478bd9Sstevel@tonic-gate np->n_name = skin(np->n_full); 777c478bd9Sstevel@tonic-gate return(np); 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * Find the tail of a list and return it. 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate struct name * 857c478bd9Sstevel@tonic-gate tailof(struct name *name) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate register struct name *np; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate np = name; 907c478bd9Sstevel@tonic-gate if (np == NIL) 917c478bd9Sstevel@tonic-gate return(NIL); 927c478bd9Sstevel@tonic-gate while (np->n_flink != NIL) 937c478bd9Sstevel@tonic-gate np = np->n_flink; 947c478bd9Sstevel@tonic-gate return(np); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * Extract a list of names from a line, 997c478bd9Sstevel@tonic-gate * and make a list of names from it. 1007c478bd9Sstevel@tonic-gate * Return the list or NIL if none found. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate struct name * 1047c478bd9Sstevel@tonic-gate extract(char line[], int arg_ntype) 1057c478bd9Sstevel@tonic-gate { 1067c478bd9Sstevel@tonic-gate short ntype = (short)arg_ntype; 1077c478bd9Sstevel@tonic-gate register char *cp; 1087c478bd9Sstevel@tonic-gate register struct name *top, *np, *t; 1097c478bd9Sstevel@tonic-gate char nbuf[BUFSIZ], abuf[BUFSIZ]; 1107c478bd9Sstevel@tonic-gate int comma; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate if (line == NOSTR || strlen(line) == 0) 1137c478bd9Sstevel@tonic-gate return(NIL); 1147c478bd9Sstevel@tonic-gate comma = docomma(line); 1157c478bd9Sstevel@tonic-gate top = NIL; 1167c478bd9Sstevel@tonic-gate np = NIL; 1177c478bd9Sstevel@tonic-gate cp = line; 1187c478bd9Sstevel@tonic-gate while ((cp = yankword(cp, nbuf, sizeof (nbuf), comma)) != NOSTR) { 1197c478bd9Sstevel@tonic-gate if (np != NIL && equal(nbuf, "at")) { 1207c478bd9Sstevel@tonic-gate nstrcpy(abuf, sizeof (abuf), nbuf); 1217c478bd9Sstevel@tonic-gate if ((cp = yankword(cp, nbuf, sizeof (nbuf), 1227c478bd9Sstevel@tonic-gate comma)) == NOSTR) { 1237c478bd9Sstevel@tonic-gate nstrcpy(nbuf, sizeof (nbuf), abuf); 1247c478bd9Sstevel@tonic-gate goto normal; 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate snprintf(abuf, sizeof (abuf), "%s@%s", np->n_name, 1277c478bd9Sstevel@tonic-gate nbuf); 1287c478bd9Sstevel@tonic-gate np->n_name = savestr(abuf); 1297c478bd9Sstevel@tonic-gate continue; 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate normal: 1327c478bd9Sstevel@tonic-gate t = nalloc(nbuf); 1337c478bd9Sstevel@tonic-gate t->n_type = ntype; 1347c478bd9Sstevel@tonic-gate if (top == NIL) 1357c478bd9Sstevel@tonic-gate top = t; 1367c478bd9Sstevel@tonic-gate else 1377c478bd9Sstevel@tonic-gate np->n_flink = t; 1387c478bd9Sstevel@tonic-gate t->n_blink = np; 1397c478bd9Sstevel@tonic-gate np = t; 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate return(top); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate * Turn a list of names into a string of the same names. 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate char * 1497c478bd9Sstevel@tonic-gate detract(register struct name *np, int ntype) 1507c478bd9Sstevel@tonic-gate { 1517c478bd9Sstevel@tonic-gate register int s; 1527c478bd9Sstevel@tonic-gate register char *cp, *top; 1537c478bd9Sstevel@tonic-gate register struct name *p; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (np == NIL) 1567c478bd9Sstevel@tonic-gate return(NOSTR); 1577c478bd9Sstevel@tonic-gate s = 0; 1587c478bd9Sstevel@tonic-gate for (p = np; p != NIL; p = p->n_flink) { 1597c478bd9Sstevel@tonic-gate if ((ntype && (p->n_type & GMASK) != ntype) 1607c478bd9Sstevel@tonic-gate || (p->n_type & GDEL)) 1617c478bd9Sstevel@tonic-gate continue; 1627c478bd9Sstevel@tonic-gate s += strlen(p->n_full) + 2; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate if (s == 0) 1657c478bd9Sstevel@tonic-gate return(NOSTR); 1667c478bd9Sstevel@tonic-gate top = (char *)salloc((unsigned)(++s)); 1677c478bd9Sstevel@tonic-gate cp = top; 1687c478bd9Sstevel@tonic-gate for (p = np; p != NIL; p = p->n_flink) { 1697c478bd9Sstevel@tonic-gate if ((ntype && (p->n_type & GMASK) != ntype) 1707c478bd9Sstevel@tonic-gate || (p->n_type & GDEL)) 1717c478bd9Sstevel@tonic-gate continue; 1727c478bd9Sstevel@tonic-gate cp = copy(p->n_full, cp); 1737c478bd9Sstevel@tonic-gate *cp++ = ','; 1747c478bd9Sstevel@tonic-gate *cp++ = ' '; 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate *cp = 0; 1777c478bd9Sstevel@tonic-gate return(top); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate struct name * 1817c478bd9Sstevel@tonic-gate outpre(struct name *to) 1827c478bd9Sstevel@tonic-gate { 1837c478bd9Sstevel@tonic-gate register struct name *np; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate for (np = to; np; np = np->n_flink) 1867c478bd9Sstevel@tonic-gate if (isfileaddr(np->n_name)) 1877c478bd9Sstevel@tonic-gate np->n_type |= GDEL; 1887c478bd9Sstevel@tonic-gate return to; 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * For each recipient in the passed name list with a / 1937c478bd9Sstevel@tonic-gate * in the name, append the message to the end of the named file 1947c478bd9Sstevel@tonic-gate * and remove him from the recipient list. 1957c478bd9Sstevel@tonic-gate * 1967c478bd9Sstevel@tonic-gate * Recipients whose name begins with | are piped through the given 1977c478bd9Sstevel@tonic-gate * program and removed. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate int 2017c478bd9Sstevel@tonic-gate outof(struct name *names, FILE *fo) 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate register int c; 2047c478bd9Sstevel@tonic-gate register struct name *np; 2057c478bd9Sstevel@tonic-gate time_t now; 2067c478bd9Sstevel@tonic-gate char *date, *fname, *shell; 2077c478bd9Sstevel@tonic-gate FILE *fout, *fin; 2087c478bd9Sstevel@tonic-gate int ispipe; 2097c478bd9Sstevel@tonic-gate int nout = 0; 2107c478bd9Sstevel@tonic-gate int fd = 0; 2117c478bd9Sstevel@tonic-gate #ifdef preSVr4 2127c478bd9Sstevel@tonic-gate char line[BUFSIZ]; 2137c478bd9Sstevel@tonic-gate #endif 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate for (np = names; np != NIL; np = np->n_flink) { 2167c478bd9Sstevel@tonic-gate if (!isfileaddr(np->n_name) && np->n_name[0] != '|') 2177c478bd9Sstevel@tonic-gate continue; 2187c478bd9Sstevel@tonic-gate nout++; 2197c478bd9Sstevel@tonic-gate ispipe = np->n_name[0] == '|'; 2207c478bd9Sstevel@tonic-gate if (ispipe) 2217c478bd9Sstevel@tonic-gate fname = np->n_name+1; 2227c478bd9Sstevel@tonic-gate else 2237c478bd9Sstevel@tonic-gate fname = safeexpand(np->n_name); 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 2267c478bd9Sstevel@tonic-gate * See if we have copied the complete message out yet. 2277c478bd9Sstevel@tonic-gate * If not, do so. 2287c478bd9Sstevel@tonic-gate */ 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if (image < 0) { 2317c478bd9Sstevel@tonic-gate fd = open(tempEdit, O_CREAT|O_EXCL|O_APPEND|O_WRONLY, 2327c478bd9Sstevel@tonic-gate 0600); 2337c478bd9Sstevel@tonic-gate if ((fd < 0) && (errno == EEXIST)) { 2347c478bd9Sstevel@tonic-gate if ((fd = open(tempEdit, O_APPEND|O_WRONLY, 2357c478bd9Sstevel@tonic-gate 0600)) < 0) { 2367c478bd9Sstevel@tonic-gate perror(tempEdit); 2377c478bd9Sstevel@tonic-gate senderr++; 2387c478bd9Sstevel@tonic-gate goto cant; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate if ((fout = fdopen(fd, "a")) == NULL) { 2427c478bd9Sstevel@tonic-gate perror(tempEdit); 2437c478bd9Sstevel@tonic-gate senderr++; 2447c478bd9Sstevel@tonic-gate goto cant; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate image = open(tempEdit, O_RDWR); 2477c478bd9Sstevel@tonic-gate unlink(tempEdit); 2487c478bd9Sstevel@tonic-gate if (image < 0) { 2497c478bd9Sstevel@tonic-gate perror(tempEdit); 2507c478bd9Sstevel@tonic-gate senderr++; 2517c478bd9Sstevel@tonic-gate goto cant; 2527c478bd9Sstevel@tonic-gate } else { 2537c478bd9Sstevel@tonic-gate rewind(fo); 2547c478bd9Sstevel@tonic-gate time(&now); 2557c478bd9Sstevel@tonic-gate date = ctime(&now); 2567c478bd9Sstevel@tonic-gate fprintf(fout, "From %s %s", myname, date); 2577c478bd9Sstevel@tonic-gate while ((c = getc(fo)) != EOF) 2587c478bd9Sstevel@tonic-gate putc(c, fout); 2597c478bd9Sstevel@tonic-gate rewind(fo); 2607c478bd9Sstevel@tonic-gate fflush(fout); 2617c478bd9Sstevel@tonic-gate if (fferror(fout)) 2627c478bd9Sstevel@tonic-gate perror(tempEdit); 2637c478bd9Sstevel@tonic-gate fclose(fout); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* 2687c478bd9Sstevel@tonic-gate * Now either copy "image" to the desired file 2697c478bd9Sstevel@tonic-gate * or give it as the standard input to the desired 2707c478bd9Sstevel@tonic-gate * program as appropriate. 2717c478bd9Sstevel@tonic-gate */ 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate if (ispipe) { 2747c478bd9Sstevel@tonic-gate wait((int *)NULL); 2757c478bd9Sstevel@tonic-gate switch (fork()) { 2767c478bd9Sstevel@tonic-gate case 0: 2777c478bd9Sstevel@tonic-gate sigchild(); 2787c478bd9Sstevel@tonic-gate sigset(SIGHUP, SIG_IGN); 2797c478bd9Sstevel@tonic-gate sigset(SIGINT, SIG_IGN); 2807c478bd9Sstevel@tonic-gate sigset(SIGQUIT, SIG_IGN); 2817c478bd9Sstevel@tonic-gate close(0); 2827c478bd9Sstevel@tonic-gate dup(image); 2837c478bd9Sstevel@tonic-gate close(image); 2847c478bd9Sstevel@tonic-gate lseek(0, 0L, 0); 2857c478bd9Sstevel@tonic-gate if ((shell = value("SHELL")) == NOSTR || *shell=='\0') 2867c478bd9Sstevel@tonic-gate shell = SHELL; 2877c478bd9Sstevel@tonic-gate (void) execlp(shell, shell, "-c", fname, (char *)0); 2887c478bd9Sstevel@tonic-gate perror(shell); 2897c478bd9Sstevel@tonic-gate exit(1); 2907c478bd9Sstevel@tonic-gate break; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate case (pid_t)-1: 2937c478bd9Sstevel@tonic-gate perror("fork"); 2947c478bd9Sstevel@tonic-gate senderr++; 2957c478bd9Sstevel@tonic-gate goto cant; 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate else { 2997c478bd9Sstevel@tonic-gate if ((fout = fopen(fname, "a")) == NULL) { 3007c478bd9Sstevel@tonic-gate perror(fname); 3017c478bd9Sstevel@tonic-gate senderr++; 3027c478bd9Sstevel@tonic-gate goto cant; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate fin = Fdopen(image, "r"); 3057c478bd9Sstevel@tonic-gate if (fin == NULL) { 3067c478bd9Sstevel@tonic-gate fprintf(stderr, 3077c478bd9Sstevel@tonic-gate gettext("Can't reopen image\n")); 3087c478bd9Sstevel@tonic-gate fclose(fout); 3097c478bd9Sstevel@tonic-gate senderr++; 3107c478bd9Sstevel@tonic-gate goto cant; 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate rewind(fin); 3137c478bd9Sstevel@tonic-gate #ifdef preSVr4 3147c478bd9Sstevel@tonic-gate putc(getc(fin), fout); 3157c478bd9Sstevel@tonic-gate while (fgets(line, sizeof line, fin)) { 3167c478bd9Sstevel@tonic-gate if (!strncmp(line, "From ", 5)) 3177c478bd9Sstevel@tonic-gate putc('>', fout); 3187c478bd9Sstevel@tonic-gate fputs(line, fout); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate #else 3217c478bd9Sstevel@tonic-gate while ((c = getc(fin)) != EOF) 3227c478bd9Sstevel@tonic-gate putc(c, fout); 3237c478bd9Sstevel@tonic-gate #endif 3247c478bd9Sstevel@tonic-gate putc('\n', fout); 3257c478bd9Sstevel@tonic-gate fflush(fout); 3267c478bd9Sstevel@tonic-gate if (fferror(fout)) 3277c478bd9Sstevel@tonic-gate senderr++, perror(fname); 3287c478bd9Sstevel@tonic-gate fclose(fout); 3297c478bd9Sstevel@tonic-gate fclose(fin); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate cant: 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * In days of old we removed the entry from the 3347c478bd9Sstevel@tonic-gate * the list; now for sake of header expansion 3357c478bd9Sstevel@tonic-gate * we leave it in and mark it as deleted. 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate #ifdef CRAZYWOW 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate register struct name *t, *x; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate if (np == top) { 3437c478bd9Sstevel@tonic-gate top = np->n_flink; 3447c478bd9Sstevel@tonic-gate if (top != NIL) 3457c478bd9Sstevel@tonic-gate top->n_blink = NIL; 3467c478bd9Sstevel@tonic-gate np = top; 3477c478bd9Sstevel@tonic-gate continue; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate x = np->n_blink; 3507c478bd9Sstevel@tonic-gate t = np->n_flink; 3517c478bd9Sstevel@tonic-gate x->n_flink = t; 3527c478bd9Sstevel@tonic-gate if (t != NIL) 3537c478bd9Sstevel@tonic-gate t->n_blink = x; 3547c478bd9Sstevel@tonic-gate np = t; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate #endif 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate np->n_type |= GDEL; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate if (image >= 0) { 3617c478bd9Sstevel@tonic-gate close(image); 3627c478bd9Sstevel@tonic-gate image = -1; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate return(nout); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Determine if the passed address is a local "send to file" address. 3697c478bd9Sstevel@tonic-gate * If any of the network metacharacters precedes any slashes, it can't 3707c478bd9Sstevel@tonic-gate * be a filename. We cheat with .'s to allow path names like ./... 3717c478bd9Sstevel@tonic-gate * If "fcc" has been unset, then short-circuit those tests, but not 3727c478bd9Sstevel@tonic-gate * the +... test. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate static int 3757c478bd9Sstevel@tonic-gate isfileaddr(char *name) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate register char *cp; 3787c478bd9Sstevel@tonic-gate char *fcc = value("fcc"); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (any('@', name)) 3817c478bd9Sstevel@tonic-gate return(0); 3827c478bd9Sstevel@tonic-gate if (*name == '+') 3837c478bd9Sstevel@tonic-gate return(1); 3847c478bd9Sstevel@tonic-gate if (fcc == NOSTR) 3857c478bd9Sstevel@tonic-gate return(0); 3867c478bd9Sstevel@tonic-gate for (cp = name; *cp; cp++) { 3877c478bd9Sstevel@tonic-gate if (*cp == '.') 3887c478bd9Sstevel@tonic-gate continue; 3897c478bd9Sstevel@tonic-gate if (any(*cp, metanet)) 3907c478bd9Sstevel@tonic-gate return(0); 3917c478bd9Sstevel@tonic-gate if (*cp == '/') 3927c478bd9Sstevel@tonic-gate return(1); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate return(0); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Map all of the aliased users in the invoker's mailrc 3997c478bd9Sstevel@tonic-gate * file and insert them into the list. 4007c478bd9Sstevel@tonic-gate * Changed after all these months of service to recursively 4017c478bd9Sstevel@tonic-gate * expand names (2/14/80). 4027c478bd9Sstevel@tonic-gate */ 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate struct name * 4057c478bd9Sstevel@tonic-gate usermap(struct name *names) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate register struct name *newnames, *np, *cp; 4087c478bd9Sstevel@tonic-gate struct grouphead *gh; 4097c478bd9Sstevel@tonic-gate register int metoo; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate newnames = NIL; 4127c478bd9Sstevel@tonic-gate np = names; 4137c478bd9Sstevel@tonic-gate metoo = (value("metoo") != NOSTR); 4147c478bd9Sstevel@tonic-gate while (np != NIL) { 4157c478bd9Sstevel@tonic-gate if (np->n_name[0] == '\\') { 4167c478bd9Sstevel@tonic-gate cp = np->n_flink; 4177c478bd9Sstevel@tonic-gate newnames = put(newnames, np); 4187c478bd9Sstevel@tonic-gate np = cp; 4197c478bd9Sstevel@tonic-gate continue; 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate gh = findgroup(np->n_name); 4227c478bd9Sstevel@tonic-gate cp = np->n_flink; 4237c478bd9Sstevel@tonic-gate if (gh != NOGRP) 4247c478bd9Sstevel@tonic-gate newnames = gexpand(newnames, gh, metoo, np->n_type); 4257c478bd9Sstevel@tonic-gate else 4267c478bd9Sstevel@tonic-gate newnames = put(newnames, np); 4277c478bd9Sstevel@tonic-gate np = cp; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate return(newnames); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * Recursively expand a group name. We limit the expansion to some 4347c478bd9Sstevel@tonic-gate * fixed level to keep things from going haywire. 4357c478bd9Sstevel@tonic-gate * Direct recursion is not expanded for convenience. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate static struct name * 4397c478bd9Sstevel@tonic-gate gexpand(struct name *nlist, struct grouphead *gh, int metoo, int arg_ntype) 4407c478bd9Sstevel@tonic-gate { 4417c478bd9Sstevel@tonic-gate short ntype = (short)arg_ntype; 4427c478bd9Sstevel@tonic-gate struct mgroup *gp; 4437c478bd9Sstevel@tonic-gate struct grouphead *ngh; 4447c478bd9Sstevel@tonic-gate struct name *np; 4457c478bd9Sstevel@tonic-gate static int depth; 4467c478bd9Sstevel@tonic-gate register char *cp; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate if (depth > MAXEXP) { 4497c478bd9Sstevel@tonic-gate printf(gettext("Expanding alias to depth larger than %d\n"), 4507c478bd9Sstevel@tonic-gate MAXEXP); 4517c478bd9Sstevel@tonic-gate return(nlist); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate depth++; 4547c478bd9Sstevel@tonic-gate for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { 4557c478bd9Sstevel@tonic-gate cp = gp->ge_name; 4567c478bd9Sstevel@tonic-gate if (*cp == '\\') 4577c478bd9Sstevel@tonic-gate goto quote; 4587c478bd9Sstevel@tonic-gate if (strcmp(cp, gh->g_name) == 0) 4597c478bd9Sstevel@tonic-gate goto quote; 4607c478bd9Sstevel@tonic-gate if ((ngh = findgroup(cp)) != NOGRP) { 4617c478bd9Sstevel@tonic-gate nlist = gexpand(nlist, ngh, metoo, ntype); 4627c478bd9Sstevel@tonic-gate continue; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate quote: 4657c478bd9Sstevel@tonic-gate np = nalloc(cp); 4667c478bd9Sstevel@tonic-gate np->n_type = ntype; 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * At this point should allow to expand 4697c478bd9Sstevel@tonic-gate * to self if only person in group 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate if (gp == gh->g_list && gp->ge_link == NOGE) 4727c478bd9Sstevel@tonic-gate goto skip; 4737c478bd9Sstevel@tonic-gate if (!metoo && samebody(myname, gp->ge_name, FALSE)) 4747c478bd9Sstevel@tonic-gate np->n_type |= GDEL; 4757c478bd9Sstevel@tonic-gate skip: 4767c478bd9Sstevel@tonic-gate nlist = put(nlist, np); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate depth--; 4797c478bd9Sstevel@tonic-gate return(nlist); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Normalize a network name for comparison purposes. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate static char * 4867c478bd9Sstevel@tonic-gate norm(register char *user, register char *ubuf, int nbangs) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate register char *cp; 4897c478bd9Sstevel@tonic-gate int inubuf = 0; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate while (*user++ == '!'); 4927c478bd9Sstevel@tonic-gate user--; 4937c478bd9Sstevel@tonic-gate if (!strchr(user, '!')) { 4947c478bd9Sstevel@tonic-gate snprintf(ubuf, BUFSIZ, "%s!%s", host, user); 4957c478bd9Sstevel@tonic-gate user = ubuf; 4967c478bd9Sstevel@tonic-gate inubuf++; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate if (nbangs) { 4997c478bd9Sstevel@tonic-gate cp = user + strlen(user); 5007c478bd9Sstevel@tonic-gate while (nbangs--) 5017c478bd9Sstevel@tonic-gate while (cp > user && *--cp != '!'); 5027c478bd9Sstevel@tonic-gate user = (cp > user) ? ++cp : cp; 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate * Now strip off all Internet-type 5057c478bd9Sstevel@tonic-gate * hosts. 5067c478bd9Sstevel@tonic-gate */ 5077c478bd9Sstevel@tonic-gate if ((cp = strchr(user, '%')) == NOSTR) 5087c478bd9Sstevel@tonic-gate cp = strchr(user, '@'); 5097c478bd9Sstevel@tonic-gate if (cp != NOSTR) { 5107c478bd9Sstevel@tonic-gate if (!inubuf) { 5117c478bd9Sstevel@tonic-gate strncpy(ubuf, user, cp - user); 5127c478bd9Sstevel@tonic-gate ubuf[cp - user] = '\0'; 5137c478bd9Sstevel@tonic-gate user = ubuf; 5147c478bd9Sstevel@tonic-gate } else 5157c478bd9Sstevel@tonic-gate *cp = '\0'; 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate return user; 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * Implement allnet options. 5237c478bd9Sstevel@tonic-gate */ 5247c478bd9Sstevel@tonic-gate int 5257c478bd9Sstevel@tonic-gate samebody(register char *user, register char *addr, int fuzzy) 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate char ubuf[BUFSIZ], abuf[BUFSIZ]; 5287c478bd9Sstevel@tonic-gate char *allnet = value("allnet"); 5297c478bd9Sstevel@tonic-gate int nbangs = allnet ? !strcmp(allnet, "uucp") ? 2 : 1 : 0; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if (fuzzy && value("fuzzymatch")) { 5327c478bd9Sstevel@tonic-gate int i; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate (void) strlcpy(ubuf, user, BUFSIZ); 5357c478bd9Sstevel@tonic-gate for (i = 0; ubuf[i]; i++) 5367c478bd9Sstevel@tonic-gate ubuf[i] = tolower(ubuf[i]); 5377c478bd9Sstevel@tonic-gate (void) strlcpy(abuf, addr, BUFSIZ); 5387c478bd9Sstevel@tonic-gate for (i = 0; abuf[i]; i++) 5397c478bd9Sstevel@tonic-gate abuf[i] = tolower(abuf[i]); 5407c478bd9Sstevel@tonic-gate return (strstr(abuf, ubuf) != NOSTR); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate user = norm(user, ubuf, nbangs); 5437c478bd9Sstevel@tonic-gate addr = norm(addr, abuf, nbangs); 5447c478bd9Sstevel@tonic-gate return strcmp(user, addr) == 0; 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* 5487c478bd9Sstevel@tonic-gate * Compute the length of the passed name list and 5497c478bd9Sstevel@tonic-gate * return it. 5507c478bd9Sstevel@tonic-gate */ 5517c478bd9Sstevel@tonic-gate static int 5527c478bd9Sstevel@tonic-gate lengthof(struct name *name) 5537c478bd9Sstevel@tonic-gate { 5547c478bd9Sstevel@tonic-gate register struct name *np; 5557c478bd9Sstevel@tonic-gate register int c; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate for (c = 0, np = name; np != NIL; c++, np = np->n_flink) 5587c478bd9Sstevel@tonic-gate ; 5597c478bd9Sstevel@tonic-gate return(c); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* 5637c478bd9Sstevel@tonic-gate * Concatenate the two passed name lists, return the result. 5647c478bd9Sstevel@tonic-gate */ 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate struct name * 5677c478bd9Sstevel@tonic-gate cat(struct name *n1, struct name *n2) 5687c478bd9Sstevel@tonic-gate { 5697c478bd9Sstevel@tonic-gate register struct name *tail; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate if (n1 == NIL) 5727c478bd9Sstevel@tonic-gate return(n2); 5737c478bd9Sstevel@tonic-gate if (n2 == NIL) 5747c478bd9Sstevel@tonic-gate return(n1); 5757c478bd9Sstevel@tonic-gate tail = tailof(n1); 5767c478bd9Sstevel@tonic-gate tail->n_flink = n2; 5777c478bd9Sstevel@tonic-gate n2->n_blink = tail; 5787c478bd9Sstevel@tonic-gate return(n1); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * Unpack the name list onto a vector of strings. 5837c478bd9Sstevel@tonic-gate * Return an error if the name list won't fit. 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate char ** 5877c478bd9Sstevel@tonic-gate unpack(struct name *np) 5887c478bd9Sstevel@tonic-gate { 5897c478bd9Sstevel@tonic-gate register char **ap, **top; 5907c478bd9Sstevel@tonic-gate register struct name *n; 5917c478bd9Sstevel@tonic-gate char hbuf[10]; 5927c478bd9Sstevel@tonic-gate int t, extra, metoo, verbose; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate n = np; 5957c478bd9Sstevel@tonic-gate if ((t = lengthof(n)) == 0) 5967c478bd9Sstevel@tonic-gate panic("No names to unpack"); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * Compute the number of extra arguments we will need. 6007c478bd9Sstevel@tonic-gate * We need at least 2 extra -- one for "mail" and one for 6017c478bd9Sstevel@tonic-gate * the terminating 0 pointer. 6027c478bd9Sstevel@tonic-gate * Additional spots may be needed to pass along -r and -f to 6037c478bd9Sstevel@tonic-gate * the host mailer. 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate extra = 2; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if (rflag != NOSTR) 6097c478bd9Sstevel@tonic-gate extra += 2; 6107c478bd9Sstevel@tonic-gate #ifdef SENDMAIL 6117c478bd9Sstevel@tonic-gate extra++; 6127c478bd9Sstevel@tonic-gate metoo = value("metoo") != NOSTR; 6137c478bd9Sstevel@tonic-gate if (metoo) 6147c478bd9Sstevel@tonic-gate extra++; 6157c478bd9Sstevel@tonic-gate verbose = value("verbose") != NOSTR; 6167c478bd9Sstevel@tonic-gate if (verbose) 6177c478bd9Sstevel@tonic-gate extra++; 6187c478bd9Sstevel@tonic-gate if (hflag) 6197c478bd9Sstevel@tonic-gate extra += 2; 620*6c83d09fSrobbin #endif /* SENDMAIL */ 6217c478bd9Sstevel@tonic-gate top = (char **) salloc((t + extra) * sizeof (char *)); 6227c478bd9Sstevel@tonic-gate ap = top; 6237c478bd9Sstevel@tonic-gate *ap++ = "mail"; 6247c478bd9Sstevel@tonic-gate if (rflag != NOSTR) { 6257c478bd9Sstevel@tonic-gate *ap++ = "-r"; 6267c478bd9Sstevel@tonic-gate *ap++ = rflag; 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate #ifdef SENDMAIL 6297c478bd9Sstevel@tonic-gate *ap++ = "-i"; 6307c478bd9Sstevel@tonic-gate if (metoo) 6317c478bd9Sstevel@tonic-gate *ap++ = "-m"; 6327c478bd9Sstevel@tonic-gate if (verbose) 6337c478bd9Sstevel@tonic-gate *ap++ = "-v"; 6347c478bd9Sstevel@tonic-gate if (hflag) { 6357c478bd9Sstevel@tonic-gate *ap++ = "-h"; 6367c478bd9Sstevel@tonic-gate snprintf(hbuf, sizeof (hbuf), "%d", hflag); 6377c478bd9Sstevel@tonic-gate *ap++ = savestr(hbuf); 6387c478bd9Sstevel@tonic-gate } 639*6c83d09fSrobbin #endif /* SENDMAIL */ 6407c478bd9Sstevel@tonic-gate while (n != NIL) { 6417c478bd9Sstevel@tonic-gate if (n->n_type & GDEL) { 6427c478bd9Sstevel@tonic-gate n = n->n_flink; 6437c478bd9Sstevel@tonic-gate continue; 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate *ap++ = n->n_name; 6467c478bd9Sstevel@tonic-gate n = n->n_flink; 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate *ap = NOSTR; 6497c478bd9Sstevel@tonic-gate return(top); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* 6537c478bd9Sstevel@tonic-gate * See if the user named himself as a destination 6547c478bd9Sstevel@tonic-gate * for outgoing mail. If so, set the global flag 6557c478bd9Sstevel@tonic-gate * selfsent so that we avoid removing his mailbox. 6567c478bd9Sstevel@tonic-gate */ 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate void 6597c478bd9Sstevel@tonic-gate mechk(struct name *names) 6607c478bd9Sstevel@tonic-gate { 6617c478bd9Sstevel@tonic-gate register struct name *np; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate for (np = names; np != NIL; np = np->n_flink) 6647c478bd9Sstevel@tonic-gate if ((np->n_type & GDEL) == 0 && 6657c478bd9Sstevel@tonic-gate samebody(np->n_name, myname, FALSE)) { 6667c478bd9Sstevel@tonic-gate selfsent++; 6677c478bd9Sstevel@tonic-gate return; 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * Remove all of the duplicates from the passed name list by 6737c478bd9Sstevel@tonic-gate * insertion sorting them, then checking for dups. 6747c478bd9Sstevel@tonic-gate * Return the head of the new list. 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate struct name * 6787c478bd9Sstevel@tonic-gate elide(struct name *names) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate register struct name *np, *t, *newnames; 6817c478bd9Sstevel@tonic-gate struct name *x; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate if (names == NIL) 6847c478bd9Sstevel@tonic-gate return(NIL); 6857c478bd9Sstevel@tonic-gate newnames = names; 6867c478bd9Sstevel@tonic-gate np = names; 6877c478bd9Sstevel@tonic-gate np = np->n_flink; 6887c478bd9Sstevel@tonic-gate if (np != NIL) 6897c478bd9Sstevel@tonic-gate np->n_blink = NIL; 6907c478bd9Sstevel@tonic-gate newnames->n_flink = NIL; 6917c478bd9Sstevel@tonic-gate while (np != NIL) { 6927c478bd9Sstevel@tonic-gate t = newnames; 6937c478bd9Sstevel@tonic-gate while (strcmp(t->n_name, np->n_name) < 0) { 6947c478bd9Sstevel@tonic-gate if (t->n_flink == NIL) 6957c478bd9Sstevel@tonic-gate break; 6967c478bd9Sstevel@tonic-gate t = t->n_flink; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * If we ran out of t's, put the new entry after 7017c478bd9Sstevel@tonic-gate * the current value of t. 7027c478bd9Sstevel@tonic-gate */ 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate if (strcmp(t->n_name, np->n_name) < 0) { 7057c478bd9Sstevel@tonic-gate t->n_flink = np; 7067c478bd9Sstevel@tonic-gate np->n_blink = t; 7077c478bd9Sstevel@tonic-gate t = np; 7087c478bd9Sstevel@tonic-gate np = np->n_flink; 7097c478bd9Sstevel@tonic-gate t->n_flink = NIL; 7107c478bd9Sstevel@tonic-gate continue; 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* 7147c478bd9Sstevel@tonic-gate * Otherwise, put the new entry in front of the 7157c478bd9Sstevel@tonic-gate * current t. If at the front of the list, 7167c478bd9Sstevel@tonic-gate * the new guy becomes the new head of the list. 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate if (t == newnames) { 7207c478bd9Sstevel@tonic-gate t = np; 7217c478bd9Sstevel@tonic-gate np = np->n_flink; 7227c478bd9Sstevel@tonic-gate t->n_flink = newnames; 7237c478bd9Sstevel@tonic-gate newnames->n_blink = t; 7247c478bd9Sstevel@tonic-gate t->n_blink = NIL; 7257c478bd9Sstevel@tonic-gate newnames = t; 7267c478bd9Sstevel@tonic-gate continue; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * The normal case -- we are inserting into the 7317c478bd9Sstevel@tonic-gate * middle of the list. 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate x = np; 7357c478bd9Sstevel@tonic-gate np = np->n_flink; 7367c478bd9Sstevel@tonic-gate x->n_flink = t; 7377c478bd9Sstevel@tonic-gate x->n_blink = t->n_blink; 7387c478bd9Sstevel@tonic-gate t->n_blink->n_flink = x; 7397c478bd9Sstevel@tonic-gate t->n_blink = x; 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* 7437c478bd9Sstevel@tonic-gate * Now the list headed up by new is sorted. 7447c478bd9Sstevel@tonic-gate * Go through it and remove duplicates. 7457c478bd9Sstevel@tonic-gate * Remember the best "type" among all the 7467c478bd9Sstevel@tonic-gate * duplicates of a name. 7477c478bd9Sstevel@tonic-gate */ 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate np = newnames; 7507c478bd9Sstevel@tonic-gate while (np != NIL) { 7517c478bd9Sstevel@tonic-gate int type; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate t = np; 7547c478bd9Sstevel@tonic-gate type = np->n_type; 7557c478bd9Sstevel@tonic-gate while (t->n_flink!=NIL && 7567c478bd9Sstevel@tonic-gate strcmp(np->n_name, t->n_flink->n_name) == 0) { 7577c478bd9Sstevel@tonic-gate t = t->n_flink; 7587c478bd9Sstevel@tonic-gate /* "To" before "Cc" before "Bcc" */ 7597c478bd9Sstevel@tonic-gate if (t->n_type < type) 7607c478bd9Sstevel@tonic-gate type = t->n_type; 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate if (t == np || t == NIL) { 7637c478bd9Sstevel@tonic-gate np = np->n_flink; 7647c478bd9Sstevel@tonic-gate continue; 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * Now t points to the last entry with the same name 7697c478bd9Sstevel@tonic-gate * as np. Make np point beyond t. 7707c478bd9Sstevel@tonic-gate */ 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate np->n_flink = t->n_flink; 7737c478bd9Sstevel@tonic-gate if (t->n_flink != NIL) 7747c478bd9Sstevel@tonic-gate t->n_flink->n_blink = np; 7757c478bd9Sstevel@tonic-gate np->n_type = type; 7767c478bd9Sstevel@tonic-gate np = np->n_flink; 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate return(newnames); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* 7827c478bd9Sstevel@tonic-gate * Put another node onto a list of names and return 7837c478bd9Sstevel@tonic-gate * the list. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate static struct name * 7877c478bd9Sstevel@tonic-gate put(struct name *list, struct name *node) 7887c478bd9Sstevel@tonic-gate { 7897c478bd9Sstevel@tonic-gate node->n_flink = list; 7907c478bd9Sstevel@tonic-gate node->n_blink = NIL; 7917c478bd9Sstevel@tonic-gate if (list != NIL) 7927c478bd9Sstevel@tonic-gate list->n_blink = node; 7937c478bd9Sstevel@tonic-gate return(node); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* 7987c478bd9Sstevel@tonic-gate * Delete the given name from a namelist. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate struct name * 8017c478bd9Sstevel@tonic-gate delname(register struct name *np, char name[]) 8027c478bd9Sstevel@tonic-gate { 8037c478bd9Sstevel@tonic-gate register struct name *p; 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate for (p = np; p != NIL; p = p->n_flink) 8067c478bd9Sstevel@tonic-gate if (samebody(name, p->n_name, FALSE)) { 8077c478bd9Sstevel@tonic-gate if (p->n_blink == NIL) { 8087c478bd9Sstevel@tonic-gate if (p->n_flink != NIL) 8097c478bd9Sstevel@tonic-gate p->n_flink->n_blink = NIL; 8107c478bd9Sstevel@tonic-gate np = p->n_flink; 8117c478bd9Sstevel@tonic-gate continue; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate if (p->n_flink == NIL) { 8147c478bd9Sstevel@tonic-gate if (p->n_blink != NIL) 8157c478bd9Sstevel@tonic-gate p->n_blink->n_flink = NIL; 8167c478bd9Sstevel@tonic-gate continue; 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate p->n_blink->n_flink = p->n_flink; 8197c478bd9Sstevel@tonic-gate p->n_flink->n_blink = p->n_blink; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate return(np); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate /* 8257c478bd9Sstevel@tonic-gate * Call the given routine on each element of the name 8267c478bd9Sstevel@tonic-gate * list, replacing said value if need be. 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate void 8307c478bd9Sstevel@tonic-gate mapf(register struct name *np, char *from) 8317c478bd9Sstevel@tonic-gate { 8327c478bd9Sstevel@tonic-gate register struct name *p; 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate if (debug) fprintf(stderr, "mapf %lx, %s\n", (long)np, from); 8357c478bd9Sstevel@tonic-gate for (p = np; p != NIL; p = p->n_flink) 8367c478bd9Sstevel@tonic-gate if ((p->n_type & GDEL) == 0) { 8377c478bd9Sstevel@tonic-gate p->n_name = netmap(p->n_name, from); 8387c478bd9Sstevel@tonic-gate p->n_full = splice(p->n_name, p->n_full); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate if (debug) fprintf(stderr, "mapf %s done\n", from); 8417c478bd9Sstevel@tonic-gate } 842