Annotation of 43BSDReno/usr.bin/mail/names.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.