X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/001d60adb3ada66e268a4217a8f0a383a08ffe3f..a12ff48697cac43c0bd58aadc3f665316752562b:/usr/src/usr.bin/mail/collect.c diff --git a/usr/src/usr.bin/mail/collect.c b/usr/src/usr.bin/mail/collect.c index b30d74309c..73a0d98617 100644 --- a/usr/src/usr.bin/mail/collect.c +++ b/usr/src/usr.bin/mail/collect.c @@ -1,12 +1,13 @@ /* - * Copyright (c) 1980 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * %sccs.include.redist.c% */ #ifndef lint -static char *sccsid = "@(#)collect.c 5.4 (Berkeley) %G%"; -#endif not lint +static char sccsid[] = "@(#)collect.c 8.1 (Berkeley) %G%"; +#endif /* not lint */ /* * Mail -- a mail program @@ -16,8 +17,7 @@ static char *sccsid = "@(#)collect.c 5.4 (Berkeley) %G%"; */ #include "rcv.h" -#include -#include +#include "extern.h" /* * Read a message from standard output and return a read file to it @@ -30,54 +30,57 @@ static char *sccsid = "@(#)collect.c 5.4 (Berkeley) %G%"; * away on dead.letter. */ -static int (*saveint)(); /* Previous SIGINT value */ -static int (*savehup)(); /* Previous SIGHUP value */ -static int (*savecont)(); /* Previous SIGCONT value */ +static sig_t saveint; /* Previous SIGINT value */ +static sig_t savehup; /* Previous SIGHUP value */ +static sig_t savetstp; /* Previous SIGTSTP value */ +static sig_t savettou; /* Previous SIGTTOU value */ +static sig_t savettin; /* Previous SIGTTIN value */ static FILE *collf; /* File for saving away */ static int hadintr; /* Have seen one SIGINT so far */ -static jmp_buf coljmp; /* To get back to work */ +static jmp_buf colljmp; /* To get back to work */ +static int colljmp_p; /* whether to long jump */ +static jmp_buf collabort; /* To end collection with error */ FILE * -collect(hp) +collect(hp, printheaders) struct header *hp; + int printheaders; { - FILE *fp, *fbuf; - int lc, cc, escape, eof; - int collrub(), intack(), collcont(); + FILE *fbuf; + int lc, cc, escape, eofcount; register int c, t; char linebuf[LINESIZE], *cp; extern char tempMail[]; - int notify(); char getsub; int omask; + void collint(), collhup(), collstop(); - noreset++; - fp = NULL; collf = NULL; - /* * Start catching signals from here, but we're still die on interrupts * until we're in the main loop. */ omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) - signal(SIGINT, value("ignore") != NOSTR ? intack : collrub); + signal(SIGINT, collint); if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) - signal(SIGHUP, collrub); - savecont = signal(SIGCONT, SIG_DFL); - if (setjmp(coljmp)) { - remove(tempMail); + signal(SIGHUP, collhup); + savetstp = signal(SIGTSTP, collstop); + savettou = signal(SIGTTOU, collstop); + savettin = signal(SIGTTIN, collstop); + if (setjmp(collabort) || setjmp(colljmp)) { + rm(tempMail); goto err; } sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); - if ((fp = fopen(tempMail, "w+")) == NULL) { + noreset++; + if ((collf = Fopen(tempMail, "w+")) == NULL) { perror(tempMail); goto err; } - collf = fp; - remove(tempMail); + unlink(tempMail); /* * If we are going to prompt for a subject, @@ -86,24 +89,21 @@ collect(hp) */ t = GTO|GSUBJECT|GCC|GNL; getsub = 0; - if (intty && sflag == NOSTR && hp->h_subject == NOSTR && value("ask")) + if (hp->h_subject == NOSTR && value("interactive") != NOSTR && + (value("ask") != NOSTR || value("asksub") != NOSTR)) t &= ~GNL, getsub++; - if (hp->h_seq != 0) { + if (printheaders) { puthead(hp, stdout, t); fflush(stdout); } - escape = ESCAPE; if ((cp = value("escape")) != NOSTR) escape = *cp; - eof = 0; + else + escape = ESCAPE; + eofcount = 0; hadintr = 0; - /* - * We can put the setjmp here because register variable - * needs to be saved in the loop. - */ - if (!setjmp(coljmp)) { - signal(SIGCONT, collcont); + if (!setjmp(colljmp)) { if (getsub) grabh(hp, GSUBJECT); } else { @@ -123,22 +123,25 @@ cont: } } for (;;) { - if (readline(stdin, linebuf) < 0) { - if (intty && value("ignoreeof") != NOSTR) { - if (++eof > 35) - break; + colljmp_p = 1; + c = readline(stdin, linebuf, LINESIZE); + colljmp_p = 0; + if (c < 0) { + if (value("interactive") != NOSTR && + value("ignoreeof") != NOSTR && ++eofcount < 25) { printf("Use \".\" to terminate letter\n"); continue; } break; } - eof = 0; + eofcount = 0; hadintr = 0; - if (intty && equal(".", linebuf) && + if (linebuf[0] == '.' && linebuf[1] == '\0' && + value("interactive") != NOSTR && (value("dot") != NOSTR || value("ignoreeof") != NOSTR)) break; - if (linebuf[0] != escape || rflag != NOSTR) { - if (putline(fp, linebuf) < 0) + if (linebuf[0] != escape || value("interactive") == NOSTR) { + if (putline(collf, linebuf) < 0) goto err; continue; } @@ -149,119 +152,88 @@ cont: * On double escape, just send the single one. * Otherwise, it's an error. */ - if (c == escape) { - if (putline(fp, &linebuf[1]) < 0) + if (putline(collf, &linebuf[1]) < 0) goto err; else break; } printf("Unknown tilde escape.\n"); break; - case 'C': /* * Dump core. */ - core(); break; - case '!': /* * Shell escape, send the balance of the * line to sh -c. */ - shell(&linebuf[2]); break; - case ':': - case '_': /* * Escape to command mode, but be nice! */ - execute(&linebuf[2], 1); goto cont; - case '.': /* * Simulate end of file on input. */ goto out; - case 'q': - case 'Q': /* * Force a quit of sending mail. * Act like an interrupt happened. */ - hadintr++; - collrub(SIGINT); + collint(SIGINT); exit(1); - case 'h': /* * Grab a bunch of headers. */ - if (!intty || !outtty) { - printf("~h: no can do!?\n"); - break; - } grabh(hp, GTO|GSUBJECT|GCC|GBCC); goto cont; - case 't': /* * Add to the To list. */ - - hp->h_to = addto(hp->h_to, &linebuf[2]); - hp->h_seq++; + hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); break; - case 's': /* * Set the Subject list. */ - cp = &linebuf[2]; while (isspace(*cp)) cp++; hp->h_subject = savestr(cp); - hp->h_seq++; break; - case 'c': /* * Add to the CC list. */ - - hp->h_cc = addto(hp->h_cc, &linebuf[2]); - hp->h_seq++; + hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); break; - case 'b': /* * Add stuff to blind carbon copies list. */ - hp->h_bcc = addto(hp->h_bcc, &linebuf[2]); - hp->h_seq++; + hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); break; - case 'd': - strcpy(linebuf + 2, deadletter); + strcpy(linebuf + 2, getdeadletter()); /* fall into . . . */ - case 'r': /* * Invoke a file: * Search for the file name, - * then open it and copy the contents to fp. + * then open it and copy the contents to collf. */ - cp = &linebuf[2]; while (isspace(*cp)) cp++; @@ -276,7 +248,7 @@ cont: printf("%s: Directory\n", cp); break; } - if ((fbuf = fopen(cp, "r")) == NULL) { + if ((fbuf = Fopen(cp, "r")) == NULL) { perror(cp); break; } @@ -284,25 +256,23 @@ cont: fflush(stdout); lc = 0; cc = 0; - while (readline(fbuf, linebuf) >= 0) { + while (readline(fbuf, linebuf, LINESIZE) >= 0) { lc++; - if ((t = putline(fp, linebuf)) < 0) { - fclose(fbuf); + if ((t = putline(collf, linebuf)) < 0) { + Fclose(fbuf); goto err; } cc += t; } - fclose(fbuf); + Fclose(fbuf); printf("%d/%d\n", lc, cc); break; - case 'w': /* * Write the message on a file. */ - cp = &linebuf[2]; - while (any(*cp, " \t")) + while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0') { fprintf(stderr, "Write what file!?\n"); @@ -310,64 +280,50 @@ cont: } if ((cp = expand(cp)) == NOSTR) break; - rewind(fp); - exwrite(cp, fp, 1); + rewind(collf); + exwrite(cp, collf, 1); break; - case 'm': + case 'M': case 'f': + case 'F': /* * Interpolate the named messages, if we * are in receiving mail mode. Does the * standard list processing garbage. * If ~f is given, we don't shift over. */ - - if (!rcvmode) { - printf("No messages to send from!?!\n"); - break; - } - cp = &linebuf[2]; - while (any(*cp, " \t")) - cp++; - if (forward(cp, fp, c) < 0) + if (forward(linebuf + 2, collf, c) < 0) goto err; goto cont; - case '?': - if ((fbuf = fopen(THELPFILE, "r")) == NULL) { - perror(THELPFILE); + if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { + perror(_PATH_TILDE); break; } - while ((t = getc(fp)) != EOF) - putchar(t); - fclose(fbuf); + while ((t = getc(fbuf)) != EOF) + (void) putchar(t); + Fclose(fbuf); break; - case 'p': /* * Print out the current state of the * message without altering anything. */ - - rewind(fp); + rewind(collf); printf("-------\nMessage contains:\n"); puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); - while ((t = getc(fp)) != EOF) - putchar(t); + while ((t = getc(collf)) != EOF) + (void) putchar(t); goto cont; - - case '^': case '|': /* * Pipe message through command. * Collect output as new message. */ - - rewind(fp); - fp = mespipe(fp, &linebuf[2]); + rewind(collf); + mespipe(collf, &linebuf[2]); goto cont; - case 'v': case 'e': /* @@ -375,37 +331,39 @@ cont: * 'e' means to use EDITOR * 'v' means to use VISUAL */ - - rewind(fp); - if ((fp = mesedit(fp, c)) == NULL) - goto err; + rewind(collf); + mesedit(collf, c); goto cont; } } goto out; err: - if (fp != NULL) { - fclose(fp); - fp = NULL; + if (collf != NULL) { + Fclose(collf); + collf = NULL; } out: - if (fp != NULL) - rewind(fp); + if (collf != NULL) + rewind(collf); + noreset--; + sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); signal(SIGINT, saveint); signal(SIGHUP, savehup); - signal(SIGCONT, savecont); + signal(SIGTSTP, savetstp); + signal(SIGTTOU, savettou); + signal(SIGTTIN, savettin); sigsetmask(omask); - noreset = 0; - return(fp); + return collf; } /* * Write a file, ex-like if f set. */ - +int exwrite(name, fp, f) char name[]; FILE *fp; + int f; { register FILE *of; register int c; @@ -423,7 +381,7 @@ exwrite(name, fp, f) fprintf(stderr, "File exists\n"); return(-1); } - if ((of = fopen(name, "w")) == NULL) { + if ((of = Fopen(name, "w")) == NULL) { perror(NOSTR); return(-1); } @@ -433,14 +391,14 @@ exwrite(name, fp, f) cc++; if (c == '\n') lc++; - putc(c, of); + (void) putc(c, of); if (ferror(of)) { perror(name); - fclose(of); + Fclose(of); return(-1); } } - fclose(of); + Fclose(of); printf("%d/%ld\n", lc, cc); fflush(stdout); return(0); @@ -448,88 +406,22 @@ exwrite(name, fp, f) /* * Edit the message being collected on fp. - * Write the message out onto some poorly-named temp file - * and point an editor at it. - * * On return, make the edit file the new temp file. */ - -FILE * +void mesedit(fp, c) FILE *fp; + int c; { - int pid; - union wait s; - FILE *fbuf; - register int t; - int (*sigint)(), (*sigcont)(); - struct stat sbuf; - extern char tempEdit[]; - register char *edit; + sig_t sigint = signal(SIGINT, SIG_IGN); + FILE *nf = run_editor(fp, (off_t)-1, c, 0); - sigint = signal(SIGINT, SIG_IGN); - sigcont = signal(SIGCONT, SIG_DFL); - if (stat(tempEdit, &sbuf) >= 0) { - printf("%s: file exists\n", tempEdit); - goto out; - } - close(creat(tempEdit, 0600)); - if ((fbuf = fopen(tempEdit, "w")) == NULL) { - perror(tempEdit); - goto out; - } - while ((t = getc(fp)) != EOF) - putc(t, fbuf); - fflush(fbuf); - if (ferror(fbuf)) { - perror(tempEdit); - remove(tempEdit); - goto fix; - } - fclose(fbuf); - if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) - edit = c == 'e' ? EDITOR : VISUAL; - pid = vfork(); - if (pid == 0) { - if (sigint != SIG_IGN) - signal(SIGINT, SIG_DFL); - execl(edit, edit, tempEdit, 0); - perror(edit); - _exit(1); - } - if (pid == -1) { - perror("fork"); - remove(tempEdit); - goto out; - } - while (wait(&s) != pid) - ; - if (s.w_status != 0) { - printf("Fatal error in \"%s\"\n", edit); - remove(tempEdit); - goto out; - } - - /* - * Now switch to new file. - */ - - if ((fbuf = fopen(tempEdit, "a+")) == NULL) { - perror(tempEdit); - remove(tempEdit); - goto out; + if (nf != NULL) { + fseek(nf, 0L, 2); + collf = nf; + Fclose(fp); } - remove(tempEdit); - collf = fbuf; - fclose(fp); - fp = fbuf; - goto out; -fix: - perror(tempEdit); -out: - signal(SIGCONT, sigcont); - signal(SIGINT, sigint); - return(fp); + (void) signal(SIGINT, sigint); } /* @@ -538,73 +430,42 @@ out: * New message collected from stdout. * Sh -c must return 0 to accept the new message. */ - -FILE * +void mespipe(fp, cmd) FILE *fp; char cmd[]; { + FILE *nf; + sig_t sigint = signal(SIGINT, SIG_IGN); extern char tempEdit[]; - register FILE *nf; - int pid; - union wait s; - int (*saveint)(); - char *Shell; - if ((nf = fopen(tempEdit, "w+")) == NULL) { + if ((nf = Fopen(tempEdit, "w+")) == NULL) { perror(tempEdit); - return(fp); - } - remove(tempEdit); - saveint = signal(SIGINT, SIG_IGN); - if ((Shell = value("SHELL")) == NULL) - Shell = "/bin/sh"; - if ((pid = vfork()) == -1) { - perror("fork"); - goto err; - } - if (pid == 0) { - int fd; - /* - * stdin = current message. - * stdout = new message. - */ - - close(0); - dup(fileno(fp)); - close(1); - dup(fileno(nf)); - for (fd = getdtablesize(); --fd > 2;) - close(fd); - execl(Shell, Shell, "-c", cmd, 0); - perror(Shell); - _exit(1); + goto out; } - while (wait(&s) != pid) - ; - if (s.w_status != 0 || pid == -1) { - fprintf(stderr, "\"%s\" failed!?\n", cmd); - goto err; + (void) unlink(tempEdit); + /* + * stdin = current message. + * stdout = new message. + */ + if (run_command(cmd, + 0, fileno(fp), fileno(nf), NOSTR, NOSTR, NOSTR) < 0) { + (void) Fclose(nf); + goto out; } if (fsize(nf) == 0) { fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); - goto err; + (void) Fclose(nf); + goto out; } - /* * Take new files. */ - - fseek(nf, 0L, 2); + (void) fseek(nf, 0L, 2); collf = nf; - fclose(fp); - signal(SIGINT, saveint); - return(nf); - -err: - fclose(nf); - signal(SIGINT, saveint); - return(fp); + (void) Fclose(fp); +out: + (void) signal(SIGINT, sigint); } /* @@ -615,19 +476,23 @@ err: * the message temporary. The flag argument is 'm' if we * should shift over and 'f' if not. */ +int forward(ms, fp, f) char ms[]; FILE *fp; + int f; { - register int *msgvec, *ip; + register int *msgvec; extern char tempMail[]; + struct ignoretab *ig; + char *tabst; msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); if (msgvec == (int *) NOSTR) return(0); if (getmsglist(ms, msgvec, 0) < 0) return(0); - if (*msgvec == NULL) { + if (*msgvec == 0) { *msgvec = first(0, MMNORM); if (*msgvec == NULL) { printf("No appropriate messages\n"); @@ -635,155 +500,107 @@ forward(ms, fp, f) } msgvec[1] = NULL; } + if (f == 'f' || f == 'F') + tabst = NOSTR; + else if ((tabst = value("indentprefix")) == NOSTR) + tabst = "\t"; + ig = isupper(f) ? NULL : ignore; printf("Interpolating:"); - for (ip = msgvec; *ip != NULL; ip++) { - touch(*ip); - printf(" %d", *ip); - if (f == 'm') { - if (transmit(&message[*ip-1], fp) < 0L) { - perror(tempMail); - return(-1); - } - } else - if (send(&message[*ip-1], fp, 0) < 0) { - perror(tempMail); - return(-1); - } - } - printf("\n"); - return(0); -} - -/* - * Send message described by the passed pointer to the - * passed output buffer. Insert a tab in front of each - * line. Return a count of the characters sent, or -1 - * on error. - */ - -long -transmit(mailp, fp) - struct message *mailp; - FILE *fp; -{ - register struct message *mp; - register int ch; - long c, n; - int bol; - FILE *ibuf; + for (; *msgvec != 0; msgvec++) { + struct message *mp = message + *msgvec - 1; - mp = mailp; - ibuf = setinput(mp); - c = mp->m_size; - n = c; - bol = 1; - while (c-- > 0L) { - ch = getc(ibuf); - if (ch == '\n') - bol = 1; - else if (bol) { - bol = 0; - putc('\t', fp); - n++; - } - putc(ch, fp); - if (ferror(fp)) { - perror("/tmp"); - return(-1L); + touch(mp); + printf(" %d", *msgvec); + if (send(mp, fp, ig, tabst) < 0) { + perror(tempMail); + return(-1); } } - return(n); + printf("\n"); + return(0); } /* * Print (continue) when continued after ^Z. */ /*ARGSUSED*/ -collcont(s) +void +collstop(s) + int s; { - - hadintr = 0; - longjmp(coljmp, 1); + sig_t old_action = signal(s, SIG_DFL); + + sigsetmask(sigblock(0) & ~sigmask(s)); + kill(0, s); + sigblock(sigmask(s)); + signal(s, old_action); + if (colljmp_p) { + colljmp_p = 0; + hadintr = 0; + longjmp(colljmp, 1); + } } /* - * On interrupt, go here to save the partial - * message on ~/dead.letter. - * Then restore signals and execute the normal - * signal routine. We only come here if signals - * were previously set anyway. + * On interrupt, come here to save the partial message in ~/dead.letter. + * Then jump out of the collection loop. */ - -collrub(s) +/*ARGSUSED*/ +void +collint(s) + int s; { - register FILE *dbuf; - register int c; - - if (s == SIGINT && hadintr == 0) { + /* + * the control flow is subtle, because we can be called from ~q. + */ + if (!hadintr) { + if (value("ignore") != NOSTR) { + puts("@"); + fflush(stdout); + clearerr(stdin); + return; + } hadintr = 1; - longjmp(coljmp, 1); + longjmp(colljmp, 1); } rewind(collf); - if (s == SIGINT && value("nosave") != NOSTR || fsize(collf) == 0) - goto done; - if ((dbuf = fopen(deadletter, "w")) == NULL) - goto done; - chmod(deadletter, 0600); - while ((c = getc(collf)) != EOF) - putc(c, dbuf); - fclose(dbuf); - -done: - fclose(collf); - signal(SIGINT, saveint); - signal(SIGHUP, savehup); - signal(SIGCONT, savecont); - if (rcvmode) { - if (s == SIGHUP) - hangup(SIGHUP); - else - stop(s); - } else - exit(1); + if (value("nosave") == NOSTR) + savedeadletter(collf); + longjmp(collabort, 1); } -/* - * Acknowledge an interrupt signal from the tty by typing an @ - */ - /*ARGSUSED*/ -intack(s) +void +collhup(s) + int s; { - - puts("@"); - fflush(stdout); - clearerr(stdin); + rewind(collf); + savedeadletter(collf); + /* + * Let's pretend nobody else wants to clean up, + * a true statement at this time. + */ + exit(1); } -/* - * Add a string to the end of a header entry field. - */ - -char * -addto(hf, news) - char hf[], news[]; +void +savedeadletter(fp) + register FILE *fp; { - register char *cp, *cp2, *linebuf; - - if (hf == NOSTR) - hf = ""; - if (*news == '\0') - return(hf); - linebuf = salloc(strlen(hf) + strlen(news) + 2); - for (cp = hf; any(*cp, " \t"); cp++) - ; - for (cp2 = linebuf; *cp;) - *cp2++ = *cp++; - *cp2++ = ' '; - for (cp = news; any(*cp, " \t"); cp++) - ; - while (*cp != '\0') - *cp2++ = *cp++; - *cp2 = '\0'; - return(linebuf); + register FILE *dbuf; + register int c; + char *cp; + + if (fsize(fp) == 0) + return; + cp = getdeadletter(); + c = umask(077); + dbuf = Fopen(cp, "a"); + (void) umask(c); + if (dbuf == NULL) + return; + while ((c = getc(fp)) != EOF) + (void) putc(c, dbuf); + Fclose(dbuf); + rewind(fp); }