Annotation of 43BSDReno/usr.bin/mail/cmd3.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[] = "@(#)cmd3.c     5.24 (Berkeley) 6/25/90";
                     22: #endif /* not lint */
                     23: 
                     24: #include "rcv.h"
                     25: 
                     26: /*
                     27:  * Mail -- a mail program
                     28:  *
                     29:  * Still more user commands.
                     30:  */
                     31: 
                     32: /*
                     33:  * Process a shell escape by saving signals, ignoring signals,
                     34:  * and forking a sh -c
                     35:  */
                     36: shell(str)
                     37:        char *str;
                     38: {
                     39:        sig_t sigint = signal(SIGINT, SIG_IGN);
                     40:        char *shell;
                     41:        char cmd[BUFSIZ];
                     42: 
                     43:        (void) strcpy(cmd, str);
                     44:        if (bangexp(cmd) < 0)
                     45:                return 1;
                     46:        if ((shell = value("SHELL")) == NOSTR)
                     47:                shell = _PATH_CSHELL;
                     48:        (void) run_command(shell, 0, -1, -1, "-c", cmd, NOSTR);
                     49:        (void) signal(SIGINT, sigint);
                     50:        printf("!\n");
                     51:        return 0;
                     52: }
                     53: 
                     54: /*
                     55:  * Fork an interactive shell.
                     56:  */
                     57: /*ARGSUSED*/
                     58: dosh(str)
                     59:        char *str;
                     60: {
                     61:        sig_t sigint = signal(SIGINT, SIG_IGN);
                     62:        char *shell;
                     63: 
                     64:        if ((shell = value("SHELL")) == NOSTR)
                     65:                shell = _PATH_CSHELL;
                     66:        (void) run_command(shell, 0, -1, -1, NOSTR);
                     67:        (void) signal(SIGINT, sigint);
                     68:        putchar('\n');
                     69:        return 0;
                     70: }
                     71: 
                     72: /*
                     73:  * Expand the shell escape by expanding unescaped !'s into the
                     74:  * last issued command where possible.
                     75:  */
                     76: 
                     77: char   lastbang[128];
                     78: 
                     79: bangexp(str)
                     80:        char *str;
                     81: {
                     82:        char bangbuf[BUFSIZ];
                     83:        register char *cp, *cp2;
                     84:        register int n;
                     85:        int changed = 0;
                     86: 
                     87:        cp = str;
                     88:        cp2 = bangbuf;
                     89:        n = BUFSIZ;
                     90:        while (*cp) {
                     91:                if (*cp == '!') {
                     92:                        if (n < strlen(lastbang)) {
                     93: overf:
                     94:                                printf("Command buffer overflow\n");
                     95:                                return(-1);
                     96:                        }
                     97:                        changed++;
                     98:                        strcpy(cp2, lastbang);
                     99:                        cp2 += strlen(lastbang);
                    100:                        n -= strlen(lastbang);
                    101:                        cp++;
                    102:                        continue;
                    103:                }
                    104:                if (*cp == '\\' && cp[1] == '!') {
                    105:                        if (--n <= 1)
                    106:                                goto overf;
                    107:                        *cp2++ = '!';
                    108:                        cp += 2;
                    109:                        changed++;
                    110:                }
                    111:                if (--n <= 1)
                    112:                        goto overf;
                    113:                *cp2++ = *cp++;
                    114:        }
                    115:        *cp2 = 0;
                    116:        if (changed) {
                    117:                printf("!%s\n", bangbuf);
                    118:                fflush(stdout);
                    119:        }
                    120:        strcpy(str, bangbuf);
                    121:        strncpy(lastbang, bangbuf, 128);
                    122:        lastbang[127] = 0;
                    123:        return(0);
                    124: }
                    125: 
                    126: /*
                    127:  * Print out a nice help message from some file or another.
                    128:  */
                    129: 
                    130: help()
                    131: {
                    132:        register c;
                    133:        register FILE *f;
                    134: 
                    135:        if ((f = Fopen(_PATH_HELP, "r")) == NULL) {
                    136:                perror(_PATH_HELP);
                    137:                return(1);
                    138:        }
                    139:        while ((c = getc(f)) != EOF)
                    140:                putchar(c);
                    141:        Fclose(f);
                    142:        return(0);
                    143: }
                    144: 
                    145: /*
                    146:  * Change user's working directory.
                    147:  */
                    148: schdir(arglist)
                    149:        char **arglist;
                    150: {
                    151:        char *cp;
                    152: 
                    153:        if (*arglist == NOSTR)
                    154:                cp = homedir;
                    155:        else
                    156:                if ((cp = expand(*arglist)) == NOSTR)
                    157:                        return(1);
                    158:        if (chdir(cp) < 0) {
                    159:                perror(cp);
                    160:                return(1);
                    161:        }
                    162:        return 0;
                    163: }
                    164: 
                    165: respond(msgvec)
                    166:        int *msgvec;
                    167: {
                    168:        if (value("Replyall") == NOSTR)
                    169:                return (_respond(msgvec));
                    170:        else
                    171:                return (_Respond(msgvec));
                    172: }
                    173: 
                    174: /*
                    175:  * Reply to a list of messages.  Extract each name from the
                    176:  * message header and send them off to mail1()
                    177:  */
                    178: _respond(msgvec)
                    179:        int *msgvec;
                    180: {
                    181:        struct message *mp;
                    182:        char *cp, *rcv, *replyto;
                    183:        char **ap;
                    184:        struct name *np;
                    185:        struct header head;
                    186: 
                    187:        if (msgvec[1] != 0) {
                    188:                printf("Sorry, can't reply to multiple messages at once\n");
                    189:                return(1);
                    190:        }
                    191:        mp = &message[msgvec[0] - 1];
                    192:        touch(mp);
                    193:        dot = mp;
                    194:        if ((rcv = skin(hfield("from", mp))) == NOSTR)
                    195:                rcv = skin(nameof(mp, 1));
                    196:        if ((replyto = skin(hfield("reply-to", mp))) != NOSTR)
                    197:                np = extract(replyto, GTO);
                    198:        else if ((cp = skin(hfield("to", mp))) != NOSTR)
                    199:                np = extract(cp, GTO);
                    200:        else
                    201:                np = NIL;
                    202:        np = elide(np);
                    203:        /*
                    204:         * Delete my name from the reply list,
                    205:         * and with it, all my alternate names.
                    206:         */
                    207:        np = delname(np, myname);
                    208:        if (altnames)
                    209:                for (ap = altnames; *ap; ap++)
                    210:                        np = delname(np, *ap);
                    211:        if (np != NIL && replyto == NOSTR)
                    212:                np = cat(np, extract(rcv, GTO));
                    213:        else if (np == NIL) {
                    214:                if (replyto != NOSTR)
                    215:                        printf("Empty reply-to field -- replying to author\n");
                    216:                np = extract(rcv, GTO);
                    217:        }
                    218:        head.h_to = np;
                    219:        if ((head.h_subject = hfield("subject", mp)) == NOSTR)
                    220:                head.h_subject = hfield("subj", mp);
                    221:        head.h_subject = reedit(head.h_subject);
                    222:        if (replyto == NOSTR && (cp = skin(hfield("cc", mp))) != NOSTR) {
                    223:                np = elide(extract(cp, GCC));
                    224:                np = delname(np, myname);
                    225:                if (altnames != 0)
                    226:                        for (ap = altnames; *ap; ap++)
                    227:                                np = delname(np, *ap);
                    228:                head.h_cc = np;
                    229:        } else
                    230:                head.h_cc = NIL;
                    231:        head.h_bcc = NIL;
                    232:        head.h_smopts = NIL;
                    233:        mail1(&head, 1);
                    234:        return(0);
                    235: }
                    236: 
                    237: /*
                    238:  * Modify the subject we are replying to to begin with Re: if
                    239:  * it does not already.
                    240:  */
                    241: char *
                    242: reedit(subj)
                    243:        register char *subj;
                    244: {
                    245:        char *newsubj;
                    246: 
                    247:        if (subj == NOSTR)
                    248:                return NOSTR;
                    249:        if ((subj[0] == 'r' || subj[0] == 'R') &&
                    250:            (subj[1] == 'e' || subj[1] == 'E') &&
                    251:            subj[2] == ':')
                    252:                return subj;
                    253:        newsubj = salloc(strlen(subj) + 5);
                    254:        strcpy(newsubj, "Re: ");
                    255:        strcpy(newsubj + 4, subj);
                    256:        return newsubj;
                    257: }
                    258: 
                    259: /*
                    260:  * Preserve the named messages, so that they will be sent
                    261:  * back to the system mailbox.
                    262:  */
                    263: 
                    264: preserve(msgvec)
                    265:        int *msgvec;
                    266: {
                    267:        register struct message *mp;
                    268:        register int *ip, mesg;
                    269: 
                    270:        if (edit) {
                    271:                printf("Cannot \"preserve\" in edit mode\n");
                    272:                return(1);
                    273:        }
                    274:        for (ip = msgvec; *ip != NULL; ip++) {
                    275:                mesg = *ip;
                    276:                mp = &message[mesg-1];
                    277:                mp->m_flag |= MPRESERVE;
                    278:                mp->m_flag &= ~MBOX;
                    279:                dot = mp;
                    280:        }
                    281:        return(0);
                    282: }
                    283: 
                    284: /*
                    285:  * Mark all given messages as unread.
                    286:  */
                    287: unread(msgvec)
                    288:        int     msgvec[];
                    289: {
                    290:        register int *ip;
                    291: 
                    292:        for (ip = msgvec; *ip != NULL; ip++) {
                    293:                dot = &message[*ip-1];
                    294:                dot->m_flag &= ~(MREAD|MTOUCH);
                    295:                dot->m_flag |= MSTATUS;
                    296:        }
                    297:        return(0);
                    298: }
                    299: 
                    300: /*
                    301:  * Print the size of each message.
                    302:  */
                    303: 
                    304: messize(msgvec)
                    305:        int *msgvec;
                    306: {
                    307:        register struct message *mp;
                    308:        register int *ip, mesg;
                    309: 
                    310:        for (ip = msgvec; *ip != NULL; ip++) {
                    311:                mesg = *ip;
                    312:                mp = &message[mesg-1];
                    313:                printf("%d: %d/%ld\n", mesg, mp->m_lines, mp->m_size);
                    314:        }
                    315:        return(0);
                    316: }
                    317: 
                    318: /*
                    319:  * Quit quickly.  If we are sourcing, just pop the input level
                    320:  * by returning an error.
                    321:  */
                    322: 
                    323: rexit(e)
                    324: {
                    325:        if (sourcing)
                    326:                return(1);
                    327:        exit(e);
                    328:        /*NOTREACHED*/
                    329: }
                    330: 
                    331: /*
                    332:  * Set or display a variable value.  Syntax is similar to that
                    333:  * of csh.
                    334:  */
                    335: 
                    336: set(arglist)
                    337:        char **arglist;
                    338: {
                    339:        register struct var *vp;
                    340:        register char *cp, *cp2;
                    341:        char varbuf[BUFSIZ], **ap, **p;
                    342:        int errs, h, s;
                    343: 
                    344:        if (*arglist == NOSTR) {
                    345:                for (h = 0, s = 1; h < HSHSIZE; h++)
                    346:                        for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
                    347:                                s++;
                    348:                ap = (char **) salloc(s * sizeof *ap);
                    349:                for (h = 0, p = ap; h < HSHSIZE; h++)
                    350:                        for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
                    351:                                *p++ = vp->v_name;
                    352:                *p = NOSTR;
                    353:                sort(ap);
                    354:                for (p = ap; *p != NOSTR; p++)
                    355:                        printf("%s\t%s\n", *p, value(*p));
                    356:                return(0);
                    357:        }
                    358:        errs = 0;
                    359:        for (ap = arglist; *ap != NOSTR; ap++) {
                    360:                cp = *ap;
                    361:                cp2 = varbuf;
                    362:                while (*cp != '=' && *cp != '\0')
                    363:                        *cp2++ = *cp++;
                    364:                *cp2 = '\0';
                    365:                if (*cp == '\0')
                    366:                        cp = "";
                    367:                else
                    368:                        cp++;
                    369:                if (equal(varbuf, "")) {
                    370:                        printf("Non-null variable name required\n");
                    371:                        errs++;
                    372:                        continue;
                    373:                }
                    374:                assign(varbuf, cp);
                    375:        }
                    376:        return(errs);
                    377: }
                    378: 
                    379: /*
                    380:  * Unset a bunch of variable values.
                    381:  */
                    382: 
                    383: unset(arglist)
                    384:        char **arglist;
                    385: {
                    386:        register struct var *vp, *vp2;
                    387:        int errs, h;
                    388:        char **ap;
                    389: 
                    390:        errs = 0;
                    391:        for (ap = arglist; *ap != NOSTR; ap++) {
                    392:                if ((vp2 = lookup(*ap)) == NOVAR) {
                    393:                        if (!sourcing) {
                    394:                                printf("\"%s\": undefined variable\n", *ap);
                    395:                                errs++;
                    396:                        }
                    397:                        continue;
                    398:                }
                    399:                h = hash(*ap);
                    400:                if (vp2 == variables[h]) {
                    401:                        variables[h] = variables[h]->v_link;
                    402:                        vfree(vp2->v_name);
                    403:                        vfree(vp2->v_value);
                    404:                        cfree((char *)vp2);
                    405:                        continue;
                    406:                }
                    407:                for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
                    408:                        ;
                    409:                vp->v_link = vp2->v_link;
                    410:                vfree(vp2->v_name);
                    411:                vfree(vp2->v_value);
                    412:                cfree((char *) vp2);
                    413:        }
                    414:        return(errs);
                    415: }
                    416: 
                    417: /*
                    418:  * Put add users to a group.
                    419:  */
                    420: 
                    421: group(argv)
                    422:        char **argv;
                    423: {
                    424:        register struct grouphead *gh;
                    425:        register struct group *gp;
                    426:        register int h;
                    427:        int s;
                    428:        char **ap, *gname, **p;
                    429: 
                    430:        if (*argv == NOSTR) {
                    431:                for (h = 0, s = 1; h < HSHSIZE; h++)
                    432:                        for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
                    433:                                s++;
                    434:                ap = (char **) salloc(s * sizeof *ap);
                    435:                for (h = 0, p = ap; h < HSHSIZE; h++)
                    436:                        for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
                    437:                                *p++ = gh->g_name;
                    438:                *p = NOSTR;
                    439:                sort(ap);
                    440:                for (p = ap; *p != NOSTR; p++)
                    441:                        printgroup(*p);
                    442:                return(0);
                    443:        }
                    444:        if (argv[1] == NOSTR) {
                    445:                printgroup(*argv);
                    446:                return(0);
                    447:        }
                    448:        gname = *argv;
                    449:        h = hash(gname);
                    450:        if ((gh = findgroup(gname)) == NOGRP) {
                    451:                gh = (struct grouphead *) calloc(sizeof *gh, 1);
                    452:                gh->g_name = vcopy(gname);
                    453:                gh->g_list = NOGE;
                    454:                gh->g_link = groups[h];
                    455:                groups[h] = gh;
                    456:        }
                    457: 
                    458:        /*
                    459:         * Insert names from the command list into the group.
                    460:         * Who cares if there are duplicates?  They get tossed
                    461:         * later anyway.
                    462:         */
                    463: 
                    464:        for (ap = argv+1; *ap != NOSTR; ap++) {
                    465:                gp = (struct group *) calloc(sizeof *gp, 1);
                    466:                gp->ge_name = vcopy(*ap);
                    467:                gp->ge_link = gh->g_list;
                    468:                gh->g_list = gp;
                    469:        }
                    470:        return(0);
                    471: }
                    472: 
                    473: /*
                    474:  * Sort the passed string vecotor into ascending dictionary
                    475:  * order.
                    476:  */
                    477: 
                    478: sort(list)
                    479:        char **list;
                    480: {
                    481:        register char **ap;
                    482:        int diction();
                    483: 
                    484:        for (ap = list; *ap != NOSTR; ap++)
                    485:                ;
                    486:        if (ap-list < 2)
                    487:                return;
                    488:        qsort((char *)list, ap-list, sizeof *list, diction);
                    489: }
                    490: 
                    491: /*
                    492:  * Do a dictionary order comparison of the arguments from
                    493:  * qsort.
                    494:  */
                    495: 
                    496: diction(a, b)
                    497:        register char **a, **b;
                    498: {
                    499:        return(strcmp(*a, *b));
                    500: }
                    501: 
                    502: /*
                    503:  * The do nothing command for comments.
                    504:  */
                    505: 
                    506: /*ARGSUSED*/
                    507: null(e)
                    508: {
                    509:        return 0;
                    510: }
                    511: 
                    512: /*
                    513:  * Change to another file.  With no argument, print information about
                    514:  * the current file.
                    515:  */
                    516: file(argv)
                    517:        register char **argv;
                    518: {
                    519: 
                    520:        if (argv[0] == NOSTR) {
                    521:                newfileinfo();
                    522:                return 0;
                    523:        }
                    524:        if (setfile(*argv) < 0)
                    525:                return 1;
                    526:        announce();
                    527:        return 0;
                    528: }
                    529: 
                    530: /*
                    531:  * Expand file names like echo
                    532:  */
                    533: echo(argv)
                    534:        char **argv;
                    535: {
                    536:        register char **ap;
                    537:        register char *cp;
                    538: 
                    539:        for (ap = argv; *ap != NOSTR; ap++) {
                    540:                cp = *ap;
                    541:                if ((cp = expand(cp)) != NOSTR) {
                    542:                        if (ap != argv)
                    543:                                putchar(' ');
                    544:                        printf("%s", cp);
                    545:                }
                    546:        }
                    547:        putchar('\n');
                    548:        return 0;
                    549: }
                    550: 
                    551: Respond(msgvec)
                    552:        int *msgvec;
                    553: {
                    554:        if (value("Replyall") == NOSTR)
                    555:                return (_Respond(msgvec));
                    556:        else
                    557:                return (_respond(msgvec));
                    558: }
                    559: 
                    560: /*
                    561:  * Reply to a series of messages by simply mailing to the senders
                    562:  * and not messing around with the To: and Cc: lists as in normal
                    563:  * reply.
                    564:  */
                    565: _Respond(msgvec)
                    566:        int msgvec[];
                    567: {
                    568:        struct header head;
                    569:        struct message *mp;
                    570:        register int *ap;
                    571:        register char *cp;
                    572: 
                    573:        head.h_to = NIL;
                    574:        for (ap = msgvec; *ap != 0; ap++) {
                    575:                mp = &message[*ap - 1];
                    576:                touch(mp);
                    577:                dot = mp;
                    578:                if ((cp = skin(hfield("from", mp))) == NOSTR)
                    579:                        cp = skin(nameof(mp, 2));
                    580:                head.h_to = cat(head.h_to, extract(cp, GTO));
                    581:        }
                    582:        if (head.h_to == NIL)
                    583:                return 0;
                    584:        mp = &message[msgvec[0] - 1];
                    585:        if ((head.h_subject = hfield("subject", mp)) == NOSTR)
                    586:                head.h_subject = hfield("subj", mp);
                    587:        head.h_subject = reedit(head.h_subject);
                    588:        head.h_cc = NIL;
                    589:        head.h_bcc = NIL;
                    590:        head.h_smopts = NIL;
                    591:        mail1(&head, 1);
                    592:        return 0;
                    593: }
                    594: 
                    595: /*
                    596:  * Conditional commands.  These allow one to parameterize one's
                    597:  * .mailrc and do some things if sending, others if receiving.
                    598:  */
                    599: 
                    600: ifcmd(argv)
                    601:        char **argv;
                    602: {
                    603:        register char *cp;
                    604: 
                    605:        if (cond != CANY) {
                    606:                printf("Illegal nested \"if\"\n");
                    607:                return(1);
                    608:        }
                    609:        cond = CANY;
                    610:        cp = argv[0];
                    611:        switch (*cp) {
                    612:        case 'r': case 'R':
                    613:                cond = CRCV;
                    614:                break;
                    615: 
                    616:        case 's': case 'S':
                    617:                cond = CSEND;
                    618:                break;
                    619: 
                    620:        default:
                    621:                printf("Unrecognized if-keyword: \"%s\"\n", cp);
                    622:                return(1);
                    623:        }
                    624:        return(0);
                    625: }
                    626: 
                    627: /*
                    628:  * Implement 'else'.  This is pretty simple -- we just
                    629:  * flip over the conditional flag.
                    630:  */
                    631: 
                    632: elsecmd()
                    633: {
                    634: 
                    635:        switch (cond) {
                    636:        case CANY:
                    637:                printf("\"Else\" without matching \"if\"\n");
                    638:                return(1);
                    639: 
                    640:        case CSEND:
                    641:                cond = CRCV;
                    642:                break;
                    643: 
                    644:        case CRCV:
                    645:                cond = CSEND;
                    646:                break;
                    647: 
                    648:        default:
                    649:                printf("Mail's idea of conditions is screwed up\n");
                    650:                cond = CANY;
                    651:                break;
                    652:        }
                    653:        return(0);
                    654: }
                    655: 
                    656: /*
                    657:  * End of if statement.  Just set cond back to anything.
                    658:  */
                    659: 
                    660: endifcmd()
                    661: {
                    662: 
                    663:        if (cond == CANY) {
                    664:                printf("\"Endif\" without matching \"if\"\n");
                    665:                return(1);
                    666:        }
                    667:        cond = CANY;
                    668:        return(0);
                    669: }
                    670: 
                    671: /*
                    672:  * Set the list of alternate names.
                    673:  */
                    674: alternates(namelist)
                    675:        char **namelist;
                    676: {
                    677:        register int c;
                    678:        register char **ap, **ap2, *cp;
                    679: 
                    680:        c = argcount(namelist) + 1;
                    681:        if (c == 1) {
                    682:                if (altnames == 0)
                    683:                        return(0);
                    684:                for (ap = altnames; *ap; ap++)
                    685:                        printf("%s ", *ap);
                    686:                printf("\n");
                    687:                return(0);
                    688:        }
                    689:        if (altnames != 0)
                    690:                cfree((char *) altnames);
                    691:        altnames = (char **) calloc((unsigned) c, sizeof (char *));
                    692:        for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
                    693:                cp = (char *) calloc((unsigned) strlen(*ap) + 1, sizeof (char));
                    694:                strcpy(cp, *ap);
                    695:                *ap2 = cp;
                    696:        }
                    697:        *ap2 = 0;
                    698:        return(0);
                    699: }

unix.superglobalmegacorp.com

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