[BACK]Return to names.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mail

Annotation of src/usr.bin/mail/names.c, Revision 1.14

1.14    ! millert     1: /*     $OpenBSD: names.c,v 1.13 2001/01/16 05:36:08 millert Exp $      */
1.2       deraadt     2: /*     $NetBSD: names.c,v 1.5 1996/06/08 19:48:32 christos Exp $       */
                      3:
1.1       deraadt     4: /*
                      5:  * Copyright (c) 1980, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: #ifndef lint
1.2       deraadt    38: #if 0
1.14    ! millert    39: static const char sccsid[] = "@(#)names.c      8.1 (Berkeley) 6/6/93";
1.2       deraadt    40: #else
1.14    ! millert    41: static const char rcsid[] = "$OpenBSD: names.c,v 1.13 2001/01/16 05:36:08 millert Exp $";
1.2       deraadt    42: #endif
1.1       deraadt    43: #endif /* not lint */
                     44:
                     45: /*
                     46:  * Mail -- a mail program
                     47:  *
                     48:  * Handle name lists.
                     49:  */
                     50:
                     51: #include "rcv.h"
                     52: #include <fcntl.h>
                     53: #include "extern.h"
                     54:
                     55: /*
                     56:  * Allocate a single element of a name list,
                     57:  * initialize its name field to the passed
                     58:  * name and return it.
                     59:  */
                     60: struct name *
1.14    ! millert    61: nalloc(char *str, int ntype)
1.1       deraadt    62: {
1.9       millert    63:        struct name *np;
1.1       deraadt    64:
1.5       millert    65:        np = (struct name *)salloc(sizeof(*np));
1.14    ! millert    66:        np->n_flink = NULL;
        !            67:        np->n_blink = NULL;
1.1       deraadt    68:        np->n_type = ntype;
                     69:        np->n_name = savestr(str);
                     70:        return(np);
                     71: }
                     72:
                     73: /*
                     74:  * Find the tail of a list and return it.
                     75:  */
                     76: struct name *
1.14    ! millert    77: tailof(struct name *name)
1.1       deraadt    78: {
1.9       millert    79:        struct name *np;
1.1       deraadt    80:
                     81:        np = name;
1.14    ! millert    82:        if (np == NULL)
        !            83:                return(NULL);
        !            84:        while (np->n_flink != NULL)
1.1       deraadt    85:                np = np->n_flink;
                     86:        return(np);
                     87: }
                     88:
                     89: /*
                     90:  * Extract a list of names from a line,
                     91:  * and make a list of names from it.
1.14    ! millert    92:  * Return the list or NULL if none found.
1.1       deraadt    93:  */
                     94: struct name *
1.14    ! millert    95: extract(char *line, int ntype)
1.1       deraadt    96: {
1.9       millert    97:        char *cp;
                     98:        struct name *top, *np, *t;
1.8       millert    99:        char *nbuf;
1.1       deraadt   100:
1.6       millert   101:        if (line == NULL || *line == '\0')
1.14    ! millert   102:                return(NULL);
1.8       millert   103:        if ((nbuf = (char *)malloc(strlen(line) + 1)) == NULL)
1.9       millert   104:                errx(1, "Out of memory");
1.14    ! millert   105:        top = NULL;
        !           106:        np = NULL;
1.1       deraadt   107:        cp = line;
1.6       millert   108:        while ((cp = yankword(cp, nbuf)) != NULL) {
1.1       deraadt   109:                t = nalloc(nbuf, ntype);
1.14    ! millert   110:                if (top == NULL)
1.1       deraadt   111:                        top = t;
                    112:                else
                    113:                        np->n_flink = t;
                    114:                t->n_blink = np;
                    115:                np = t;
                    116:        }
1.8       millert   117:        (void)free(nbuf);
1.4       millert   118:        return(top);
1.1       deraadt   119: }
                    120:
                    121: /*
                    122:  * Turn a list of names into a string of the same names.
                    123:  */
                    124: char *
