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

1.1       root        1: static char    *rcsrev = "$Revision: 1.5 $";
                      2: static char    *rcshdr =
                      3: "$Header: /src386/bin/mail/RCS/mail.c,v 1.5 93/06/21 17:47:04 bin Exp Locker: bin $";
                      4: /*
                      5:  * $Header: /src386/bin/mail/RCS/mail.c,v 1.5 93/06/21 17:47:04 bin Exp Locker: bin $
                      6:  * $Log:       mail.c,v $
                      7:  * Revision 1.5  93/06/21  17:47:04  bin
                      8:  * bob h removed xmail referencs from help message.
                      9:  * 
                     10:  * Revision 1.4  92/05/28  10:28:53  bin
                     11:  * bob h added a test for new msgsep scheme so that mail will exit
                     12:  * if it does not detect the new sep scheme.
                     13:  * 
                     14:  * Revision 1.2  92/04/20  10:07:46  bin
                     15:  * The 'final' fix using CORRECT sources to properly write a msgsep at the
                     16:  * top of a save file if new file is opened or if saving the first message
                     17:  * of a mailbox to a file
                     18:  * 
                     19:  * Revision 1.1  92/04/20  09:03:08  bin
                     20:  * Initial revision
                     21:  * 
                     22:  * Revision 3.4        91/02/18  17:14:10      piggy
                     23:  * Fixed "q" command so that it works with a non-setuid mail.
                     24:  * 
                     25:  * Revision 3.3        91/02/18  09:30:09      piggy
                     26:  * Fixed two mishandlings of args[].
                     27:  * 
                     28:  * Revision 3.2        91/02/08  15:16:07      piggy
                     29:  * Updated error messages to include malloc failures.
                     30:  * 
                     31:  * Revision 3.1        91/02/08  14:34:28      piggy
                     32:  * Made csplit non-destructive.
                     33:  * 
                     34:  * Revision 3.0        91/02/07  15:19:14      piggy
                     35:  * *** empty log message ***
                     36:  * 
                     37:  * Revision 2.13       90/03/30  16:16:19      wgl
                     38:  * Correct seek pointer work within readmail.
                     39:  * 
                     40:  * Revision 2.12       90/03/12  14:19:08      wgl
                     41:  * New version of send doing aliases in a different place.
                     42:  * 
                     43:  * Revision 2.11       90/03/08  16:41:15      wgl
                     44:  * Add code to get signature file.
                     45:  * 
                     46:  * Revision 2.10       90/03/02  10:41:59      wgl
                     47:  * Add the -a flag so that uucp does not look like it is coming from
                     48:  * somewhere else.
                     49:  * 
                     50:  * Revision 2.9        90/03/01  11:17:19      wgl
                     51:  * Final conversion to rely soley on ^A^A as separators.
                     52:  * Effectively delete concept of m_hsize.
                     53:  * 
                     54:  * Revision 2.8        90/03/01  10:14:31      wgl
                     55:  * Go buy separators, not "From_" lines.
                     56:  * 
                     57:  * Revision 2.7        90/02/28  17:11:41      wgl
                     58:  * Add version print, add some changes to the message-id field.
                     59:  * 
                     60:  * Revision 2.6        90/02/28  16:42:09      wgl
                     61:  * Version number fakeout.
                     62:  * 
                     63:  * Revision 2.5        90/02/28  16:19:44      wgl
                     64:  * Try again to get versioin number right.
                     65:  * 
                     66:  * Revision 2.4        90/02/28  16:18:56      wgl
                     67:  * Get version number right.
                     68:  * 
                     69:  * Revision 2.3        90/02/28  16:04:59      wgl
                     70:  * Many changes; ripped out send.
                     71:  * Changes are to make it work with uucp and internet mail.
                     72:  * 
                     73:  * Revision 1.6        89/02/22  05:34:00      bin
                     74:  * Changes by rec to integrate with lauren's uumail.
                     75:  * 
                     76:  * Revision 1.5        88/09/01  14:49:01      bin
                     77:  * Source administration: Re-install declaration of getenv. 
                     78:  * It was inserted after epstein made his copy.
                     79:  * 
                     80:  * Revision 1.4        88/09/01  14:44:49      bin
                     81:  * Mark Epsteins changes for ASKCC and for message scrolling, and interrupt
                     82:  * handling during processing.
                     83:  * 
                     84:  * Revision 1.3        88/09/01  14:27:41      bin
                     85:  * declare getenv to get rid of integer pointer pun error message.
                     86:  * 
                     87:  * Revision 1.2        88/09/01  11:02:23      bin
                     88:  * Remove extra declaration of header which had rcs stuff in it.
                     89:  * 
                     90:  * Revision 1.1        88/09/01  10:55:34      bin
                     91:  * Initial revision
                     92:  * 
                     93:  */
                     94: /*
                     95:  * The mail command.
                     96:  * Coherent electronic postal system, user agent.
                     97:  * With v3.0 this program no longer runs setuid.
                     98:  * Modifications by rec january 1986 to include xmail.
                     99:  *              by epstein november 1987 to include CC:
                    100:  *              by epstein november 1987 to allow ^C exit to leave you in
                    101:  *                                       mail command processor
                    102:  *              by epstein november 1987 to substitute /usr/games/fortune
                    103:  *                                       for printing encrypted messages
                    104:  *             by rec february 1989 to tail to lauren weinstein's
                    105:  *                     mail for alias expansion and uucp queuing.
                    106:  *             by wgl January 1990 to handle uucp mail more directly.
                    107:  */
                    108: 
                    109: char   isummary[] = "\
                    110: \
                    111: Command summary:\n\
                    112:        d               Delete current message and print the next message\n\
                    113:        m [user ...]    Mail current message to each named 'user'\n\
                    114:        p               Print current message again\n\
                    115:        q               Quit and update the mailbox\n\
                    116:        r               Reverse direction of scan\n\
                    117:        s [file ...]    Save message in each named 'file'\n\
                    118:        t [user ...]    Mail standard input to each named 'user'\n\
                    119:        w [file ...]    Save message in each named 'file' without its header\n\
                    120:        x               Exit without updating mailbox\n\
                    121:        newline         Print the next message\n\
                    122:        .               Print current message again\n\
                    123:        +               Print the next message\n\
                    124:        -               Print the previous message\n\
                    125:        EOF             Put undeleted mail back into mailbox and quit\n\
                    126:        ?               Print this command summary\n\
                    127:        !command        Pass 'command' to the shell to execute\n\
                    128: If no 'file' is specified, 'mbox' in user's home directory is default.\n\
                    129: If no 'user' is specified, the invoking user is default.\n\
                    130: \
                    131: ";
                    132: 
                    133: #include "mail.h"
                    134: 
                    135: #define        NARGS   64              /* Maximum # args to interactive command */
                    136: 
                    137: #define TRACE  printf
                    138: #define TRUE   1
                    139: #define FALSE  0
                    140: 
                    141: extern char    *getenv();
                    142: extern int     optind;
                    143: extern char    *optarg;
                    144: extern char    getopt();
                    145: extern char    *malloc();
                    146: int    csplit();
                    147: char   *eat_ws();
                    148: char   *find_ws();
                    149: char   *revnop();
                    150: 
                    151: int    mflag;                  /* `You have mail.' message to recipient */
                    152: int    rflag;                  /* Reverse order of print */
                    153: int    qflag;                  /* Exit after interrrupts */
                    154: int    pflag;                  /* Print mail */
                    155: int    verbflag;               /* verbose */
                    156: int    callmexmail;            /* Xmail modifier present */
                    157: int    callmermail;            /* rmail modifier present */
                    158: struct msg {
                    159:        struct msg *m_next;             /* Link to next message */
                    160:        struct msg *m_prev;             /* Link to previous message */
                    161:        int     m_flag;                 /* Flags - non-zero if deleted */
                    162:        int     m_hsize;                /* Size of header of message */
                    163:        fsize_t m_seek;                 /* Start position of message */
                    164:        fsize_t m_end;                  /* End of message */
                    165: };
                    166: struct msg     *m_first = NULL;        /* First message */
                    167: struct msg     *m_last = NULL;         /* Last message */
                    168: 
                    169: struct tm      *tp;
                    170: 
                    171: char   iusage[] = "Bad command--type '?' for command summary\n";
                    172: char   nombox[] = "No mailbox '%s'.\n";
                    173: char   nomail[] = "No mail.\n";
                    174: char   noperm[] = "Mailbox '%s' access denied.\n";
                    175: char   moerr[] = "Cannot open mailbox '%s'\n";
                    176: char   wrerr[] = "Write error on '%s'\n";
                    177: char   nosave[] = "Cannot save letter in '%s'\n";
                    178: char   allocerr[] = "%s: Can't malloc.\n";
                    179: 
                    180: FILE   *mfp;                           /* Mailbox stream */
                    181: int    myuid;                          /* User-id of mail user */
                    182: int    mygid;                          /* Group-id of mail user */
                    183: char   myname[25];                     /* User name */
                    184: char   myfullname[50];
                    185: char   mymbox[256];                    /* $HOME/mbox           */
                    186: char   mydead[256];                    /* $HOME/dead.letter    */
                    187: char   mysig[256];                     /* $HOME/.sig.mail      */
                    188: char   myalias[256];                   /* $HOME/.aliases       */
                    189: char   spoolname[50] = SPOOLDIR;
                    190: char   *mailbox = spoolname;
                    191: char   cmdname[1024];          /* Command for x{en,de}code filter */
                    192:                                /* and for tail recursion to uumail */
                    193:                                /* and for editor recursion */
                    194: 
                    195: char   *args[NARGS];                   /* Interactive command arglist */
                    196: char   msgline[NLINE];
                    197: char   cline[NCLINE] = "+\n";
                    198: char   *temp;                          /* Currently open temp file     */
                    199: char   templ[] = "/tmp/mailXXXXXX";    /* Temp file name template      */
                    200: char   *editname;                      /* name of editor               */
                    201: char   *scatname;                      /* name of scat filter          */
                    202: char   *askcc;                         /* Ask for CC: list? (YES/NO)   */
                    203: 
                    204: /* fsize_t     ftell(); */
                    205: char   *getlogin();
                    206: char   *mktemp();
                    207: int    catchintr();
                    208: int    catchpipe();
                    209: char   asuser [32];
                    210: 
                    211: typedef short int bool;
                    212: bool watch_first_msg;
                    213: bool delete_first_msg;
                    214: 
                    215: main(argc, argv)
                    216: char *argv[];
                    217: {
                    218:        register char *ap;
                    219:        char    c, *foo;
                    220:        int i;
                    221: 
                    222:        umask(077);
                    223:        logopen();
                    224: 
                    225:        /* Explicitly NULL out args.  */
                    226:        for (i = 0; i < NARGS; ++i) {
                    227:                args[i] = NULL;
                    228:        }
                    229: 
                    230:        ap = argv[0];
                    231:        if ( (foo=rindex(ap, '/')) != NULL )
                    232:                ap = foo+1;
                    233: 
                    234:        callmermail = (strcmp(ap, "rmail") == 0);
                    235:        callmexmail = (strcmp(ap, "xmail") == 0);
                    236: 
                    237:        if (callmermail)
                    238:                logdump("argv0 = rmail\n");
                    239: 
                    240:        asuser [0] = '\0';
                    241:        signal(SIGINT, catchintr);
                    242:        signal(SIGPIPE, catchpipe);
                    243:        while ((c = getopt(argc, argv, "a:f:mpqrv")) != EOF) {
                    244:                switch(c) {
                    245:                case 'f':
                    246:                        if (!callmermail)
                    247:                                mailbox = optarg;
                    248:                        break;
                    249:                case 'a':
                    250:                        strcpy(asuser, optarg);
                    251:                        break;
                    252:                case 'm':
                    253:                        mflag++;
                    254:                        break;
                    255:                case 'p':
                    256:                        pflag++;
                    257:                        break;
                    258:                case 'q':
                    259:                        qflag++;
                    260:                        break;
                    261:                case 'r':
                    262:                        rflag++;
                    263:                        break;
                    264:                case 'v':
                    265:                        fprintf(stderr, "mail, ver. %s\n", revnop());
                    266:                        verbflag++;
                    267:                        break;
                    268:                default:
                    269:                        usage();
                    270:                }
                    271:        }
                    272:        if (callmermail) 
                    273:                verbflag = mflag = pflag = rflag = 0;
                    274:        setname();
                    275:        if (optind < argc) {
                    276:                qflag = 1;
                    277:                if ( send2(stdin, &argv[optind], (fsize_t)0,
                    278:                                                 (fsize_t)MAXLONG, 1) != 0 )
                    279:                        rmexit(1);
                    280:        } else {
                    281:                if ( ! pflag)
                    282:                        callmexmail = 0;
                    283:                commands();
                    284:        }
                    285:        rmexit(0);
                    286: }
                    287: 
                    288: /*
                    289:  * Setup all the identities for the current user.
                    290:  */
                    291: setname()
                    292: {
                    293:        register struct passwd *pwp;
                    294:        register char *np;
                    295:        extern struct passwd * getpwnam();
                    296: 
                    297:        if (strlen(asuser) > 0) {
                    298:                if((pwp = getpwnam(asuser)) == NULL)
                    299:                        merr("No such user %s.\n", asuser);
                    300:                myuid = pwp -> pw_uid;
                    301:        } else          
                    302:                myuid = getuid();
                    303:        if ((pwp = getpwuid(myuid)) == NULL)
                    304:                merr("Who are you?\n");
                    305:        np = pwp->pw_name;
                    306:        mygid = pwp->pw_gid;
                    307:        strcat(spoolname, np);
                    308:        strcpy(myname, np);
                    309:        strcpy(myfullname, pwp->pw_gecos);
                    310:        strcpy(mymbox, pwp->pw_dir);
                    311:        strcat(mymbox, "/mbox");
                    312:        strcpy(mydead, pwp->pw_dir);
                    313:        strcat(mydead, "/dead.letter");
                    314:        strcpy(mysig, pwp->pw_dir);
                    315:        strcat(mysig, "/.sig.mail");
                    316:        strcpy(myalias, pwp->pw_dir);
                    317:        strcat(myalias, "/.aliases");
                    318:        mktemp(templ);
                    319: 
                    320:        if ((editname=getenv("EDITOR"))==NULL)
                    321:                editname = "/bin/ed";
                    322: 
                    323:        if ( ((scatname=getenv("PAGER")) != NULL) &&
                    324:             (strlen(scatname) == 0) )
                    325:                scatname = NULL;
                    326: 
                    327:        if ((askcc=getenv("ASKCC")) != NULL)
                    328:                if ( strcmp(askcc, "YES") )
                    329:                        askcc = NULL;
                    330: }
                    331: 
                    332: /*
                    333:  * Process mail's interactive commands
                    334:  * for reading/deleting/saving mail.
                    335:  */
                    336: commands()
                    337: {
                    338:        register struct msg *mp;
                    339:        struct msg *dest;
                    340:        struct stat filestats;
                    341:        register char **fnp;
                    342:        register FILE *fp;
                    343:        fsize_t seek;
                    344:        int need_to_add_sep;
                    345:        char am_i_sep[7];
                    346:        bool first_msg_read;
                    347:        int testfile; /* used to test if file exists */
                    348: 
                    349:        readmail();
                    350:        mprint(mp = rflag ? m_last : m_first);
                    351:        for (;;) {
                    352:                readmail();
                    353:                intcheck();
                    354: 
                    355:        /* if pflag is set, then we will loop through and print all messages
                    356:         * without stopping between messages for command prompts
                    357:         */
                    358:                if(!pflag){
                    359:                        callmexmail = 0;
                    360:                        mmsg("? ");
                    361:                        if (fgets(cline, sizeof cline, stdin) == NULL){
                    362:                                if(intcheck())
                    363:                                        continue;
                    364:                                break;
                    365:                        }
                    366:                }
                    367: 
                    368:                switch (cline[0]) {
                    369:                case 'd':
                    370:                        if (cline[1] != '\n')
                    371:                                goto usage;
                    372:                        mp->m_flag += 1;
                    373:                        if(mp->m_seek == 5)
                    374:                                delete_first_msg = TRUE;
                    375:                        goto advance;
                    376: 
                    377:                case 'm':
                    378:                case 't':
                    379:                        if (csplit(cline, args) == 1) {
                    380:                                /* We don't want to put anything into
                    381:                                   args that we didn't get from malloc. */
                    382: 
                    383:                                if (args[1] != NULL) {
                    384:                                        free(args[1]);
                    385:                                }
                    386:                                args[1] = malloc(strlen(myname) + 1);
                    387:                                strcpy(args[1], myname);
                    388:                                args[2] = NULL;
                    389:                        }
                    390:                        callmexmail = (cline[1] == 'x');
                    391:                        if (cline[0] == 'm') {
                    392:        /* when forwarding mail, seek  to msg start + 5 to rid the msgsep */
                    393:                        send2(mfp, args+1, (mp->m_seek + 5), mp->m_end - ((sizeof(MSGSEP) - 1) *2), 0);
                    394:                                fseek(mfp, mp->m_seek, 0);
                    395:                        } else
                    396:                                send2(stdin, args+1, 0L, (fsize_t)MAXLONG, 1);
                    397:                        break;
                    398: 
                    399:                case '.':
                    400:                case 'p':
                    401:                        if (cline[1] == 'x') {
                    402:                                callmexmail = 1;
                    403:                                if (cline[2] != '\n')
                    404:                                        goto usage;
                    405:                        } else if (cline[1] != '\n')
                    406:                                goto usage;
                    407:                        if (mprint(mp))
                    408:                                break;
                    409:                        goto advance;
                    410: 
                    411:                case 'q':
                    412:                        if (cline[1] != '\n')
                    413:                                goto usage;
                    414:                        mquit();
                    415:                        /* NOTREACHED */
                    416: 
                    417:                case 'r':
                    418:                        if (cline[1] != '\n')
                    419:                                goto usage;
                    420:                        rflag = ! rflag;
                    421:                        break;
                    422:                case 's':
                    423:                case 'w':
                    424:                        if (csplit(cline, args) == 1) {
                    425:                                /* We don't want to put anything into
                    426:                                   args that we didn't get from malloc. */
                    427: 
                    428:                                if (args[1] != NULL) {
                    429:                                        free(args[1]);
                    430:                                }
                    431:                                args[1] = malloc(strlen(mymbox) + 1);
                    432:                                strcpy(args[1], mymbox);
                    433:                                args[2] = NULL;
                    434:                        }
                    435:                        seek = mp->m_seek;
                    436:                        if (cline[0] == 'w')
                    437:                                seek += mp->m_hsize;
                    438:                        for (fnp = &args[1]; *fnp != NULL; fnp++) {
                    439:                                fp = NULL;
                    440: 
                    441:                                testfile = stat(*fnp, &filestats);
                    442: 
                    443:                /* attempt to open the file and write */
                    444: 
                    445:                                if ( (maccess(*fnp) < 0) 
                    446:                                  || ( (fp = fopen(*fnp,"a")) == NULL)
                    447:                                  || (mcopy(mfp,fp,seek,mp->m_end,0)))
                    448:                                        mmsg(nosave, *fnp);
                    449: 
                    450:                /* close the output file. Because some screwy 'not logic'
                    451:                 * was used to determine how msg seps were treated in elm
                    452:                 * (and I actually understood it after a while), it was
                    453:                 * semi implemented here for SCO mail format compatibility.
                    454:                 * Unfortunately, for reasons not clear to me yet, sometimes
                    455:                 * a message is copied to the out file with no msgsep appended
                    456:                 * to the end of it. So, after appending our message to the
                    457:                 * outfile, we will reopen the outfile, seek to the last
                    458:                 * byte - 5, and see if the last 5 bytes are a msgsep. If
                    459:                 * not, close the file and reopen for append and then write
                    460:                 * the msgsep.
                    461:                 */
                    462:                                if (fp != NULL) {
                    463:                                        fflush(fp);
                    464:                                        fclose(fp);
                    465:                                        stat(*fnp,&filestats);
                    466:                                        fp = fopen(*fnp,"r");
                    467: /*             TRACE("Seeking to position %d\n",(filestats.st_size - 5)); */
                    468:                                fseek(fp,(filestats.st_size - 5),0);
                    469:                                        fgets(am_i_sep,sizeof(MSGSEP),fp);
                    470:                                        fclose(fp);
                    471:                                        need_to_add_sep = strcmp(am_i_sep,MSGSEP
                    472: );
                    473:                                        if(need_to_add_sep){
                    474:                                                fp = fopen(*fnp,"a");
                    475:                                                fprintf(fp,MSGSEP);
                    476:                                                fflush(fp);
                    477:                                                fclose(fp);
                    478:                                        }
                    479:                        
                    480:                                        
                    481:                                        chown(*fnp, myuid, mygid);
                    482:                                }
                    483:                        }
                    484:                        break;
                    485: 
                    486:                case 'x':
                    487:                        if (cline[1] != '\n')
                    488:                                goto usage;
                    489:                        rmexit(0);
                    490:                        /* NOTREACHED */
                    491: 
                    492:                case '!':
                    493:                        if (system(cline+1) == 127)
                    494:                                mmsg("Try again\n");
                    495:                        else
                    496:                                mmsg("!\n");
                    497:                        break;
                    498: 
                    499:                case '?':
                    500:                        mmsg(isummary);
                    501:                        break;
                    502: 
                    503:                case '-':
                    504:                        if (cline[1] != '\n')
                    505:                                goto usage;
                    506:                        dest = rflag ? m_last : m_first;
                    507:                        goto nextmsg;
                    508: 
                    509:                case '+':
                    510:                        if (cline[1] != '\n')
                    511:                                goto usage;
                    512:                case '\n':
                    513:                advance:
                    514:                        dest = rflag ? m_first : m_last;
                    515:                nextmsg:
                    516:                        do {
                    517:                                if (mp == dest) {
                    518:                                        if (pflag)
                    519:                                                return;
                    520:                                        mmsg("No more messages.\n");
                    521:                                        break;
                    522:                                }
                    523:                                mp = (dest==m_last) ? mp->m_next : mp->m_prev;
                    524:                        } while (mprint(mp) == 0);
                    525:                        break;
                    526: 
                    527:                default:
                    528:                usage:
                    529:                        mmsg(iusage);
                    530:                        break;
                    531:                }
                    532:        }
                    533:        putc('\n', stderr);
                    534:        mquit();
                    535: }
                    536: 
                    537: /*
                    538:  * Read through the mail-box file
                    539:  * constructing list of letters.
                    540:  * On subsequent calls, append any additional mail
                    541:  * and notify the user.
                    542:  */
                    543: readmail()
                    544: {
                    545:        typedef short int bool;
                    546:        register struct msg *mp;
                    547:        struct stat sb;
                    548:        static long m_last_end;
                    549:        int datasw;
                    550:        bool newmsg;
                    551:        static bool checked_format;
                    552:        static fsize_t original_box_size;
                    553:        char convert_cmd[65];
                    554: 
                    555:        if (m_first == NULL) {
                    556:                if (stat(mailbox, &sb) < 0)
                    557:                        merr(nombox, mailbox);
                    558:                if (sb.st_size == 0)
                    559:                        merr(nomail);
                    560: 
                    561:                /* the following will open the mailbox and read the first
                    562:                 * line. If it is not a MSGSEP, then a message will be printed
                    563:                 * to run cvmail and exit.
                    564:                 */
                    565: 
                    566:                if(!checked_format){
                    567:                        if ((mfp = fopen(mailbox, "r")) == NULL)
                    568:                                merr(moerr, mailbox);
                    569:                        if(fgets(msgline, sizeof msgline, mfp) == NULL){
                    570:                                printf("Can not determine mailbox format\n");
                    571:                                exit(1);
                    572:                        }
                    573:                        fclose(mfp);
                    574:                        checked_format = TRUE;
                    575:                        if(strcmp(MSGSEP, msgline)){
                    576:                                printf("Your mailbox or mailfile needs to be converted to the proper format.\n");
                    577:                                strcpy(convert_cmd, "/bin/cvmail ");
                    578:                                strcat(convert_cmd, mailbox);
                    579:                                printf("\nTo manually convert your mailbox, run: %s\n\n", convert_cmd);
                    580:                                exit(1);
                    581:                        }
                    582:                }
                    583: 
                    584:                original_box_size = sb.st_size;
                    585:                if (access(mailbox, AREAD) < 0)
                    586:                        merr(noperm, mailbox);
                    587:                if ((mfp = fopen(mailbox, "r")) == NULL)
                    588:                        merr(moerr, mailbox);
                    589:                m_last_end = 0;
                    590:        } else {
                    591:                fstat(fileno(mfp), &sb);
                    592:                if (sb.st_size == m_last_end)
                    593:                        return;
                    594:                if (sb.st_size != original_box_size){
                    595:                        mmsg("More mail received.\n");
                    596:                        original_box_size = sb.st_size;
                    597:                }
                    598:        }
                    599: 
                    600:        /* we will enter a loop which reads the mailbox line by line.
                    601:         * When it hits a MSGSEP indicating the end of a mail message,
                    602:         * a struct msg will be set with the start and end positions
                    603:         * of the message read. We will continue through this loop until 
                    604:         * struct msg's have been built for all messages.
                    605:         */
                    606: 
                    607:        newmsg = TRUE;
                    608:        for(mlock(myuid);;) {
                    609:                fseek(mfp, m_last_end, 0);
                    610:                datasw = 0;
                    611:                while (fgets(msgline, sizeof msgline, mfp) != NULL) {
                    612:                        /* NB: this means the implicit message
                    613:                           seperator is actually "\n\1\1\n".  */
                    614:                        if(!(datasw = strcmp(MSGSEP, msgline))){
                    615: 
                    616:                                /* message seperator */
                    617:                                if (((newmsg = !newmsg) == TRUE) && (ftell(mfp) != 5)){
                    618:                                        mp = (struct msg *)myalloc(sizeof(*mp));
                    619:                                        mp->m_next = NULL;
                    620:                                        mp->m_prev = m_last;
                    621:                                        mp->m_flag = mp->m_hsize = 0;
                    622:        /* start position of msg */     mp->m_seek = m_last_end;
                    623:        /* end position of msg */       mp->m_end = m_last_end = ftell(mfp);
                    624: /*     TRACE("Message ends at %ld\n",ftell(mfp)); */
                    625:                                        if (m_first == NULL)
                    626:                                                m_last = m_first = mp;
                    627:                                        else
                    628:                                                m_last = m_last->m_next = mp;
                    629:                                }
                    630:                        }
                    631:                }
                    632: 
                    633:                if(!datasw) /* data ended with message seperator */
                    634:                        break;
                    635: 
                    636:                /* unterminated data, patch and retry */
                    637:                fclose(mfp);
                    638:                if ((mfp = fopen(mailbox, "a")) == NULL)
                    639:                        merr(moerr, mailbox);
                    640:                fprintf(mfp, MSGSEP); /* terminate it */
                    641:                fclose(mfp);
                    642:                if ((mfp = fopen(mailbox, "r")) == NULL)
                    643:                        merr(moerr, mailbox);
                    644:                mmsg("Incomplete message found.\n");
                    645:        }
                    646:        munlock();
                    647: }
                    648: 
                    649: /*
                    650:  * Lock the appropriately-numbered mailbox
                    651:  * (numbered by user-number) from multiple
                    652:  * accesses. There is a (small) race here
                    653:  * which will be overlooked for now.
                    654:  */
                    655: char   *lockname;
                    656: 
                    657: mlock(uid)
                    658: int uid;
                    659: {
                    660:        register int fd;
                    661:        static char lock[32];
                    662: 
                    663:        lockname = lock;
                    664:        sprintf(lock, "/tmp/maillock%d", uid);
                    665:        while (access(lockname, 0) == 0)
                    666:                sleep(1);
                    667:        if ((fd = creat(lockname, 0)) >= 0)
                    668:                close(fd);
                    669: }
                    670: 
                    671: /*
                    672:  * Unlock the currently-set lock (by `mlock')
                    673:  * also called from rmexit.
                    674:  */
                    675: munlock()
                    676: {
                    677:        if (lockname != NULL)
                    678:                unlink(lockname);
                    679:        lockname = NULL;
                    680: }
                    681: 
                    682: /*
                    683:  * Exit, after rewriting the
                    684:  * mailbox
                    685:  */
                    686: mquit()
                    687: {
                    688:        register struct msg *mp;
                    689:        register FILE *nfp, *tmpfp;
                    690:        struct stat sb;
                    691: 
                    692:        /* Get new stuff. */
                    693:        readmail();
                    694:        /* There is a slight race here.  We really should
                    695:           lock BEFORE the readmail(), but readmail() does unlocks...
                    696:           FIX ME. */
                    697:        mlock(myuid);
                    698: 
                    699:        if (mailbox != spoolname && maccess(mailbox) < 0)
                    700:                merr(noperm, mailbox);
                    701:        fstat(fileno(mfp), &sb);
                    702:        signal(SIGINT, SIG_IGN);
                    703:        signal(SIGPIPE, SIG_IGN);
                    704: 
                    705:        /* Make a copy of the mail box; we're going to overwrite it.  */
                    706:        tmpfp = tmp_copy(mfp);
                    707:        fclose(mfp);
                    708: 
                    709:        if ((nfp = fopen(mailbox, "w")) == NULL)
                    710:                merr("Cannot re-write '%s'\n", mailbox);
                    711:        chown(mailbox, sb.st_uid, sb.st_gid);
                    712:        chmod(mailbox, sb.st_mode&0777);
                    713:        for (mp = m_first; mp != NULL; mp = mp->m_next) {
                    714: 
                    715:                if (mp->m_flag == 0) {
                    716:                        if(delete_first_msg){
                    717:                                mp->m_seek = mp->m_seek+5;
                    718:                                delete_first_msg = FALSE;
                    719:                        }
                    720:                        if (mcopy(tmpfp, nfp, mp->m_seek, mp->m_end, 0)) {
                    721:                                merr(wrerr, mailbox);
                    722:                        }
                    723:                } /* if (mp->m_flag == 0) */
                    724: 
                    725:        } /* for (walk through the linked list of messages) */
                    726: 
                    727:        fclose(nfp);
                    728:        fclose(tmpfp);
                    729:        munlock();
                    730:        rmexit(0);
                    731: }
                    732: 
                    733: /*
                    734:  * Print the current message, given by
                    735:  * the message pointer (`mp').
                    736:  */
                    737: mprint(mp)
                    738: register struct msg *mp;
                    739: {
                    740:        FILE *xfp;
                    741: 
                    742:        if (mp->m_flag)
                    743:                return 0;
                    744:        if (callmexmail) {
                    745:                if (scatname != NULL) 
                    746:                        sprintf(cmdname, "xdecode | %s", scatname);
                    747:                else
                    748:                        sprintf(cmdname, "xdecode");
                    749:                if ((xfp = popen(cmdname, "w")) == NULL)
                    750:                        return 0;
                    751:                fprintf(xfp, MSGSEP);
                    752:                mcopy(mfp, xfp, mp->m_seek+mp->m_hsize, mp->m_end, 1);
                    753:                pclose(xfp);
                    754:        } else {
                    755:                fseek(mfp, mp->m_seek, 0);
                    756:                if (fgets(msgline, sizeof msgline, mfp) != NULL &&
                    757:                    strncmp(msgline, "From xmail", 10) == 0) {
                    758:                        printf("From xmail\n");
                    759:                        system("/usr/games/fortune");
                    760:                        return(1);
                    761:                }
                    762:                if (scatname != NULL) {
                    763:                        sprintf(cmdname, "%s", scatname);
                    764:                        if ((xfp = popen(cmdname, "w")) == NULL)
                    765:                                return(0);
                    766:                        mcopy(mfp, xfp, mp->m_seek, mp->m_end - 5, 1);
                    767:                        if ( ((pclose(xfp)>>8)&0xFF) == SIGINT )
                    768:                                putc('\n', stdout);
                    769:                } else {
                    770:                        mcopy(mfp, stdout, mp->m_seek, mp->m_end - 5, 1);
                    771:                }
                    772:        }
                    773:        return (1);
                    774: }
                    775: 
                    776: /*
                    777:  *     Get additional users to receive message (CC:)
                    778:  */
                    779: 
                    780: char **
                    781: getcc()
                    782: {
                    783:        static  char names[NCLINE];
                    784:        static  char *ccargs[NARGS];
                    785: 
                    786:        ccargs[0] = NULL;
                    787:        mmsg("CC: ");
                    788:        if ( fgets(names, sizeof names, stdin) == NULL )
                    789:                return(ccargs);
                    790: 
                    791:        csplit(names, ccargs);
                    792:        return(ccargs);
                    793: }
                    794: 
                    795:        
                    796: /*
                    797:  * Errors, usage, and exit removing
                    798:  * any tempfiles left around.
                    799:  */
                    800: mmsg(x)
                    801: {
                    802:        fprintf(stderr, "%r", &x);
                    803: }
                    804: 
                    805: merr(x, s)
                    806: char *x, *s;
                    807: {
                    808:        mmsg(x, s);
                    809:        logdump("merr: ");
                    810:        logdump(x, s);
                    811:        rmexit(1);
                    812: }
                    813: 
                    814: rmexit(s)
                    815: int s;
                    816: {
                    817:        if (temp != NULL)
                    818:                unlink(temp);
                    819:        munlock();
                    820: 
                    821:        logdump("About to exit, status = 0x%04x\n", s);
                    822:        logclose();
                    823: 
                    824:        exit(s);
                    825: }
                    826: 
                    827: /*
                    828:  * Catch interrupts, taking the
                    829:  * appropriate action based on
                    830:  * the `-q' option.
                    831:  */
                    832: int    intrflag;               /* On when interrupt sent       */
                    833: int    pipeflag;               /* On when broken pipe caught   */
                    834: 
                    835: catchintr()
                    836: {
                    837:        logdump("Caught SIGINT\n");
                    838:        if (qflag)
                    839:                rmexit(1);
                    840:        intrflag = 1;
                    841:        signal(SIGINT, catchintr);
                    842: }
                    843: 
                    844: catchpipe()
                    845: {
                    846:        logdump("Caught SIGPIPE\n");
                    847:        pipeflag = 1;
                    848:        signal(SIGPIPE, catchpipe);
                    849: }
                    850: 
                    851: intcheck()
                    852: {
                    853:        if (intrflag || pipeflag) {
                    854:                if (intrflag)
                    855:                        putc('\n', stdout);
                    856:                intrflag = pipeflag = 0;
                    857:                return (1);
                    858:        }
                    859:        return (0);
                    860: }
                    861: 
                    862: /*
                    863:  * Call the system to execute a command line
                    864:  * which is passed as an argument.
                    865:  * Change the user id and group id.
                    866:  */
                    867: system(line)
                    868: char *line;
                    869: {
                    870:        int status, pid;
                    871:        register wpid;
                    872:        register int (*intfun)(), (*quitfun)();
                    873: 
                    874:        if ((pid = fork()) < 0)
                    875:                return (-1);
                    876:        if (pid == 0) {         /* Child */
                    877:                setuid(myuid);
                    878:                setgid(mygid);
                    879:                execl("/bin/sh", "sh", "-c", line, NULL);
                    880:                exit(0177);
                    881:        }
                    882:        intfun = signal(SIGINT, SIG_IGN);
                    883:        quitfun = signal(SIGQUIT, SIG_IGN);
                    884:        while ((wpid = wait(&status))!=pid && wpid>=0)
                    885:                ;
                    886:        if (wpid < 0)
                    887:                status = wpid;
                    888:        signal(SIGINT, intfun);
                    889:        signal(SIGQUIT, quitfun);
                    890:        return (status);
                    891: }
                    892: 
                    893: char   *
                    894: revnop()
                    895: {
                    896:        register        char *cp;
                    897:        register        char c;
                    898:        static          char revnobuf[32];
                    899: 
                    900:        if ((cp = index(rcsrev, ' ')) != NULL) {
                    901:                while (((c = *++cp) == ' ') && (c != '\0'))
                    902:                        ;
                    903:                strcpy(revnobuf, cp);
                    904:                if ((cp = index(revnobuf, ' ')) != NULL)
                    905:                        *cp = '\0';
                    906:                return (revnobuf);
                    907:        } else
                    908:                return("OOPS");
                    909: }
                    910: 
                    911: /*
                    912:  * Split a command line up into
                    913:  * argv (passed) and argc (returned).
                    914:  * We assume that elements of "args" are either NULL or they were
                    915:  * returned from malloc, so that they can be freed.
                    916:  */
                    917: int
                    918: csplit(command, args)
                    919: char *command;
                    920: char **args;
                    921: {
                    922:        register char *cp;
                    923:        int i, argsize;
                    924: 
                    925:        i = 0; /* Start filling in at the zero'th arg.  */
                    926:        cp = eat_ws(command);   
                    927: 
                    928:        /* Walk "cp" through "command", copying segments as we go.  */
                    929:        while ( *cp != CNULL ) {
                    930:                /* We've found an argument; find some space.  */
                    931:                if (args[i] != NULL ) {
                    932:                        free(args[i]);
                    933:                }
                    934: 
                    935:                /* Figure out how big the argment is.  */
                    936:                argsize = (int) (find_ws(cp) - cp);
                    937: 
                    938:                /* Alloc enough space for it--include the trailing NULL.  */
                    939:                if ((args[i] = malloc(argsize + 1)) == NULL) {
                    940:                        mmsg(allocerr, "csplit");
                    941:                        return(0);  /* Is this the approriate action?? */
                    942:                }
                    943: 
                    944:                /* Copy the argument into the space.  */
                    945:                memcpy(args[i], cp, argsize);
                    946:                args[i][argsize] = CNULL; /* This may be redundant.  */
                    947: 
                    948:                /* Make sure that cp points to after the argument.  */
                    949:                cp += argsize;
                    950: 
                    951:                cp = eat_ws(cp);
                    952:                ++i;
                    953:        } /* while (walk "cp" through "command") */
                    954: 
                    955:        args[i] = NULL;
                    956:        return (i);
                    957: }
                    958: 
                    959: /*
                    960:  * Find the next occurence of non-white space in character string s.
                    961:  */
                    962: char *
                    963: eat_ws(s)
                    964:        char *s;
                    965: {
                    966:        while(isspace(*s)){
                    967:                ++s;
                    968:        }
                    969:        return(s);
                    970: }
                    971: 
                    972: /*
                    973:  * Find next occurence of white space in character string s.
                    974:  */
                    975: char *
                    976: find_ws(s)
                    977:        register char *s;
                    978: {
                    979:        while((*s != CNULL) && !isspace(*s) ){
                    980:                ++s;
                    981:        }
                    982:        return(s);
                    983: }      

unix.superglobalmegacorp.com

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