int gethfromtty(struct header *hp, int gflags) { hadintr = 0; while (grabh(hp, gflags) != 0) { if (collabort()) return(-1); } return(0); }
FILE * collect(struct header *hp, int printheaders) { FILE *fbuf; int lc, cc, escape, eofcount, fd, c, t; char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub; sigset_t nset; int longline, lastlong, rc; /* So we don't make 2 or more lines out of a long input line. */ collf = NULL; /* * Start catching signals from here, but we're still die on interrupts * until we're in the main loop. */ (void)sigemptyset(&nset); (void)sigaddset(&nset, SIGINT); (void)sigaddset(&nset, SIGHUP); (void)sigprocmask(SIG_BLOCK, &nset, NULL); if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) (void)signal(SIGINT, collint); if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) (void)signal(SIGHUP, collhup); savetstp = signal(SIGTSTP, collstop); savettou = signal(SIGTTOU, collstop); savettin = signal(SIGTTIN, collstop); if (setjmp(collabort) || setjmp(colljmp)) { (void)rm(tempname); goto err; } (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); noreset++; (void)snprintf(tempname, sizeof(tempname), "%s/mail.RsXXXXXXXXXX", tmpdir); if ((fd = mkstemp(tempname)) == -1 || (collf = Fdopen(fd, "w+")) == NULL) { warn("%s", tempname); goto err; } (void)rm(tempname); /* * If we are going to prompt for a subject, * refrain from printing a newline after * the headers (since some people mind). */ t = GTO|GSUBJECT|GCC|GNL; getsub = 0; if (hp->h_subject == NULL && value("interactive") != NULL && (value("ask") != NULL || value("asksub") != NULL)) t &= ~GNL, getsub++; if (printheaders) { puthead(hp, stdout, t); (void)fflush(stdout); } if ((cp = value("escape")) != NULL) escape = *cp; else escape = ESCAPE; eofcount = 0; hadintr = 0; lastlong = 0; longline = 0; if (!setjmp(colljmp)) { if (getsub) grabh(hp, GSUBJECT); } else { /* * Come here for printing the after-signal message. * Duplicate messages won't be printed because * the write is aborted if we get a SIGTTOU. */ cont: if (hadintr) { (void)fflush(stdout); fprintf(stderr, "\n(Interrupt -- one more to kill letter)\n"); } else { printf("(continue)\n"); (void)fflush(stdout); } } for (;;) { colljmp_p = 1; c = readline(stdin, linebuf, LINESIZE); colljmp_p = 0; if (c < 0) { if (value("interactive") != NULL && value("ignoreeof") != NULL && ++eofcount < 25) { printf("Use \".\" to terminate letter\n"); continue; } break; } lastlong = longline; longline = c == LINESIZE - 1; eofcount = 0; hadintr = 0; if (linebuf[0] == '.' && linebuf[1] == '\0' && value("interactive") != NULL && !lastlong && (value("dot") != NULL || value("ignoreeof") != NULL)) break; if (linebuf[0] != escape || value("interactive") == NULL || lastlong) { if (putline(collf, linebuf, !longline) < 0) goto err; continue; } c = linebuf[1]; switch (c) { default: /* * On double escape, just send the single one. * Otherwise, it's an error. */ if (c == escape) { if (putline(collf, &linebuf[1], !longline) < 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': /* * Force a quit of sending mail. * Act like an interrupt happened. */ hadintr++; collint(SIGINT); exit(1); case 'x': /* * Exit, do not save in dead.letter. */ goto err; case 'h': /* * Grab a bunch of headers. */ grabh(hp, GTO|GSUBJECT|GCC|GBCC); goto cont; case 't': /* * Add to the To list. */ hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); break; case 's': /* * Set the Subject line. */ cp = &linebuf[2]; while (isspace((unsigned char)*cp)) cp++; hp->h_subject = savestr(cp); break; case 'R': /* * Set the Reply-To line. */ cp = &linebuf[2]; while (isspace((unsigned char)*cp)) cp++; hp->h_replyto = savestr(cp); break; case 'c': /* * Add to the CC list. */ hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); break; case 'b': /* * Add to the BCC list. */ hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); break; case 'i': case 'A': case 'a': /* * Insert named variable in message. */ switch(c) { case 'i': cp = &linebuf[2]; while(isspace((unsigned char)*cp)) cp++; break; case 'a': cp = "sign"; break; case 'A': cp = "Sign"; break; default: goto err; } if(*cp != '\0' && (cp = value(cp)) != NULL) { printf("%s\n", cp); if(putline(collf, cp, 1) < 0) goto err; } break; case 'd': /* * Read in the dead letter file. */ if (strlcpy(linebuf + 2, getdeadletter(), sizeof(linebuf) - 2) >= sizeof(linebuf) - 2) { printf("Line buffer overflow\n"); break; } /* FALLTHROUGH */ case 'r': case '<': /* * Invoke a file: * Search for the file name, * then open it and copy the contents to collf. */ cp = &linebuf[2]; while (isspace((unsigned char)*cp)) cp++; if (*cp == '\0') { printf("Interpolate what file?\n"); break; } cp = expand(cp); if (cp == NULL) break; if (*cp == '!') { /* * Insert stdout of command. */ char *sh; int nullfd, tempfd, rc; char tempname2[PATHSIZE]; if ((nullfd = open(_PATH_DEVNULL, O_RDONLY, 0)) == -1) { warn(_PATH_DEVNULL); break; } (void)snprintf(tempname2, sizeof(tempname2), "%s/mail.ReXXXXXXXXXX", tmpdir); if ((tempfd = mkstemp(tempname2)) == -1 || (fbuf = Fdopen(tempfd, "w+")) == NULL) { warn("%s", tempname2); break; } (void)unlink(tempname2); if ((sh = value("SHELL")) == NULL) sh = _PATH_CSHELL; rc = run_command(sh, 0, nullfd, fileno(fbuf), "-c", cp+1, NULL); close(nullfd); if (rc < 0) { (void)Fclose(fbuf); break; } if (fsize(fbuf) == 0) { fprintf(stderr, "No bytes from command \"%s\"\n", cp+1); (void)Fclose(fbuf); break; } rewind(fbuf); } else if (isdir(cp)) { printf("%s: Directory\n", cp); break; } else if ((fbuf = Fopen(cp, "r")) == NULL) { warn("%s", cp); break; } printf("\"%s\" ", cp); (void)fflush(stdout); lc = 0; cc = 0; while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) { if (rc != LINESIZE - 1) lc++; if ((t = putline(collf, linebuf, rc != LINESIZE - 1)) < 0) { (void)Fclose(fbuf); goto err; } cc += t; } (void)Fclose(fbuf); printf("%d/%d\n", lc, cc); break; case 'w': /* * Write the message on a file. */ cp = &linebuf[2]; while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0') { fprintf(stderr, "Write what file!?\n"); break; } if ((cp = expand(cp)) == NULL) break; 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 (forward(linebuf + 2, collf, tempname, c) < 0) goto err; goto cont; case '?': if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { warn("%s", _PATH_TILDE); break; } while ((t = getc(fbuf)) != EOF) (void)putchar(t); (void)Fclose(fbuf); break; case 'p': /* * Print out the current state of the * message without altering anything. */ rewind(collf); printf("-------\nMessage contains:\n"); puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); while ((t = getc(collf)) != EOF) (void)putchar(t); goto cont; case '|': /* * Pipe message through command. * Collect output as new message. */ rewind(collf); mespipe(collf, &linebuf[2]); goto cont; case 'v': case 'e': /* * Edit the current message. * 'e' means to use EDITOR * 'v' means to use VISUAL */ rewind(collf); mesedit(collf, c); goto cont; } } goto out; err: if (collf != NULL) { (void)Fclose(collf); collf = NULL; } out: if (collf != NULL) rewind(collf); noreset--; (void)sigprocmask(SIG_BLOCK, &nset, NULL); (void)signal(SIGINT, saveint); (void)signal(SIGHUP, savehup); (void)signal(SIGTSTP, savetstp); (void)signal(SIGTTOU, savettou); (void)signal(SIGTTIN, savettin); (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); return (collf); }
FILE * collect(struct header *hp, int printheaders, struct message *mp, char *quotefile, int doprefix, int tflag) { FILE *fbuf; struct ignoretab *quoteig; int lc, cc, escape, eofcount; int c, t; char *linebuf = NULL, *cp, *quote = NULL; size_t linesize; char *tempMail = NULL; int getfields; sigset_t oset, nset; long count; enum sendaction action; sighandler_type savedtop; const char tildehelp[] = "-------------------- ~ ESCAPES ----------------------------\n\ ~~ Quote a single tilde\n\ ~@ [file ...] Edit attachment list\n\ ~b users Add users to \"blind\" cc list\n\ ~c users Add users to cc list\n\ ~d Read in dead.letter\n\ ~e Edit the message buffer\n\ ~f messages Read in messages without indenting lines\n\ ~F messages Same as ~f, but keep all header lines\n\ ~h Prompt for to list, subject, cc, and \"blind\" cc list\n\ ~r file Read a file into the message buffer\n\ ~p Print the message buffer\n\ ~q Abort message composition and save text to dead.letter\n\ ~m messages Read in messages with each line indented\n\ ~M messages Same as ~m, but keep all header lines\n\ ~s subject Set subject\n\ ~t users Add users to to list\n\ ~v Invoke display editor on message\n\ ~w file Write message onto file\n\ ~x Abort message composition and discard text written so far\n\ ~!command Invoke the shell\n\ ~:command Execute a regular command\n\ -----------------------------------------------------------\n"; (void) &escape; (void) &eofcount; (void) &getfields; (void) &tempMail; (void) &tflag; (void) "e; collf = NULL; /* * Start catching signals from here, but we're still die on interrupts * until we're in the main loop. */ sigemptyset(&nset); sigaddset(&nset, SIGINT); sigaddset(&nset, SIGHUP); sigprocmask(SIG_BLOCK, &nset, &oset); handlerpush(collint); if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN) safe_signal(SIGINT, collint); if ((savehup = safe_signal(SIGHUP, SIG_IGN)) != SIG_IGN) safe_signal(SIGHUP, collhup); savetstp = safe_signal(SIGTSTP, collstop); savettou = safe_signal(SIGTTOU, collstop); savettin = safe_signal(SIGTTIN, collstop); if (sigsetjmp(collabort, 1)) { if (tempMail != NULL) { rm(tempMail); Ftfree(&tempMail); } goto err; } if (sigsetjmp(colljmp, 1)) { if (tempMail != NULL) { rm(tempMail); Ftfree(&tempMail); } goto err; } sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); noreset++; if ((collf = Ftemp(&tempMail, "Rs", "w+", 0600, 1)) == NULL) { perror(catgets(catd, CATSET, 51, "temporary mail file")); goto err; } unlink(tempMail); Ftfree(&tempMail); if ((cp = value("MAILX_HEAD")) != NULL) { if (is_a_tty[0]) putesc(cp, stdout); putesc(cp, collf); } /* * If we are going to prompt for a subject, * refrain from printing a newline after * the headers (since some people mind). */ getfields = 0; if (!tflag) { t = GTO|GSUBJECT|GCC|GNL; if (value("fullnames")) t |= GCOMMA; if (hp->h_subject == NULL && value("interactive") != NULL && (value("ask") != NULL || value("asksub") != NULL)) t &= ~GNL, getfields |= GSUBJECT; if (hp->h_to == NULL && value("interactive") != NULL) t &= ~GNL, getfields |= GTO; if (value("bsdcompat") == NULL && value("askatend") == NULL && value("interactive")) { if (hp->h_bcc == NULL && value("askbcc")) t &= ~GNL, getfields |= GBCC; if (hp->h_cc == NULL && value("askcc")) t &= ~GNL, getfields |= GCC; } if (printheaders) { puthead(hp, stdout, t, SEND_TODISP, CONV_NONE, NULL, NULL); fflush(stdout); } } /* * Quote an original message */ if (mp != NULL && (doprefix || (quote = value("quote")) != NULL)) { quoteig = allignore; action = SEND_QUOTE; if (doprefix) { quoteig = fwdignore; if ((cp = value("fwdheading")) == NULL) cp = "-------- Original Message --------"; if (*cp) { fprintf(collf, "%s\n", cp); fprintf(stdout, "%s\n", cp); } } else if (strcmp(quote, "noheading") == 0) { /*EMPTY*/; } else if (strcmp(quote, "headers") == 0) { quoteig = ignore; } else if (strcmp(quote, "allheaders") == 0) { quoteig = NULL; action = SEND_QUOTE_ALL; } else { cp = hfield("from", mp); if (cp != NULL) { mime_write(cp, strlen(cp), collf, CONV_FROMHDR, TD_NONE, NULL, (size_t) 0, NULL, NULL); mime_write(cp, strlen(cp), stdout, CONV_FROMHDR, TD_NONE, NULL, (size_t) 0, NULL, NULL); fwrite(catgets(catd, CATSET, 52, " wrote:\n\n"), sizeof(char), 9, collf); fwrite(catgets(catd, CATSET, 52, " wrote:\n\n"), sizeof(char), 9, stdout); } } cp = value("indentprefix"); if (cp != NULL && *cp == '\0') cp = "\t"; send(mp, collf, quoteig, doprefix ? NULL : cp, action, NULL); send(mp, stdout, quoteig, doprefix ? NULL : cp, action, NULL); } if ((cp = value("escape")) != NULL) escape = *cp; else escape = ESCAPE; eofcount = 0; hadintr = 0; if (!sigsetjmp(colljmp, 1)) { if (getfields) grabh(hp, getfields, 1); if (quotefile != NULL) { if (include_file(NULL, quotefile, &lc, &cc, 1) != 0) goto err; } } else { /* * Come here for printing the after-signal message. * Duplicate messages won't be printed because * the write is aborted if we get a SIGTTOU. */ cont: if (hadintr) { fflush(stdout); fprintf(stderr, catgets(catd, CATSET, 53, "\n(Interrupt -- one more to kill letter)\n")); } else { printf(catgets(catd, CATSET, 54, "(continue)\n")); fflush(stdout); } } if (value("interactive") == NULL && tildeflag <= 0 && !is_a_tty[0] && !tflag) { /* * No tilde escapes, interrupts not expected. Copy * standard input the simple way. */ linebuf = srealloc(linebuf, linesize = BUFSIZ); while ((count = fread(linebuf, sizeof *linebuf, linesize, stdin)) > 0) { if (fwrite(linebuf, sizeof *linebuf, count, collf) != count) goto err; } goto out; } for (;;) { colljmp_p = 1; count = readline(stdin, &linebuf, &linesize); colljmp_p = 0; if (count < 0) { if (value("interactive") != NULL && value("ignoreeof") != NULL && ++eofcount < 25) { printf(catgets(catd, CATSET, 55, "Use \".\" to terminate letter\n")); continue; } break; } if (tflag && count == 0) { rewind(collf); if (makeheader(collf, hp) != OKAY) goto err; rewind(collf); tflag = 0; continue; } eofcount = 0; hadintr = 0; if (linebuf[0] == '.' && linebuf[1] == '\0' && value("interactive") != NULL && (value("dot") != NULL || value("ignoreeof") != NULL)) break; if (linebuf[0] != escape || (value("interactive") == NULL && tildeflag == 0 || tildeflag < 0)) { if (putline(collf, linebuf, count) < 0) goto err; continue; } c = linebuf[1]; switch (c) { default: /* * On double escape, just send the single one. * Otherwise, it's an error. */ if (c == escape) { if (putline(collf, &linebuf[1], count - 1) < 0) goto err; else break; } printf(catgets(catd, CATSET, 56, "Unknown tilde escape.\n")); break; #ifdef DEBUG_COMMANDS case 'C': /* * Dump core. */ core(NULL); break; #endif /* DEBUG_COMMANDS */ 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! */ inhook = 0; execute(&linebuf[2], 1, count - 2); goto cont; case '.': /* * Simulate end of file on input. */ goto out; case 'x': /* * Same as 'q', but no dead.letter saving. */ hadintr++; collint(0); exit(1); /*NOTREACHED*/ case 'q': /* * Force a quit of sending mail. * Act like an interrupt happened. */ hadintr++; collint(SIGINT); exit(1); /*NOTREACHED*/ case 'h': /* * Grab a bunch of headers. */ do grabh(hp, GTO|GSUBJECT|GCC|GBCC, value("bsdcompat") != NULL && value("bsdorder") != NULL); while (hp->h_to == NULL); goto cont; case 'H': /* * Grab extra headers. */ do grabh(hp, GEXTRA, 0); while (check_from_and_sender(hp->h_from, hp->h_sender)); goto cont; case 't': /* * Add to the To list. */ while ((hp->h_to = checkaddrs(cat(hp->h_to, sextract(&linebuf[2], GTO|GFULL)))) == NULL); break; case 's': /* * Set the Subject list. */ cp = &linebuf[2]; while (whitechar(*cp & 0377)) cp++; hp->h_subject = savestr(cp); break; case '@': /* * Edit the attachment list. */ if (linebuf[2] != '\0') hp->h_attach = append_attachments(hp->h_attach, &linebuf[2]); else hp->h_attach = edit_attachments(hp->h_attach); break; case 'c': /* * Add to the CC list. */ hp->h_cc = checkaddrs(cat(hp->h_cc, sextract(&linebuf[2], GCC|GFULL))); break; case 'b': /* * Add stuff to blind carbon copies list. */ hp->h_bcc = checkaddrs(cat(hp->h_bcc, sextract(&linebuf[2], GBCC|GFULL))); break; case 'd': strncpy(linebuf + 2, getdeadletter(), linesize - 2); linebuf[linesize-1]='\0'; /*FALLTHRU*/ case 'r': case '<': /* * Invoke a file: * Search for the file name, * then open it and copy the contents to collf. */ cp = &linebuf[2]; while (whitechar(*cp & 0377)) cp++; if (*cp == '\0') { printf(catgets(catd, CATSET, 57, "Interpolate what file?\n")); break; } if (*cp == '!') { insertcommand(collf, cp + 1); break; } cp = expand(cp); if (cp == NULL) break; if (is_dir(cp)) { printf(catgets(catd, CATSET, 58, "%s: Directory\n"), cp); break; } if ((fbuf = Fopen(cp, "r")) == NULL) { perror(cp); break; } printf(catgets(catd, CATSET, 59, "\"%s\" "), cp); fflush(stdout); if (include_file(fbuf, cp, &lc, &cc, 0) != 0) goto err; printf(catgets(catd, CATSET, 60, "%d/%d\n"), lc, cc); break; case 'i': /* * Insert an environment variable into the file. */ cp = &linebuf[2]; while (whitechar(*cp & 0377)) cp++; if ((cp = value(cp)) == NULL || *cp == '\0') break; if (is_a_tty[0]) putesc(cp, stdout); putesc(cp, collf); break; case 'a': case 'A': /* * Insert the contents of a signature variable. */ if ((cp = value(c == 'a' ? "sign" : "Sign")) != NULL && *cp != '\0') { if (is_a_tty[0]) putesc(cp, stdout); putesc(cp, collf); } break; case 'w': /* * Write the message on a file. */ cp = &linebuf[2]; while (blankchar(*cp & 0377)) cp++; if (*cp == '\0') { fprintf(stderr, catgets(catd, CATSET, 61, "Write what file!?\n")); break; } if ((cp = expand(cp)) == NULL) break; 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 (forward(linebuf + 2, collf, c) < 0) goto err; goto cont; case '?': fputs(tildehelp, stdout); break; case 'p': /* * Print out the current state of the * message without altering anything. */ print_collf(collf, hp); goto cont; case '|': /* * Pipe message through command. * Collect output as new message. */ rewind(collf); mespipe(&linebuf[2]); goto cont; case 'v': case 'e': /* * Edit the current message. * 'e' means to use EDITOR * 'v' means to use VISUAL */ rewind(collf); mesedit(c, value("editheaders") ? hp : NULL); goto cont; } } goto out; err: if (collf != NULL) { Fclose(collf); collf = NULL; } out: if (collf != NULL) { if ((cp = value("MAILX_TAIL")) != NULL) { if (is_a_tty[0]) putesc(cp, stdout); fflush(collf); putesc(cp, collf); } rewind(collf); } handlerpop(); noreset--; sigemptyset(&nset); sigaddset(&nset, SIGINT); sigaddset(&nset, SIGHUP); #ifndef OLDBUG sigprocmask(SIG_BLOCK, &nset, (sigset_t *)NULL); #else sigprocmask(SIG_BLOCK, &nset, &oset); #endif safe_signal(SIGINT, saveint); safe_signal(SIGHUP, savehup); safe_signal(SIGTSTP, savetstp); safe_signal(SIGTTOU, savettou); safe_signal(SIGTTIN, savettin); sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); return collf; }
FILE * collect(struct header *hp, int printheaders) { FILE *fbuf; int lc, cc, fd, c, t, lastlong, rc, sig; int escape, eofcount, longline; char getsub; char linebuf[LINESIZE], tempname[PATHSIZE], *cp; collf = NULL; eofcount = 0; hadintr = 0; lastlong = 0; longline = 0; if ((cp = value("escape")) != NULL) escape = *cp; else escape = ESCAPE; noreset++; (void)snprintf(tempname, sizeof(tempname), "%s/mail.RsXXXXXXXXXX", tmpdir); if ((fd = mkstemp(tempname)) == -1 || (collf = Fdopen(fd, "w+")) == NULL) { warn("%s", tempname); goto err; } (void)rm(tempname); /* * If we are going to prompt for a subject, * refrain from printing a newline after * the headers (since some people mind). */ t = GTO|GSUBJECT|GCC|GNL; getsub = 0; if (hp->h_subject == NULL && value("interactive") != NULL && (value("ask") != NULL || value("asksub") != NULL)) t &= ~GNL, getsub++; if (printheaders) { puthead(hp, stdout, t); fflush(stdout); } if (getsub && gethfromtty(hp, GSUBJECT) == -1) goto err; if (0) { cont: /* Come here for printing the after-suspend message. */ if (isatty(0)) { puts("(continue)"); fflush(stdout); } } for (;;) { c = readline(stdin, linebuf, LINESIZE, &sig); /* Act on any signal caught during readline() ignoring 'c' */ switch (sig) { case 0: break; case SIGINT: if (collabort()) goto err; continue; case SIGHUP: rewind(collf); savedeadletter(collf); /* * Let's pretend nobody else wants to clean up, * a true statement at this time. */ exit(1); default: /* Stopped due to job control */ (void)kill(0, sig); goto cont; } /* No signal, check for error */ if (c < 0) { if (value("interactive") != NULL && value("ignoreeof") != NULL && ++eofcount < 25) { puts("Use \".\" to terminate letter"); continue; } break; } lastlong = longline; longline = (c == LINESIZE - 1); eofcount = 0; hadintr = 0; if (linebuf[0] == '.' && linebuf[1] == '\0' && value("interactive") != NULL && !lastlong && (value("dot") != NULL || value("ignoreeof") != NULL)) break; if (linebuf[0] != escape || value("interactive") == NULL || lastlong) { if (putline(collf, linebuf, !longline) < 0) goto err; continue; } c = linebuf[1]; switch (c) { default: /* * On double escape, just send the single one. * Otherwise, it's an error. */ if (c == escape) { if (putline(collf, &linebuf[1], !longline) < 0) goto err; else break; } puts("Unknown tilde escape."); 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': /* * Force a quit of sending mail. * Act like an interrupt happened. */ hadintr++; collabort(); fputs("Interrupt\n", stderr); goto err; case 'x': /* * Force a quit of sending mail. * Do not save the message. */ goto err; case 'h': /* * Grab a bunch of headers. */ grabh(hp, GTO|GSUBJECT|GCC|GBCC); goto cont; case 't': /* * Add to the To list. */ 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); break; case 'c': /* * Add to the CC list. */ hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); break; case 'b': /* * Add stuff to blind carbon copies list. */ hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); break; case 'd': linebuf[2] = '\0'; strlcat(linebuf, getdeadletter(), sizeof(linebuf)); /* fall into . . . */ case 'r': case '<': /* * Invoke a file: * Search for the file name, * then open it and copy the contents to collf. */ cp = &linebuf[2]; while (isspace(*cp)) cp++; if (*cp == '\0') { puts("Interpolate what file?"); break; } cp = expand(cp); if (cp == NULL) break; if (isdir(cp)) { printf("%s: Directory\n", cp); break; } if ((fbuf = Fopen(cp, "r")) == NULL) { warn("%s", cp); break; } printf("\"%s\" ", cp); fflush(stdout); lc = 0; cc = 0; while ((rc = readline(fbuf, linebuf, LINESIZE, NULL)) >= 0) { if (rc != LINESIZE - 1) lc++; if ((t = putline(collf, linebuf, rc != LINESIZE-1)) < 0) { (void)Fclose(fbuf); goto err; } cc += t; } (void)Fclose(fbuf); printf("%d/%d\n", lc, cc); break; case 'w': /* * Write the message on a file. */ cp = &linebuf[2]; while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0') { fputs("Write what file!?\n", stderr); break; } if ((cp = expand(cp)) == NULL) break; 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 (forward(linebuf + 2, collf, tempname, c) < 0) goto err; goto cont; case '?': if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { warn(_PATH_TILDE); break; } while ((t = getc(fbuf)) != EOF) (void)putchar(t); (void)Fclose(fbuf); break; case 'p': /* * Print out the current state of the * message without altering anything. */ rewind(collf); puts("-------\nMessage contains:"); puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); while ((t = getc(collf)) != EOF) (void)putchar(t); goto cont; case '|': /* * Pipe message through command. * Collect output as new message. */ rewind(collf); mespipe(collf, &linebuf[2]); goto cont; case 'v': case 'e': /* * Edit the current message. * 'e' means to use EDITOR * 'v' means to use VISUAL */ rewind(collf); mesedit(collf, c); goto cont; } } if (value("interactive") != NULL) { if (value("askcc") != NULL || value("askbcc") != NULL) { if (value("askcc") != NULL) { if (gethfromtty(hp, GCC) == -1) goto err; } if (value("askbcc") != NULL) { if (gethfromtty(hp, GBCC) == -1) goto err; } } else { puts("EOT"); (void)fflush(stdout); } } goto out; err: if (collf != NULL) { (void)Fclose(collf); collf = NULL; } out: if (collf != NULL) rewind(collf); noreset--; return(collf); }
/* * Mail a message on standard input to the people indicated * in the passed header. (Internal interface). */ void mail1(struct header *hp, int printheaders) { char *cp; char *nbuf; int pid; char **namelist; struct name *to, *nsto; FILE *mtf; /* * Collect user's mail from standard input. * Get the result as mtf. */ if ((mtf = collect(hp, printheaders)) == NULL) return; if (value("interactive") != NULL) { if (value("askcc") != NULL || value("askbcc") != NULL) { if (value("askcc") != NULL) grabh(hp, GCC); if (value("askbcc") != NULL) grabh(hp, GBCC); } else { printf("EOT\n"); (void)fflush(stdout); } } if (fsize(mtf) == 0) { if (value("dontsendempty") != NULL) goto out; if (hp->h_subject == NULL) printf("No message, no subject; hope that's ok\n"); else printf("Null message body; hope that's ok\n"); } /* * Now, take the user names from the combined * to and cc lists and do all the alias * processing. */ senderr = 0; to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); if (to == NULL) { printf("No recipients specified\n"); senderr++; } /* * Look through the recipient list for names with /'s * in them which we write to as files directly. */ to = outof(to, mtf, hp); if (senderr) savedeadletter(mtf); to = elide(to); if (count(to) == 0) goto out; if (value("recordrecip") != NULL) { /* * Before fixing the header, save old To:. * We do this because elide above has sorted To: list, and * we would like to save message in a file named by the first * recipient the user has entered, not the one being the first * after sorting happened. */ if ((nsto = malloc(sizeof(struct name))) == NULL) err(1, "Out of memory"); bcopy(hp->h_to, nsto, sizeof(struct name)); } fixhead(hp, to); if ((mtf = infix(hp, mtf)) == NULL) { fprintf(stderr, ". . . message lost, sorry.\n"); return; } namelist = unpack(cat(hp->h_smopts, to)); if (debug) { char **t; printf("Sendmail arguments:"); for (t = namelist; *t != NULL; t++) printf(" \"%s\"", *t); printf("\n"); goto out; } if (value("recordrecip") != NULL) { /* * Extract first recipient username from saved To: and use it * as a filename. */ if ((nbuf = malloc(strlen(detract(nsto, 0)) + 1)) == NULL) err(1, "Out of memory"); if ((cp = yanklogin(detract(nsto, 0), nbuf)) != NULL) (void)savemail(expand(nbuf), mtf); free(nbuf); free(nsto); } else if ((cp = value("record")) != NULL) (void)savemail(expand(cp), mtf); /* * Fork, set up the temporary mail file as standard * input for "mail", and exec with the user list we generated * far above. */ pid = fork(); if (pid == -1) { warn("fork"); savedeadletter(mtf); goto out; } if (pid == 0) { sigset_t nset; (void)sigemptyset(&nset); (void)sigaddset(&nset, SIGHUP); (void)sigaddset(&nset, SIGINT); (void)sigaddset(&nset, SIGQUIT); (void)sigaddset(&nset, SIGTSTP); (void)sigaddset(&nset, SIGTTIN); (void)sigaddset(&nset, SIGTTOU); prepare_child(&nset, fileno(mtf), -1); if ((cp = value("sendmail")) != NULL) cp = expand(cp); else cp = _PATH_SENDMAIL; execv(cp, namelist); warn("%s", cp); _exit(1); } if (value("verbose") != NULL) (void)wait_child(pid); else free_child(pid); out: (void)Fclose(mtf); }