|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.