Annotation of researchv8dc/cmd/upas/print/print.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *     print mail
                      3:  */
                      4: #include <stdio.h>
                      5: #include <sys/types.h>
                      6: #include <sys/stat.h>
                      7: #include <setjmp.h>
                      8: #include <ctype.h>
                      9: #include "mail.h"
                     10: #include "letter.h"
                     11: #include "string.h"
                     12: 
                     13: /* globals */
                     14: static int flgp;
                     15: static int manual;
                     16: static int forward;
                     17: static int nlet;
                     18: static int error;
                     19: static int otherfile;
                     20: static jmp_buf sjbuf;
                     21: #define seq(i) (forward ? i-1 : nlet-i)
                     22: static int changed;            /* true if mail file has been changed */
                     23: 
                     24: /* exported */
                     25: char *thissys;
                     26: 
                     27: /* imported */
                     28: extern void lock();
                     29: extern void unlock();
                     30: extern char *getlogin();
                     31: extern char *getenv();
                     32: extern char *getarg();
                     33: extern FILE *popen();
                     34: extern char *mailpath();
                     35: extern long getunix();
                     36: extern char *getsysname();
                     37: extern char *P();
                     38: extern void V();
                     39: 
                     40: /* predefined */
                     41: static char *doargs();
                     42: static long copymt();
                     43: static void domanual();
                     44: static void doauto();
                     45: static int docommand();
                     46: static int copyback();
                     47: static int done();
                     48: static int special_mailfile();
                     49: static int doprint();
                     50: static void dohelp();
                     51: static void print_from();
                     52: static int reply();
                     53: static int remail();
                     54: static int squirrel_away();
                     55: 
                     56: main(argc, argv)
                     57: char **argv;
                     58: {
                     59:        struct stat stbuf;
                     60:        char *mp, *tp;
                     61:        long mailsize;
                     62:        FILE *malf;
                     63: 
                     64:        mp = doargs(argc, argv);
                     65:        if (stat(mp, &stbuf) < 0 || stbuf.st_size == 0L) {
                     66:                printf("No mail.\n");
                     67:                return 0;
                     68:        }
                     69:        thissys = getsysname();
                     70:        (void)signal(SIGINT, done);
                     71:        (void)signal(SIGHUP, done);
                     72:        lock(mp);
                     73:        tp = otherfile ? NULL : P();
                     74:        if (tp != NULL)
                     75:                fprintf(stderr, "You are already reading mail on %s!\n\n", tp);
                     76:        malf = fopen(mp, "r");
                     77:        if (malf == NULL) {
                     78:                fprintf(stderr, "mail: cannot read %s.\n", mp);
                     79:                error++;
                     80:                (void)done();
                     81:        }
                     82: 
                     83:        /* see if we're piping or forwarding */
                     84:        if(special_mailfile(mp))
                     85:                (void)done();
                     86: 
                     87:        /* make temporary */
                     88:        inittmp();
                     89: 
                     90:        /* read mbox */
                     91:        mailsize = copymt(malf);
                     92:        fclose(malf);
                     93:        unlock();
                     94: 
                     95:        /* print the mail */
                     96:        if (flgp)
                     97:                printall();
                     98:        else {
                     99:                if (manual)
                    100:                        domanual();
                    101:                else
                    102:                        doauto();
                    103:        }
                    104:        if (changed)
                    105:                copyback(mailsize, mp);
                    106:        (void)done();
                    107: 
                    108:        return 0;
                    109: }
                    110: 
                    111: /*     Output all messages */
                    112: printall()
                    113: {
                    114:        int i, current;
                    115: 
                    116:        for (i = 0; i < nlet; i++) {
                    117:                current = forward ? i : nlet - i - 1;
                    118:                doprint(current);
                    119:        }
                    120: }
                    121: 
                    122: /* remember an interrupt happened */
                    123: rememberint()
                    124: {
                    125:        signal(SIGINT, rememberint);
                    126:        clearerr(stdin);
                    127:        clearerr(stdout);
                    128:        longjmp(sjbuf, 1);
                    129: }
                    130: 
                    131: #define eatwhite(p) while(*p==' '||*p=='\t') p++
                    132: 
                    133: /*
                    134:  *     Return a letter number
                    135:  */
                    136: static int
                    137: lnumber(pp, dot, def)
                    138:        char **pp;
                    139: {
                    140:        eatwhite(*pp);
                    141:        switch(**pp) {
                    142:        case '$':
                    143:                (*pp)++;
                    144:                dot = nlet;
                    145:                break;
                    146:        case 'n':
                    147:        case '+':
                    148:                (*pp)++;
                    149:                dot = dot + 1;
                    150:                break;
                    151:        case '^':
                    152:        case '-':
                    153:                (*pp)++;
                    154:                dot = dot - 1;
                    155:                break;
                    156:        case '.':
                    157:                (*pp)++;
                    158:                break;
                    159:        case '0': case '1': case '2': case '3': case '4':
                    160:        case '5': case '6': case '7': case '8': case '9':
                    161:                dot = 0;
                    162:                while (isdigit(**pp))
                    163:                        dot = dot*10 + *(*pp)++ - '0';
                    164:                break;          /* first letter is 1 */
                    165:        default:
                    166:                dot = def;
                    167:                break;
                    168:        }
                    169:        if (dot <= 0)
                    170:                dot = 1;
                    171:        return dot;
                    172: }
                    173: 
                    174: /*
                    175:  *     Read and parse a command line.  A command consists of an optional
                    176:  *     range, a single letter command, and optional arguments.
                    177:  */
                    178: static char *
                    179: parse(cmdp, firstp, lastp, dot)
                    180:        char *cmdp;             /* the 1 letter command */
                    181:        int *firstp;            /* first command in a range */
                    182:        int *lastp;             /* last command in a range */
                    183:        int dot;                /* current letter */
                    184: {
                    185:        static char resp[CMDSIZE];
                    186:        char *p = resp;
                    187: 
                    188:        /* get command and dump trailing newline */
                    189:        printf("? ");
                    190:        fflush(stdout);
                    191:        if (fgets(resp, CMDSIZE, stdin) == NULL)
                    192:                return NULL;
                    193:        p[strlen(p) - 1] = '\0';
                    194: 
                    195:        /* get range */
                    196:        eatwhite(p);
                    197:        if (*p != '\0') {
                    198:                if (*p == ',')
                    199:                        *firstp = 1;
                    200:                else
                    201:                        *firstp = lnumber(&p, dot, dot);
                    202:                eatwhite(p);
                    203:                if (*p != ',')
                    204:                        *lastp = *firstp;
                    205:                else {
                    206:                        p++;
                    207:                        *lastp = lnumber(&p, dot, nlet);
                    208:                }
                    209:        } else
                    210:                *firstp = *lastp = dot+1;
                    211:        
                    212:        /* get command */
                    213:        eatwhite(p);
                    214:        if (*p != '\0')
                    215:                *cmdp = *p++;
                    216:        else
                    217:                *cmdp = 'p';
                    218: 
                    219:        /* compound command */
                    220:        if (*cmdp == 'd' && (*p == 'q' || *p == 'p'))
                    221:                *(cmdp+1) = *p++;
                    222:        else
                    223:                *(cmdp+1) = '\0';
                    224:        eatwhite(p);
                    225:        return p;
                    226: }
                    227: 
                    228: /*     Process user commands in the new style.
                    229:  *     All actions are prompted for.
                    230:  */
                    231: static void
                    232: domanual()
                    233: {
                    234:        int dot=1, print, i;
                    235:        int first, last;
                    236:        char cmd[2], *args;
                    237: 
                    238:        printf("%d letters\n", nlet);
                    239:        while (1) {
                    240:                /* in case of interrupt, come back here but don't print */
                    241:                if (setjmp(sjbuf))      /* after long jump */
                    242:                        printf("\n");
                    243:                signal(SIGINT, rememberint);
                    244:                args = parse(cmd, &first, &last, dot);
                    245:                if (args == NULL)
                    246:                        break;
                    247:                for (i = first; i <= last && i <= nlet; i++) {
                    248:                        dot = i;        /* must be here in case of interrupt */
                    249:                        if (docommand(cmd[0], args, i, &print) < 0)
                    250:                                return;
                    251:                }
                    252:                switch (cmd[1]) {
                    253:                case 'q':
                    254:                        return;
                    255:                case 'p':
                    256:                        doprint(seq(++dot));
                    257:                        break;
                    258:                }
                    259:        }
                    260: }
                    261: 
                    262: /*     Process user commands in the old style.
                    263:  *     This implies printing the next message 
                    264:  *     without prompting for it
                    265:  */
                    266: static void
                    267: doauto()
                    268: {
                    269:        int print=1, dot=1, i;
                    270:        int first, last;
                    271:        char cmd[2], *args;
                    272: 
                    273:        while (dot <= nlet && dot >= 0) {
                    274:                /* in case of interrupt, come back here but don't print */
                    275:                if (setjmp(sjbuf))      /* after long jump */
                    276:                        printf("\n");
                    277:                else {          /* here normally */
                    278:                        signal(SIGINT, rememberint);
                    279:                        if (print)
                    280:                                doprint(seq(dot));
                    281:                }
                    282:                print = 0;
                    283:                args = parse(cmd, &first, &last, dot);
                    284:                if (args == NULL)
                    285:                        break;
                    286:                for (i = first; i <= last && i <= nlet; i++) {
                    287:                        dot = i;        /* in case of interrupt while printing */
                    288:                        dot = docommand(cmd[0], args, i, &print);
                    289:                }
                    290:                if (dot > 0 && dot < last)
                    291:                        dot = last;
                    292:                switch (cmd[1]) {
                    293:                case 'q':
                    294:                        return;
                    295:                case 'p':
                    296:                        print++;
                    297:                        break;
                    298:                }
                    299:        }
                    300: }
                    301: 
                    302: /*
                    303:  *     Perform a command.
                    304:  */
                    305: static int
                    306: docommand(cmd, args, dot, pflag)
                    307:        char cmd;               /* command to perform */
                    308:        char *args;             /* arguments to the command */
                    309:        int dot;                /* the message to apply it to */
                    310:        int *pflag;             /* (returned) true if next message to be printed */
                    311: {
                    312:        switch (cmd) {
                    313:        default:
                    314:                printf("usage\n");
                    315:        case '?':
                    316:                dohelp();
                    317:                break;
                    318:        case 'h':
                    319:                print_from(seq(dot));
                    320:                break;
                    321:        case '=':
                    322:                printf("at letter %d\n", dot);  
                    323:                break;
                    324:        case 'p':
                    325:                doprint(seq(dot));
                    326:                break;
                    327:        case 'x':
                    328:                changed = 0;
                    329:                dot = -1;
                    330:                break;
                    331:        case 'y':
                    332:        case 'w':
                    333:        case 's':
                    334:                if (squirrel_away(seq(dot), args) == 0) {
                    335:                        (void)ldelete(seq(dot));
                    336:                        changed++;
                    337:                        (*pflag)++;
                    338:                        dot++;
                    339:                }
                    340:                break;
                    341:        case 'm':
                    342:                if (remail(seq(dot), args) == 0) {
                    343:                        (void)ldelete(seq(dot));
                    344:                        changed++;
                    345:                        (*pflag)++;
                    346:                        dot++;
                    347:                }
                    348:                break;
                    349:        case 'r':
                    350:                if (*args != '\0') {
                    351:                        fprintf(stderr, "invalid: r takes no arguments\n");
                    352:                        break;
                    353:                }
                    354:                (void)reply(seq(dot));
                    355:                printf("!\n");
                    356:                break;
                    357:        case '!':
                    358:                system(args);
                    359:                printf("!\n");
                    360:                break;
                    361:        case 'd':
                    362:                if (*args != '\0') {
                    363:                        fprintf(stderr,"invalid: d takes no arguments\n");
                    364:                        break;
                    365:                }
                    366:                (void)ldelete(seq(dot));
                    367:                changed++;
                    368:                (*pflag)++;
                    369:                dot++;
                    370:                break;
                    371:        case 'u':
                    372:                if (*args != '\0') {
                    373:                        fprintf(stderr,"invalid: u takes no arguments\n");
                    374:                        break;
                    375:                }
                    376:                (void)lundelete(seq(dot));
                    377:                (*pflag)++;
                    378:                dot++;
                    379:                break;
                    380:        case 'q':
                    381:                dot = -1;
                    382:                break;
                    383:        }
                    384:        return dot;
                    385: }
                    386: 
                    387: /* copy mail to temp file, returns size of mail file */
                    388: static long
                    389: copymt(mfp)
                    390:        FILE *mfp;
                    391: {
                    392:        letter *lp=NULL;
                    393:        char line[FROMLINESIZE];
                    394: 
                    395:        /* read in letters */
                    396:        while (fgets(line, FROMLINESIZE, mfp) != NULL) {
                    397:                if (strncmp(line, FROM, FSIZE)==0 || lp==NULL) {
                    398:                        lp = lopen(nlet++, "w");
                    399:                }
                    400:                lputs(line, lp);
                    401:        }
                    402: 
                    403:        /* remember where end of file is */
                    404:        return ftell(mfp);
                    405: }
                    406: 
                    407: /* copy temp or whatever back to /usr/spool/mail */
                    408: static int
                    409: copyback(oldsize, mp)
                    410:        long oldsize;
                    411:        char *mp;
                    412: {
                    413:        register i;
                    414:        register int new = 0;
                    415:        struct stat stbuf;
                    416:        letter *lp;
                    417:        FILE *malf;
                    418: 
                    419:        lock(mp);
                    420: 
                    421:        /* read new mail that arrived while we were printing */
                    422:        stat(mp, &stbuf);
                    423:        if (stbuf.st_size != oldsize) {   /* new mail has arrived */
                    424:                malf = fopen(mp, "r");
                    425:                if (malf == NULL) {
                    426:                        fprintf(stderr, "mail: can't re-read %s\n", mp);
                    427:                        (void)done();
                    428:                }
                    429:                fseek(malf, oldsize, 0);
                    430:                (void)copymt(malf);
                    431:                fclose(malf);
                    432:                new++;
                    433:        }
                    434: 
                    435:        /* turn off interrupts while writing back */
                    436:        signal(SIGHUP, SIG_IGN);
                    437:        signal(SIGINT, SIG_IGN);
                    438:        signal(SIGQUIT, SIG_IGN);
                    439:        signal(SIGTERM, SIG_IGN);
                    440: 
                    441:        /* write the sucker back */
                    442:        malf = fopen(mp, "w");
                    443:        if (malf == NULL) {
                    444:                fprintf(stderr, "mail: can't rewrite %s\n", mp);
                    445:                (void)done();
                    446:        }
                    447:        for (i = 0; i < nlet; i++)
                    448:                if ((lp=lopen(i, "ru")) != NULL) {
                    449:                        copyfrom(lp, malf);
                    450:                }
                    451:        fclose(malf);
                    452:        unlock();
                    453:        if (new)
                    454:                printf("new mail arrived\n");
                    455: }
                    456: 
                    457: /* come here to finish up */
                    458: static int
                    459: done()
                    460: {
                    461:        unlock();
                    462:        V();
                    463:        releasetmp();
                    464:        exit(error);
                    465:        return 0;
                    466: }
                    467: 
                    468: static char *
                    469: doargs(argc, argv)
                    470:        int argc;
                    471:        char *argv[];
                    472: {
                    473:        static char mailfile[256];
                    474: 
                    475:        (void)strcpy(mailfile, mailpath(getlogin()));
                    476: 
                    477:        for (; argc>1; argv++, argc--) {
                    478:                if (argv[1][0]=='-') {
                    479:                        if (argv[1][1]=='p') {
                    480:                                flgp++;
                    481:                        } else if (argv[1][1]=='f') {
                    482:                                if (argc>=3) {
                    483:                                        strcpy(mailfile, argv[2]);
                    484:                                        argv++;
                    485:                                        argc--;
                    486:                                        otherfile = 1;
                    487:                                }
                    488:                        } else if (argv[1][1]=='r') {
                    489:                                forward = 1;
                    490:                        } else if (argv[1][1]=='m') {
                    491:                                manual = 1;
                    492:                        } else {
                    493:                                fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
                    494:                                done();
                    495:                        }
                    496:                } else
                    497:                        break;
                    498:        }
                    499:        return mailfile;
                    500: }
                    501: 
                    502: /* return non-zero if this is not a normal mail file */
                    503: static int
                    504: special_mailfile(mp)
                    505:        char *mp;               /* mail file */
                    506: {
                    507:        char fbuf[256];
                    508:        char *sp1, *sp2;
                    509:        int stat;
                    510: 
                    511:        sp2 = "";
                    512: 
                    513:        /* if something is being done to the mail, go away */
                    514:        stat = delivery_status(mp, fbuf);
                    515:        switch(stat & MFTYPE) {
                    516:        case MF_FORWARD:
                    517:                sp1 = "Your mail is being forwarded to";
                    518:                break;
                    519:        case MF_PIPE:
                    520:                sp1 = "Your mail is being piped to";
                    521:                break;
                    522:        default:
                    523:                return 0;
                    524:        }
                    525: 
                    526:        if (stat & MFEXTRA)
                    527:                sp2 = "and your mailbox contains extra stuff\n";
                    528:        printf("%s %s %s\n", sp1, fbuf, sp2);
                    529:        return stat & MFTYPE;
                    530: }
                    531: 
                    532: static void
                    533: dohelp()
                    534: {
                    535:        printf("Commands are of the form '[range] command [args]'.\n");
                    536:        printf("The command can be:\n");
                    537:        printf("d\tdelete\n");
                    538:        printf("u\tundelete\n");
                    539:        printf("h\tprint from lines of all messages\n");
                    540:        printf("m user\tmail to user\n");
                    541:        printf("p\tprint\n");
                    542:        printf("r\treply to last message\n");
                    543:        printf("q\tquit\n");
                    544:        printf("s[file]\tsave (default mbox)\n");
                    545:        printf("x\texit without changing mail\n");
                    546:        printf("=\tprint current message number\n");
                    547:        printf("! cmd\texecute cmd\n");
                    548: }
                    549: 
                    550: /* print the from line (and status) of each message */
                    551: static void
                    552: print_from(let)
                    553:        int let;
                    554: {
                    555:        int deleted;
                    556:        char from[FROMLINESIZE];
                    557:        letter *lp;
                    558: 
                    559:        lp = lopen(let, "ru");
                    560:        if (lp == NULL) {
                    561:                deleted = 1;
                    562:                lp = lopen(let, "r");
                    563:        } else
                    564:                deleted = 0;
                    565:        lgets(from, FROMLINESIZE, lp);
                    566:        printf("%3d %c %4d  %s", seq(let), deleted?'d':' ',
                    567:                lsize(lp), from+FSIZE);
                    568: }
                    569: 
                    570: /* save a letter in a file, return 0 if successful */
                    571: static int
                    572: squirrel_away(let, resp)
                    573:        int let;
                    574:        char *resp;
                    575: {
                    576:        char *p;
                    577:        letter *lp;
                    578:        char path[PATHSIZE];
                    579:        int problems=0;
                    580:        FILE *malf;
                    581: 
                    582:        if (*resp == '\0') {
                    583:                p = getenv("HOME");
                    584:                if(p != 0) {
                    585:                        strcpy(resp, p);
                    586:                        strcat(resp, "/mbox");
                    587:                } else
                    588:                        strcpy(resp, "mbox");
                    589:        }
                    590:        for (p = resp; (p = getarg(path, p)) != NULL; ) {
                    591:                malf = fopen(path, "a");
                    592:                if (malf == NULL) {
                    593:                        fprintf(stderr, "mail: cannot append to %s\n", path);
                    594:                        problems++;
                    595:                        continue;
                    596:                }
                    597:                lp = lopen(let, "r");
                    598:                copyfrom(lp, malf);
                    599:                fclose(malf);
                    600:        }
                    601:        return problems;
                    602: }
                    603: 
                    604: /* reply to mail, return 0 if no problems */
                    605: static char replyline[FROMLINESIZE];
                    606: static char replycmd[CMDSIZE];
                    607: static int
                    608: reply(let)
                    609:        int let;
                    610: {
                    611:        char *sp;
                    612:        letter *lp;
                    613: 
                    614:        lp = lopen(let, "r");
                    615:        lgets(replyline, FROMLINESIZE, lp);
                    616:        sp = strchr(replyline+FSIZE, ' ');
                    617:        if (sp != NULL)
                    618:                *sp = '\0';
                    619:        strcpy(replycmd, "/bin/mail ");
                    620:        strcat(replycmd, replyline+FSIZE);
                    621:        printf("!%s\n", replycmd);
                    622:        system(replycmd);
                    623:        return 0;
                    624: }
                    625: 
                    626: /* pass mail onto someone else, return 0 if no problems */
                    627: static int
                    628: remail(let, resp)
                    629:        int let;
                    630:        char *resp;
                    631: {
                    632:        char cmd[CMDSIZE];
                    633:        FILE *pipf;
                    634:        letter *lp;
                    635: 
                    636:        if (*resp == '\0') {
                    637:                fprintf(stderr, "invalid: m requires a destination\n");
                    638:                return -1;
                    639:        }
                    640:        strcpy(cmd, "mail ");
                    641:        strcat(cmd, resp);
                    642: 
                    643:        /* fork so that mail becomes super-user again */
                    644:        pipf = popen(cmd, "w");
                    645:        if(pipf == NULL) {
                    646:                fprintf(stderr, "mail: can't fork to remail\n");
                    647:                return -1;
                    648:        }
                    649:        lp = lopen(let, "r");
                    650:        copyfrom(lp, pipf);
                    651:        return pclose(pipf);
                    652: }
                    653: 
                    654: /* output the letter */
                    655: static int
                    656: doprint(let)
                    657:        int let;
                    658: {
                    659:        letter *lp;
                    660: 
                    661:        lp = lopen(let, "r");
                    662:        if (lp == NULL)
                    663:                return -1;
                    664:        copyfrom(lp, stdout);
                    665:        return 0;
                    666: }

unix.superglobalmegacorp.com

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