|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)collect.c 5.22 (Berkeley) 6/25/90"; ! 22: #endif /* not lint */ ! 23: ! 24: /* ! 25: * Mail -- a mail program ! 26: * ! 27: * Collect input from standard input, handling ! 28: * ~ escapes. ! 29: */ ! 30: ! 31: #include "rcv.h" ! 32: #include <sys/stat.h> ! 33: ! 34: /* ! 35: * Read a message from standard output and return a read file to it ! 36: * or NULL on error. ! 37: */ ! 38: ! 39: /* ! 40: * The following hokiness with global variables is so that on ! 41: * receipt of an interrupt signal, the partial message can be salted ! 42: * away on dead.letter. ! 43: */ ! 44: ! 45: static sig_t saveint; /* Previous SIGINT value */ ! 46: static sig_t savehup; /* Previous SIGHUP value */ ! 47: static sig_t savetstp; /* Previous SIGTSTP value */ ! 48: static sig_t savettou; /* Previous SIGTTOU value */ ! 49: static sig_t savettin; /* Previous SIGTTIN value */ ! 50: static FILE *collf; /* File for saving away */ ! 51: static int hadintr; /* Have seen one SIGINT so far */ ! 52: ! 53: static jmp_buf colljmp; /* To get back to work */ ! 54: static int colljmp_p; /* whether to long jump */ ! 55: static jmp_buf collabort; /* To end collection with error */ ! 56: ! 57: FILE * ! 58: collect(hp, printheaders) ! 59: struct header *hp; ! 60: { ! 61: FILE *fbuf; ! 62: int lc, cc, escape, eofcount; ! 63: int collint(), collhup(), collstop(); ! 64: register int c, t; ! 65: char linebuf[LINESIZE], *cp; ! 66: extern char tempMail[]; ! 67: char getsub; ! 68: int omask; ! 69: ! 70: collf = NULL; ! 71: /* ! 72: * Start catching signals from here, but we're still die on interrupts ! 73: * until we're in the main loop. ! 74: */ ! 75: omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); ! 76: if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) ! 77: signal(SIGINT, collint); ! 78: if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) ! 79: signal(SIGHUP, collhup); ! 80: savetstp = signal(SIGTSTP, collstop); ! 81: savettou = signal(SIGTTOU, collstop); ! 82: savettin = signal(SIGTTIN, collstop); ! 83: if (setjmp(collabort) || setjmp(colljmp)) { ! 84: remove(tempMail); ! 85: goto err; ! 86: } ! 87: sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); ! 88: ! 89: noreset++; ! 90: if ((collf = Fopen(tempMail, "w+")) == NULL) { ! 91: perror(tempMail); ! 92: goto err; ! 93: } ! 94: unlink(tempMail); ! 95: ! 96: /* ! 97: * If we are going to prompt for a subject, ! 98: * refrain from printing a newline after ! 99: * the headers (since some people mind). ! 100: */ ! 101: t = GTO|GSUBJECT|GCC|GNL; ! 102: getsub = 0; ! 103: if (hp->h_subject == NOSTR && value("interactive") != NOSTR && ! 104: (value("ask") != NOSTR || value("asksub") != NOSTR)) ! 105: t &= ~GNL, getsub++; ! 106: if (printheaders) { ! 107: puthead(hp, stdout, t); ! 108: fflush(stdout); ! 109: } ! 110: if ((cp = value("escape")) != NOSTR) ! 111: escape = *cp; ! 112: else ! 113: escape = ESCAPE; ! 114: eofcount = 0; ! 115: hadintr = 0; ! 116: ! 117: if (!setjmp(colljmp)) { ! 118: if (getsub) ! 119: grabh(hp, GSUBJECT); ! 120: } else { ! 121: /* ! 122: * Come here for printing the after-signal message. ! 123: * Duplicate messages won't be printed because ! 124: * the write is aborted if we get a SIGTTOU. ! 125: */ ! 126: cont: ! 127: if (hadintr) { ! 128: fflush(stdout); ! 129: fprintf(stderr, ! 130: "\n(Interrupt -- one more to kill letter)\n"); ! 131: } else { ! 132: printf("(continue)\n"); ! 133: fflush(stdout); ! 134: } ! 135: } ! 136: for (;;) { ! 137: colljmp_p = 1; ! 138: c = readline(stdin, linebuf, LINESIZE); ! 139: colljmp_p = 0; ! 140: if (c < 0) { ! 141: if (value("interactive") != NOSTR && ! 142: value("ignoreeof") != NOSTR && ++eofcount < 25) { ! 143: printf("Use \".\" to terminate letter\n"); ! 144: continue; ! 145: } ! 146: break; ! 147: } ! 148: eofcount = 0; ! 149: hadintr = 0; ! 150: if (linebuf[0] == '.' && linebuf[1] == '\0' && ! 151: value("interactive") != NOSTR && ! 152: (value("dot") != NOSTR || value("ignoreeof") != NOSTR)) ! 153: break; ! 154: if (linebuf[0] != escape || value("interactive") == NOSTR) { ! 155: if (putline(collf, linebuf) < 0) ! 156: goto err; ! 157: continue; ! 158: } ! 159: c = linebuf[1]; ! 160: switch (c) { ! 161: default: ! 162: /* ! 163: * On double escape, just send the single one. ! 164: * Otherwise, it's an error. ! 165: */ ! 166: if (c == escape) { ! 167: if (putline(collf, &linebuf[1]) < 0) ! 168: goto err; ! 169: else ! 170: break; ! 171: } ! 172: printf("Unknown tilde escape.\n"); ! 173: break; ! 174: case 'C': ! 175: /* ! 176: * Dump core. ! 177: */ ! 178: core(); ! 179: break; ! 180: case '!': ! 181: /* ! 182: * Shell escape, send the balance of the ! 183: * line to sh -c. ! 184: */ ! 185: shell(&linebuf[2]); ! 186: break; ! 187: case ':': ! 188: /* ! 189: * Escape to command mode, but be nice! ! 190: */ ! 191: execute(&linebuf[2], 1); ! 192: goto cont; ! 193: case '.': ! 194: /* ! 195: * Simulate end of file on input. ! 196: */ ! 197: goto out; ! 198: case 'q': ! 199: /* ! 200: * Force a quit of sending mail. ! 201: * Act like an interrupt happened. ! 202: */ ! 203: hadintr++; ! 204: collint(SIGINT); ! 205: exit(1); ! 206: case 'h': ! 207: /* ! 208: * Grab a bunch of headers. ! 209: */ ! 210: grabh(hp, GTO|GSUBJECT|GCC|GBCC); ! 211: goto cont; ! 212: case 't': ! 213: /* ! 214: * Add to the To list. ! 215: */ ! 216: hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); ! 217: break; ! 218: case 's': ! 219: /* ! 220: * Set the Subject list. ! 221: */ ! 222: cp = &linebuf[2]; ! 223: while (isspace(*cp)) ! 224: cp++; ! 225: hp->h_subject = savestr(cp); ! 226: break; ! 227: case 'c': ! 228: /* ! 229: * Add to the CC list. ! 230: */ ! 231: hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); ! 232: break; ! 233: case 'b': ! 234: /* ! 235: * Add stuff to blind carbon copies list. ! 236: */ ! 237: hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); ! 238: break; ! 239: case 'd': ! 240: strcpy(linebuf + 2, getdeadletter()); ! 241: /* fall into . . . */ ! 242: case 'r': ! 243: /* ! 244: * Invoke a file: ! 245: * Search for the file name, ! 246: * then open it and copy the contents to collf. ! 247: */ ! 248: cp = &linebuf[2]; ! 249: while (isspace(*cp)) ! 250: cp++; ! 251: if (*cp == '\0') { ! 252: printf("Interpolate what file?\n"); ! 253: break; ! 254: } ! 255: cp = expand(cp); ! 256: if (cp == NOSTR) ! 257: break; ! 258: if (isdir(cp)) { ! 259: printf("%s: Directory\n", cp); ! 260: break; ! 261: } ! 262: if ((fbuf = Fopen(cp, "r")) == NULL) { ! 263: perror(cp); ! 264: break; ! 265: } ! 266: printf("\"%s\" ", cp); ! 267: fflush(stdout); ! 268: lc = 0; ! 269: cc = 0; ! 270: while (readline(fbuf, linebuf, LINESIZE) >= 0) { ! 271: lc++; ! 272: if ((t = putline(collf, linebuf)) < 0) { ! 273: Fclose(fbuf); ! 274: goto err; ! 275: } ! 276: cc += t; ! 277: } ! 278: Fclose(fbuf); ! 279: printf("%d/%d\n", lc, cc); ! 280: break; ! 281: case 'w': ! 282: /* ! 283: * Write the message on a file. ! 284: */ ! 285: cp = &linebuf[2]; ! 286: while (*cp == ' ' || *cp == '\t') ! 287: cp++; ! 288: if (*cp == '\0') { ! 289: fprintf(stderr, "Write what file!?\n"); ! 290: break; ! 291: } ! 292: if ((cp = expand(cp)) == NOSTR) ! 293: break; ! 294: rewind(collf); ! 295: exwrite(cp, collf, 1); ! 296: break; ! 297: case 'm': ! 298: case 'M': ! 299: case 'f': ! 300: case 'F': ! 301: /* ! 302: * Interpolate the named messages, if we ! 303: * are in receiving mail mode. Does the ! 304: * standard list processing garbage. ! 305: * If ~f is given, we don't shift over. ! 306: */ ! 307: if (forward(linebuf + 2, collf, c) < 0) ! 308: goto err; ! 309: goto cont; ! 310: case '?': ! 311: if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { ! 312: perror(_PATH_TILDE); ! 313: break; ! 314: } ! 315: while ((t = getc(fbuf)) != EOF) ! 316: (void) putchar(t); ! 317: Fclose(fbuf); ! 318: break; ! 319: case 'p': ! 320: /* ! 321: * Print out the current state of the ! 322: * message without altering anything. ! 323: */ ! 324: rewind(collf); ! 325: printf("-------\nMessage contains:\n"); ! 326: puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); ! 327: while ((t = getc(collf)) != EOF) ! 328: (void) putchar(t); ! 329: goto cont; ! 330: case '|': ! 331: /* ! 332: * Pipe message through command. ! 333: * Collect output as new message. ! 334: */ ! 335: rewind(collf); ! 336: mespipe(collf, &linebuf[2]); ! 337: goto cont; ! 338: case 'v': ! 339: case 'e': ! 340: /* ! 341: * Edit the current message. ! 342: * 'e' means to use EDITOR ! 343: * 'v' means to use VISUAL ! 344: */ ! 345: rewind(collf); ! 346: mesedit(collf, c); ! 347: goto cont; ! 348: } ! 349: } ! 350: goto out; ! 351: err: ! 352: if (collf != NULL) { ! 353: Fclose(collf); ! 354: collf = NULL; ! 355: } ! 356: out: ! 357: if (collf != NULL) ! 358: rewind(collf); ! 359: noreset--; ! 360: sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); ! 361: signal(SIGINT, saveint); ! 362: signal(SIGHUP, savehup); ! 363: signal(SIGTSTP, savetstp); ! 364: signal(SIGTTOU, savettou); ! 365: signal(SIGTTIN, savettin); ! 366: sigsetmask(omask); ! 367: return collf; ! 368: } ! 369: ! 370: /* ! 371: * Write a file, ex-like if f set. ! 372: */ ! 373: ! 374: exwrite(name, fp, f) ! 375: char name[]; ! 376: FILE *fp; ! 377: { ! 378: register FILE *of; ! 379: register int c; ! 380: long cc; ! 381: int lc; ! 382: struct stat junk; ! 383: ! 384: if (f) { ! 385: printf("\"%s\" ", name); ! 386: fflush(stdout); ! 387: } ! 388: if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) { ! 389: if (!f) ! 390: fprintf(stderr, "%s: ", name); ! 391: fprintf(stderr, "File exists\n"); ! 392: return(-1); ! 393: } ! 394: if ((of = Fopen(name, "w")) == NULL) { ! 395: perror(NOSTR); ! 396: return(-1); ! 397: } ! 398: lc = 0; ! 399: cc = 0; ! 400: while ((c = getc(fp)) != EOF) { ! 401: cc++; ! 402: if (c == '\n') ! 403: lc++; ! 404: (void) putc(c, of); ! 405: if (ferror(of)) { ! 406: perror(name); ! 407: Fclose(of); ! 408: return(-1); ! 409: } ! 410: } ! 411: Fclose(of); ! 412: printf("%d/%ld\n", lc, cc); ! 413: fflush(stdout); ! 414: return(0); ! 415: } ! 416: ! 417: /* ! 418: * Edit the message being collected on fp. ! 419: * On return, make the edit file the new temp file. ! 420: */ ! 421: mesedit(fp, c) ! 422: FILE *fp; ! 423: { ! 424: sig_t sigint = signal(SIGINT, SIG_IGN); ! 425: FILE *nf = run_editor(fp, (off_t)-1, c, 0); ! 426: ! 427: if (nf != NULL) { ! 428: fseek(nf, (off_t)0, 2); ! 429: collf = nf; ! 430: Fclose(fp); ! 431: } ! 432: (void) signal(SIGINT, sigint); ! 433: } ! 434: ! 435: /* ! 436: * Pipe the message through the command. ! 437: * Old message is on stdin of command; ! 438: * New message collected from stdout. ! 439: * Sh -c must return 0 to accept the new message. ! 440: */ ! 441: mespipe(fp, cmd) ! 442: FILE *fp; ! 443: char cmd[]; ! 444: { ! 445: FILE *nf; ! 446: sig_t sigint = signal(SIGINT, SIG_IGN); ! 447: extern char tempEdit[]; ! 448: ! 449: if ((nf = Fopen(tempEdit, "w+")) == NULL) { ! 450: perror(tempEdit); ! 451: goto out; ! 452: } ! 453: (void) unlink(tempEdit); ! 454: /* ! 455: * stdin = current message. ! 456: * stdout = new message. ! 457: */ ! 458: if (run_command(cmd, 0, fileno(fp), fileno(nf), NOSTR) < 0) { ! 459: (void) Fclose(nf); ! 460: goto out; ! 461: } ! 462: if (fsize(nf) == 0) { ! 463: fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); ! 464: (void) Fclose(nf); ! 465: goto out; ! 466: } ! 467: /* ! 468: * Take new files. ! 469: */ ! 470: (void) fseek(nf, 0L, 2); ! 471: collf = nf; ! 472: (void) Fclose(fp); ! 473: out: ! 474: (void) signal(SIGINT, sigint); ! 475: } ! 476: ! 477: /* ! 478: * Interpolate the named messages into the current ! 479: * message, preceding each line with a tab. ! 480: * Return a count of the number of characters now in ! 481: * the message, or -1 if an error is encountered writing ! 482: * the message temporary. The flag argument is 'm' if we ! 483: * should shift over and 'f' if not. ! 484: */ ! 485: forward(ms, fp, f) ! 486: char ms[]; ! 487: FILE *fp; ! 488: { ! 489: register int *msgvec; ! 490: extern char tempMail[]; ! 491: struct ignoretab *ig; ! 492: char *tabst; ! 493: ! 494: msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); ! 495: if (msgvec == (int *) NOSTR) ! 496: return(0); ! 497: if (getmsglist(ms, msgvec, 0) < 0) ! 498: return(0); ! 499: if (*msgvec == 0) { ! 500: *msgvec = first(0, MMNORM); ! 501: if (*msgvec == NULL) { ! 502: printf("No appropriate messages\n"); ! 503: return(0); ! 504: } ! 505: msgvec[1] = NULL; ! 506: } ! 507: if (f == 'f' || f == 'F') ! 508: tabst = NOSTR; ! 509: else if ((tabst = value("indentprefix")) == NOSTR) ! 510: tabst = "\t"; ! 511: ig = isupper(f) ? NULL : ignore; ! 512: printf("Interpolating:"); ! 513: for (; *msgvec != 0; msgvec++) { ! 514: struct message *mp = message + *msgvec - 1; ! 515: ! 516: touch(mp); ! 517: printf(" %d", *msgvec); ! 518: if (send(mp, fp, ig, tabst) < 0) { ! 519: perror(tempMail); ! 520: return(-1); ! 521: } ! 522: } ! 523: printf("\n"); ! 524: return(0); ! 525: } ! 526: ! 527: /* ! 528: * Print (continue) when continued after ^Z. ! 529: */ ! 530: /*ARGSUSED*/ ! 531: collstop(s) ! 532: { ! 533: sig_t old_action = signal(s, SIG_DFL); ! 534: ! 535: sigsetmask(sigblock(0) & ~sigmask(s)); ! 536: kill(0, s); ! 537: sigblock(sigmask(s)); ! 538: signal(s, old_action); ! 539: if (colljmp_p) { ! 540: colljmp_p = 0; ! 541: hadintr = 0; ! 542: longjmp(colljmp, 1); ! 543: } ! 544: } ! 545: ! 546: /* ! 547: * On interrupt, come here to save the partial message in ~/dead.letter. ! 548: * Then jump out of the collection loop. ! 549: */ ! 550: /*ARGSUSED*/ ! 551: collint(s) ! 552: { ! 553: /* ! 554: * the control flow is subtle, because we can be called from ~q. ! 555: */ ! 556: if (!hadintr) { ! 557: if (value("ignore") != NOSTR) { ! 558: puts("@"); ! 559: fflush(stdout); ! 560: clearerr(stdin); ! 561: return; ! 562: } ! 563: hadintr = 1; ! 564: longjmp(colljmp, 1); ! 565: } ! 566: rewind(collf); ! 567: if (value("nosave") == NOSTR) ! 568: savedeadletter(collf); ! 569: longjmp(collabort, 1); ! 570: } ! 571: ! 572: /*ARGSUSED*/ ! 573: collhup(s) ! 574: { ! 575: rewind(collf); ! 576: savedeadletter(collf); ! 577: /* ! 578: * Let's pretend nobody else wants to clean up, ! 579: * a true statement at this time. ! 580: */ ! 581: exit(1); ! 582: } ! 583: ! 584: savedeadletter(fp) ! 585: register FILE *fp; ! 586: { ! 587: register FILE *dbuf; ! 588: register int c; ! 589: char *cp; ! 590: ! 591: if (fsize(fp) == 0) ! 592: return; ! 593: cp = getdeadletter(); ! 594: c = umask(077); ! 595: dbuf = Fopen(cp, "a"); ! 596: (void) umask(c); ! 597: if (dbuf == NULL) ! 598: return; ! 599: while ((c = getc(fp)) != EOF) ! 600: (void) putc(c, dbuf); ! 601: Fclose(dbuf); ! 602: rewind(fp); ! 603: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.