1.14    ! millert   125: detract(struct name *np, int ntype)
1.1       deraadt   126: {
1.9       millert   127:        int s, comma;
                    128:        char *cp, *top;
                    129:        struct name *p;
1.1       deraadt   130:
                    131:        comma = ntype & GCOMMA;
1.14    ! millert   132:        if (np == NULL)
1.6       millert   133:                return(NULL);
1.1       deraadt   134:        ntype &= ~GCOMMA;
                    135:        s = 0;
                    136:        if (debug && comma)
1.4       millert   137:                fputs("detract asked to insert commas\n", stderr);
1.14    ! millert   138:        for (p = np; p != NULL; p = p->n_flink) {
1.1       deraadt   139:                if (ntype && (p->n_type & GMASK) != ntype)
                    140:                        continue;
                    141:                s += strlen(p->n_name) + 1;
                    142:                if (comma)
                    143:                        s++;
                    144:        }
                    145:        if (s == 0)
1.6       millert   146:                return(NULL);
1.1       deraadt   147:        s += 2;
                    148:        top = salloc(s);
                    149:        cp = top;
1.14    ! millert   150:        for (p = np; p != NULL; p = p->n_flink) {
1.1       deraadt   151:                if (ntype && (p->n_type & GMASK) != ntype)
                    152:                        continue;
                    153:                cp = copy(p->n_name, cp);
1.14    ! millert   154:                if (comma && p->n_flink != NULL)
1.1       deraadt   155:                        *cp++ = ',';
                    156:                *cp++ = ' ';
                    157:        }
                    158:        *--cp = 0;
                    159:        if (comma && *--cp == ',')
                    160:                *cp = 0;
                    161:        return(top);
                    162: }
                    163:
                    164: /*
                    165:  * Grab a single word (liberal word)
                    166:  * Throw away things between ()'s, and take anything between <>.
                    167:  */
                    168: char *
1.14    ! millert   169: yankword(char *ap, char *wbuf)
1.1       deraadt   170: {
1.9       millert   171:        char *cp, *cp2;
1.1       deraadt   172:
                    173:        cp = ap;
                    174:        for (;;) {
                    175:                if (*cp == '\0')
1.6       millert   176:                        return(NULL);
1.1       deraadt   177:                if (*cp == '(') {
1.9       millert   178:                        int nesting = 0;
1.1       deraadt   179:
                    180:                        while (*cp != '\0') {
                    181:                                switch (*cp++) {
                    182:                                case '(':
                    183:                                        nesting++;
                    184:                                        break;
                    185:                                case ')':
                    186:                                        --nesting;
                    187:                                        break;
                    188:                                }
                    189:                                if (nesting <= 0)
                    190:                                        break;
                    191:                        }
                    192:                } else if (*cp == ' ' || *cp == '\t' || *cp == ',')
                    193:                        cp++;
                    194:                else
                    195:                        break;
                    196:        }
                    197:        if (*cp ==  '<')
                    198:                for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';)
                    199:                        ;
                    200:        else
1.3       millert   201:                for (cp2 = wbuf; *cp && !strchr(" \t,(", *cp); *cp2++ = *cp++)
1.1       deraadt   202:                        ;
                    203:        *cp2 = '\0';
1.4       millert   204:        return(cp);
1.1       deraadt   205: }
                    206:
                    207: /*
                    208:  * For each recipient in the passed name list with a /
                    209:  * in the name, append the message to the end of the named file
                    210:  * and remove him from the recipient list.
                    211:  *
                    212:  * Recipients whose name begins with | are piped through the given
                    213:  * program and removed.
                    214:  */
                    215: struct name *
