Annotation of coherent/d/bin/mail.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * $Header: /newbits/bin/mail.c,v 1.6 89/02/22 05:34:00 bin Exp $
                      3:  * $Log:       /newbits/bin/mail.c,v $
                      4:  * Revision 1.6        89/02/22  05:34:00      bin
                      5:  * Changes by rec to integrate with lauren's uumail.
                      6:  * 
                      7:  * Revision 1.5        88/09/01  14:49:01      bin
                      8:  * Source administration: Re-install declaration of getenv. 
                      9:  * It was inserted after epstein made his copy.
                     10:  * 
                     11:  * Revision 1.4        88/09/01  14:44:49      bin
                     12:  * Mark Epsteins changes for ASKCC and for message scrolling, and interrupt
                     13:  * handling during processing.
                     14:  * 
                     15:  * Revision 1.3        88/09/01  14:27:41      bin
                     16:  * declare getenv to get rid of integer pointer pun error message.
                     17:  * 
                     18:  * Revision 1.2        88/09/01  11:02:23      bin
                     19:  * Remove extra declaration of header which had rcs stuff in it.
                     20:  * 
                     21:  * Revision 1.1        88/09/01  10:55:34      bin
                     22:  * Initial revision
                     23:  * 
                     24:  */
                     25: static char    *rcsrev = "$Revision 1.1 $";
                     26: static char    *rcshdr =
                     27:        "$Header: /newbits/bin/mail.c,v 1.6 89/02/22 05:34:00 bin Exp $";
                     28: 
                     29: /*
                     30:  * The mail command.
                     31:  * Coherent electronic postal system.
                     32:  * (NOTE: this command is written in such a way that
                     33:  * it assumed that it is setuid on execution to `root'.
                     34:  * All file accession is checked on this basis).
                     35:  * Modifications by rec january 1986 to include xmail.
                     36:  *              by epstein november 1987 to include CC:
                     37:  *              by epstein november 1987 to allow ^C exit to leave you in
                     38:  *                                       mail command processor
                     39:  *              by epstein november 1987 to substitute /usr/games/fortune
                     40:  *                                       for printing encrypted messages
                     41:  *             by rec february 1989 to tail to lauren weinstein's
                     42:  *                     mail for alias expansion and uucp queuing.
                     43:  */
                     44: 
                     45: char helpmessage[] = "\
                     46: \
                     47: mail -- computer mail\n\
                     48: xmail -- secret computer mail\n\
                     49: Usage: mail [ options ] [ user ... ]\n\
                     50: or:    xmail [ options ] user [ ... ]\n\
                     51: Options:\n\
                     52:        -f file         Print mail from 'file' instead of the default\n\
                     53:        -p              Print mail non-interactively\n\
                     54:        -q              Exit on interrupt, leaving mail unchanged\n\
                     55:        -r              Print mail in reverse order, latest first\n\
                     56: If 'user' is present, send each a mail message read from standard input.\n\
                     57: If 'xmail' is the command, use xencode to encrypt the mail messages.\n\
                     58: Mail message ends with EOF of a line containing only '.'.  Otherwise, read\n\
                     59: and print the invoking user's mailbox.\n\
                     60: \
                     61: ";
                     62: 
                     63: char   isummary[] = "\
                     64: \
                     65: Command summary:\n\
                     66:        d               Delete current message and print the next message\n\
                     67:        m [user ...]    Mail current message to each named 'user'\n\
                     68:        p               Print current message again\n\
                     69:        q               Quit and update the mailbox\n\
                     70:        r               Reverse direction of scan\n\
                     71:        s [file ...]    Save message in each named 'file'\n\
                     72:        t [user ...]    Mail standard input to each named 'user'\n\
                     73:        w [file ...]    Save message in each named 'file' without its header\n\
                     74:        x               Exit without updating mailbox\n\
                     75:        newline         Print the next message\n\
                     76:        .               Print current message again\n\
                     77:        +               Print the next message\n\
                     78:        -               Print the previous message\n\
                     79:        EOF             Put undeleted mail back into mailbox and quit\n\
                     80:        ?               Print this command summary\n\
                     81:        !command        Pass 'command' to the shell to execute\n\
                     82: If no 'file' is specified, 'mbox' in user's home directory is default.\n\
                     83: If no 'user' is specified, the invoking user is default.\n\
                     84: If the 'm', 'p', 't' commands are followed by an 'x',\n\
                     85: then the public key cryptosystem is applied to the message.\n\
                     86: \
                     87: ";
                     88: 
                     89: #include <stdio.h>
                     90: #include <pwd.h>
                     91: #include <utmp.h>
                     92: #include <types.h>
                     93: #include <access.h>
                     94: #include <signal.h>
                     95: #include <sys/mdata.h>
                     96: #include <sys/stat.h>
                     97: #include <time.h>
                     98: 
                     99: #define        SPOOLDIR        "/usr/spool/mail/"
                    100: #define PUBKEYDIR      "/usr/spool/pubkey/"
                    101: #define        NARGS   64              /* Maximum # args to interactive command */
                    102: #define        NLINE   512             /* Longest line in a message */
                    103: #define        NCLINE  256             /* Length of an interactive command */
                    104: 
                    105: extern char    *getenv();
                    106: 
                    107: 
                    108: 
                    109: int    rflag;                  /* Reverse order of print */
                    110: int    qflag;                  /* Exit after interrrupts */
                    111: int    pflag;                  /* Print mail */
                    112: int    eflag;                  /* Edit this mail */
                    113: int    callmexmail;            /* Xmail modifier present */
                    114: 
                    115: struct msg {
                    116:        struct msg *m_next;             /* Link to next message */
                    117:        struct msg *m_prev;             /* Link to previous message */
                    118:        int     m_flag;                 /* Flags - non-zero if deleted */
                    119:        int     m_hsize;                /* Size of header of message */
                    120:        fsize_t m_seek;                 /* Start position of message */
                    121:        fsize_t m_end;                  /* End of message */
                    122: };
                    123: struct msg     *m_first = NULL;        /* First message */
                    124: struct msg     *m_last = NULL;         /* Last message */
                    125: 
                    126: struct tm      *tp;
                    127: 
                    128: char   iusage[] = "Bad command--type '?' for command summary\n";
                    129: char   nombox[] = "No mailbox '%s'.\n";
                    130: char   nomail[] = "No mail.\n";
                    131: char   noperm[] = "Mailbox '%s' access denied.\n";
                    132: char   nosend[] = "Can't send mail to '%s'\n";
                    133: char   moerr[] = "Cannot open mailbox '%s'\n";
                    134: char   wrerr[] = "Write error on '%s'\n";
                    135: char   toerr[] = "Cannot create temporary file\n";
                    136: char   nosave[] = "Cannot save letter in '%s'\n";
                    137: char   nopubk[] = "Can't send xmail to '%s'\n";
                    138: 
                    139: FILE   *mfp;                           /* Mailbox stream */
                    140: int    myuid;                          /* User-id of mail user */
                    141: int    mygid;                          /* Group-id of mail user */
                    142: char   myname[25];                     /* User name */
                    143: char   mymbox[256];                    /* $HOME/mbox */
                    144: char   spoolname[50] = SPOOLDIR;
                    145: char   *mailbox = spoolname;
                    146: char   boxname[64];            /* Destination mailbox */
                    147: char   keyname[64];            /* Destination public key file name */
                    148: char   cmdname[1024];          /* Command for x{en,de}code filter */
                    149:                                /* and for tail recursion to uumail */
                    150:                                /* and for editor recursion */
                    151: char   header[256];            /* Message header */
                    152: 
                    153: char   *args[NARGS];                   /* Interactive command arglist */
                    154: char   msgline[NLINE];
                    155: char   cline[NCLINE] = "+\n";
                    156: 
                    157: char   *temp;                          /* Currently open temp file */
                    158: char   templ[] = "/tmp/mailXXXXXX";    /* Temp file name template */
                    159: char   *editname;                      /* name of editor          */
                    160: char   *askcc;                         /* Ask for CC: list? (YES/NO) */
                    161: 
                    162: fsize_t        ftell();
                    163: char   *getlogin();
                    164: char   *mktemp();
                    165: char   *index();
                    166: char   *parent();
                    167: int    catchintr();
                    168: char   *malloc();
                    169: 
                    170: main(argc, argv)
                    171: char *argv[];
                    172: {
                    173:        register char *ap;
                    174: 
                    175:        callmexmail = (strcmp(argv[0], "xmail") == 0);
                    176:        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                    177:                signal(SIGINT, catchintr);
                    178:        if (argc>1 && *argv[1]=='-') {
                    179:                while (argc>1 && *argv[1]=='-') {
                    180:                        for (ap=&argv[1][1]; *ap != '\0'; ap++)
                    181:                                switch (*ap) {
                    182:                                case 'f':
                    183:                                        if (argc < 3)
                    184:                                                usage();
                    185:                                        mailbox = argv[2];
                    186:                                        argv++;
                    187:                                        argc--;
                    188:                                        break;
                    189: 
                    190:                                case 'm':
                    191:                                        break;
                    192: 
                    193:                                case 'p':
                    194:                                        pflag++;
                    195:                                        break;
                    196: 
                    197:                                case 'q':
                    198:                                        qflag++;
                    199:                                        break;
                    200: 
                    201:                                case 'r':
                    202:                                        rflag++;
                    203:                                        break;
                    204: 
                    205:                                default:
                    206:                                        usage();
                    207:                                }
                    208:                        argv++;
                    209:                        argc--;
                    210:                }
                    211:        }
                    212:        setname();
                    213:        if (argc > 1) {
                    214:                qflag = 1;
                    215:                send(stdin, &argv[1], (fsize_t)0, (fsize_t)MAXLONG);
                    216:        } else {
                    217:                if ( ! pflag)
                    218:                        callmexmail = 0;
                    219:                commands();
                    220:        }
                    221:        rmexit(0);
                    222: }
                    223: 
                    224: /*
                    225:  * Setup all the identities for the current user.
                    226:  */
                    227: setname()
                    228: {
                    229:        register struct passwd *pwp;
                    230:        register char *np;
                    231: 
                    232:        if ((np = getlogin()) == NULL) {
                    233:                myuid = getuid();
                    234:                if ((pwp = getpwuid(myuid)) == NULL)
                    235:                        merr("Who are you?\n");
                    236:                np = pwp->pw_name;
                    237:        } else {
                    238:                if ((pwp = getpwnam(np)) != NULL)
                    239:                        myuid = pwp->pw_uid;
                    240:        }
                    241:        mygid = pwp->pw_gid;
                    242:        strcat(spoolname, np);
                    243:        strcpy(myname, np);
                    244:        strcpy(mymbox, pwp->pw_dir);
                    245:        strcat(mymbox, "/mbox");
                    246:        mktemp(templ);
                    247: 
                    248:        if ((editname=getenv("EDITOR"))==NULL)
                    249:                editname = "/bin/ed";
                    250: 
                    251:        if ((askcc=getenv("ASKCC")) != NULL)
                    252:                if ( strcmp(askcc, "YES") || !isatty(fileno(stdin)) )
                    253:                        askcc = NULL;
                    254: }
                    255: 
                    256: /*
                    257:  * Send the message found on
                    258:  * the file pointer to the list
                    259:  * of people (argv style) with
                    260:  * a NULL pointer at the end.
                    261:  * The message is copied to a temp-file
                    262:  * from position `start' to `end' (or EOF).
                    263:  */
                    264: send(fp, users, start, end)
                    265: FILE *fp;
                    266: register char **users;
                    267: fsize_t start, end;
                    268: {
                    269:        FILE *tfp, *xfp;
                    270:        char **getcc();
                    271: 
                    272:        temp = templ;
                    273:        if ((tfp = fopen(temp, "w")) != NULL) {
                    274:                fclose(tfp);
                    275:                if ((tfp = fopen(temp, "r+w")) == NULL)
                    276:                        merr(toerr);
                    277:        } else
                    278:                merr(toerr);
                    279:        chown(temp, myuid, mygid);
                    280:        unlink(temp);
                    281:        temp = NULL;
                    282:        fseek(fp, start, 0);
                    283:        end -= start;
                    284: 
                    285:        eflag = 0;
                    286:        for (;;) {
                    287:                if (fgets(msgline, sizeof msgline, fp) == NULL)
                    288:                        break;
                    289:                if (fp == stdin)
                    290:                        if ((strcmp(".\n", msgline)==0))
                    291:                                break;
                    292:                        else if ((strcmp("?\n", msgline)==0)) {
                    293:                                eflag = 1;
                    294:                                break;
                    295:                        }
                    296:                if (strncmp("From ", msgline, 5) == 0)
                    297:                        putc('>', tfp);
                    298:                fputs(msgline, tfp);
                    299: 
                    300:                end -= strlen(msgline); /* compiler bug */              
                    301:                if (end <= 0) {
                    302:                        break;
                    303:                }
                    304:        }
                    305:        /*
                    306:         * If interrupted, bug out.
                    307:         */
                    308:        if (intcheck()) {
                    309:                fclose(tfp);
                    310:                return;
                    311:        }
                    312:        /*
                    313:         * Now, see if user wants to edit the message
                    314:         */
                    315:        if (eflag) {
                    316:                xfp = tfp;
                    317:                temp = templ;
                    318:                if ((tfp = fopen(temp, "wr")) == NULL)
                    319:                        merr(toerr);
                    320:                chown(temp, myuid, mygid);
                    321:                mcopy(xfp, tfp, (fsize_t)0, (fsize_t)MAXLONG, 0);
                    322:                fclose(xfp);
                    323:                sprintf(cmdname, "%s %s", editname, templ);
                    324:                system(cmdname);
                    325:                unlink(temp);
                    326:                temp = NULL;
                    327:        }
                    328:        /*
                    329:         * Otherwise if empty message, bug out.
                    330:         */
                    331:        else if (ftell(tfp) == 0) {
                    332:                fclose(tfp);
                    333:                return;
                    334:        }
                    335:        /*
                    336:         * Now see if a copy list is requested.
                    337:         */
                    338:        if (askcc)
                    339:          users = getcc(users);
                    340:        /*
                    341:         * Now send the message.
                    342:         */
                    343:        if (callmexmail)
                    344:          xsend(users, tfp);
                    345:        else
                    346:          usend(users, tfp);
                    347: }
                    348: 
                    349: char *subject()
                    350: {
                    351:   /* lauren's mail refuses to read a subject from standard input */
                    352:   /* without discarding the rest of the message */
                    353:   /* and refuses to accept an empty subject on the command line */
                    354:   /* so we supply a subject */
                    355:   static char *subject[] = {
                    356: #if 0
                    357:     "national security", "world peace", "elvis sighted",
                    358:     "ayatollah ups reward", "new version", "old version",
                    359:     "budget deficit", "technical support", "worker satisfaction",
                    360:     "profit sharing", "fringe benefit", "coherent software",
                    361:     "computer virus", "no subject", "forbidden",
                    362:     "to memory failure", "ive", "object", "not specified",
                    363:     "new policy", "old policy", "pass words",
                    364: #else
                    365:     " "
                    366: #endif
                    367:   };
                    368:   srand((int)time(NULL));
                    369:   return subject[rand() % (sizeof(subject)/sizeof(subject[0]))];
                    370: }
                    371: 
                    372: usend(users, tfp) char **users; FILE *tfp;
                    373: {
                    374:   FILE *xfp;
                    375:   strcpy(cmdname, "/usr/bin/uumail");
                    376:   while (*users) {
                    377:     strcat(cmdname, " ");
                    378:     strcat(cmdname, *users++);
                    379:   }
                    380:   strcat(cmdname, " -n -s'");
                    381:   strcat(cmdname, subject());
                    382:   strcat(cmdname, "'");
                    383:   rewind(tfp);
                    384:   if ((xfp = popen(cmdname, "w")) == NULL) {
                    385:     mmsg("Can't pipe to uumail\n");
                    386:     return;
                    387:   }
                    388:   if (mcopy(tfp, xfp, (fsize_t)0, (fsize_t)MAXLONG), 0)
                    389:     merr(wrerr, cmdname);
                    390:   pclose(xfp);
                    391: }
                    392: xsend(users, tfp) char **users; FILE *tfp;
                    393: {
                    394:        register char **ulist;
                    395:        register char *cp;
                    396:        register struct passwd *pwp;
                    397:        time_t curtime;
                    398:        FILE *xfp;
                    399: 
                    400:        time(&curtime);
                    401:        tp = localtime(&curtime);
                    402:        cp = asctime(tp);
                    403:        cp[strlen(cp)-1] = 0;
                    404:        sprintf(header, "From %s %s %s\n", myname, cp,
                    405:            tzname[tp->tm_isdst ? 1 : 0]);
                    406:        if (users[0]!=NULL && users[1]!=NULL) {
                    407:                strcat(header, "(cc:");
                    408:                for (ulist = users; *ulist != NULL; ulist++) {
                    409:                        strcat(header, " ");
                    410:                        strcat(header, *ulist);
                    411:                }
                    412:                strcat(header, ")\n");
                    413:        }
                    414:        for (ulist = users; *ulist!=NULL; ulist++) {
                    415:                rewind(tfp);
                    416:                sprintf(boxname, "%s%s", SPOOLDIR, *ulist);
                    417:                sprintf(cmdname, "xencode %s >> %s", *ulist, boxname);
                    418:                if (index(*ulist, '!') != NULL
                    419:                 || (pwp = getpwnam(*ulist)) == NULL) {
                    420:                        mmsg(nosend, *ulist);
                    421:                        continue;
                    422:                }
                    423:                if (xaccess(*ulist) == 0) {
                    424:                        mmsg(nopubk, *ulist);
                    425:                        continue;
                    426:                }
                    427:                mlock(pwp->pw_uid);
                    428:                if ((xfp = fopen(boxname, "a")) == NULL) {
                    429:                        mmsg(nosend, *ulist);
                    430:                        munlock();
                    431:                        continue;
                    432:                }
                    433:                chown(boxname, pwp->pw_uid, pwp->pw_gid);
                    434:                fprintf(xfp, "From xmail %s %s\n", cp,
                    435:                  tzname[tp->tm_isdst ? 1 : 0]);
                    436:                fclose(xfp);
                    437:                if ((xfp = popen(cmdname, "w")) == NULL) {
                    438:                        mmsg("Can't pipe to xencode\n");
                    439:                        continue;
                    440:                }
                    441:                if (fwrite(header, strlen(header), 1, xfp) != 1
                    442:                 || mcopy(tfp, xfp, (fsize_t)0, (fsize_t)MAXLONG), 0) {
                    443:                        merr(wrerr, cmdname);
                    444:                }
                    445:                pclose(xfp);
                    446:                munlock();
                    447:        }
                    448:        fclose(tfp);
                    449: }
                    450: 
                    451: /*
                    452:  * Check access on a file.
                    453:  */
                    454: maccess(name)
                    455: char *name;
                    456: {
                    457:        struct stat sb;
                    458: 
                    459:        if (stat(name, &sb) < 0) {
                    460:                if (access(parent(name), ACREAT) < 0)
                    461:                        return (-1);
                    462:        } else if (access(name, AWRITE) < 0)
                    463:                return (-1);
                    464:        return (0);
                    465: }
                    466: 
                    467: /*
                    468:  * Check enrollment for xmail.
                    469:  */
                    470: xaccess(name) char *name;
                    471: {
                    472:        struct stat sb;
                    473:        sprintf(keyname, "%s%s", PUBKEYDIR, name);
                    474:        return stat(keyname, &sb) >= 0;
                    475: }
                    476: /*
                    477:  * Find the parent directory for access permissions.
                    478:  */
                    479: char *
                    480: parent(name)
                    481: char *name;
                    482: {
                    483:        register char *cp, *xp;
                    484:        static char p[256];
                    485:        char *rindex();
                    486: 
                    487:        xp = rindex(name, '/');
                    488:        if (xp == NULL)
                    489:                return (".");
                    490:        if (xp == name)
                    491:                return ("/");
                    492:        if (xp - name >= 256)
                    493:                return ("");
                    494:        cp = p;
                    495:        while (name < xp)
                    496:                *cp++ = *name++;
                    497:        *cp = 0;
                    498:        return (p);
                    499: }
                    500: 
                    501: /*
                    502:  * Copy from the file stream `ifp' (starting at
                    503:  * position `start' and ending at `end' or EOF)
                    504:  * to the file stream `ofp' which is assumed
                    505:  * to be already correctly positioned.
                    506:  * Returns non-zero on errors.
                    507:  * intstop == 1 means stop on interrupt
                    508:  * intstop == 0 means ignore interrupt
                    509:  */
                    510: mcopy(ifp, ofp, start, end, intstop)
                    511: register FILE *ifp, *ofp;
                    512: fsize_t start, end;
                    513: {
                    514:        register int c;
                    515: 
                    516:        fseek(ifp, start, 0);
                    517:        end -= start;
                    518:        if (intstop)
                    519:                while (!intcheck() && end-- > 0  &&  (c = getc(ifp))!=EOF)
                    520:                        putc(c, ofp);
                    521:        else
                    522:                while (end-- > 0  &&  (c = getc(ifp))!=EOF)
                    523:                        putc(c, ofp);
                    524:        fflush(ofp);
                    525:        if (ferror(ofp))
                    526:                return (1);
                    527:        return (0);
                    528: }
                    529: 
                    530: /*
                    531:  * Process mail's interactive commands
                    532:  * for reading/deleting/saving mail.
                    533:  */
                    534: commands()
                    535: {
                    536:        register struct msg *mp;
                    537:        struct msg *dest;
                    538:        register char **fnp;
                    539:        register FILE *fp;
                    540:        fsize_t seek;
                    541: 
                    542:        readmail();
                    543:        mprint(mp = rflag ? m_last : m_first);
                    544:        for (;;) {
                    545:                readmail();
                    546:                intcheck();
                    547:                if ( ! pflag) {
                    548:                        callmexmail = 0;
                    549:                        mmsg("? ");
                    550:                        if (fgets(cline, sizeof cline, stdin) == NULL) {
                    551:                                if (intcheck())
                    552:                                        continue;
                    553:                                break;
                    554:                        }
                    555:                }
                    556:                switch (cline[0]) {
                    557:                case 'd':
                    558:                        if (cline[1] != '\n')
                    559:                                goto usage;
                    560:                        mp->m_flag += 1;
                    561:                        goto advance;
                    562: 
                    563:                case 'm':
                    564:                case 't':
                    565:                        if (csplit(cline, args) == 1) {
                    566:                                args[1] = myname;
                    567:                                args[2] = NULL;
                    568:                        }
                    569:                        callmexmail = (cline[1] == 'x');
                    570:                        if (cline[0] == 'm')
                    571:                                send(mfp, args+1, mp->m_seek, mp->m_end);
                    572:                        else
                    573:                                send(stdin, args+1, 0L, (fsize_t)MAXLONG);
                    574:                        break;
                    575: 
                    576:                case '.':
                    577:                case 'p':
                    578:                        if (cline[1] == 'x') {
                    579:                                callmexmail = 1;
                    580:                                if (cline[2] != '\n')
                    581:                                        goto usage;
                    582:                        } else if (cline[1] != '\n')
                    583:                                goto usage;
                    584:                        if (mprint(mp))
                    585:                                break;
                    586:                        goto advance;
                    587: 
                    588:                case 'q':
                    589:                        if (cline[1] != '\n')
                    590:                                goto usage;
                    591:                        mquit();
                    592:                        /* NOTREACHED */
                    593: 
                    594:                case 'r':
                    595:                        if (cline[1] != '\n')
                    596:                                goto usage;
                    597:                        rflag = ! rflag;
                    598:                        break;
                    599:                case 's':
                    600:                case 'w':
                    601:                        if (csplit(cline, args) == 1) {
                    602:                                args[1] = mymbox;
                    603:                                args[2] = NULL;
                    604:                        }
                    605:                        seek = mp->m_seek;
                    606:                        if (cline[0] == 'w')
                    607:                                seek += mp->m_hsize;
                    608:                        for (fnp = &args[1]; *fnp != NULL; fnp++) {
                    609:                                fp = NULL;
                    610:                                if (maccess(*fnp) < 0
                    611:                                 || (fp = fopen(*fnp, "a")) == NULL
                    612:                                 || mcopy(mfp, fp, seek, mp->m_end, 0))
                    613:                                        mmsg(nosave, *fnp);
                    614:                                if (fp != NULL) {
                    615:                                        fclose(fp);
                    616:                                        chown(*fnp, myuid, mygid);
                    617:                                }
                    618:                        }
                    619:                        break;
                    620: 
                    621:                case 'x':
                    622:                        if (cline[1] != '\n')
                    623:                                goto usage;
                    624:                        rmexit(0);
                    625:                        /* NOTREACHED */
                    626: 
                    627:                case '!':
                    628:                        if (system(cline+1) == 127)
                    629:                                mmsg("Try again\n");
                    630:                        else
                    631:                                mmsg("!\n");
                    632:                        break;
                    633: 
                    634:                case '?':
                    635:                        mmsg(isummary);
                    636:                        break;
                    637: 
                    638:                case '-':
                    639:                        if (cline[1] != '\n')
                    640:                                goto usage;
                    641:                        dest = rflag ? m_last : m_first;
                    642:                        goto nextmsg;
                    643: 
                    644:                case '+':
                    645:                        if (cline[1] != '\n')
                    646:                                goto usage;
                    647:                case '\n':
                    648:                advance:
                    649:                        dest = rflag ? m_first : m_last;
                    650:                nextmsg:
                    651:                        do {
                    652:                                if (mp == dest) {
                    653:                                        if (pflag)
                    654:                                                return;
                    655:                                        mmsg("No more messages.\n");
                    656:                                        break;
                    657:                                }
                    658:                                mp = (dest==m_last) ? mp->m_next : mp->m_prev;
                    659:                        } while (mprint(mp) == 0);
                    660:                        break;
                    661: 
                    662:                default:
                    663:                usage:
                    664:                        mmsg(iusage);
                    665:                        break;
                    666:                }
                    667:        }
                    668:        putc('\n', stderr);
                    669:        mquit();
                    670: }
                    671: 
                    672: /*
                    673:  * Read through the mail-box file
                    674:  * constructing list of letters.
                    675:  * On subsequent calls, append any additional mail
                    676:  * and notify the user.
                    677:  */
                    678: readmail()
                    679: {
                    680:        register struct msg *mp, *lmp;
                    681:        struct stat sb;
                    682:        static long m_last_end;
                    683:        long last;
                    684: 
                    685:        if (m_first == NULL) {
                    686:                if (stat(mailbox, &sb) < 0)
                    687:                        merr(nombox, mailbox);
                    688:                if (sb.st_size == 0)
                    689:                        merr(nomail);
                    690:                if (access(mailbox, AREAD) < 0)
                    691:                        merr(noperm, mailbox);
                    692:                if ((mfp = fopen(mailbox, "r")) == NULL)
                    693:                        merr(moerr, mailbox);
                    694:                mp = lmp = NULL;
                    695:                last = m_last_end = 0;
                    696:        } else {
                    697:                fstat(fileno(mfp), &sb);
                    698:                if (sb.st_size == m_last_end)
                    699:                        return;
                    700:                mmsg("More mail received.\n");
                    701:                mp = lmp = m_last;
                    702:                last = mp->m_end;
                    703:                fseek(mfp, m_last_end, 0);
                    704:        }
                    705:        mlock(myuid);
                    706:        while (fgets(msgline, sizeof msgline, mfp) != NULL) {
                    707:                 if (strncmp("From ", msgline, 5) == 0) {
                    708:                        mp = (struct msg *)malloc(sizeof(*mp));
                    709:                        mp->m_prev = NULL;
                    710:                        mp->m_next = NULL;
                    711:                        mp->m_flag = 0;
                    712:                        mp->m_hsize = strlen(msgline);
                    713:                        mp->m_seek = ftell(mfp)-mp->m_hsize;
                    714:                        if (lmp == NULL) {
                    715:                                m_first = mp;
                    716:                        } else {
                    717:                                lmp->m_next = mp;
                    718:                                lmp->m_end = last;
                    719:                        }
                    720:                        mp->m_prev = lmp;
                    721:                        m_last = lmp = mp;
                    722:                }
                    723:                if (strcmp("\n", msgline) != 0
                    724:                 && strcmp("\1\1\n", msgline) != 0)
                    725:                        last = ftell(mfp);
                    726:        }
                    727:        if (mp == NULL)
                    728:                merr("Not mailbox format '%s'\n", mailbox);
                    729:        mp->m_end = last;
                    730:        m_last_end = ftell(mfp);
                    731:        munlock();
                    732: }
                    733: 
                    734: /*
                    735:  * Split a command line up into
                    736:  * argv (passed) and argc (returned).
                    737:  */
                    738: int
                    739: csplit(command, args)
                    740: char *command;
                    741: char **args;
                    742: {
                    743:        register char *cp;
                    744:        register char **ap;
                    745:        register int c;
                    746: 
                    747:        cp = command;
                    748:        ap = args;
                    749:        for (;;) {
                    750:                while ((c = *cp)==' ' || c=='\t')
                    751:                        *cp++ = '\0';
                    752:                if (*cp == '\n')
                    753:                        *cp = '\0';
                    754:                if (*cp == '\0')
                    755:                        break;
                    756:                *ap++ = cp;
                    757:                while ((c = *cp)!=' ' && c!='\t' && c!='\n' && c!='\0')
                    758:                        cp++;
                    759:        }
                    760:        *ap = NULL;
                    761:        return (ap - args);
                    762: }
                    763: 
                    764: /*
                    765:  * Lock the appropriately-numbered mailbox
                    766:  * (numbered by user-number) from multiple
                    767:  * accesses. There is a (small) race here
                    768:  * which will be overlooked for now.
                    769:  */
                    770: char   *lockname;
                    771: 
                    772: mlock(uid)
                    773: int uid;
                    774: {
                    775:        register int fd;
                    776:        static char lock[32];
                    777: 
                    778:        lockname = lock;
                    779:        sprintf(lock, "/tmp/maillock%d", uid);
                    780:        while (access(lockname, 0) == 0)
                    781:                sleep(1);
                    782:        if ((fd = creat(lockname, 0)) >= 0)
                    783:                close(fd);
                    784: }
                    785: 
                    786: /*
                    787:  * Unlock the currently-set lock (by `mlock')
                    788:  * also called from rmexit.
                    789:  */
                    790: munlock()
                    791: {
                    792:        if (lockname != NULL)
                    793:                unlink(lockname);
                    794:        lockname = NULL;
                    795: }
                    796: 
                    797: /*
                    798:  * Exit, after rewriting the
                    799:  * mailbox
                    800:  */
                    801: mquit()
                    802: {
                    803:        register struct msg *mp;
                    804:        register FILE *nfp;
                    805:        struct stat sb;
                    806: 
                    807:        readmail();
                    808:        mlock(myuid);
                    809:        if (mailbox != spoolname && maccess(mailbox) < 0)
                    810:                merr(noperm, mailbox);
                    811:        fstat(fileno(mfp), &sb);
                    812:        signal(SIGINT, SIG_IGN);
                    813:        unlink(mailbox);
                    814:        if ((nfp = fopen(mailbox, "w")) == NULL)
                    815:                merr("Cannot re-write '%s'\n", mailbox);
                    816:        chown(mailbox, sb.st_uid, sb.st_gid);
                    817:        chmod(mailbox, sb.st_mode&0777);
                    818:        for (mp = m_first; mp != NULL; mp = mp->m_next)
                    819:                if (mp->m_flag == 0
                    820:                 && mcopy(mfp, nfp, mp->m_seek, mp->m_end, 0))
                    821:                        merr(wrerr, mailbox);
                    822:        fclose(nfp);
                    823:        fclose(mfp);
                    824:        munlock();
                    825:        rmexit(0);
                    826: }
                    827: 
                    828: /*
                    829:  * Print the current message, given by
                    830:  * the message pointer (`mp').
                    831:  */
                    832: mprint(mp)
                    833: register struct msg *mp;
                    834: {
                    835:        FILE *xfp;
                    836:        if (mp->m_flag)
                    837:                return 0;
                    838:        if (callmexmail) {
                    839:                sprintf(cmdname, "xdecode");
                    840:                if ((xfp = popen(cmdname, "w")) == NULL) {
                    841:                        return 0;
                    842:                }
                    843:                mcopy(mfp, xfp, mp->m_seek+mp->m_hsize, mp->m_end, 1);
                    844:                pclose(xfp);
                    845:        } else {
                    846:                fseek(mfp, mp->m_seek, 0);
                    847:                if (fgets(msgline, sizeof msgline, mfp) != NULL &&
                    848:                    strncmp(msgline, "From xmail", 10) == 0) {
                    849:                        printf("From xmail\n");
                    850:                        system("/usr/games/fortune");
                    851:                        return(1);
                    852:                }
                    853:                mcopy(mfp, stdout, mp->m_seek, mp->m_end, 1);
                    854:        }
                    855:        return (1);
                    856: }
                    857: 
                    858: /*
                    859:  *     Get additional users to receive message (CC:)
                    860:  */
                    861: 
                    862: char **
                    863: getcc(users)
                    864: register char **users;
                    865: {
                    866:        register char **ulist = args;
                    867:        static  char names[NCLINE];
                    868: 
                    869:        mmsg("CC: ");
                    870:        if ( fgets(names, sizeof names, stdin) == NULL )
                    871:                return(users);
                    872: 
                    873:        while (*users != NULL)
                    874:                *ulist++ = *users++;
                    875: 
                    876:        csplit(names, ulist);
                    877:        return(args);
                    878: }
                    879: 
                    880:        
                    881: /*
                    882:  * Errors, usage, and exit removing
                    883:  * any tempfiles left around.
                    884:  */
                    885: mmsg(x, s)
                    886: char *x, *s;
                    887: {
                    888:        fprintf(stderr, x, s);
                    889: }
                    890: 
                    891: merr(x, s)
                    892: char *x, *s;
                    893: {
                    894:        mmsg(x, s);
                    895:        rmexit(1);
                    896: }
                    897: 
                    898: usage()
                    899: {
                    900:        mmsg(helpmessage);
                    901:        rmexit(1);
                    902: }
                    903: 
                    904: rmexit(s)
                    905: int s;
                    906: {
                    907:        if (temp != NULL)
                    908:                unlink(temp);
                    909:        munlock();
                    910:        exit(s);
                    911: }
                    912: 
                    913: /*
                    914:  * Catch interrupts, taking the
                    915:  * appropriate action based on
                    916:  * the `-q' option.
                    917:  */
                    918: int    intflag;                /* On when interrupt sent */
                    919: 
                    920: catchintr()
                    921: {
                    922:        signal(SIGINT, SIG_IGN);
                    923:        if (qflag)
                    924:                rmexit(1);
                    925:        intflag = 1;
                    926:        signal(SIGINT, catchintr);
                    927: }
                    928: 
                    929: intcheck()
                    930: {
                    931:        if (intflag) {
                    932:                intflag = 0;
                    933:                putc('\n', stderr);
                    934:                return (1);
                    935:        }
                    936:        return (0);
                    937: }
                    938: 
                    939: /*
                    940:  * Call the system to execute a command line
                    941:  * which is passed as an argument.
                    942:  * Change the user id and group id.
                    943:  */
                    944: system(line)
                    945: char *line;
                    946: {
                    947:        int status, pid;
                    948:        register wpid;
                    949:        register int (*intfun)(), (*quitfun)();
                    950: 
                    951:        if ((pid = fork()) < 0)
                    952:                return (-1);
                    953:        if (pid == 0) {         /* Child */
                    954:                setuid(myuid);
                    955:                setgid(mygid);
                    956:                execl("/bin/sh", "sh", "-c", line, NULL);
                    957:                exit(0177);
                    958:        }
                    959:        intfun = signal(SIGINT, SIG_IGN);
                    960:        quitfun = signal(SIGQUIT, SIG_IGN);
                    961:        while ((wpid = wait(&status))!=pid && wpid>=0)
                    962:                ;
                    963:        if (wpid < 0)
                    964:                status = wpid;
                    965:        signal(SIGINT, intfun);
                    966:        signal(SIGQUIT, quitfun);
                    967:        return (status);
                    968: }

unix.superglobalmegacorp.com

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