|
|
1.1 ! root 1: # ! 2: ! 3: /* ! 4: * Mail -- a mail program ! 5: * ! 6: * Collect input from standard input, handling ! 7: * ~ escapes. ! 8: */ ! 9: ! 10: #include "rcv.h" ! 11: #include <sys/stat.h> ! 12: ! 13: /* ! 14: * Read a message from standard output and return a read file to it ! 15: * or NULL on error. ! 16: */ ! 17: ! 18: /* ! 19: * The following hokiness with global variables is so that on ! 20: * receipt of an interrupt signal, the partial message can be salted ! 21: * away on dead.letter. The output file must be available to flush, ! 22: * and the input to read. Several open files could be saved all through ! 23: * Mail if stdio allowed simultaneous read/write access. ! 24: */ ! 25: ! 26: static int (*savesig)(); /* Previous SIGINT value */ ! 27: static FILE *newi; /* File for saving away */ ! 28: static FILE *newo; /* Output side of same */ ! 29: static int hf; /* Ignore interrups */ ! 30: static int nofault; /* Soft signal if set */ ! 31: static int hadintr; /* Have seen one SIGINT so far */ ! 32: ! 33: static jmp_buf coljmp; /* To get back to work */ ! 34: ! 35: FILE * ! 36: collect(hp) ! 37: struct header *hp; ! 38: { ! 39: FILE *ibuf, *fbuf, *obuf; ! 40: int lc, cc, escape, collrub(), intack(), stopdot; ! 41: register int c, t; ! 42: char linebuf[LINESIZE], *cp; ! 43: extern char tempMail[]; ! 44: ! 45: stopdot = (value("dot") != NOSTR) && intty; ! 46: ibuf = obuf = NULL; ! 47: if (value("ignore") != NOSTR) ! 48: hf = 1; ! 49: else ! 50: hf = 0; ! 51: nofault = 1; ! 52: hadintr = 0; ! 53: if ((savesig = signal(SIGINT, SIG_IGN)) != SIG_IGN) ! 54: signal(SIGINT, hf ? intack : collrub); ! 55: newi = NULL; ! 56: newo = NULL; ! 57: if ((obuf = fopen(tempMail, "w")) == NULL) { ! 58: perror(tempMail); ! 59: goto err; ! 60: } ! 61: newo = obuf; ! 62: if ((ibuf = fopen(tempMail, "r")) == NULL) { ! 63: perror(tempMail); ! 64: newo = NULL; ! 65: fclose(obuf); ! 66: goto err; ! 67: } ! 68: newi = ibuf; ! 69: remove(tempMail); ! 70: if (hp->h_seq != 0) { ! 71: puthead(hp, stdout, GTO|GSUBJECT|GCC); ! 72: fflush(stdout); ! 73: } ! 74: if (intty && hp->h_subject == NOSTR && value("ask")) ! 75: grabh(hp, GSUBJECT); ! 76: escape = ESCAPE; ! 77: if ((cp = value("escape")) != NOSTR) ! 78: escape = *cp; ! 79: for (;;) { ! 80: setjmp(coljmp); ! 81: nofault = 0; ! 82: flush(); ! 83: if (readline(stdin, linebuf) <= 0) ! 84: break; ! 85: hadintr = 0; ! 86: if (stopdot && equal(".", linebuf)) ! 87: break; ! 88: if (linebuf[0] != escape || ! 89: (!intty && value("henry") == NOSTR)) { ! 90: if ((t = putline(obuf, linebuf)) < 0) ! 91: goto err; ! 92: continue; ! 93: } ! 94: c = linebuf[1]; ! 95: nofault= 0; ! 96: switch (c) { ! 97: default: ! 98: /* ! 99: * On double escape, just send the single one. ! 100: * Otherwise, it's an error. ! 101: */ ! 102: ! 103: if (c == escape) { ! 104: if (putline(obuf, &linebuf[1]) < 0) ! 105: goto err; ! 106: else ! 107: break; ! 108: } ! 109: printf("Unknown tilde escape.\n"); ! 110: break; ! 111: ! 112: case 'C': ! 113: /* ! 114: * Dump core. ! 115: */ ! 116: ! 117: core(); ! 118: break; ! 119: ! 120: case '!': ! 121: /* ! 122: * Shell escape, send the balance of the ! 123: * line to sh -c. ! 124: */ ! 125: ! 126: shell(&linebuf[2]); ! 127: break; ! 128: ! 129: case ':': ! 130: case '_': ! 131: /* ! 132: * Escape to command mode, but be nice! ! 133: */ ! 134: ! 135: nofault = 0; ! 136: execute(&linebuf[2]); ! 137: break; ! 138: ! 139: case '.': ! 140: /* ! 141: * Simulate end of file on input. ! 142: */ ! 143: goto eof; ! 144: ! 145: case 'q': ! 146: case 'Q': ! 147: /* ! 148: * Force a quit of sending mail. ! 149: * Act like an interrupt happened. ! 150: */ ! 151: ! 152: nofault = 0; ! 153: hadintr++; ! 154: collrub(SIGINT); ! 155: exit(1); ! 156: ! 157: case 'h': ! 158: /* ! 159: * Grab a bunch of headers. ! 160: */ ! 161: if (!intty || !outtty) { ! 162: printf("~h: no can do!?\n"); ! 163: break; ! 164: } ! 165: grabh(hp, GTO|GSUBJECT|GCC); ! 166: printf("(continue)\n"); ! 167: break; ! 168: ! 169: case 't': ! 170: /* ! 171: * Add to the To list. ! 172: */ ! 173: ! 174: hp->h_to = addto(hp->h_to, &linebuf[2]); ! 175: hp->h_seq++; ! 176: break; ! 177: ! 178: case 's': ! 179: /* ! 180: * Set the Subject list. ! 181: */ ! 182: ! 183: cp = &linebuf[2]; ! 184: while (any(*cp, " \t")) ! 185: cp++; ! 186: hp->h_subject = savestr(cp); ! 187: hp->h_seq++; ! 188: break; ! 189: ! 190: case 'c': ! 191: /* ! 192: * Add to the CC list. ! 193: */ ! 194: ! 195: hp->h_cc = addto(hp->h_cc, &linebuf[2]); ! 196: hp->h_seq++; ! 197: break; ! 198: ! 199: case 'b': ! 200: /* ! 201: * Add stuff to blind carbon copies list. ! 202: */ ! 203: hp->h_bcc = addto(hp->h_bcc, &linebuf[2]); ! 204: hp->h_seq++; ! 205: break; ! 206: ! 207: case 'd': ! 208: copy(deadletter, &linebuf[2]); ! 209: /* fall into . . . */ ! 210: ! 211: case 'r': ! 212: /* ! 213: * Invoke a file: ! 214: * Search for the file name, ! 215: * then open it and copy the contents to obuf. ! 216: */ ! 217: ! 218: cp = &linebuf[2]; ! 219: while (any(*cp, " \t")) ! 220: cp++; ! 221: if (*cp == '\0') { ! 222: printf("Interpolate what file?\n"); ! 223: break; ! 224: } ! 225: cp = expand(cp); ! 226: if (cp == NOSTR) ! 227: break; ! 228: if (isdir(cp)) { ! 229: printf("%s: directory\n"); ! 230: break; ! 231: } ! 232: if ((fbuf = fopen(cp, "r")) == NULL) { ! 233: perror(cp); ! 234: break; ! 235: } ! 236: printf("\"%s\" ", cp); ! 237: flush(); ! 238: lc = 0; ! 239: cc = 0; ! 240: while (readline(fbuf, linebuf) > 0) { ! 241: lc++; ! 242: if ((t = putline(obuf, linebuf)) < 0) { ! 243: fclose(fbuf); ! 244: goto err; ! 245: } ! 246: cc += t; ! 247: } ! 248: fclose(fbuf); ! 249: printf("%d/%d\n", lc, cc); ! 250: break; ! 251: ! 252: case 'w': ! 253: /* ! 254: * Write the message on a file. ! 255: */ ! 256: ! 257: cp = &linebuf[2]; ! 258: while (any(*cp, " \t")) ! 259: cp++; ! 260: if (*cp == '\0') { ! 261: fprintf(stderr, "Write what file!?\n"); ! 262: break; ! 263: } ! 264: if ((cp = expand(cp)) == NOSTR) ! 265: break; ! 266: fflush(obuf); ! 267: rewind(ibuf); ! 268: exwrite(cp, ibuf, 1); ! 269: break; ! 270: ! 271: case 'm': ! 272: case 'f': ! 273: /* ! 274: * Interpolate the named messages, if we ! 275: * are in receiving mail mode. Does the ! 276: * standard list processing garbage. ! 277: * If ~f is given, we don't shift over. ! 278: */ ! 279: ! 280: if (!rcvmode) { ! 281: printf("No messages to send from!?!\n"); ! 282: break; ! 283: } ! 284: cp = &linebuf[2]; ! 285: while (any(*cp, " \t")) ! 286: cp++; ! 287: if (forward(cp, obuf, c) < 0) ! 288: goto err; ! 289: printf("(continue)\n"); ! 290: break; ! 291: ! 292: case '?': ! 293: nofault = 0; ! 294: if ((fbuf = fopen(THELPFILE, "r")) == NULL) { ! 295: printf("No help just now.\n"); ! 296: break; ! 297: } ! 298: t = getc(fbuf); ! 299: while (t != -1) { ! 300: putchar(t); ! 301: t = getc(fbuf); ! 302: } ! 303: fclose(fbuf); ! 304: break; ! 305: ! 306: case 'p': ! 307: /* ! 308: * Print out the current state of the ! 309: * message without altering anything. ! 310: */ ! 311: ! 312: fflush(obuf); ! 313: rewind(ibuf); ! 314: nofault = 0; ! 315: printf("-------\nMessage contains:\n"); ! 316: puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC); ! 317: t = getc(ibuf); ! 318: while (t != EOF) { ! 319: putchar(t); ! 320: t = getc(ibuf); ! 321: } ! 322: printf("(continue)\n"); ! 323: break; ! 324: ! 325: case '^': ! 326: case '|': ! 327: /* ! 328: * Pipe message through command. ! 329: * Collect output as new message. ! 330: */ ! 331: ! 332: obuf = mespipe(ibuf, obuf, &linebuf[2]); ! 333: newo = obuf; ! 334: ibuf = newi; ! 335: newi = ibuf; ! 336: printf("(continue)\n"); ! 337: break; ! 338: ! 339: case 'v': ! 340: case 'e': ! 341: /* ! 342: * Edit the current message. ! 343: * 'e' means to use EDITOR ! 344: * 'v' means to use VISUAL ! 345: */ ! 346: ! 347: if ((obuf = mesedit(ibuf, obuf, c)) == NULL) ! 348: goto err; ! 349: newo = obuf; ! 350: ibuf = newi; ! 351: printf("(continue)\n"); ! 352: break; ! 353: break; ! 354: } ! 355: } ! 356: eof: ! 357: fclose(obuf); ! 358: rewind(ibuf); ! 359: signal(SIGINT, savesig); ! 360: return(ibuf); ! 361: ! 362: err: ! 363: if (ibuf != NULL) ! 364: fclose(ibuf); ! 365: if (obuf != NULL) ! 366: fclose(obuf); ! 367: signal(SIGINT, savesig); ! 368: return(NULL); ! 369: } ! 370: ! 371: /* ! 372: * Non destructively interrogate the value of the given signal. ! 373: */ ! 374: ! 375: psig(n) ! 376: { ! 377: register (*wassig)(); ! 378: ! 379: wassig = signal(n, SIG_IGN); ! 380: signal(n, wassig); ! 381: return((int) wassig); ! 382: } ! 383: ! 384: /* ! 385: * Write a file, ex-like if f set. ! 386: */ ! 387: ! 388: exwrite(name, ibuf, f) ! 389: char name[]; ! 390: FILE *ibuf; ! 391: { ! 392: register FILE *of; ! 393: register int c; ! 394: long cc; ! 395: int lc; ! 396: struct stat junk; ! 397: ! 398: if (f) { ! 399: printf("\"%s\" ", name); ! 400: fflush(stdout); ! 401: } ! 402: if (stat(name, &junk) >= 0) { ! 403: if (!f) ! 404: fprintf(stderr, "%s: ", name); ! 405: fprintf(stderr, "File exists\n", name); ! 406: return(-1); ! 407: } ! 408: if ((of = fopen(name, "w")) == NULL) { ! 409: perror(NOSTR); ! 410: return(-1); ! 411: } ! 412: lc = 0; ! 413: cc = 0; ! 414: while ((c = getc(ibuf)) != EOF) { ! 415: cc++; ! 416: if (c == '\n') ! 417: lc++; ! 418: putc(c, of); ! 419: if (ferror(of)) { ! 420: perror(name); ! 421: fclose(of); ! 422: return(-1); ! 423: } ! 424: } ! 425: fclose(of); ! 426: printf("%d/%ld\n", lc, cc); ! 427: fflush(stdout); ! 428: return(0); ! 429: } ! 430: ! 431: /* ! 432: * Edit the message being collected on ibuf and obuf. ! 433: * Write the message out onto some poorly-named temp file ! 434: * and point an editor at it. ! 435: * ! 436: * On return, make the edit file the new temp file. ! 437: */ ! 438: ! 439: FILE * ! 440: mesedit(ibuf, obuf, c) ! 441: FILE *ibuf, *obuf; ! 442: { ! 443: int pid, s; ! 444: FILE *fbuf; ! 445: register int t; ! 446: int (*sig)(); ! 447: struct stat sbuf; ! 448: extern char tempMail[], tempEdit[]; ! 449: register char *edit; ! 450: ! 451: sig = signal(SIGINT, SIG_IGN); ! 452: if (stat(tempEdit, &sbuf) >= 0) { ! 453: printf("%s: file exists\n", tempEdit); ! 454: goto out; ! 455: } ! 456: close(creat(tempEdit, 0600)); ! 457: if ((fbuf = fopen(tempEdit, "w")) == NULL) { ! 458: perror(tempEdit); ! 459: goto out; ! 460: } ! 461: fflush(obuf); ! 462: rewind(ibuf); ! 463: t = getc(ibuf); ! 464: while (t != EOF) { ! 465: putc(t, fbuf); ! 466: t = getc(ibuf); ! 467: } ! 468: fflush(fbuf); ! 469: if (ferror(fbuf)) { ! 470: perror(tempEdit); ! 471: remove(tempEdit); ! 472: goto fix; ! 473: } ! 474: fclose(fbuf); ! 475: if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) ! 476: edit = c == 'e' ? EDITOR : VISUAL; ! 477: pid = vfork(); ! 478: if (pid == 0) { ! 479: if (sig != SIG_IGN) ! 480: signal(SIGINT, SIG_DFL); ! 481: execl(edit, edit, tempEdit, 0); ! 482: perror(edit); ! 483: _exit(1); ! 484: } ! 485: if (pid == -1) { ! 486: perror("fork"); ! 487: remove(tempEdit); ! 488: goto out; ! 489: } ! 490: while (wait(&s) != pid) ! 491: ; ! 492: if (s != 0) { ! 493: printf("Fatal error in \"%s\"\n", edit); ! 494: remove(tempEdit); ! 495: goto out; ! 496: } ! 497: ! 498: /* ! 499: * Now switch to new file. ! 500: */ ! 501: ! 502: if ((fbuf = fopen(tempEdit, "a")) == NULL) { ! 503: perror(tempEdit); ! 504: remove(tempEdit); ! 505: goto out; ! 506: } ! 507: if ((ibuf = fopen(tempEdit, "r")) == NULL) { ! 508: perror(tempEdit); ! 509: fclose(fbuf); ! 510: remove(tempEdit); ! 511: goto out; ! 512: } ! 513: remove(tempEdit); ! 514: fclose(obuf); ! 515: fclose(newi); ! 516: obuf = fbuf; ! 517: goto out; ! 518: fix: ! 519: perror(tempEdit); ! 520: out: ! 521: signal(SIGINT, sig); ! 522: newi = ibuf; ! 523: return(obuf); ! 524: } ! 525: ! 526: /* ! 527: * Pipe the message through the command. ! 528: * Old message is on stdin of command; ! 529: * New message collected from stdout. ! 530: * Sh -c must return 0 to accept the new message. ! 531: */ ! 532: ! 533: FILE * ! 534: mespipe(ibuf, obuf, cmd) ! 535: FILE *ibuf, *obuf; ! 536: char cmd[]; ! 537: { ! 538: register FILE *ni, *no; ! 539: int pid, s; ! 540: int (*savesig)(); ! 541: char *Shell; ! 542: ! 543: newi = ibuf; ! 544: if ((no = fopen(tempEdit, "w")) == NULL) { ! 545: perror(tempEdit); ! 546: return(obuf); ! 547: } ! 548: if ((ni = fopen(tempEdit, "r")) == NULL) { ! 549: perror(tempEdit); ! 550: fclose(no); ! 551: remove(tempEdit); ! 552: return(obuf); ! 553: } ! 554: remove(tempEdit); ! 555: savesig = signal(SIGINT, SIG_IGN); ! 556: fflush(obuf); ! 557: rewind(ibuf); ! 558: if ((Shell = value("SHELL")) == NULL) ! 559: Shell = "/bin/sh"; ! 560: if ((pid = vfork()) == -1) { ! 561: perror("fork"); ! 562: goto err; ! 563: } ! 564: if (pid == 0) { ! 565: /* ! 566: * stdin = current message. ! 567: * stdout = new message. ! 568: */ ! 569: ! 570: close(0); ! 571: dup(fileno(ibuf)); ! 572: close(1); ! 573: dup(fileno(no)); ! 574: for (s = 4; s < 15; s++) ! 575: close(s); ! 576: execl(Shell, Shell, "-c", cmd, 0); ! 577: perror(Shell); ! 578: _exit(1); ! 579: } ! 580: while (wait(&s) != pid) ! 581: ; ! 582: if (s != 0 || pid == -1) { ! 583: fprintf(stderr, "\"%s\" failed!?\n", cmd); ! 584: goto err; ! 585: } ! 586: if (fsize(ni) == 0) { ! 587: fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); ! 588: goto err; ! 589: } ! 590: ! 591: /* ! 592: * Take new files. ! 593: */ ! 594: ! 595: newi = ni; ! 596: fclose(ibuf); ! 597: fclose(obuf); ! 598: signal(SIGINT, savesig); ! 599: return(no); ! 600: ! 601: err: ! 602: fclose(no); ! 603: fclose(ni); ! 604: signal(SIGINT, savesig); ! 605: return(obuf); ! 606: } ! 607: ! 608: /* ! 609: * Interpolate the named messages into the current ! 610: * message, preceding each line with a tab. ! 611: * Return a count of the number of characters now in ! 612: * the message, or -1 if an error is encountered writing ! 613: * the message temporary. The flag argument is 'm' if we ! 614: * should shift over and 'f' if not. ! 615: */ ! 616: ! 617: forward(ms, obuf, f) ! 618: char ms[]; ! 619: FILE *obuf; ! 620: { ! 621: register int *msgvec, *ip; ! 622: extern char tempMail[]; ! 623: ! 624: msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); ! 625: if (msgvec == (int *) NOSTR) ! 626: return(0); ! 627: if (getmsglist(ms, msgvec, 0) < 0) ! 628: return(0); ! 629: if (*msgvec == NULL) { ! 630: *msgvec = first(0, MMNORM); ! 631: if (*msgvec == NULL) { ! 632: printf("No appropriate messages\n"); ! 633: return(0); ! 634: } ! 635: msgvec[1] = NULL; ! 636: } ! 637: printf("Interpolating:"); ! 638: for (ip = msgvec; *ip != NULL; ip++) { ! 639: touch(*ip); ! 640: printf(" %d", *ip); ! 641: if (f == 'm') { ! 642: if (transmit(&message[*ip-1], obuf) < 0) { ! 643: perror(tempMail); ! 644: return(-1); ! 645: } ! 646: } else ! 647: if (send(&message[*ip-1], obuf) < 0) { ! 648: perror(tempMail); ! 649: return(-1); ! 650: } ! 651: } ! 652: printf("\n"); ! 653: return(0); ! 654: } ! 655: ! 656: /* ! 657: * Send message described by the passed pointer to the ! 658: * passed output buffer. Insert a tab in front of each ! 659: * line. Return a count of the characters sent, or -1 ! 660: * on error. ! 661: */ ! 662: ! 663: transmit(mailp, obuf) ! 664: struct message *mailp; ! 665: FILE *obuf; ! 666: { ! 667: register struct message *mp; ! 668: register int c, ch; ! 669: int n, bol; ! 670: FILE *ibuf; ! 671: ! 672: mp = mailp; ! 673: ibuf = setinput(mp); ! 674: c = msize(mp); ! 675: n = c; ! 676: bol = 1; ! 677: while (c-- > 0) { ! 678: if (bol) { ! 679: bol = 0; ! 680: putc('\t', obuf); ! 681: n++; ! 682: if (ferror(obuf)) { ! 683: perror("/tmp"); ! 684: return(-1); ! 685: } ! 686: } ! 687: ch = getc(ibuf); ! 688: if (ch == '\n') ! 689: bol++; ! 690: putc(ch, obuf); ! 691: if (ferror(obuf)) { ! 692: perror("/tmp"); ! 693: return(-1); ! 694: } ! 695: } ! 696: return(n); ! 697: } ! 698: ! 699: /* ! 700: * On interrupt, go here to save the partial ! 701: * message on #/dead.letter. ! 702: * Then restore signals and execute the normal ! 703: * signal routine. We only come here if signals ! 704: * were previously set anyway. ! 705: */ ! 706: ! 707: collrub(s) ! 708: { ! 709: register FILE *dbuf; ! 710: register int c; ! 711: ! 712: #ifdef V7 ! 713: signal(s, SIG_IGN); ! 714: #else ! 715: signal(SIGINT, SIG_IGN); ! 716: #endif ! 717: if (nofault) { ! 718: #ifdef V7 ! 719: signal(s, collrub); ! 720: #else ! 721: signal(SIGINT, collrub); ! 722: #endif ! 723: return; ! 724: } ! 725: if (hadintr == 0) { ! 726: hadintr++; ! 727: clrbuf(stdout); ! 728: printf("\n(Interrupt -- one more to kill letter)\n"); ! 729: #ifdef V7 ! 730: signal(s, collrub); ! 731: #else ! 732: signal(SIGINT, collrub); ! 733: #endif ! 734: longjmp(coljmp, 1); ! 735: } ! 736: fclose(newo); ! 737: rewind(newi); ! 738: if (value("nosave") != NOSTR) ! 739: goto done; ! 740: if ((dbuf = fopen(deadletter, "w")) == NULL) ! 741: goto done; ! 742: chmod(deadletter, 0600); ! 743: while ((c = getc(newi)) != EOF) ! 744: putc(c, dbuf); ! 745: fclose(dbuf); ! 746: ! 747: done: ! 748: fclose(newi); ! 749: signal(SIGINT, savesig); ! 750: if (rcvmode) ! 751: stop(); ! 752: else ! 753: exit(1); ! 754: } ! 755: ! 756: /* ! 757: * Acknowledge an interrupt signal from the tty by typing an @ ! 758: */ ! 759: ! 760: intack(s) ! 761: { ! 762: ! 763: signal(SIGINT, SIG_IGN); ! 764: putchar('@'); ! 765: fflush(stdout); ! 766: clearerr(stdin); ! 767: signal(SIGINT, intack); ! 768: } ! 769: ! 770: /* ! 771: * Add a string to the end of a header entry field. ! 772: */ ! 773: ! 774: char * ! 775: addto(hf, news) ! 776: char hf[], news[]; ! 777: { ! 778: register char *cp, *cp2, *linebuf; ! 779: ! 780: if (hf == NOSTR) ! 781: hf = ""; ! 782: linebuf = salloc(strlen(hf) + strlen(news) + 1); ! 783: for (cp = hf; any(*cp, " \t"); cp++) ! 784: ; ! 785: for (cp2 = linebuf; *cp;) ! 786: *cp2++ = *cp++; ! 787: *cp2++ = ' '; ! 788: for (cp = news; any(*cp, " \t"); cp++) ! 789: ; ! 790: while (*cp != '\0') ! 791: *cp2++ = *cp++; ! 792: *cp2 = '\0'; ! 793: return(linebuf); ! 794: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.