1.14    ! millert   216: outof(struct name *names, FILE *fo, struct header *hp)
1.1       deraadt   217: {
1.9       millert   218:        int c, ispipe;
                    219:        struct name *np, *top;
1.2       deraadt   220:        time_t now;
                    221:        char *date, *fname;
1.1       deraadt   222:        FILE *fout, *fin;
                    223:
                    224:        top = names;
                    225:        np = names;
1.5       millert   226:        (void)time(&now);
1.1       deraadt   227:        date = ctime(&now);
1.14    ! millert   228:        while (np != NULL) {
1.1       deraadt   229:                if (!isfileaddr(np->n_name) && np->n_name[0] != '|') {
                    230:                        np = np->n_flink;
                    231:                        continue;
                    232:                }
                    233:                ispipe = np->n_name[0] == '|';
                    234:                if (ispipe)
                    235:                        fname = np->n_name+1;
                    236:                else
                    237:                        fname = expand(np->n_name);
                    238:
                    239:                /*
                    240:                 * See if we have copied the complete message out yet.
                    241:                 * If not, do so.
                    242:                 */
                    243:                if (image < 0) {
1.7       millert   244:                        int fd;
                    245:                        char tempname[PATHSIZE];
                    246:
                    247:                        (void)snprintf(tempname, sizeof(tempname),
                    248:                            "%s/mail.ReXXXXXXXXXX", tmpdir);
                    249:                        if ((fd = mkstemp(tempname)) == -1 ||
                    250:                            (fout = Fdopen(fd, "a")) == NULL) {
1.11      millert   251:                                warn("%s", tempname);
1.1       deraadt   252:                                senderr++;
                    253:                                goto cant;
                    254:                        }
1.7       millert   255:                        image = open(tempname, O_RDWR);
                    256:                        (void)rm(tempname);
1.1       deraadt   257:                        if (image < 0) {
1.11      millert   258:                                warn("%s", tempname);
1.1       deraadt   259:                                senderr++;
1.4       millert   260:                                (void)Fclose(fout);
1.1       deraadt   261:                                goto cant;
                    262:                        }
1.5       millert   263:                        (void)fcntl(image, F_SETFD, 1);
1.1       deraadt   264:                        fprintf(fout, "From %s %s", myname, date);
                    265:                        puthead(hp, fout, GTO|GSUBJECT|GCC|GNL);
                    266:                        while ((c = getc(fo)) != EOF)
1.5       millert   267:                                (void)putc(c, fout);
1.1       deraadt   268:                        rewind(fo);
1.5       millert   269:                        (void)putc('\n', fout);
                    270:                        (void)fflush(fout);
1.1       deraadt   271:                        if (ferror(fout))
1.11      millert   272:                                warn("%s", tempname);
1.4       millert   273:                        (void)Fclose(fout);
1.1       deraadt   274:                }
                    275:
                    276:                /*
                    277:                 * Now either copy "image" to the desired file
                    278:                 * or give it as the standard input to the desired
                    279:                 * program as appropriate.
                    280:                 */
                    281:                if (ispipe) {
1.14    ! millert   282:                        pid_t pid;
1.1       deraadt   283:                        char *shell;
1.2       deraadt   284:                        sigset_t nset;
1.1       deraadt   285:
                    286:                        /*
                    287:                         * XXX
                    288:                         * We can't really reuse the same image file,
                    289:                         * because multiple piped recipients will
                    290:                         * share the same lseek location and trample
                    291:                         * on one another.
                    292:                         */
1.13      millert   293:                        shell = value("SHELL");
1.2       deraadt   294:                        sigemptyset(&nset);
                    295:                        sigaddset(&nset, SIGHUP);
                    296:                        sigaddset(&nset, SIGINT);
                    297:                        sigaddset(&nset, SIGQUIT);
                    298:                        pid = start_command(shell, &nset,
1.6       millert   299:                                image, -1, "-c", fname, NULL);
1.1       deraadt   300:                        if (pid < 0) {
                    301:                                senderr++;
                    302:                                goto cant;
                    303:                        }
                    304:                        free_child(pid);
                    305:                } else {
                    306:                        int f;
                    307:                        if ((fout = Fopen(fname, "a")) == NULL) {
1.11      millert   308:                                warn("%s", fname);
1.1       deraadt   309:                                senderr++;
                    310:                                goto cant;
                    311:                        }
                    312:                        if ((f = dup(image)) < 0) {
1.4       millert   313:                                warn("dup");
1.1       deraadt   314:                                fin = NULL;
                    315:                        } else
                    316:                                fin = Fdopen(f, "r");
                    317:                        if (fin == NULL) {
1.4       millert   318:                                fputs("Can't reopen image\n", stderr);
                    319:                                (void)Fclose(fout);
1.1       deraadt   320:                                senderr++;
                    321:                                goto cant;
                    322:                        }
                    323:                        rewind(fin);
                    324:                        while ((c = getc(fin)) != EOF)
1.5       millert   325:                                (void)putc(c, fout);
1.4       millert   326:                        if (ferror(fout)) {
                    327:                                senderr++;
1.11      millert   328:                                warn("%s", fname);
1.4       millert   329:                        }
                    330:                        (void)Fclose(fout);
                    331:                        (void)Fclose(fin);
1.1       deraadt   332:                }
                    333: cant:
                    334:                /*
                    335:                 * In days of old we removed the entry from the
                    336:                 * the list; now for sake of header expansion
                    337:                 * we leave it in and mark it as deleted.
                    338:                 */
                    339:                np->n_type |= GDEL;
                    340:                np = np->n_flink;
                    341:        }
                    342:        if (image >= 0) {
1.4       millert   343:                (void)close(image);
1.1       deraadt   344:                image = -1;
                    345:        }
                    346:        return(top);
                    347: }
                    348:
                    349: /*
                    350:  * Determine if the passed address is a local "send to file" address.
                    351:  * If any of the network metacharacters precedes any slashes, it can't
                    352:  * be a filename.  We cheat with .'s to allow path names like ./...
                    353:  */
                    354: int
