send.c revision 88227
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 3574769Smikeh#if 0 361590Srgrimesstatic char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; 3774769Smikeh#endif 3874769Smikehstatic const char rcsid[] = 3974769Smikeh "$FreeBSD: head/usr.bin/mail/send.c 88227 2001-12-19 21:50:22Z ache $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes#include "rcv.h" 431590Srgrimes#include "extern.h" 441590Srgrimes 451590Srgrimes/* 461590Srgrimes * Mail -- a mail program 471590Srgrimes * 481590Srgrimes * Mail to others. 491590Srgrimes */ 501590Srgrimes 511590Srgrimes/* 521590Srgrimes * Send message described by the passed pointer to the 531590Srgrimes * passed output buffer. Return -1 on error. 541590Srgrimes * Adjust the status: field if need be. 551590Srgrimes * If doign is given, suppress ignored header fields. 561590Srgrimes * prefix is a string to prepend to each output line. 571590Srgrimes */ 581590Srgrimesint 5974769Smikehsendmessage(mp, obuf, doign, prefix) 6077274Smikeh struct message *mp; 611590Srgrimes FILE *obuf; 621590Srgrimes struct ignoretab *doign; 631590Srgrimes char *prefix; 641590Srgrimes{ 651590Srgrimes long count; 6677274Smikeh FILE *ibuf; 6777274Smikeh char *cp, *cp2, line[LINESIZE]; 681590Srgrimes int ishead, infld, ignoring, dostat, firstline; 6977274Smikeh int c, length, prefixlen; 701590Srgrimes 711590Srgrimes /* 721590Srgrimes * Compute the prefix string, without trailing whitespace 731590Srgrimes */ 7477274Smikeh if (prefix != NULL) { 751590Srgrimes cp2 = 0; 7677274Smikeh for (cp = prefix; *cp != '\0'; cp++) 771590Srgrimes if (*cp != ' ' && *cp != '\t') 781590Srgrimes cp2 = cp; 7977274Smikeh prefixlen = cp2 == NULL ? 0 : cp2 - prefix + 1; 801590Srgrimes } 811590Srgrimes ibuf = setinput(mp); 821590Srgrimes count = mp->m_size; 831590Srgrimes ishead = 1; 841590Srgrimes dostat = doign == 0 || !isign("status", doign); 851590Srgrimes infld = 0; 861590Srgrimes firstline = 1; 871590Srgrimes /* 881590Srgrimes * Process headers first 891590Srgrimes */ 901590Srgrimes while (count > 0 && ishead) { 9174769Smikeh if (fgets(line, sizeof(line), ibuf) == NULL) 921590Srgrimes break; 931590Srgrimes count -= length = strlen(line); 941590Srgrimes if (firstline) { 958874Srgrimes /* 961590Srgrimes * First line is the From line, so no headers 971590Srgrimes * there to worry about 981590Srgrimes */ 991590Srgrimes firstline = 0; 1001590Srgrimes ignoring = doign == ignoreall; 1011590Srgrimes } else if (line[0] == '\n') { 1021590Srgrimes /* 1031590Srgrimes * If line is blank, we've reached end of 1041590Srgrimes * headers, so force out status: field 1051590Srgrimes * and note that we are no longer in header 1061590Srgrimes * fields 1071590Srgrimes */ 1081590Srgrimes if (dostat) { 1091590Srgrimes statusput(mp, obuf, prefix); 1101590Srgrimes dostat = 0; 1111590Srgrimes } 1121590Srgrimes ishead = 0; 1131590Srgrimes ignoring = doign == ignoreall; 1141590Srgrimes } else if (infld && (line[0] == ' ' || line[0] == '\t')) { 1151590Srgrimes /* 1161590Srgrimes * If this line is a continuation (via space or tab) 1171590Srgrimes * of a previous header field, just echo it 1181590Srgrimes * (unless the field should be ignored). 1191590Srgrimes * In other words, nothing to do. 1201590Srgrimes */ 1211590Srgrimes } else { 1221590Srgrimes /* 1231590Srgrimes * Pick up the header field if we have one. 1241590Srgrimes */ 12577274Smikeh for (cp = line; (c = *cp++) != '\0' && c != ':' && 12688227Sache !isspace((unsigned char)c);) 1271590Srgrimes ; 1281590Srgrimes cp2 = --cp; 12988227Sache while (isspace((unsigned char)*cp++)) 1301590Srgrimes ; 1311590Srgrimes if (cp[-1] != ':') { 1321590Srgrimes /* 1331590Srgrimes * Not a header line, force out status: 1341590Srgrimes * This happens in uucp style mail where 1351590Srgrimes * there are no headers at all. 1361590Srgrimes */ 1371590Srgrimes if (dostat) { 1381590Srgrimes statusput(mp, obuf, prefix); 1391590Srgrimes dostat = 0; 1401590Srgrimes } 1411590Srgrimes if (doign != ignoreall) 1421590Srgrimes /* add blank line */ 14377274Smikeh (void)putc('\n', obuf); 1441590Srgrimes ishead = 0; 1451590Srgrimes ignoring = 0; 1461590Srgrimes } else { 1471590Srgrimes /* 1481590Srgrimes * If it is an ignored field and 1491590Srgrimes * we care about such things, skip it. 1501590Srgrimes */ 15177274Smikeh *cp2 = '\0'; /* temporarily null terminate */ 1521590Srgrimes if (doign && isign(line, doign)) 1531590Srgrimes ignoring = 1; 1541590Srgrimes else if ((line[0] == 's' || line[0] == 'S') && 1551590Srgrimes strcasecmp(line, "status") == 0) { 1561590Srgrimes /* 1571590Srgrimes * If the field is "status," go compute 1581590Srgrimes * and print the real Status: field 1591590Srgrimes */ 1601590Srgrimes if (dostat) { 1611590Srgrimes statusput(mp, obuf, prefix); 1621590Srgrimes dostat = 0; 1631590Srgrimes } 1641590Srgrimes ignoring = 1; 1651590Srgrimes } else { 1661590Srgrimes ignoring = 0; 1671590Srgrimes *cp2 = c; /* restore */ 1681590Srgrimes } 1691590Srgrimes infld = 1; 1701590Srgrimes } 1711590Srgrimes } 1721590Srgrimes if (!ignoring) { 1731590Srgrimes /* 1741590Srgrimes * Strip trailing whitespace from prefix 1751590Srgrimes * if line is blank. 1761590Srgrimes */ 17777274Smikeh if (prefix != NULL) { 1781590Srgrimes if (length > 1) 1791590Srgrimes fputs(prefix, obuf); 1801590Srgrimes else 18177274Smikeh (void)fwrite(prefix, sizeof(*prefix), 18277274Smikeh prefixlen, obuf); 18374769Smikeh } 18477274Smikeh (void)fwrite(line, sizeof(*line), length, obuf); 1851590Srgrimes if (ferror(obuf)) 18677274Smikeh return (-1); 1871590Srgrimes } 1881590Srgrimes } 1891590Srgrimes /* 1901590Srgrimes * Copy out message body 1911590Srgrimes */ 1921590Srgrimes if (doign == ignoreall) 1931590Srgrimes count--; /* skip final blank line */ 19477274Smikeh if (prefix != NULL) 1951590Srgrimes while (count > 0) { 19674769Smikeh if (fgets(line, sizeof(line), ibuf) == NULL) { 1971590Srgrimes c = 0; 1981590Srgrimes break; 1991590Srgrimes } 2001590Srgrimes count -= c = strlen(line); 2011590Srgrimes /* 2021590Srgrimes * Strip trailing whitespace from prefix 2031590Srgrimes * if line is blank. 2041590Srgrimes */ 2051590Srgrimes if (c > 1) 2061590Srgrimes fputs(prefix, obuf); 2071590Srgrimes else 20877274Smikeh (void)fwrite(prefix, sizeof(*prefix), 20977274Smikeh prefixlen, obuf); 21077274Smikeh (void)fwrite(line, sizeof(*line), c, obuf); 2111590Srgrimes if (ferror(obuf)) 21277274Smikeh return (-1); 2131590Srgrimes } 2141590Srgrimes else 2151590Srgrimes while (count > 0) { 2161590Srgrimes c = count < LINESIZE ? count : LINESIZE; 21777274Smikeh if ((c = fread(line, sizeof(*line), c, ibuf)) <= 0) 2181590Srgrimes break; 2191590Srgrimes count -= c; 22077274Smikeh if (fwrite(line, sizeof(*line), c, obuf) != c) 22177274Smikeh return (-1); 2221590Srgrimes } 2231590Srgrimes if (doign == ignoreall && c > 0 && line[c - 1] != '\n') 2241590Srgrimes /* no final blank line */ 2251590Srgrimes if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) 22677274Smikeh return (-1); 22777274Smikeh return (0); 2281590Srgrimes} 2291590Srgrimes 2301590Srgrimes/* 2311590Srgrimes * Output a reasonable looking status field. 2321590Srgrimes */ 2331590Srgrimesvoid 2341590Srgrimesstatusput(mp, obuf, prefix) 23577274Smikeh struct message *mp; 2361590Srgrimes FILE *obuf; 2371590Srgrimes char *prefix; 2381590Srgrimes{ 2391590Srgrimes char statout[3]; 24077274Smikeh char *cp = statout; 2411590Srgrimes 2421590Srgrimes if (mp->m_flag & MREAD) 2431590Srgrimes *cp++ = 'R'; 2441590Srgrimes if ((mp->m_flag & MNEW) == 0) 2451590Srgrimes *cp++ = 'O'; 24677274Smikeh *cp = '\0'; 24777274Smikeh if (statout[0] != '\0') 2481590Srgrimes fprintf(obuf, "%sStatus: %s\n", 24977274Smikeh prefix == NULL ? "" : prefix, statout); 2501590Srgrimes} 2511590Srgrimes 2521590Srgrimes/* 2531590Srgrimes * Interface between the argument list and the mail1 routine 2541590Srgrimes * which does all the dirty work. 2551590Srgrimes */ 2561590Srgrimesint 25732189Sjoergmail(to, cc, bcc, smopts, subject, replyto) 2581590Srgrimes struct name *to, *cc, *bcc, *smopts; 25932189Sjoerg char *subject, *replyto; 2601590Srgrimes{ 2611590Srgrimes struct header head; 2621590Srgrimes 2631590Srgrimes head.h_to = to; 2641590Srgrimes head.h_subject = subject; 2651590Srgrimes head.h_cc = cc; 2661590Srgrimes head.h_bcc = bcc; 2671590Srgrimes head.h_smopts = smopts; 26832189Sjoerg head.h_replyto = replyto; 26977274Smikeh head.h_inreplyto = NULL; 2701590Srgrimes mail1(&head, 0); 27177274Smikeh return (0); 2721590Srgrimes} 2731590Srgrimes 2741590Srgrimes 2751590Srgrimes/* 2761590Srgrimes * Send mail to a bunch of user names. The interface is through 2771590Srgrimes * the mail routine below. 2781590Srgrimes */ 2791590Srgrimesint 2801590Srgrimessendmail(str) 2811590Srgrimes char *str; 2821590Srgrimes{ 2831590Srgrimes struct header head; 2841590Srgrimes 2851590Srgrimes head.h_to = extract(str, GTO); 28677274Smikeh head.h_subject = NULL; 28777274Smikeh head.h_cc = NULL; 28877274Smikeh head.h_bcc = NULL; 28977274Smikeh head.h_smopts = NULL; 29078193Smikeh head.h_replyto = value("REPLYTO"); 29177274Smikeh head.h_inreplyto = NULL; 2921590Srgrimes mail1(&head, 0); 29377274Smikeh return (0); 2941590Srgrimes} 2951590Srgrimes 2961590Srgrimes/* 2971590Srgrimes * Mail a message on standard input to the people indicated 2981590Srgrimes * in the passed header. (Internal interface). 2991590Srgrimes */ 3001590Srgrimesvoid 3011590Srgrimesmail1(hp, printheaders) 3021590Srgrimes struct header *hp; 3031590Srgrimes int printheaders; 3041590Srgrimes{ 3051590Srgrimes char *cp; 3061590Srgrimes int pid; 3071590Srgrimes char **namelist; 3081590Srgrimes struct name *to; 3091590Srgrimes FILE *mtf; 3101590Srgrimes 3111590Srgrimes /* 3121590Srgrimes * Collect user's mail from standard input. 3131590Srgrimes * Get the result as mtf. 3141590Srgrimes */ 3151590Srgrimes if ((mtf = collect(hp, printheaders)) == NULL) 3161590Srgrimes return; 31777274Smikeh if (value("interactive") != NULL) { 31888150Smikeh if (value("askcc") != NULL || value("askbcc") != NULL) { 31988150Smikeh if (value("askcc") != NULL) 32088150Smikeh grabh(hp, GCC); 32188150Smikeh if (value("askbcc") != NULL) 32288150Smikeh grabh(hp, GBCC); 32388150Smikeh } else { 3241590Srgrimes printf("EOT\n"); 32577274Smikeh (void)fflush(stdout); 3261590Srgrimes } 32774769Smikeh } 32874769Smikeh if (fsize(mtf) == 0) { 32978904Smikeh if (value("dontsendempty") != NULL) 33078904Smikeh goto out; 33177274Smikeh if (hp->h_subject == NULL) 3321590Srgrimes printf("No message, no subject; hope that's ok\n"); 3331590Srgrimes else 3341590Srgrimes printf("Null message body; hope that's ok\n"); 33574769Smikeh } 3361590Srgrimes /* 3371590Srgrimes * Now, take the user names from the combined 3381590Srgrimes * to and cc lists and do all the alias 3391590Srgrimes * processing. 3401590Srgrimes */ 3411590Srgrimes senderr = 0; 3421590Srgrimes to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); 34377274Smikeh if (to == NULL) { 3441590Srgrimes printf("No recipients specified\n"); 3451590Srgrimes senderr++; 3461590Srgrimes } 3471590Srgrimes /* 3481590Srgrimes * Look through the recipient list for names with /'s 3491590Srgrimes * in them which we write to as files directly. 3501590Srgrimes */ 3511590Srgrimes to = outof(to, mtf, hp); 3521590Srgrimes if (senderr) 3531590Srgrimes savedeadletter(mtf); 3541590Srgrimes to = elide(to); 3551590Srgrimes if (count(to) == 0) 3561590Srgrimes goto out; 3571590Srgrimes fixhead(hp, to); 3581590Srgrimes if ((mtf = infix(hp, mtf)) == NULL) { 3591590Srgrimes fprintf(stderr, ". . . message lost, sorry.\n"); 3601590Srgrimes return; 3611590Srgrimes } 3621590Srgrimes namelist = unpack(cat(hp->h_smopts, to)); 3631590Srgrimes if (debug) { 3641590Srgrimes char **t; 3651590Srgrimes 3661590Srgrimes printf("Sendmail arguments:"); 36777274Smikeh for (t = namelist; *t != NULL; t++) 3681590Srgrimes printf(" \"%s\"", *t); 3691590Srgrimes printf("\n"); 3701590Srgrimes goto out; 3711590Srgrimes } 37277274Smikeh if ((cp = value("record")) != NULL) 37377274Smikeh (void)savemail(expand(cp), mtf); 3741590Srgrimes /* 3751590Srgrimes * Fork, set up the temporary mail file as standard 3761590Srgrimes * input for "mail", and exec with the user list we generated 3771590Srgrimes * far above. 3781590Srgrimes */ 3791590Srgrimes pid = fork(); 3801590Srgrimes if (pid == -1) { 38174769Smikeh warn("fork"); 3821590Srgrimes savedeadletter(mtf); 3831590Srgrimes goto out; 3841590Srgrimes } 3851590Srgrimes if (pid == 0) { 38688150Smikeh sigset_t nset; 38788150Smikeh (void)sigemptyset(&nset); 38888150Smikeh (void)sigaddset(&nset, SIGHUP); 38988150Smikeh (void)sigaddset(&nset, SIGINT); 39088150Smikeh (void)sigaddset(&nset, SIGQUIT); 39188150Smikeh (void)sigaddset(&nset, SIGTSTP); 39288150Smikeh (void)sigaddset(&nset, SIGTTIN); 39388150Smikeh (void)sigaddset(&nset, SIGTTOU); 39488150Smikeh prepare_child(&nset, fileno(mtf), -1); 39577274Smikeh if ((cp = value("sendmail")) != NULL) 3961590Srgrimes cp = expand(cp); 3971590Srgrimes else 3981590Srgrimes cp = _PATH_SENDMAIL; 3991590Srgrimes execv(cp, namelist); 40074769Smikeh warn("%s", cp); 4011590Srgrimes _exit(1); 4021590Srgrimes } 40377274Smikeh if (value("verbose") != NULL) 40477274Smikeh (void)wait_child(pid); 4051590Srgrimes else 4061590Srgrimes free_child(pid); 4071590Srgrimesout: 40877274Smikeh (void)Fclose(mtf); 4091590Srgrimes} 4101590Srgrimes 4111590Srgrimes/* 4121590Srgrimes * Fix the header by glopping all of the expanded names from 4131590Srgrimes * the distribution list into the appropriate fields. 4141590Srgrimes */ 4151590Srgrimesvoid 4161590Srgrimesfixhead(hp, tolist) 4171590Srgrimes struct header *hp; 4181590Srgrimes struct name *tolist; 4191590Srgrimes{ 42077274Smikeh struct name *np; 4211590Srgrimes 42277274Smikeh hp->h_to = NULL; 42377274Smikeh hp->h_cc = NULL; 42477274Smikeh hp->h_bcc = NULL; 42577274Smikeh for (np = tolist; np != NULL; np = np->n_flink) 42688150Smikeh /* Don't copy deleted addresses to the header */ 42788150Smikeh if (np->n_type & GDEL) 42888150Smikeh continue; 4291590Srgrimes if ((np->n_type & GMASK) == GTO) 4301590Srgrimes hp->h_to = 43177274Smikeh cat(hp->h_to, nalloc(np->n_name, np->n_type)); 4321590Srgrimes else if ((np->n_type & GMASK) == GCC) 4331590Srgrimes hp->h_cc = 43477274Smikeh cat(hp->h_cc, nalloc(np->n_name, np->n_type)); 4351590Srgrimes else if ((np->n_type & GMASK) == GBCC) 4361590Srgrimes hp->h_bcc = 43777274Smikeh cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); 4381590Srgrimes} 4391590Srgrimes 4401590Srgrimes/* 4411590Srgrimes * Prepend a header in front of the collected stuff 4421590Srgrimes * and return the new file. 4431590Srgrimes */ 4441590SrgrimesFILE * 4451590Srgrimesinfix(hp, fi) 4461590Srgrimes struct header *hp; 4471590Srgrimes FILE *fi; 4481590Srgrimes{ 44977274Smikeh FILE *nfo, *nfi; 45077274Smikeh int c, fd; 45174769Smikeh char tempname[PATHSIZE]; 4521590Srgrimes 45377274Smikeh (void)snprintf(tempname, sizeof(tempname), 45477274Smikeh "%s/mail.RsXXXXXXXXXX", tmpdir); 45574769Smikeh if ((fd = mkstemp(tempname)) == -1 || 45674769Smikeh (nfo = Fdopen(fd, "w")) == NULL) { 45774769Smikeh warn("%s", tempname); 45877274Smikeh return (fi); 4591590Srgrimes } 46074769Smikeh if ((nfi = Fopen(tempname, "r")) == NULL) { 46174769Smikeh warn("%s", tempname); 46277274Smikeh (void)Fclose(nfo); 46377274Smikeh (void)rm(tempname); 46477274Smikeh return (fi); 4651590Srgrimes } 46677274Smikeh (void)rm(tempname); 46777274Smikeh (void)puthead(hp, nfo, 46877274Smikeh GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA); 4691590Srgrimes c = getc(fi); 4701590Srgrimes while (c != EOF) { 47177274Smikeh (void)putc(c, nfo); 4721590Srgrimes c = getc(fi); 4731590Srgrimes } 4741590Srgrimes if (ferror(fi)) { 47574769Smikeh warnx("read"); 4761590Srgrimes rewind(fi); 47777274Smikeh return (fi); 4781590Srgrimes } 47977274Smikeh (void)fflush(nfo); 4801590Srgrimes if (ferror(nfo)) { 48174769Smikeh warn("%s", tempname); 48277274Smikeh (void)Fclose(nfo); 48377274Smikeh (void)Fclose(nfi); 4841590Srgrimes rewind(fi); 48577274Smikeh return (fi); 4861590Srgrimes } 48777274Smikeh (void)Fclose(nfo); 48877274Smikeh (void)Fclose(fi); 4891590Srgrimes rewind(nfi); 49077274Smikeh return (nfi); 4911590Srgrimes} 4921590Srgrimes 4931590Srgrimes/* 4941590Srgrimes * Dump the to, subject, cc header on the 4951590Srgrimes * passed file buffer. 4961590Srgrimes */ 4971590Srgrimesint 4981590Srgrimesputhead(hp, fo, w) 4991590Srgrimes struct header *hp; 5001590Srgrimes FILE *fo; 5011590Srgrimes int w; 5021590Srgrimes{ 50377274Smikeh int gotcha; 5041590Srgrimes 5051590Srgrimes gotcha = 0; 50677274Smikeh if (hp->h_to != NULL && w & GTO) 5071590Srgrimes fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; 50877274Smikeh if (hp->h_subject != NULL && w & GSUBJECT) 5091590Srgrimes fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 51077274Smikeh if (hp->h_cc != NULL && w & GCC) 5111590Srgrimes fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; 51277274Smikeh if (hp->h_bcc != NULL && w & GBCC) 5131590Srgrimes fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; 51477274Smikeh if (hp->h_replyto != NULL && w & GREPLYTO) 51532189Sjoerg fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++; 51677274Smikeh if (hp->h_inreplyto != NULL && w & GINREPLYTO) 51732189Sjoerg fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++; 5181590Srgrimes if (gotcha && w & GNL) 51977274Smikeh (void)putc('\n', fo); 52077274Smikeh return (0); 5211590Srgrimes} 5221590Srgrimes 5231590Srgrimes/* 5241590Srgrimes * Format the given header line to not exceed 72 characters. 5251590Srgrimes */ 5261590Srgrimesvoid 5271590Srgrimesfmt(str, np, fo, comma) 52877274Smikeh const char *str; 52977274Smikeh struct name *np; 5301590Srgrimes FILE *fo; 5311590Srgrimes int comma; 5321590Srgrimes{ 53377274Smikeh int col, len; 5341590Srgrimes 5351590Srgrimes comma = comma ? 1 : 0; 5361590Srgrimes col = strlen(str); 5371590Srgrimes if (col) 5381590Srgrimes fputs(str, fo); 53977274Smikeh for (; np != NULL; np = np->n_flink) { 54077274Smikeh if (np->n_flink == NULL) 5411590Srgrimes comma = 0; 5421590Srgrimes len = strlen(np->n_name); 5431590Srgrimes col++; /* for the space */ 5441590Srgrimes if (col + len + comma > 72 && col > 4) { 54577274Smikeh fprintf(fo, "\n "); 5461590Srgrimes col = 4; 5471590Srgrimes } else 54877274Smikeh fprintf(fo, " "); 5491590Srgrimes fputs(np->n_name, fo); 5501590Srgrimes if (comma) 55177274Smikeh fprintf(fo, ","); 5521590Srgrimes col += len + comma; 5531590Srgrimes } 55477274Smikeh fprintf(fo, "\n"); 5551590Srgrimes} 5561590Srgrimes 5571590Srgrimes/* 5581590Srgrimes * Save the outgoing mail on the passed file. 5591590Srgrimes */ 5601590Srgrimes 5611590Srgrimes/*ARGSUSED*/ 5621590Srgrimesint 5631590Srgrimessavemail(name, fi) 5641590Srgrimes char name[]; 56577274Smikeh FILE *fi; 5661590Srgrimes{ 56777274Smikeh FILE *fo; 5681590Srgrimes char buf[BUFSIZ]; 56977274Smikeh int i; 57077274Smikeh time_t now; 5711590Srgrimes 5721590Srgrimes if ((fo = Fopen(name, "a")) == NULL) { 57374769Smikeh warn("%s", name); 5741590Srgrimes return (-1); 5751590Srgrimes } 57677274Smikeh (void)time(&now); 5771590Srgrimes fprintf(fo, "From %s %s", myname, ctime(&now)); 57877274Smikeh while ((i = fread(buf, 1, sizeof(buf), fi)) > 0) 57977274Smikeh (void)fwrite(buf, 1, i, fo); 58077274Smikeh fprintf(fo, "\n"); 58177274Smikeh (void)fflush(fo); 5821590Srgrimes if (ferror(fo)) 58374769Smikeh warn("%s", name); 58477274Smikeh (void)Fclose(fo); 5851590Srgrimes rewind(fi); 5861590Srgrimes return (0); 5871590Srgrimes} 588