Annotation of coherent/d/bin/mail.c, revision 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.