1.14    ! millert   355: isfileaddr(char *name)
1.1       deraadt   356: {
1.9       millert   357:        char *cp;
1.1       deraadt   358:
                    359:        if (*name == '+')
1.4       millert   360:                return(1);
1.1       deraadt   361:        for (cp = name; *cp; cp++) {
                    362:                if (*cp == '!' || *cp == '%' || *cp == '@')
1.4       millert   363:                        return(0);
1.1       deraadt   364:                if (*cp == '/')
1.4       millert   365:                        return(1);
1.1       deraadt   366:        }
1.4       millert   367:        return(0);
1.1       deraadt   368: }
                    369:
                    370: /*
                    371:  * Map all of the aliased users in the invoker's mailrc
                    372:  * file and insert them into the list.
                    373:  * Changed after all these months of service to recursively
                    374:  * expand names (2/14/80).
                    375:  */
                    376: struct name *
1.14    ! millert   377: usermap(struct name *names)
1.1       deraadt   378: {
1.9       millert   379:        struct name *new, *np, *cp;
1.1       deraadt   380:        struct grouphead *gh;
1.9       millert   381:        int metoo;
1.1       deraadt   382:
1.14    ! millert   383:        new = NULL;
1.1       deraadt   384:        np = names;
1.6       millert   385:        metoo = (value("metoo") != NULL);
1.14    ! millert   386:        while (np != NULL) {
1.1       deraadt   387:                if (np->n_name[0] == '\\') {
                    388:                        cp = np->n_flink;
                    389:                        new = put(new, np);
                    390:                        np = cp;
                    391:                        continue;
                    392:                }
                    393:                gh = findgroup(np->n_name);
                    394:                cp = np->n_flink;
1.14    ! millert   395:                if (gh != NULL)
1.1       deraadt   396:                        new = gexpand(new, gh, metoo, np->n_type);
                    397:                else
                    398:                        new = put(new, np);
                    399:                np = cp;
                    400:        }
                    401:        return(new);
                    402: }
                    403:
                    404: /*
                    405:  * Recursively expand a group name.  We limit the expansion to some
                    406:  * fixed level to keep things from going haywire.
                    407:  * Direct recursion is not expanded for convenience.
                    408:  */
                    409: struct name *
