collect.c revision 1590
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimesstatic char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; 361590Srgrimes#endif /* not lint */ 371590Srgrimes 381590Srgrimes/* 391590Srgrimes * Mail -- a mail program 401590Srgrimes * 411590Srgrimes * Collect input from standard input, handling 421590Srgrimes * ~ escapes. 431590Srgrimes */ 441590Srgrimes 451590Srgrimes#include "rcv.h" 461590Srgrimes#include "extern.h" 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * Read a message from standard output and return a read file to it 501590Srgrimes * or NULL on error. 511590Srgrimes */ 521590Srgrimes 531590Srgrimes/* 541590Srgrimes * The following hokiness with global variables is so that on 551590Srgrimes * receipt of an interrupt signal, the partial message can be salted 561590Srgrimes * away on dead.letter. 571590Srgrimes */ 581590Srgrimes 591590Srgrimesstatic sig_t saveint; /* Previous SIGINT value */ 601590Srgrimesstatic sig_t savehup; /* Previous SIGHUP value */ 611590Srgrimesstatic sig_t savetstp; /* Previous SIGTSTP value */ 621590Srgrimesstatic sig_t savettou; /* Previous SIGTTOU value */ 631590Srgrimesstatic sig_t savettin; /* Previous SIGTTIN value */ 641590Srgrimesstatic FILE *collf; /* File for saving away */ 651590Srgrimesstatic int hadintr; /* Have seen one SIGINT so far */ 661590Srgrimes 671590Srgrimesstatic jmp_buf colljmp; /* To get back to work */ 681590Srgrimesstatic int colljmp_p; /* whether to long jump */ 691590Srgrimesstatic jmp_buf collabort; /* To end collection with error */ 701590Srgrimes 711590SrgrimesFILE * 721590Srgrimescollect(hp, printheaders) 731590Srgrimes struct header *hp; 741590Srgrimes int printheaders; 751590Srgrimes{ 761590Srgrimes FILE *fbuf; 771590Srgrimes int lc, cc, escape, eofcount; 781590Srgrimes register int c, t; 791590Srgrimes char linebuf[LINESIZE], *cp; 801590Srgrimes extern char tempMail[]; 811590Srgrimes char getsub; 821590Srgrimes int omask; 831590Srgrimes void collint(), collhup(), collstop(); 841590Srgrimes 851590Srgrimes collf = NULL; 861590Srgrimes /* 871590Srgrimes * Start catching signals from here, but we're still die on interrupts 881590Srgrimes * until we're in the main loop. 891590Srgrimes */ 901590Srgrimes omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); 911590Srgrimes if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 921590Srgrimes signal(SIGINT, collint); 931590Srgrimes if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) 941590Srgrimes signal(SIGHUP, collhup); 951590Srgrimes savetstp = signal(SIGTSTP, collstop); 961590Srgrimes savettou = signal(SIGTTOU, collstop); 971590Srgrimes savettin = signal(SIGTTIN, collstop); 981590Srgrimes if (setjmp(collabort) || setjmp(colljmp)) { 991590Srgrimes rm(tempMail); 1001590Srgrimes goto err; 1011590Srgrimes } 1021590Srgrimes sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); 1031590Srgrimes 1041590Srgrimes noreset++; 1051590Srgrimes if ((collf = Fopen(tempMail, "w+")) == NULL) { 1061590Srgrimes perror(tempMail); 1071590Srgrimes goto err; 1081590Srgrimes } 1091590Srgrimes unlink(tempMail); 1101590Srgrimes 1111590Srgrimes /* 1121590Srgrimes * If we are going to prompt for a subject, 1131590Srgrimes * refrain from printing a newline after 1141590Srgrimes * the headers (since some people mind). 1151590Srgrimes */ 1161590Srgrimes t = GTO|GSUBJECT|GCC|GNL; 1171590Srgrimes getsub = 0; 1181590Srgrimes if (hp->h_subject == NOSTR && value("interactive") != NOSTR && 1191590Srgrimes (value("ask") != NOSTR || value("asksub") != NOSTR)) 1201590Srgrimes t &= ~GNL, getsub++; 1211590Srgrimes if (printheaders) { 1221590Srgrimes puthead(hp, stdout, t); 1231590Srgrimes fflush(stdout); 1241590Srgrimes } 1251590Srgrimes if ((cp = value("escape")) != NOSTR) 1261590Srgrimes escape = *cp; 1271590Srgrimes else 1281590Srgrimes escape = ESCAPE; 1291590Srgrimes eofcount = 0; 1301590Srgrimes hadintr = 0; 1311590Srgrimes 1321590Srgrimes if (!setjmp(colljmp)) { 1331590Srgrimes if (getsub) 1341590Srgrimes grabh(hp, GSUBJECT); 1351590Srgrimes } else { 1361590Srgrimes /* 1371590Srgrimes * Come here for printing the after-signal message. 1381590Srgrimes * Duplicate messages won't be printed because 1391590Srgrimes * the write is aborted if we get a SIGTTOU. 1401590Srgrimes */ 1411590Srgrimescont: 1421590Srgrimes if (hadintr) { 1431590Srgrimes fflush(stdout); 1441590Srgrimes fprintf(stderr, 1451590Srgrimes "\n(Interrupt -- one more to kill letter)\n"); 1461590Srgrimes } else { 1471590Srgrimes printf("(continue)\n"); 1481590Srgrimes fflush(stdout); 1491590Srgrimes } 1501590Srgrimes } 1511590Srgrimes for (;;) { 1521590Srgrimes colljmp_p = 1; 1531590Srgrimes c = readline(stdin, linebuf, LINESIZE); 1541590Srgrimes colljmp_p = 0; 1551590Srgrimes if (c < 0) { 1561590Srgrimes if (value("interactive") != NOSTR && 1571590Srgrimes value("ignoreeof") != NOSTR && ++eofcount < 25) { 1581590Srgrimes printf("Use \".\" to terminate letter\n"); 1591590Srgrimes continue; 1601590Srgrimes } 1611590Srgrimes break; 1621590Srgrimes } 1631590Srgrimes eofcount = 0; 1641590Srgrimes hadintr = 0; 1651590Srgrimes if (linebuf[0] == '.' && linebuf[1] == '\0' && 1661590Srgrimes value("interactive") != NOSTR && 1671590Srgrimes (value("dot") != NOSTR || value("ignoreeof") != NOSTR)) 1681590Srgrimes break; 1691590Srgrimes if (linebuf[0] != escape || value("interactive") == NOSTR) { 1701590Srgrimes if (putline(collf, linebuf) < 0) 1711590Srgrimes goto err; 1721590Srgrimes continue; 1731590Srgrimes } 1741590Srgrimes c = linebuf[1]; 1751590Srgrimes switch (c) { 1761590Srgrimes default: 1771590Srgrimes /* 1781590Srgrimes * On double escape, just send the single one. 1791590Srgrimes * Otherwise, it's an error. 1801590Srgrimes */ 1811590Srgrimes if (c == escape) { 1821590Srgrimes if (putline(collf, &linebuf[1]) < 0) 1831590Srgrimes goto err; 1841590Srgrimes else 1851590Srgrimes break; 1861590Srgrimes } 1871590Srgrimes printf("Unknown tilde escape.\n"); 1881590Srgrimes break; 1891590Srgrimes case 'C': 1901590Srgrimes /* 1911590Srgrimes * Dump core. 1921590Srgrimes */ 1931590Srgrimes core(); 1941590Srgrimes break; 1951590Srgrimes case '!': 1961590Srgrimes /* 1971590Srgrimes * Shell escape, send the balance of the 1981590Srgrimes * line to sh -c. 1991590Srgrimes */ 2001590Srgrimes shell(&linebuf[2]); 2011590Srgrimes break; 2021590Srgrimes case ':': 2031590Srgrimes /* 2041590Srgrimes * Escape to command mode, but be nice! 2051590Srgrimes */ 2061590Srgrimes execute(&linebuf[2], 1); 2071590Srgrimes goto cont; 2081590Srgrimes case '.': 2091590Srgrimes /* 2101590Srgrimes * Simulate end of file on input. 2111590Srgrimes */ 2121590Srgrimes goto out; 2131590Srgrimes case 'q': 2141590Srgrimes /* 2151590Srgrimes * Force a quit of sending mail. 2161590Srgrimes * Act like an interrupt happened. 2171590Srgrimes */ 2181590Srgrimes hadintr++; 2191590Srgrimes collint(SIGINT); 2201590Srgrimes exit(1); 2211590Srgrimes case 'h': 2221590Srgrimes /* 2231590Srgrimes * Grab a bunch of headers. 2241590Srgrimes */ 2251590Srgrimes grabh(hp, GTO|GSUBJECT|GCC|GBCC); 2261590Srgrimes goto cont; 2271590Srgrimes case 't': 2281590Srgrimes /* 2291590Srgrimes * Add to the To list. 2301590Srgrimes */ 2311590Srgrimes hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); 2321590Srgrimes break; 2331590Srgrimes case 's': 2341590Srgrimes /* 2351590Srgrimes * Set the Subject list. 2361590Srgrimes */ 2371590Srgrimes cp = &linebuf[2]; 2381590Srgrimes while (isspace(*cp)) 2391590Srgrimes cp++; 2401590Srgrimes hp->h_subject = savestr(cp); 2411590Srgrimes break; 2421590Srgrimes case 'c': 2431590Srgrimes /* 2441590Srgrimes * Add to the CC list. 2451590Srgrimes */ 2461590Srgrimes hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); 2471590Srgrimes break; 2481590Srgrimes case 'b': 2491590Srgrimes /* 2501590Srgrimes * Add stuff to blind carbon copies list. 2511590Srgrimes */ 2521590Srgrimes hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); 2531590Srgrimes break; 2541590Srgrimes case 'd': 2551590Srgrimes strcpy(linebuf + 2, getdeadletter()); 2561590Srgrimes /* fall into . . . */ 2571590Srgrimes case 'r': 2581590Srgrimes /* 2591590Srgrimes * Invoke a file: 2601590Srgrimes * Search for the file name, 2611590Srgrimes * then open it and copy the contents to collf. 2621590Srgrimes */ 2631590Srgrimes cp = &linebuf[2]; 2641590Srgrimes while (isspace(*cp)) 2651590Srgrimes cp++; 2661590Srgrimes if (*cp == '\0') { 2671590Srgrimes printf("Interpolate what file?\n"); 2681590Srgrimes break; 2691590Srgrimes } 2701590Srgrimes cp = expand(cp); 2711590Srgrimes if (cp == NOSTR) 2721590Srgrimes break; 2731590Srgrimes if (isdir(cp)) { 2741590Srgrimes printf("%s: Directory\n", cp); 2751590Srgrimes break; 2761590Srgrimes } 2771590Srgrimes if ((fbuf = Fopen(cp, "r")) == NULL) { 2781590Srgrimes perror(cp); 2791590Srgrimes break; 2801590Srgrimes } 2811590Srgrimes printf("\"%s\" ", cp); 2821590Srgrimes fflush(stdout); 2831590Srgrimes lc = 0; 2841590Srgrimes cc = 0; 2851590Srgrimes while (readline(fbuf, linebuf, LINESIZE) >= 0) { 2861590Srgrimes lc++; 2871590Srgrimes if ((t = putline(collf, linebuf)) < 0) { 2881590Srgrimes Fclose(fbuf); 2891590Srgrimes goto err; 2901590Srgrimes } 2911590Srgrimes cc += t; 2921590Srgrimes } 2931590Srgrimes Fclose(fbuf); 2941590Srgrimes printf("%d/%d\n", lc, cc); 2951590Srgrimes break; 2961590Srgrimes case 'w': 2971590Srgrimes /* 2981590Srgrimes * Write the message on a file. 2991590Srgrimes */ 3001590Srgrimes cp = &linebuf[2]; 3011590Srgrimes while (*cp == ' ' || *cp == '\t') 3021590Srgrimes cp++; 3031590Srgrimes if (*cp == '\0') { 3041590Srgrimes fprintf(stderr, "Write what file!?\n"); 3051590Srgrimes break; 3061590Srgrimes } 3071590Srgrimes if ((cp = expand(cp)) == NOSTR) 3081590Srgrimes break; 3091590Srgrimes rewind(collf); 3101590Srgrimes exwrite(cp, collf, 1); 3111590Srgrimes break; 3121590Srgrimes case 'm': 3131590Srgrimes case 'M': 3141590Srgrimes case 'f': 3151590Srgrimes case 'F': 3161590Srgrimes /* 3171590Srgrimes * Interpolate the named messages, if we 3181590Srgrimes * are in receiving mail mode. Does the 3191590Srgrimes * standard list processing garbage. 3201590Srgrimes * If ~f is given, we don't shift over. 3211590Srgrimes */ 3221590Srgrimes if (forward(linebuf + 2, collf, c) < 0) 3231590Srgrimes goto err; 3241590Srgrimes goto cont; 3251590Srgrimes case '?': 3261590Srgrimes if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { 3271590Srgrimes perror(_PATH_TILDE); 3281590Srgrimes break; 3291590Srgrimes } 3301590Srgrimes while ((t = getc(fbuf)) != EOF) 3311590Srgrimes (void) putchar(t); 3321590Srgrimes Fclose(fbuf); 3331590Srgrimes break; 3341590Srgrimes case 'p': 3351590Srgrimes /* 3361590Srgrimes * Print out the current state of the 3371590Srgrimes * message without altering anything. 3381590Srgrimes */ 3391590Srgrimes rewind(collf); 3401590Srgrimes printf("-------\nMessage contains:\n"); 3411590Srgrimes puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); 3421590Srgrimes while ((t = getc(collf)) != EOF) 3431590Srgrimes (void) putchar(t); 3441590Srgrimes goto cont; 3451590Srgrimes case '|': 3461590Srgrimes /* 3471590Srgrimes * Pipe message through command. 3481590Srgrimes * Collect output as new message. 3491590Srgrimes */ 3501590Srgrimes rewind(collf); 3511590Srgrimes mespipe(collf, &linebuf[2]); 3521590Srgrimes goto cont; 3531590Srgrimes case 'v': 3541590Srgrimes case 'e': 3551590Srgrimes /* 3561590Srgrimes * Edit the current message. 3571590Srgrimes * 'e' means to use EDITOR 3581590Srgrimes * 'v' means to use VISUAL 3591590Srgrimes */ 3601590Srgrimes rewind(collf); 3611590Srgrimes mesedit(collf, c); 3621590Srgrimes goto cont; 3631590Srgrimes } 3641590Srgrimes } 3651590Srgrimes goto out; 3661590Srgrimeserr: 3671590Srgrimes if (collf != NULL) { 3681590Srgrimes Fclose(collf); 3691590Srgrimes collf = NULL; 3701590Srgrimes } 3711590Srgrimesout: 3721590Srgrimes if (collf != NULL) 3731590Srgrimes rewind(collf); 3741590Srgrimes noreset--; 3751590Srgrimes sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); 3761590Srgrimes signal(SIGINT, saveint); 3771590Srgrimes signal(SIGHUP, savehup); 3781590Srgrimes signal(SIGTSTP, savetstp); 3791590Srgrimes signal(SIGTTOU, savettou); 3801590Srgrimes signal(SIGTTIN, savettin); 3811590Srgrimes sigsetmask(omask); 3821590Srgrimes return collf; 3831590Srgrimes} 3841590Srgrimes 3851590Srgrimes/* 3861590Srgrimes * Write a file, ex-like if f set. 3871590Srgrimes */ 3881590Srgrimesint 3891590Srgrimesexwrite(name, fp, f) 3901590Srgrimes char name[]; 3911590Srgrimes FILE *fp; 3921590Srgrimes int f; 3931590Srgrimes{ 3941590Srgrimes register FILE *of; 3951590Srgrimes register int c; 3961590Srgrimes long cc; 3971590Srgrimes int lc; 3981590Srgrimes struct stat junk; 3991590Srgrimes 4001590Srgrimes if (f) { 4011590Srgrimes printf("\"%s\" ", name); 4021590Srgrimes fflush(stdout); 4031590Srgrimes } 4041590Srgrimes if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) { 4051590Srgrimes if (!f) 4061590Srgrimes fprintf(stderr, "%s: ", name); 4071590Srgrimes fprintf(stderr, "File exists\n"); 4081590Srgrimes return(-1); 4091590Srgrimes } 4101590Srgrimes if ((of = Fopen(name, "w")) == NULL) { 4111590Srgrimes perror(NOSTR); 4121590Srgrimes return(-1); 4131590Srgrimes } 4141590Srgrimes lc = 0; 4151590Srgrimes cc = 0; 4161590Srgrimes while ((c = getc(fp)) != EOF) { 4171590Srgrimes cc++; 4181590Srgrimes if (c == '\n') 4191590Srgrimes lc++; 4201590Srgrimes (void) putc(c, of); 4211590Srgrimes if (ferror(of)) { 4221590Srgrimes perror(name); 4231590Srgrimes Fclose(of); 4241590Srgrimes return(-1); 4251590Srgrimes } 4261590Srgrimes } 4271590Srgrimes Fclose(of); 4281590Srgrimes printf("%d/%ld\n", lc, cc); 4291590Srgrimes fflush(stdout); 4301590Srgrimes return(0); 4311590Srgrimes} 4321590Srgrimes 4331590Srgrimes/* 4341590Srgrimes * Edit the message being collected on fp. 4351590Srgrimes * On return, make the edit file the new temp file. 4361590Srgrimes */ 4371590Srgrimesvoid 4381590Srgrimesmesedit(fp, c) 4391590Srgrimes FILE *fp; 4401590Srgrimes int c; 4411590Srgrimes{ 4421590Srgrimes sig_t sigint = signal(SIGINT, SIG_IGN); 4431590Srgrimes FILE *nf = run_editor(fp, (off_t)-1, c, 0); 4441590Srgrimes 4451590Srgrimes if (nf != NULL) { 4461590Srgrimes fseek(nf, 0L, 2); 4471590Srgrimes collf = nf; 4481590Srgrimes Fclose(fp); 4491590Srgrimes } 4501590Srgrimes (void) signal(SIGINT, sigint); 4511590Srgrimes} 4521590Srgrimes 4531590Srgrimes/* 4541590Srgrimes * Pipe the message through the command. 4551590Srgrimes * Old message is on stdin of command; 4561590Srgrimes * New message collected from stdout. 4571590Srgrimes * Sh -c must return 0 to accept the new message. 4581590Srgrimes */ 4591590Srgrimesvoid 4601590Srgrimesmespipe(fp, cmd) 4611590Srgrimes FILE *fp; 4621590Srgrimes char cmd[]; 4631590Srgrimes{ 4641590Srgrimes FILE *nf; 4651590Srgrimes sig_t sigint = signal(SIGINT, SIG_IGN); 4661590Srgrimes extern char tempEdit[]; 4671590Srgrimes char *shell; 4681590Srgrimes 4691590Srgrimes if ((nf = Fopen(tempEdit, "w+")) == NULL) { 4701590Srgrimes perror(tempEdit); 4711590Srgrimes goto out; 4721590Srgrimes } 4731590Srgrimes (void) unlink(tempEdit); 4741590Srgrimes /* 4751590Srgrimes * stdin = current message. 4761590Srgrimes * stdout = new message. 4771590Srgrimes */ 4781590Srgrimes if ((shell = value("SHELL")) == NOSTR) 4791590Srgrimes shell = _PATH_CSHELL; 4801590Srgrimes if (run_command(shell, 4811590Srgrimes 0, fileno(fp), fileno(nf), "-c", cmd, NOSTR) < 0) { 4821590Srgrimes (void) Fclose(nf); 4831590Srgrimes goto out; 4841590Srgrimes } 4851590Srgrimes if (fsize(nf) == 0) { 4861590Srgrimes fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); 4871590Srgrimes (void) Fclose(nf); 4881590Srgrimes goto out; 4891590Srgrimes } 4901590Srgrimes /* 4911590Srgrimes * Take new files. 4921590Srgrimes */ 4931590Srgrimes (void) fseek(nf, 0L, 2); 4941590Srgrimes collf = nf; 4951590Srgrimes (void) Fclose(fp); 4961590Srgrimesout: 4971590Srgrimes (void) signal(SIGINT, sigint); 4981590Srgrimes} 4991590Srgrimes 5001590Srgrimes/* 5011590Srgrimes * Interpolate the named messages into the current 5021590Srgrimes * message, preceding each line with a tab. 5031590Srgrimes * Return a count of the number of characters now in 5041590Srgrimes * the message, or -1 if an error is encountered writing 5051590Srgrimes * the message temporary. The flag argument is 'm' if we 5061590Srgrimes * should shift over and 'f' if not. 5071590Srgrimes */ 5081590Srgrimesint 5091590Srgrimesforward(ms, fp, f) 5101590Srgrimes char ms[]; 5111590Srgrimes FILE *fp; 5121590Srgrimes int f; 5131590Srgrimes{ 5141590Srgrimes register int *msgvec; 5151590Srgrimes extern char tempMail[]; 5161590Srgrimes struct ignoretab *ig; 5171590Srgrimes char *tabst; 5181590Srgrimes 5191590Srgrimes msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); 5201590Srgrimes if (msgvec == (int *) NOSTR) 5211590Srgrimes return(0); 5221590Srgrimes if (getmsglist(ms, msgvec, 0) < 0) 5231590Srgrimes return(0); 5241590Srgrimes if (*msgvec == 0) { 5251590Srgrimes *msgvec = first(0, MMNORM); 5261590Srgrimes if (*msgvec == NULL) { 5271590Srgrimes printf("No appropriate messages\n"); 5281590Srgrimes return(0); 5291590Srgrimes } 5301590Srgrimes msgvec[1] = NULL; 5311590Srgrimes } 5321590Srgrimes if (f == 'f' || f == 'F') 5331590Srgrimes tabst = NOSTR; 5341590Srgrimes else if ((tabst = value("indentprefix")) == NOSTR) 5351590Srgrimes tabst = "\t"; 5361590Srgrimes ig = isupper(f) ? NULL : ignore; 5371590Srgrimes printf("Interpolating:"); 5381590Srgrimes for (; *msgvec != 0; msgvec++) { 5391590Srgrimes struct message *mp = message + *msgvec - 1; 5401590Srgrimes 5411590Srgrimes touch(mp); 5421590Srgrimes printf(" %d", *msgvec); 5431590Srgrimes if (send(mp, fp, ig, tabst) < 0) { 5441590Srgrimes perror(tempMail); 5451590Srgrimes return(-1); 5461590Srgrimes } 5471590Srgrimes } 5481590Srgrimes printf("\n"); 5491590Srgrimes return(0); 5501590Srgrimes} 5511590Srgrimes 5521590Srgrimes/* 5531590Srgrimes * Print (continue) when continued after ^Z. 5541590Srgrimes */ 5551590Srgrimes/*ARGSUSED*/ 5561590Srgrimesvoid 5571590Srgrimescollstop(s) 5581590Srgrimes int s; 5591590Srgrimes{ 5601590Srgrimes sig_t old_action = signal(s, SIG_DFL); 5611590Srgrimes 5621590Srgrimes sigsetmask(sigblock(0) & ~sigmask(s)); 5631590Srgrimes kill(0, s); 5641590Srgrimes sigblock(sigmask(s)); 5651590Srgrimes signal(s, old_action); 5661590Srgrimes if (colljmp_p) { 5671590Srgrimes colljmp_p = 0; 5681590Srgrimes hadintr = 0; 5691590Srgrimes longjmp(colljmp, 1); 5701590Srgrimes } 5711590Srgrimes} 5721590Srgrimes 5731590Srgrimes/* 5741590Srgrimes * On interrupt, come here to save the partial message in ~/dead.letter. 5751590Srgrimes * Then jump out of the collection loop. 5761590Srgrimes */ 5771590Srgrimes/*ARGSUSED*/ 5781590Srgrimesvoid 5791590Srgrimescollint(s) 5801590Srgrimes int s; 5811590Srgrimes{ 5821590Srgrimes /* 5831590Srgrimes * the control flow is subtle, because we can be called from ~q. 5841590Srgrimes */ 5851590Srgrimes if (!hadintr) { 5861590Srgrimes if (value("ignore") != NOSTR) { 5871590Srgrimes puts("@"); 5881590Srgrimes fflush(stdout); 5891590Srgrimes clearerr(stdin); 5901590Srgrimes return; 5911590Srgrimes } 5921590Srgrimes hadintr = 1; 5931590Srgrimes longjmp(colljmp, 1); 5941590Srgrimes } 5951590Srgrimes rewind(collf); 5961590Srgrimes if (value("nosave") == NOSTR) 5971590Srgrimes savedeadletter(collf); 5981590Srgrimes longjmp(collabort, 1); 5991590Srgrimes} 6001590Srgrimes 6011590Srgrimes/*ARGSUSED*/ 6021590Srgrimesvoid 6031590Srgrimescollhup(s) 6041590Srgrimes int s; 6051590Srgrimes{ 6061590Srgrimes rewind(collf); 6071590Srgrimes savedeadletter(collf); 6081590Srgrimes /* 6091590Srgrimes * Let's pretend nobody else wants to clean up, 6101590Srgrimes * a true statement at this time. 6111590Srgrimes */ 6121590Srgrimes exit(1); 6131590Srgrimes} 6141590Srgrimes 6151590Srgrimesvoid 6161590Srgrimessavedeadletter(fp) 6171590Srgrimes register FILE *fp; 6181590Srgrimes{ 6191590Srgrimes register FILE *dbuf; 6201590Srgrimes register int c; 6211590Srgrimes char *cp; 6221590Srgrimes 6231590Srgrimes if (fsize(fp) == 0) 6241590Srgrimes return; 6251590Srgrimes cp = getdeadletter(); 6261590Srgrimes c = umask(077); 6271590Srgrimes dbuf = Fopen(cp, "a"); 6281590Srgrimes (void) umask(c); 6291590Srgrimes if (dbuf == NULL) 6301590Srgrimes return; 6311590Srgrimes while ((c = getc(fp)) != EOF) 6321590Srgrimes (void) putc(c, dbuf); 6331590Srgrimes Fclose(dbuf); 6341590Srgrimes rewind(fp); 6351590Srgrimes} 636