names.c revision 216564
1139749Simp/* 297883Sgibbs * Copyright (c) 1980, 1993 397883Sgibbs * The Regents of the University of California. All rights reserved. 4133122Sgibbs * 5102681Sgibbs * Redistribution and use in source and binary forms, with or without 697883Sgibbs * modification, are permitted provided that the following conditions 797883Sgibbs * are met: 897883Sgibbs * 1. Redistributions of source code must retain the above copyright 997883Sgibbs * notice, this list of conditions and the following disclaimer. 1097883Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1197883Sgibbs * notice, this list of conditions and the following disclaimer in the 1297883Sgibbs * documentation and/or other materials provided with the distribution. 1397883Sgibbs * 4. Neither the name of the University nor the names of its contributors 1497883Sgibbs * may be used to endorse or promote products derived from this software 1597883Sgibbs * without specific prior written permission. 1697883Sgibbs * 1797883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1897883Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1997883Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2097883Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2197883Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2297883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2397883Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2497883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2597883Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2697883Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2797883Sgibbs * SUCH DAMAGE. 2897883Sgibbs */ 2997883Sgibbs 3097883Sgibbs#ifndef lint 3197883Sgibbs#if 0 3297883Sgibbsstatic char sccsid[] = "@(#)names.c 8.1 (Berkeley) 6/6/93"; 3397883Sgibbs#endif 3497883Sgibbs#endif /* not lint */ 3597883Sgibbs#include <sys/cdefs.h> 3697883Sgibbs__FBSDID("$FreeBSD: head/usr.bin/mail/names.c 216564 2010-12-19 16:25:23Z charnier $"); 3797883Sgibbs 3897883Sgibbs/* 3997883Sgibbs * Mail -- a mail program 4097883Sgibbs * 4197883Sgibbs * Handle name lists. 42129134Sgibbs */ 4397883Sgibbs 4497883Sgibbs#include "rcv.h" 4597883Sgibbs#include <fcntl.h> 4697883Sgibbs#include "extern.h" 4797883Sgibbs 4897883Sgibbs/* 4997883Sgibbs * Allocate a single element of a name list, 5097883Sgibbs * initialize its name field to the passed 5197883Sgibbs * name and return it. 5297883Sgibbs */ 5397883Sgibbsstruct name * 5497883Sgibbsnalloc(char str[], int ntype) 5597883Sgibbs{ 5697883Sgibbs struct name *np; 5797883Sgibbs 5897883Sgibbs np = (struct name *)salloc(sizeof(*np)); 59104023Sgibbs np->n_flink = NULL; 60104023Sgibbs np->n_blink = NULL; 61104023Sgibbs np->n_type = ntype; 62104023Sgibbs np->n_name = savestr(str); 63104023Sgibbs return (np); 64104023Sgibbs} 65104023Sgibbs 66104023Sgibbs/* 6797883Sgibbs * Find the tail of a list and return it. 68107441Sscottl */ 69107441Sscottlstruct name * 70107441Sscottltailof(struct name *name) 71107441Sscottl{ 72107441Sscottl struct name *np; 73107441Sscottl 74104023Sgibbs np = name; 75107441Sscottl if (np == NULL) 76107441Sscottl return (NULL); 77107441Sscottl while (np->n_flink != NULL) 78107441Sscottl np = np->n_flink; 79107441Sscottl return (np); 80107441Sscottl} 81107441Sscottl 8297883Sgibbs/* 8397883Sgibbs * Extract a list of names from a line, 8497883Sgibbs * and make a list of names from it. 8597883Sgibbs * Return the list or NULL if none found. 8697883Sgibbs */ 8797883Sgibbsstruct name * 8897883Sgibbsextract(char line[], int ntype) 8997883Sgibbs{ 9097883Sgibbs char *cp, *nbuf; 91102681Sgibbs struct name *top, *np, *t; 92102681Sgibbs 9397883Sgibbs if (line == NULL || *line == '\0') 9497883Sgibbs return (NULL); 9597883Sgibbs if ((nbuf = malloc(strlen(line) + 1)) == NULL) 9697883Sgibbs err(1, "Out of memory"); 9797883Sgibbs top = NULL; 9897883Sgibbs np = NULL; 9997883Sgibbs cp = line; 10097883Sgibbs while ((cp = yankword(cp, nbuf)) != NULL) { 10197883Sgibbs t = nalloc(nbuf, ntype); 10297883Sgibbs if (top == NULL) 10397883Sgibbs top = t; 10497883Sgibbs else 105102681Sgibbs np->n_flink = t; 106102681Sgibbs t->n_blink = np; 107102681Sgibbs np = t; 108102681Sgibbs } 109102681Sgibbs (void)free(nbuf); 110102681Sgibbs return (top); 111102681Sgibbs} 112102681Sgibbs 11397883Sgibbs/* 11497883Sgibbs * Turn a list of names into a string of the same names. 11597883Sgibbs */ 11697883Sgibbschar * 11797883Sgibbsdetract(struct name *np, int ntype) 11897883Sgibbs{ 11997883Sgibbs int s, comma; 12097883Sgibbs char *cp, *top; 12197883Sgibbs struct name *p; 122102681Sgibbs 123107441Sscottl comma = ntype & GCOMMA; 124107441Sscottl if (np == NULL) 125102681Sgibbs return (NULL); 126102681Sgibbs ntype &= ~GCOMMA; 127102681Sgibbs s = 0; 128102681Sgibbs if (debug && comma) 129102681Sgibbs fprintf(stderr, "detract asked to insert commas\n"); 13097883Sgibbs for (p = np; p != NULL; p = p->n_flink) { 13197883Sgibbs if (ntype && (p->n_type & GMASK) != ntype) 13297883Sgibbs continue; 13397883Sgibbs s += strlen(p->n_name) + 1; 13497883Sgibbs if (comma) 13597883Sgibbs s++; 136102681Sgibbs } 13797883Sgibbs if (s == 0) 13897883Sgibbs return (NULL); 13997883Sgibbs s += 2; 14097883Sgibbs top = salloc(s); 14197883Sgibbs cp = top; 14297883Sgibbs for (p = np; p != NULL; p = p->n_flink) { 14397883Sgibbs if (ntype && (p->n_type & GMASK) != ntype) 14497883Sgibbs continue; 145102681Sgibbs cp += strlcpy(cp, p->n_name, strlen(p->n_name) + 1); 146102681Sgibbs if (comma && p->n_flink != NULL) 14797883Sgibbs *cp++ = ','; 14897883Sgibbs *cp++ = ' '; 14997883Sgibbs } 15097883Sgibbs *--cp = '\0'; 151102681Sgibbs if (comma && *--cp == ',') 15297883Sgibbs *cp = '\0'; 15397883Sgibbs return (top); 15497883Sgibbs} 15597883Sgibbs 156102681Sgibbs/* 15797883Sgibbs * Grab a single word (liberal word) 15897883Sgibbs * Throw away things between ()'s, and take anything between <>. 15997883Sgibbs */ 16097883Sgibbschar * 16197883Sgibbsyankword(char *ap, char wbuf[]) 162102681Sgibbs{ 163102681Sgibbs char *cp, *cp2; 164102681Sgibbs 165102681Sgibbs cp = ap; 166102681Sgibbs for (;;) { 167102681Sgibbs if (*cp == '\0') 168107441Sscottl return (NULL); 169109588Sgibbs if (*cp == '(') { 170109588Sgibbs int nesting = 0; 171109588Sgibbs 172109588Sgibbs while (*cp != '\0') { 173109588Sgibbs switch (*cp++) { 174109588Sgibbs case '(': 175109588Sgibbs nesting++; 176109588Sgibbs break; 177109588Sgibbs case ')': 178109588Sgibbs --nesting; 179109588Sgibbs break; 180109588Sgibbs } 181109588Sgibbs if (nesting <= 0) 182109588Sgibbs break; 183109588Sgibbs } 184109588Sgibbs } else if (*cp == ' ' || *cp == '\t' || *cp == ',') 185109588Sgibbs cp++; 186107441Sscottl else 187107441Sscottl break; 188107441Sscottl } 189107441Sscottl if (*cp == '<') 190114623Sgibbs for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';) 191114623Sgibbs ; 192102681Sgibbs else 19397883Sgibbs for (cp2 = wbuf; *cp != '\0' && strchr(" \t,(", *cp) == NULL; 19497883Sgibbs *cp2++ = *cp++) 19597883Sgibbs ; 19697883Sgibbs *cp2 = '\0'; 19797883Sgibbs return (cp); 19897883Sgibbs} 19997883Sgibbs 20097883Sgibbs/* 201102681Sgibbs * Grab a single login name (liberal word) 202102681Sgibbs * Throw away things between ()'s, take anything between <>, 203102681Sgibbs * and look for words before metacharacters %, @, !. 204107623Sscottl */ 205102681Sgibbschar * 206102681Sgibbsyanklogin(char *ap, char wbuf[]) 207102681Sgibbs{ 208102681Sgibbs char *cp, *cp2, *cp_temp; 20997883Sgibbs int n; 21097883Sgibbs 21197883Sgibbs cp = ap; 21297883Sgibbs for (;;) { 21397883Sgibbs if (*cp == '\0') 21497883Sgibbs return (NULL); 21597883Sgibbs if (*cp == '(') { 21697883Sgibbs int nesting = 0; 217102681Sgibbs 218102681Sgibbs while (*cp != '\0') { 219102681Sgibbs switch (*cp++) { 220102681Sgibbs case '(': 221102681Sgibbs nesting++; 222102681Sgibbs break; 223102681Sgibbs case ')': 22497883Sgibbs --nesting; 22597883Sgibbs break; 22697883Sgibbs } 22797883Sgibbs if (nesting <= 0) 22897883Sgibbs break; 22997883Sgibbs } 23097883Sgibbs } else if (*cp == ' ' || *cp == '\t' || *cp == ',') 23197883Sgibbs cp++; 232102681Sgibbs else 233102681Sgibbs break; 234102681Sgibbs } 235102681Sgibbs 236102681Sgibbs /* 237102681Sgibbs * Now, let's go forward till we meet the needed character, 238102681Sgibbs * and step one word back. 23997883Sgibbs */ 24097883Sgibbs 24197883Sgibbs /* First, remember current point. */ 24297883Sgibbs cp_temp = cp; 24397883Sgibbs n = 0; 24497883Sgibbs 24597883Sgibbs /* 24697883Sgibbs * Note that we look ahead in a cycle. This is safe, since 24797883Sgibbs * non-end of string is checked first. 248102681Sgibbs */ 249102681Sgibbs while(*cp != '\0' && strchr("@%!", *(cp + 1)) == NULL) 250102681Sgibbs cp++; 251102681Sgibbs 252102681Sgibbs /* 253102681Sgibbs * Now, start stepping back to the first non-word character, 254102681Sgibbs * while counting the number of symbols in a word. 255102681Sgibbs */ 25697883Sgibbs while(cp != cp_temp && strchr(" \t,<>", *(cp - 1)) == NULL) { 25797883Sgibbs n++; 25897883Sgibbs cp--; 25997883Sgibbs } 26097883Sgibbs 26197883Sgibbs /* Finally, grab the word forward. */ 26297883Sgibbs cp2 = wbuf; 26397883Sgibbs while(n >= 0) { 26497883Sgibbs *cp2++=*cp++; 26597883Sgibbs n--; 26697883Sgibbs } 26797883Sgibbs 26897883Sgibbs *cp2 = '\0'; 26997883Sgibbs return (cp); 27097883Sgibbs} 27197883Sgibbs 27297883Sgibbs/* 27397883Sgibbs * For each recipient in the passed name list with a / 27497883Sgibbs * in the name, append the message to the end of the named file 27597883Sgibbs * and remove him from the recipient list. 27697883Sgibbs * 27797883Sgibbs * Recipients whose name begins with | are piped through the given 27897883Sgibbs * program and removed. 279109588Sgibbs */ 28097883Sgibbsstruct name * 28197883Sgibbsoutof(struct name *names, FILE *fo, struct header *hp) 282115329Sgibbs{ 28397883Sgibbs int c, ispipe; 28497883Sgibbs struct name *np, *top; 28597883Sgibbs time_t now; 28697883Sgibbs char *date, *fname; 28797883Sgibbs FILE *fout, *fin; 28897883Sgibbs 289109588Sgibbs top = names; 29097883Sgibbs np = names; 291102681Sgibbs (void)time(&now); 292102681Sgibbs date = ctime(&now); 293102681Sgibbs while (np != NULL) { 294102681Sgibbs if (!isfileaddr(np->n_name) && np->n_name[0] != '|') { 295102681Sgibbs np = np->n_flink; 29697883Sgibbs continue; 29797883Sgibbs } 29897883Sgibbs ispipe = np->n_name[0] == '|'; 29997883Sgibbs if (ispipe) 30097883Sgibbs fname = np->n_name+1; 30197883Sgibbs else 302109588Sgibbs fname = expand(np->n_name); 30397883Sgibbs 304102681Sgibbs /* 305102681Sgibbs * See if we have copied the complete message out yet. 306102681Sgibbs * If not, do so. 307102681Sgibbs */ 308102681Sgibbs 30997883Sgibbs if (image < 0) { 31097883Sgibbs int fd; 31197883Sgibbs char tempname[PATHSIZE]; 31297883Sgibbs 31397883Sgibbs (void)snprintf(tempname, sizeof(tempname), 31497883Sgibbs "%s/mail.ReXXXXXXXXXX", tmpdir); 315109588Sgibbs if ((fd = mkstemp(tempname)) == -1 || 31697883Sgibbs (fout = Fdopen(fd, "a")) == NULL) { 31797883Sgibbs warn("%s", tempname); 31897883Sgibbs senderr++; 31997883Sgibbs goto cant; 32097883Sgibbs } 32197883Sgibbs image = open(tempname, O_RDWR); 32297883Sgibbs (void)rm(tempname); 32397883Sgibbs if (image < 0) { 32497883Sgibbs warn("%s", tempname); 32597883Sgibbs senderr++; 32697883Sgibbs (void)Fclose(fout); 32797883Sgibbs goto cant; 32897883Sgibbs } 32997883Sgibbs (void)fcntl(image, F_SETFD, 1); 33097883Sgibbs fprintf(fout, "From %s %s", myname, date); 33197883Sgibbs puthead(hp, fout, 33297883Sgibbs GTO|GSUBJECT|GCC|GREPLYTO|GINREPLYTO|GNL); 33397883Sgibbs while ((c = getc(fo)) != EOF) 33497883Sgibbs (void)putc(c, fout); 33597883Sgibbs rewind(fo); 33697883Sgibbs fprintf(fout, "\n"); 33797883Sgibbs (void)fflush(fout); 33897883Sgibbs if (ferror(fout)) { 33997883Sgibbs warn("%s", tempname); 34097883Sgibbs senderr++; 34197883Sgibbs (void)Fclose(fout); 34297883Sgibbs goto cant; 34397883Sgibbs } 34497883Sgibbs (void)Fclose(fout); 34597883Sgibbs } 34697883Sgibbs 34797883Sgibbs /* 34897883Sgibbs * Now either copy "image" to the desired file 34997883Sgibbs * or give it as the standard input to the desired 35097883Sgibbs * program as appropriate. 35197883Sgibbs */ 35297883Sgibbs 35397883Sgibbs if (ispipe) { 35497883Sgibbs int pid; 35597883Sgibbs char *sh; 356102681Sgibbs sigset_t nset; 357102681Sgibbs 358102681Sgibbs /* 359102681Sgibbs * XXX 360102681Sgibbs * We can't really reuse the same image file, 361102681Sgibbs * because multiple piped recipients will 362102681Sgibbs * share the same lseek location and trample 363102681Sgibbs * on one another. 364102681Sgibbs */ 365102681Sgibbs if ((sh = value("SHELL")) == NULL) 366102681Sgibbs sh = _PATH_CSHELL; 367102681Sgibbs (void)sigemptyset(&nset); 368102681Sgibbs (void)sigaddset(&nset, SIGHUP); 369102681Sgibbs (void)sigaddset(&nset, SIGINT); 370102681Sgibbs (void)sigaddset(&nset, SIGQUIT); 371102681Sgibbs pid = start_command(sh, &nset, image, -1, "-c", fname, 372102681Sgibbs NULL); 373102681Sgibbs if (pid < 0) { 374102681Sgibbs senderr++; 37597883Sgibbs goto cant; 37697883Sgibbs } 37797883Sgibbs free_child(pid); 37897883Sgibbs } else { 37997883Sgibbs int f; 38097883Sgibbs if ((fout = Fopen(fname, "a")) == NULL) { 38197883Sgibbs warn("%s", fname); 38297883Sgibbs senderr++; 383102681Sgibbs goto cant; 384102681Sgibbs } 385102681Sgibbs if ((f = dup(image)) < 0) { 386102681Sgibbs warn("dup"); 387102681Sgibbs fin = NULL; 388102681Sgibbs } else 389102681Sgibbs fin = Fdopen(f, "r"); 390102681Sgibbs if (fin == NULL) { 39197883Sgibbs fprintf(stderr, "Can't reopen image\n"); 39297883Sgibbs (void)Fclose(fout); 39397883Sgibbs senderr++; 39497883Sgibbs goto cant; 39597883Sgibbs } 39697883Sgibbs rewind(fin); 39797883Sgibbs while ((c = getc(fin)) != EOF) 39897883Sgibbs (void)putc(c, fout); 39997883Sgibbs if (ferror(fout)) { 400102681Sgibbs warnx("%s", fname); 401107441Sscottl senderr++; 402102681Sgibbs (void)Fclose(fout); 403102681Sgibbs (void)Fclose(fin); 404102681Sgibbs goto cant; 405102681Sgibbs } 406102681Sgibbs (void)Fclose(fout); 407102681Sgibbs (void)Fclose(fin); 408102681Sgibbs } 409102681Sgibbscant: 410102681Sgibbs /* 41197883Sgibbs * In days of old we removed the entry from the 41297883Sgibbs * the list; now for sake of header expansion 41397883Sgibbs * we leave it in and mark it as deleted. 41497883Sgibbs */ 41597883Sgibbs np->n_type |= GDEL; 41697883Sgibbs np = np->n_flink; 41797883Sgibbs } 41897883Sgibbs if (image >= 0) { 41997883Sgibbs (void)close(image); 420102681Sgibbs image = -1; 421102681Sgibbs } 422102681Sgibbs return (top); 423102681Sgibbs} 424102681Sgibbs 425102681Sgibbs/* 42697883Sgibbs * Determine if the passed address is a local "send to file" address. 42797883Sgibbs * If any of the network metacharacters precedes any slashes, it can't 42897883Sgibbs * be a filename. We cheat with .'s to allow path names like ./... 42997883Sgibbs */ 43097883Sgibbsint 43197883Sgibbsisfileaddr(char *name) 43297883Sgibbs{ 43397883Sgibbs char *cp; 43497883Sgibbs 435102681Sgibbs if (*name == '+') 436102681Sgibbs return (1); 437102681Sgibbs for (cp = name; *cp != '\0'; cp++) { 438102681Sgibbs if (*cp == '!' || *cp == '%' || *cp == '@') 439102681Sgibbs return (0); 440102681Sgibbs if (*cp == '/') 441102681Sgibbs return (1); 44297883Sgibbs } 44397883Sgibbs return (0); 44497883Sgibbs} 44597883Sgibbs 44697883Sgibbs/* 44797883Sgibbs * Map all of the aliased users in the invoker's mailrc 44897883Sgibbs * file and insert them into the list. 44997883Sgibbs * Changed after all these months of service to recursively 45097883Sgibbs * expand names (2/14/80). 451102681Sgibbs */ 452102681Sgibbs 453102681Sgibbsstruct name * 45497883Sgibbsusermap(struct name *names) 45597883Sgibbs{ 45697883Sgibbs struct name *new, *np, *cp; 45797883Sgibbs struct grouphead *gh; 45897883Sgibbs int metoo; 45997883Sgibbs 460102681Sgibbs new = NULL; 461102681Sgibbs np = names; 462102681Sgibbs metoo = (value("metoo") != NULL); 463102681Sgibbs while (np != NULL) { 46497883Sgibbs if (np->n_name[0] == '\\') { 46597883Sgibbs cp = np->n_flink; 46697883Sgibbs new = put(new, np); 46797883Sgibbs np = cp; 46897883Sgibbs continue; 46997883Sgibbs } 47097883Sgibbs gh = findgroup(np->n_name); 47197883Sgibbs cp = np->n_flink; 47297883Sgibbs if (gh != NULL) 473102681Sgibbs new = gexpand(new, gh, metoo, np->n_type); 474102681Sgibbs else 475102681Sgibbs new = put(new, np); 47697883Sgibbs np = cp; 47797883Sgibbs } 47897883Sgibbs return (new); 47997883Sgibbs} 48097883Sgibbs 48197883Sgibbs/* 48297883Sgibbs * Recursively expand a group name. We limit the expansion to some 48397883Sgibbs * fixed level to keep things from going haywire. 48497883Sgibbs * Direct recursion is not expanded for convenience. 48597883Sgibbs */ 48697883Sgibbs 48797883Sgibbsstruct name * 48897883Sgibbsgexpand(struct name *nlist, struct grouphead *gh, int metoo, int ntype) 48997883Sgibbs{ 49097883Sgibbs struct group *gp; 49197883Sgibbs struct grouphead *ngh; 49297883Sgibbs struct name *np; 49397883Sgibbs static int depth; 49497883Sgibbs char *cp; 49597883Sgibbs 49697883Sgibbs if (depth > MAXEXP) { 49797883Sgibbs printf("Expanding alias to depth larger than %d\n", MAXEXP); 49897883Sgibbs return (nlist); 499107441Sscottl } 500107441Sscottl depth++; 501107441Sscottl for (gp = gh->g_list; gp != NULL; gp = gp->ge_link) { 502107441Sscottl cp = gp->ge_name; 503107441Sscottl if (*cp == '\\') 504107441Sscottl goto quote; 505107441Sscottl if (strcmp(cp, gh->g_name) == 0) 506107441Sscottl goto quote; 507107441Sscottl if ((ngh = findgroup(cp)) != NULL) { 508107441Sscottl nlist = gexpand(nlist, ngh, metoo, ntype); 509107441Sscottl continue; 51097883Sgibbs } 51197883Sgibbsquote: 51297883Sgibbs np = nalloc(cp, ntype); 51397883Sgibbs /* 51497883Sgibbs * At this point should allow to expand 51597883Sgibbs * to self if only person in group 51697883Sgibbs */ 51797883Sgibbs if (gp == gh->g_list && gp->ge_link == NULL) 51897883Sgibbs goto skip; 51997883Sgibbs if (!metoo && strcmp(cp, myname) == 0) 52097883Sgibbs np->n_type |= GDEL; 52197883Sgibbsskip: 52297883Sgibbs nlist = put(nlist, np); 52397883Sgibbs } 52497883Sgibbs depth--; 52597883Sgibbs return (nlist); 52697883Sgibbs} 52797883Sgibbs 52897883Sgibbs/* 52997883Sgibbs * Concatenate the two passed name lists, return the result. 53097883Sgibbs */ 53197883Sgibbsstruct name * 53297883Sgibbscat(struct name *n1, struct name *n2) 53397883Sgibbs{ 53497883Sgibbs struct name *tail; 53597883Sgibbs 53697883Sgibbs if (n1 == NULL) 53797883Sgibbs return (n2); 53897883Sgibbs if (n2 == NULL) 53997883Sgibbs return (n1); 54097883Sgibbs tail = tailof(n1); 54197883Sgibbs tail->n_flink = n2; 54297883Sgibbs n2->n_blink = tail; 54397883Sgibbs return (n1); 54497883Sgibbs} 54597883Sgibbs 54697883Sgibbs/* 54797883Sgibbs * Unpack the name list onto a vector of strings. 54897883Sgibbs * Return an error if the name list won't fit. 54997883Sgibbs */ 55097883Sgibbschar ** 55197883Sgibbsunpack(struct name *np) 55297883Sgibbs{ 55397883Sgibbs char **ap, **top; 55497883Sgibbs struct name *n; 55597883Sgibbs int t, extra, metoo, verbose; 55697883Sgibbs 55797883Sgibbs n = np; 55897883Sgibbs if ((t = count(n)) == 0) 55997883Sgibbs errx(1, "No names to unpack"); 56097883Sgibbs /* 56197883Sgibbs * Compute the number of extra arguments we will need. 56297883Sgibbs * We need at least two extra -- one for "mail" and one for 56397883Sgibbs * the terminating 0 pointer. Additional spots may be needed 56497883Sgibbs * to pass along -f to the host mailer. 56597883Sgibbs */ 56697883Sgibbs extra = 2; 56797883Sgibbs extra++; 56897883Sgibbs metoo = value("metoo") != NULL; 56997883Sgibbs if (metoo) 57097883Sgibbs extra++; 57197883Sgibbs verbose = value("verbose") != NULL; 57297883Sgibbs if (verbose) 57397883Sgibbs extra++; 57497883Sgibbs top = (char **)salloc((t + extra) * sizeof(*top)); 57597883Sgibbs ap = top; 57697883Sgibbs *ap++ = "send-mail"; 57797883Sgibbs *ap++ = "-i"; 57897883Sgibbs if (metoo) 57997883Sgibbs *ap++ = "-m"; 58097883Sgibbs if (verbose) 58197883Sgibbs *ap++ = "-v"; 58297883Sgibbs for (; n != NULL; n = n->n_flink) 583102681Sgibbs if ((n->n_type & GDEL) == 0) 584102681Sgibbs *ap++ = n->n_name; 585102681Sgibbs *ap = NULL; 586102681Sgibbs return (top); 587102681Sgibbs} 588102681Sgibbs 589102681Sgibbs/* 590102681Sgibbs * Remove all of the duplicates from the passed name list by 591102681Sgibbs * insertion sorting them, then checking for dups. 592102681Sgibbs * Return the head of the new list. 593102681Sgibbs */ 594102681Sgibbsstruct name * 595102681Sgibbselide(struct name *names) 596102681Sgibbs{ 597102681Sgibbs struct name *np, *t, *new; 598102681Sgibbs struct name *x; 599102681Sgibbs 600102681Sgibbs if (names == NULL) 601102681Sgibbs return (NULL); 602102681Sgibbs new = names; 60397883Sgibbs np = names; 60497883Sgibbs np = np->n_flink; 60597883Sgibbs if (np != NULL) 60697883Sgibbs np->n_blink = NULL; 60797883Sgibbs new->n_flink = NULL; 60897883Sgibbs while (np != NULL) { 60997883Sgibbs t = new; 61097883Sgibbs while (strcasecmp(t->n_name, np->n_name) < 0) { 61197883Sgibbs if (t->n_flink == NULL) 61297883Sgibbs break; 61397883Sgibbs t = t->n_flink; 61497883Sgibbs } 61597883Sgibbs 61697883Sgibbs /* 61797883Sgibbs * If we ran out of t's, put the new entry after 61897883Sgibbs * the current value of t. 61997883Sgibbs */ 620102681Sgibbs 621102681Sgibbs if (strcasecmp(t->n_name, np->n_name) < 0) { 622102681Sgibbs t->n_flink = np; 623102681Sgibbs np->n_blink = t; 62497883Sgibbs t = np; 62597883Sgibbs np = np->n_flink; 62697883Sgibbs t->n_flink = NULL; 62797883Sgibbs continue; 62897883Sgibbs } 62997883Sgibbs 63097883Sgibbs /* 63197883Sgibbs * Otherwise, put the new entry in front of the 63297883Sgibbs * current t. If at the front of the list, 63397883Sgibbs * the new guy becomes the new head of the list. 63497883Sgibbs */ 63597883Sgibbs 63697883Sgibbs if (t == new) { 63797883Sgibbs t = np; 63897883Sgibbs np = np->n_flink; 63997883Sgibbs t->n_flink = new; 64097883Sgibbs new->n_blink = t; 641102681Sgibbs t->n_blink = NULL; 642102681Sgibbs new = t; 64397883Sgibbs continue; 64497883Sgibbs } 64597883Sgibbs 64697883Sgibbs /* 64797883Sgibbs * The normal case -- we are inserting into the 64897883Sgibbs * middle of the list. 64997883Sgibbs */ 65097883Sgibbs 65197883Sgibbs x = np; 652102681Sgibbs np = np->n_flink; 653102681Sgibbs x->n_flink = t; 65497883Sgibbs x->n_blink = t->n_blink; 65597883Sgibbs t->n_blink->n_flink = x; 65697883Sgibbs t->n_blink = x; 65797883Sgibbs } 65897883Sgibbs 65997883Sgibbs /* 66097883Sgibbs * Now the list headed up by new is sorted. 66197883Sgibbs * Go through it and remove duplicates. 66297883Sgibbs */ 663102681Sgibbs 664102681Sgibbs np = new; 66597883Sgibbs while (np != NULL) { 66697883Sgibbs t = np; 66797883Sgibbs while (t->n_flink != NULL && 66897883Sgibbs strcasecmp(np->n_name, t->n_flink->n_name) == 0) 66997883Sgibbs t = t->n_flink; 67097883Sgibbs if (t == np || t == NULL) { 67197883Sgibbs np = np->n_flink; 67297883Sgibbs continue; 67397883Sgibbs } 674102681Sgibbs 675102681Sgibbs /* 676102681Sgibbs * Now t points to the last entry with the same name 677102681Sgibbs * as np. Make np point beyond t. 678102681Sgibbs */ 679102681Sgibbs 68097883Sgibbs np->n_flink = t->n_flink; 68197883Sgibbs if (t->n_flink != NULL) 68297883Sgibbs t->n_flink->n_blink = np; 68397883Sgibbs np = np->n_flink; 68497883Sgibbs } 68597883Sgibbs return (new); 68697883Sgibbs} 68797883Sgibbs 68897883Sgibbs/* 689102681Sgibbs * Put another node onto a list of names and return 69097883Sgibbs * the list. 69197883Sgibbs */ 69297883Sgibbsstruct name * 69397883Sgibbsput(struct name *list, struct name *node) 69497883Sgibbs{ 69597883Sgibbs node->n_flink = list; 69697883Sgibbs node->n_blink = NULL; 69797883Sgibbs if (list != NULL) 69897883Sgibbs list->n_blink = node; 699102681Sgibbs return (node); 70097883Sgibbs} 70197883Sgibbs 70297883Sgibbs/* 70397883Sgibbs * Determine the number of undeleted elements in 70497883Sgibbs * a name list and return it. 70597883Sgibbs */ 70697883Sgibbsint 70797883Sgibbscount(struct name *np) 70897883Sgibbs{ 709102681Sgibbs int c; 71097883Sgibbs 71197883Sgibbs for (c = 0; np != NULL; np = np->n_flink) 71297883Sgibbs if ((np->n_type & GDEL) == 0) 71397883Sgibbs c++; 71497883Sgibbs return (c); 71597883Sgibbs} 71697883Sgibbs 71797883Sgibbs/* 71897883Sgibbs * Delete the given name from a namelist. 719102681Sgibbs */ 720102681Sgibbsstruct name * 721102681Sgibbsdelname(struct name *np, char name[]) 722102681Sgibbs{ 723102681Sgibbs struct name *p; 724102681Sgibbs 72597883Sgibbs for (p = np; p != NULL; p = p->n_flink) 72697883Sgibbs if (strcasecmp(p->n_name, name) == 0) { 72797883Sgibbs if (p->n_blink == NULL) { 72897883Sgibbs if (p->n_flink != NULL) 72997883Sgibbs p->n_flink->n_blink = NULL; 73097883Sgibbs np = p->n_flink; 73197883Sgibbs continue; 73297883Sgibbs } 73397883Sgibbs if (p->n_flink == NULL) { 734102681Sgibbs if (p->n_blink != NULL) 73597883Sgibbs p->n_blink->n_flink = NULL; 73697883Sgibbs continue; 73797883Sgibbs } 73897883Sgibbs p->n_blink->n_flink = p->n_flink; 73997883Sgibbs p->n_flink->n_blink = p->n_blink; 74097883Sgibbs } 74197883Sgibbs return (np); 74297883Sgibbs} 74397883Sgibbs 744102681Sgibbs/* 74597883Sgibbs * Pretty print a name list 74697883Sgibbs * Uncomment it if you need it. 74797883Sgibbs */ 74897883Sgibbs 74997883Sgibbs/* 75097883Sgibbsvoid 75197883Sgibbsprettyprint(struct name *name) 75297883Sgibbs{ 75397883Sgibbs struct name *np; 754102681Sgibbs 75597883Sgibbs np = name; 75697883Sgibbs while (np != NULL) { 75797883Sgibbs fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); 75897883Sgibbs np = np->n_flink; 75997883Sgibbs } 76097883Sgibbs fprintf(stderr, "\n"); 76197883Sgibbs} 76297883Sgibbs*/ 76397883Sgibbs