1.14    ! millert   410: gexpand(struct name *nlist, struct grouphead *gh, int metoo, int ntype)
1.1       deraadt   411: {
                    412:        struct group *gp;
                    413:        struct grouphead *ngh;
                    414:        struct name *np;
                    415:        static int depth;
                    416:        char *cp;
                    417:
                    418:        if (depth > MAXEXP) {
                    419:                printf("Expanding alias to depth larger than %d\n", MAXEXP);
                    420:                return(nlist);
                    421:        }
                    422:        depth++;
1.14    ! millert   423:        for (gp = gh->g_list; gp != NULL; gp = gp->ge_link) {
1.1       deraadt   424:                cp = gp->ge_name;
                    425:                if (*cp == '\\')
                    426:                        goto quote;
                    427:                if (strcmp(cp, gh->g_name) == 0)
                    428:                        goto quote;
1.14    ! millert   429:                if ((ngh = findgroup(cp)) != NULL) {
1.1       deraadt   430:                        nlist = gexpand(nlist, ngh, metoo, ntype);
                    431:                        continue;
                    432:                }
                    433: quote:
                    434:                np = nalloc(cp, ntype);
                    435:                /*
                    436:                 * At this point should allow to expand
                    437:                 * to self if only person in group
                    438:                 */
1.14    ! millert   439:                if (gp == gh->g_list && gp->ge_link == NULL)
1.1       deraadt   440:                        goto skip;
                    441:                if (!metoo && strcmp(cp, myname) == 0)
                    442:                        np->n_type |= GDEL;
                    443: skip:
                    444:                nlist = put(nlist, np);
                    445:        }
                    446:        depth--;
                    447:        return(nlist);
                    448: }
                    449:
                    450: /*
                    451:  * Concatenate the two passed name lists, return the result.
                    452:  */
                    453: struct name *
1.14    ! millert   454: cat(struct name *n1, struct name *n2)
1.1       deraadt   455: {
1.9       millert   456:        struct name *tail;
1.1       deraadt   457:
1.14    ! millert   458:        if (n1 == NULL)
1.1       deraadt   459:                return(n2);
1.14    ! millert   460:        if (n2 == NULL)
1.1       deraadt   461:                return(n1);
                    462:        tail = tailof(n1);
                    463:        tail->n_flink = n2;
                    464:        n2->n_blink = tail;
                    465:        return(n1);
                    466: }
                    467:
                    468: /*
                    469:  * Unpack the name list onto a vector of strings.
                    470:  * Return an error if the name list won't fit.
                    471:  */
                    472: char **
1.14    ! millert   473: unpack(struct name *np, struct name *sm)
1.1       deraadt   474: {
1.9       millert   475:        char **ap, **top;
1.1       deraadt   476:        int t, extra, metoo, verbose;
                    477:
1.12      mickey    478:        if ((t = count(np)) == 0)
1.9       millert   479:                errx(1, "No names to unpack");
1.12      mickey    480:        t += count(sm);
                    481:
1.1       deraadt   482:        /*
                    483:         * Compute the number of extra arguments we will need.
1.10      millert   484:         * We need at least four extra -- one for "send-mail", one for the
                    485:         * "-i" flag, one for the "--" to signal end of command line
                    486:         * arguments, and one for the terminating 0 pointer.
1.1       deraadt   487:         */
1.10      millert   488:        extra = 4;
1.6       millert   489:        metoo = value("metoo") != NULL;
1.1       deraadt   490:        if (metoo)
                    491:                extra++;
1.6       millert   492:        verbose = value("verbose") != NULL;
1.1       deraadt   493:        if (verbose)
                    494:                extra++;
1.5       millert   495:        top = (char **)salloc((t + extra) * sizeof(*top));
1.1       deraadt   496:        ap = top;
                    497:        *ap++ = "send-mail";
                    498:        *ap++ = "-i";
                    499:        if (metoo)
                    500:                *ap++ = "-m";
                    501:        if (verbose)
                    502:                *ap++ = "-v";
1.14    ! millert   503:        for (; sm != NULL; sm = sm->n_flink)
1.12      mickey    504:                if ((sm->n_type & GDEL) == 0)
                    505:                        *ap++ = sm->n_name;
1.10      millert   506:        *ap++ = "--";
1.14    ! millert   507:        for (; np != NULL; np = np->n_flink)
1.12      mickey    508:                if ((np->n_type & GDEL) == 0)
                    509:                        *ap++ = np->n_name;
1.6       millert   510:        *ap = NULL;
1.1       deraadt   511:        return(top);
                    512: }
                    513:
                    514: /*
                    515:  * Remove all of the duplicates from the passed name list by
                    516:  * insertion sorting them, then checking for dups.
                    517:  * Return the head of the new list.
                    518:  */
                    519: struct name *
1.14    ! millert   520: elide(struct name *names)
1.1       deraadt   521: {
1.9       millert   522:        struct name *np, *t, *new;
1.1       deraadt   523:        struct name *x;
                    524:
1.14    ! millert   525:        if (names == NULL)
        !           526:                return(NULL);
1.1       deraadt   527:        new = names;
                    528:        np = names;
                    529:        np = np->n_flink;
1.14    ! millert   530:        if (np != NULL)
        !           531:                np->n_blink = NULL;
        !           532:        new->n_flink = NULL;
        !           533:        while (np != NULL) {
1.1       deraadt   534:                t = new;
                    535:                while (strcasecmp(t->n_name, np->n_name) < 0) {
1.14    ! millert   536:                        if (t->n_flink == NULL)
1.1       deraadt   537:                                break;
                    538:                        t = t->n_flink;
                    539:                }
                    540:
                    541:                /*
                    542:                 * If we ran out of t's, put the new entry after
                    543:                 * the current value of t.
                    544:                 */
                    545:                if (strcasecmp(t->n_name, np->n_name) < 0) {
                    546:                        t->n_flink = np;
                    547:                        np->n_blink = t;
                    548:                        t = np;
                    549:                        np = np->n_flink;
1.14    ! millert   550:                        t->n_flink = NULL;
1.1       deraadt   551:                        continue;
                    552:                }
                    553:
                    554:                /*
                    555:                 * Otherwise, put the new entry in front of the
                    556:                 * current t.  If at the front of the list,
                    557:                 * the new guy becomes the new head of the list.
                    558:                 */
                    559:                if (t == new) {
                    560:                        t = np;
                    561:                        np = np->n_flink;
                    562:                        t->n_flink = new;
                    563:                        new->n_blink = t;
1.14    ! millert   564:                        t->n_blink = NULL;
1.1       deraadt   565:                        new = t;
                    566:                        continue;
                    567:                }
                    568:
                    569:                /*
                    570:                 * The normal case -- we are inserting into the
                    571:                 * middle of the list.
                    572:                 */
                    573:                x = np;
                    574:                np = np->n_flink;
                    575:                x->n_flink = t;
                    576:                x->n_blink = t->n_blink;
                    577:                t->n_blink->n_flink = x;
                    578:                t->n_blink = x;
                    579:        }
                    580:
                    581:        /*
                    582:         * Now the list headed up by new is sorted.
                    583:         * Go through it and remove duplicates.
                    584:         */
                    585:        np = new;
1.14    ! millert   586:        while (np != NULL) {
1.1       deraadt   587:                t = np;
1.14    ! millert   588:                while (t->n_flink != NULL &&
1.1       deraadt   589:                       strcasecmp(np->n_name, t->n_flink->n_name) == 0)
                    590:                        t = t->n_flink;
1.14    ! millert   591:                if (t == np || t == NULL) {
1.1       deraadt   592:                        np = np->n_flink;
                    593:                        continue;
                    594:                }
                    595:
                    596:                /*
                    597:                 * Now t points to the last entry with the same name
                    598:                 * as np.  Make np point beyond t.
                    599:                 */
                    600:                np->n_flink = t->n_flink;
1.14    ! millert   601:                if (t->n_flink != NULL)
1.1       deraadt   602:                        t->n_flink->n_blink = np;
                    603:                np = np->n_flink;
                    604:        }
                    605:        return(new);
                    606: }
                    607:
                    608: /*
                    609:  * Put another node onto a list of names and return
                    610:  * the list.
                    611:  */
                    612: struct name *
1.14    ! millert   613: put(struct name *list, struct name *node)
1.1       deraadt   614: {
                    615:        node->n_flink = list;
1.14    ! millert   616:        node->n_blink = NULL;
        !           617:        if (list != NULL)
1.1       deraadt   618:                list->n_blink = node;
                    619:        return(node);
                    620: }
                    621:
                    622: /*
                    623:  * Determine the number of undeleted elements in
                    624:  * a name list and return it.
                    625:  */
                    626: int
1.14    ! millert   627: count(struct name *np)
1.1       deraadt   628: {
1.9       millert   629:        int c;
1.1       deraadt   630:
1.14    ! millert   631:        for (c = 0; np != NULL; np = np->n_flink)
1.1       deraadt   632:                if ((np->n_type & GDEL) == 0)
                    633:                        c++;
1.4       millert   634:        return(c);
1.1       deraadt   635: }
                    636:
                    637: /*
                    638:  * Delete the given name from a namelist.
                    639:  */
                    640: struct name *
1.14    ! millert   641: delname(struct name *np, char *name)
1.1       deraadt   642: {
1.9       millert   643:        struct name *p;
1.1       deraadt   644:
1.14    ! millert   645:        for (p = np; p != NULL; p = p->n_flink)
1.13      millert   646:                if ((strcasecmp(p->n_name, name) == 0) ||
                    647:                    (value("allnet") &&
                    648:                    strncasecmp(p->n_name, name, strlen(name)) == 0 &&
                    649:                    *(p->n_name+strlen(name)) == '@')) {
1.14    ! millert   650:                        if (p->n_blink == NULL) {
        !           651:                                if (p->n_flink != NULL)
        !           652:                                        p->n_flink->n_blink = NULL;
1.1       deraadt   653:                                np = p->n_flink;
                    654:                                continue;
                    655:                        }
1.14    ! millert   656:                        if (p->n_flink == NULL) {
        !           657:                                if (p->n_blink != NULL)
        !           658:                                        p->n_blink->n_flink = NULL;
1.1       deraadt   659:                                continue;
                    660:                        }
                    661:                        p->n_blink->n_flink = p->n_flink;
                    662:                        p->n_flink->n_blink = p->n_blink;
                    663:                }
1.4       millert   664:        return(np);
1.1       deraadt   665: }
                    666:
                    667: /*
                    668:  * Pretty print a name list
                    669:  * Uncomment it if you need it.
                    670:  */
1.14    ! millert   671: #if 0
1.1       deraadt   672: void
                    673: prettyprint(name)
                    674:        struct name *name;
                    675: {
1.9       millert   676:        struct name *np;
1.1       deraadt   677:
                    678:        np = name;
1.14    ! millert   679:        while (np != NULL) {
1.1       deraadt   680:                fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
                    681:                np = np->n_flink;
                    682:        }
1.4       millert   683:        putc('\n', stderr);
1.1       deraadt   684: }
1.14    ! millert   685: #endif