send.c revision 74769
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 74769 2001-03-25 04:57:05Z mikeh $"; 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) 601590Srgrimes register struct message *mp; 611590Srgrimes FILE *obuf; 621590Srgrimes struct ignoretab *doign; 631590Srgrimes char *prefix; 641590Srgrimes{ 651590Srgrimes long count; 661590Srgrimes register FILE *ibuf; 671590Srgrimes char line[LINESIZE]; 681590Srgrimes int ishead, infld, ignoring, dostat, firstline; 691590Srgrimes register char *cp, *cp2; 701590Srgrimes register int c; 711590Srgrimes int length; 721590Srgrimes int prefixlen; 731590Srgrimes 741590Srgrimes /* 751590Srgrimes * Compute the prefix string, without trailing whitespace 761590Srgrimes */ 771590Srgrimes if (prefix != NOSTR) { 781590Srgrimes cp2 = 0; 791590Srgrimes for (cp = prefix; *cp; cp++) 801590Srgrimes if (*cp != ' ' && *cp != '\t') 811590Srgrimes cp2 = cp; 821590Srgrimes prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1; 831590Srgrimes } 841590Srgrimes ibuf = setinput(mp); 851590Srgrimes count = mp->m_size; 861590Srgrimes ishead = 1; 871590Srgrimes dostat = doign == 0 || !isign("status", doign); 881590Srgrimes infld = 0; 891590Srgrimes firstline = 1; 901590Srgrimes /* 911590Srgrimes * Process headers first 921590Srgrimes */ 931590Srgrimes while (count > 0 && ishead) { 9474769Smikeh if (fgets(line, sizeof(line), ibuf) == NULL) 951590Srgrimes break; 961590Srgrimes count -= length = strlen(line); 971590Srgrimes if (firstline) { 988874Srgrimes /* 991590Srgrimes * First line is the From line, so no headers 1001590Srgrimes * there to worry about 1011590Srgrimes */ 1021590Srgrimes firstline = 0; 1031590Srgrimes ignoring = doign == ignoreall; 1041590Srgrimes } else if (line[0] == '\n') { 1051590Srgrimes /* 1061590Srgrimes * If line is blank, we've reached end of 1071590Srgrimes * headers, so force out status: field 1081590Srgrimes * and note that we are no longer in header 1091590Srgrimes * fields 1101590Srgrimes */ 1111590Srgrimes if (dostat) { 1121590Srgrimes statusput(mp, obuf, prefix); 1131590Srgrimes dostat = 0; 1141590Srgrimes } 1151590Srgrimes ishead = 0; 1161590Srgrimes ignoring = doign == ignoreall; 1171590Srgrimes } else if (infld && (line[0] == ' ' || line[0] == '\t')) { 1181590Srgrimes /* 1191590Srgrimes * If this line is a continuation (via space or tab) 1201590Srgrimes * of a previous header field, just echo it 1211590Srgrimes * (unless the field should be ignored). 1221590Srgrimes * In other words, nothing to do. 1231590Srgrimes */ 1241590Srgrimes } else { 1251590Srgrimes /* 1261590Srgrimes * Pick up the header field if we have one. 1271590Srgrimes */ 1281590Srgrimes for (cp = line; (c = *cp++) && c != ':' && !isspace(c);) 1291590Srgrimes ; 1301590Srgrimes cp2 = --cp; 1311590Srgrimes while (isspace(*cp++)) 1321590Srgrimes ; 1331590Srgrimes if (cp[-1] != ':') { 1341590Srgrimes /* 1351590Srgrimes * Not a header line, force out status: 1361590Srgrimes * This happens in uucp style mail where 1371590Srgrimes * there are no headers at all. 1381590Srgrimes */ 1391590Srgrimes if (dostat) { 1401590Srgrimes statusput(mp, obuf, prefix); 1411590Srgrimes dostat = 0; 1421590Srgrimes } 1431590Srgrimes if (doign != ignoreall) 1441590Srgrimes /* add blank line */ 1451590Srgrimes (void) putc('\n', obuf); 1461590Srgrimes ishead = 0; 1471590Srgrimes ignoring = 0; 1481590Srgrimes } else { 1491590Srgrimes /* 1501590Srgrimes * If it is an ignored field and 1511590Srgrimes * we care about such things, skip it. 1521590Srgrimes */ 1531590Srgrimes *cp2 = 0; /* temporarily null terminate */ 1541590Srgrimes if (doign && isign(line, doign)) 1551590Srgrimes ignoring = 1; 1561590Srgrimes else if ((line[0] == 's' || line[0] == 'S') && 1571590Srgrimes strcasecmp(line, "status") == 0) { 1581590Srgrimes /* 1591590Srgrimes * If the field is "status," go compute 1601590Srgrimes * and print the real Status: field 1611590Srgrimes */ 1621590Srgrimes if (dostat) { 1631590Srgrimes statusput(mp, obuf, prefix); 1641590Srgrimes dostat = 0; 1651590Srgrimes } 1661590Srgrimes ignoring = 1; 1671590Srgrimes } else { 1681590Srgrimes ignoring = 0; 1691590Srgrimes *cp2 = c; /* restore */ 1701590Srgrimes } 1711590Srgrimes infld = 1; 1721590Srgrimes } 1731590Srgrimes } 1741590Srgrimes if (!ignoring) { 1751590Srgrimes /* 1761590Srgrimes * Strip trailing whitespace from prefix 1771590Srgrimes * if line is blank. 1781590Srgrimes */ 17974769Smikeh if (prefix != NOSTR) { 1801590Srgrimes if (length > 1) 1811590Srgrimes fputs(prefix, obuf); 1821590Srgrimes else 1831590Srgrimes (void) fwrite(prefix, sizeof *prefix, 1841590Srgrimes prefixlen, obuf); 18574769Smikeh } 1861590Srgrimes (void) fwrite(line, sizeof *line, length, obuf); 1871590Srgrimes if (ferror(obuf)) 1881590Srgrimes return -1; 1891590Srgrimes } 1901590Srgrimes } 1911590Srgrimes /* 1921590Srgrimes * Copy out message body 1931590Srgrimes */ 1941590Srgrimes if (doign == ignoreall) 1951590Srgrimes count--; /* skip final blank line */ 1961590Srgrimes if (prefix != NOSTR) 1971590Srgrimes while (count > 0) { 19874769Smikeh if (fgets(line, sizeof(line), ibuf) == NULL) { 1991590Srgrimes c = 0; 2001590Srgrimes break; 2011590Srgrimes } 2021590Srgrimes count -= c = strlen(line); 2031590Srgrimes /* 2041590Srgrimes * Strip trailing whitespace from prefix 2051590Srgrimes * if line is blank. 2061590Srgrimes */ 2071590Srgrimes if (c > 1) 2081590Srgrimes fputs(prefix, obuf); 2091590Srgrimes else 2101590Srgrimes (void) fwrite(prefix, sizeof *prefix, 2111590Srgrimes prefixlen, obuf); 2121590Srgrimes (void) fwrite(line, sizeof *line, c, obuf); 2131590Srgrimes if (ferror(obuf)) 2141590Srgrimes return -1; 2151590Srgrimes } 2161590Srgrimes else 2171590Srgrimes while (count > 0) { 2181590Srgrimes c = count < LINESIZE ? count : LINESIZE; 2191590Srgrimes if ((c = fread(line, sizeof *line, c, ibuf)) <= 0) 2201590Srgrimes break; 2211590Srgrimes count -= c; 2221590Srgrimes if (fwrite(line, sizeof *line, c, obuf) != c) 2231590Srgrimes return -1; 2241590Srgrimes } 2251590Srgrimes if (doign == ignoreall && c > 0 && line[c - 1] != '\n') 2261590Srgrimes /* no final blank line */ 2271590Srgrimes if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) 2281590Srgrimes return -1; 2291590Srgrimes return 0; 2301590Srgrimes} 2311590Srgrimes 2321590Srgrimes/* 2331590Srgrimes * Output a reasonable looking status field. 2341590Srgrimes */ 2351590Srgrimesvoid 2361590Srgrimesstatusput(mp, obuf, prefix) 2371590Srgrimes register struct message *mp; 2381590Srgrimes FILE *obuf; 2391590Srgrimes char *prefix; 2401590Srgrimes{ 2411590Srgrimes char statout[3]; 2421590Srgrimes register char *cp = statout; 2431590Srgrimes 2441590Srgrimes if (mp->m_flag & MREAD) 2451590Srgrimes *cp++ = 'R'; 2461590Srgrimes if ((mp->m_flag & MNEW) == 0) 2471590Srgrimes *cp++ = 'O'; 2481590Srgrimes *cp = 0; 2491590Srgrimes if (statout[0]) 2501590Srgrimes fprintf(obuf, "%sStatus: %s\n", 2511590Srgrimes prefix == NOSTR ? "" : prefix, statout); 2521590Srgrimes} 2531590Srgrimes 2541590Srgrimes/* 2551590Srgrimes * Interface between the argument list and the mail1 routine 2561590Srgrimes * which does all the dirty work. 2571590Srgrimes */ 2581590Srgrimesint 25932189Sjoergmail(to, cc, bcc, smopts, subject, replyto) 2601590Srgrimes struct name *to, *cc, *bcc, *smopts; 26132189Sjoerg char *subject, *replyto; 2621590Srgrimes{ 2631590Srgrimes struct header head; 2641590Srgrimes 2651590Srgrimes head.h_to = to; 2661590Srgrimes head.h_subject = subject; 2671590Srgrimes head.h_cc = cc; 2681590Srgrimes head.h_bcc = bcc; 2691590Srgrimes head.h_smopts = smopts; 27032189Sjoerg head.h_replyto = replyto; 27132189Sjoerg head.h_inreplyto = NOSTR; 2721590Srgrimes mail1(&head, 0); 2731590Srgrimes return(0); 2741590Srgrimes} 2751590Srgrimes 2761590Srgrimes 2771590Srgrimes/* 2781590Srgrimes * Send mail to a bunch of user names. The interface is through 2791590Srgrimes * the mail routine below. 2801590Srgrimes */ 2811590Srgrimesint 2821590Srgrimessendmail(str) 2831590Srgrimes char *str; 2841590Srgrimes{ 2851590Srgrimes struct header head; 2861590Srgrimes 2871590Srgrimes head.h_to = extract(str, GTO); 2881590Srgrimes head.h_subject = NOSTR; 2891590Srgrimes head.h_cc = NIL; 2901590Srgrimes head.h_bcc = NIL; 2911590Srgrimes head.h_smopts = NIL; 29232189Sjoerg if ((head.h_replyto = getenv("REPLYTO")) == NULL) 29332189Sjoerg head.h_replyto = NOSTR; 29432189Sjoerg head.h_inreplyto = NOSTR; 2951590Srgrimes mail1(&head, 0); 2961590Srgrimes return(0); 2971590Srgrimes} 2981590Srgrimes 2991590Srgrimes/* 3001590Srgrimes * Mail a message on standard input to the people indicated 3011590Srgrimes * in the passed header. (Internal interface). 3021590Srgrimes */ 3031590Srgrimesvoid 3041590Srgrimesmail1(hp, printheaders) 3051590Srgrimes struct header *hp; 3061590Srgrimes int printheaders; 3071590Srgrimes{ 3081590Srgrimes char *cp; 3091590Srgrimes int pid; 3101590Srgrimes char **namelist; 3111590Srgrimes struct name *to; 3121590Srgrimes FILE *mtf; 3131590Srgrimes 3141590Srgrimes /* 3151590Srgrimes * Collect user's mail from standard input. 3161590Srgrimes * Get the result as mtf. 3171590Srgrimes */ 3181590Srgrimes if ((mtf = collect(hp, printheaders)) == NULL) 3191590Srgrimes return; 32074769Smikeh if (value("interactive") != NOSTR) { 3211590Srgrimes if (value("askcc") != NOSTR) 3221590Srgrimes grabh(hp, GCC); 3231590Srgrimes else { 3241590Srgrimes printf("EOT\n"); 3251590Srgrimes (void) fflush(stdout); 3261590Srgrimes } 32774769Smikeh } 32874769Smikeh if (fsize(mtf) == 0) { 3291590Srgrimes if (hp->h_subject == NOSTR) 3301590Srgrimes printf("No message, no subject; hope that's ok\n"); 3311590Srgrimes else 3321590Srgrimes printf("Null message body; hope that's ok\n"); 33374769Smikeh } 3341590Srgrimes /* 3351590Srgrimes * Now, take the user names from the combined 3361590Srgrimes * to and cc lists and do all the alias 3371590Srgrimes * processing. 3381590Srgrimes */ 3391590Srgrimes senderr = 0; 3401590Srgrimes to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); 3411590Srgrimes if (to == NIL) { 3421590Srgrimes printf("No recipients specified\n"); 3431590Srgrimes senderr++; 3441590Srgrimes } 3451590Srgrimes /* 3461590Srgrimes * Look through the recipient list for names with /'s 3471590Srgrimes * in them which we write to as files directly. 3481590Srgrimes */ 3491590Srgrimes to = outof(to, mtf, hp); 3501590Srgrimes if (senderr) 3511590Srgrimes savedeadletter(mtf); 3521590Srgrimes to = elide(to); 3531590Srgrimes if (count(to) == 0) 3541590Srgrimes goto out; 3551590Srgrimes fixhead(hp, to); 3561590Srgrimes if ((mtf = infix(hp, mtf)) == NULL) { 3571590Srgrimes fprintf(stderr, ". . . message lost, sorry.\n"); 3581590Srgrimes return; 3591590Srgrimes } 3601590Srgrimes namelist = unpack(cat(hp->h_smopts, to)); 3611590Srgrimes if (debug) { 3621590Srgrimes char **t; 3631590Srgrimes 3641590Srgrimes printf("Sendmail arguments:"); 3651590Srgrimes for (t = namelist; *t != NOSTR; t++) 3661590Srgrimes printf(" \"%s\"", *t); 3671590Srgrimes printf("\n"); 3681590Srgrimes goto out; 3691590Srgrimes } 3701590Srgrimes if ((cp = value("record")) != NOSTR) 3711590Srgrimes (void) savemail(expand(cp), mtf); 3721590Srgrimes /* 3731590Srgrimes * Fork, set up the temporary mail file as standard 3741590Srgrimes * input for "mail", and exec with the user list we generated 3751590Srgrimes * far above. 3761590Srgrimes */ 3771590Srgrimes pid = fork(); 3781590Srgrimes if (pid == -1) { 37974769Smikeh warn("fork"); 3801590Srgrimes savedeadletter(mtf); 3811590Srgrimes goto out; 3821590Srgrimes } 3831590Srgrimes if (pid == 0) { 3841590Srgrimes prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)| 3851590Srgrimes sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU), 3861590Srgrimes fileno(mtf), -1); 3871590Srgrimes if ((cp = value("sendmail")) != NOSTR) 3881590Srgrimes cp = expand(cp); 3891590Srgrimes else 3901590Srgrimes cp = _PATH_SENDMAIL; 3911590Srgrimes execv(cp, namelist); 39274769Smikeh warn("%s", cp); 3931590Srgrimes _exit(1); 3941590Srgrimes } 3951590Srgrimes if (value("verbose") != NOSTR) 3961590Srgrimes (void) wait_child(pid); 3971590Srgrimes else 3981590Srgrimes free_child(pid); 3991590Srgrimesout: 4001590Srgrimes (void) Fclose(mtf); 4011590Srgrimes} 4021590Srgrimes 4031590Srgrimes/* 4041590Srgrimes * Fix the header by glopping all of the expanded names from 4051590Srgrimes * the distribution list into the appropriate fields. 4061590Srgrimes */ 4071590Srgrimesvoid 4081590Srgrimesfixhead(hp, tolist) 4091590Srgrimes struct header *hp; 4101590Srgrimes struct name *tolist; 4111590Srgrimes{ 4121590Srgrimes register struct name *np; 4131590Srgrimes 4141590Srgrimes hp->h_to = NIL; 4151590Srgrimes hp->h_cc = NIL; 4161590Srgrimes hp->h_bcc = NIL; 4171590Srgrimes for (np = tolist; np != NIL; np = np->n_flink) 4181590Srgrimes if ((np->n_type & GMASK) == GTO) 4191590Srgrimes hp->h_to = 4201590Srgrimes cat(hp->h_to, nalloc(np->n_name, np->n_type)); 4211590Srgrimes else if ((np->n_type & GMASK) == GCC) 4221590Srgrimes hp->h_cc = 4231590Srgrimes cat(hp->h_cc, nalloc(np->n_name, np->n_type)); 4241590Srgrimes else if ((np->n_type & GMASK) == GBCC) 4251590Srgrimes hp->h_bcc = 4261590Srgrimes cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); 4271590Srgrimes} 4281590Srgrimes 4291590Srgrimes/* 4301590Srgrimes * Prepend a header in front of the collected stuff 4311590Srgrimes * and return the new file. 4321590Srgrimes */ 4331590SrgrimesFILE * 4341590Srgrimesinfix(hp, fi) 4351590Srgrimes struct header *hp; 4361590Srgrimes FILE *fi; 4371590Srgrimes{ 4381590Srgrimes register FILE *nfo, *nfi; 4391590Srgrimes register int c; 44074769Smikeh int fd; 44174769Smikeh char tempname[PATHSIZE]; 4421590Srgrimes 44374769Smikeh snprintf(tempname, sizeof(tempname), "%s/mail.RsXXXXXXXXXX", tmpdir); 44474769Smikeh if ((fd = mkstemp(tempname)) == -1 || 44574769Smikeh (nfo = Fdopen(fd, "w")) == NULL) { 44674769Smikeh warn("%s", tempname); 4471590Srgrimes return(fi); 4481590Srgrimes } 44974769Smikeh if ((nfi = Fopen(tempname, "r")) == NULL) { 45074769Smikeh warn("%s", tempname); 4511590Srgrimes (void) Fclose(nfo); 45274769Smikeh (void) rm(tempname); 4531590Srgrimes return(fi); 4541590Srgrimes } 45574769Smikeh (void) rm(tempname); 45632234Sjoerg (void) puthead(hp, nfo, 45732234Sjoerg GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA); 4581590Srgrimes c = getc(fi); 4591590Srgrimes while (c != EOF) { 4601590Srgrimes (void) putc(c, nfo); 4611590Srgrimes c = getc(fi); 4621590Srgrimes } 4631590Srgrimes if (ferror(fi)) { 46474769Smikeh warnx("read"); 4651590Srgrimes rewind(fi); 4661590Srgrimes return(fi); 4671590Srgrimes } 4681590Srgrimes (void) fflush(nfo); 4691590Srgrimes if (ferror(nfo)) { 47074769Smikeh warn("%s", tempname); 4711590Srgrimes (void) Fclose(nfo); 4721590Srgrimes (void) Fclose(nfi); 4731590Srgrimes rewind(fi); 4741590Srgrimes return(fi); 4751590Srgrimes } 4761590Srgrimes (void) Fclose(nfo); 4771590Srgrimes (void) Fclose(fi); 4781590Srgrimes rewind(nfi); 4791590Srgrimes return(nfi); 4801590Srgrimes} 4811590Srgrimes 4821590Srgrimes/* 4831590Srgrimes * Dump the to, subject, cc header on the 4841590Srgrimes * passed file buffer. 4851590Srgrimes */ 4861590Srgrimesint 4871590Srgrimesputhead(hp, fo, w) 4881590Srgrimes struct header *hp; 4891590Srgrimes FILE *fo; 4901590Srgrimes int w; 4911590Srgrimes{ 4921590Srgrimes register int gotcha; 4931590Srgrimes 4941590Srgrimes gotcha = 0; 4951590Srgrimes if (hp->h_to != NIL && w & GTO) 4961590Srgrimes fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; 4971590Srgrimes if (hp->h_subject != NOSTR && w & GSUBJECT) 4981590Srgrimes fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 4991590Srgrimes if (hp->h_cc != NIL && w & GCC) 5001590Srgrimes fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; 5011590Srgrimes if (hp->h_bcc != NIL && w & GBCC) 5021590Srgrimes fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; 50332234Sjoerg if (hp->h_replyto != NOSTR && w & GREPLYTO) 50432189Sjoerg fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++; 50532234Sjoerg if (hp->h_inreplyto != NOSTR && w & GINREPLYTO) 50632189Sjoerg fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++; 5071590Srgrimes if (gotcha && w & GNL) 5081590Srgrimes (void) putc('\n', fo); 5091590Srgrimes return(0); 5101590Srgrimes} 5111590Srgrimes 5121590Srgrimes/* 5131590Srgrimes * Format the given header line to not exceed 72 characters. 5141590Srgrimes */ 5151590Srgrimesvoid 5161590Srgrimesfmt(str, np, fo, comma) 5171590Srgrimes char *str; 5181590Srgrimes register struct name *np; 5191590Srgrimes FILE *fo; 5201590Srgrimes int comma; 5211590Srgrimes{ 5221590Srgrimes register col, len; 5231590Srgrimes 5241590Srgrimes comma = comma ? 1 : 0; 5251590Srgrimes col = strlen(str); 5261590Srgrimes if (col) 5271590Srgrimes fputs(str, fo); 5281590Srgrimes for (; np != NIL; np = np->n_flink) { 5291590Srgrimes if (np->n_flink == NIL) 5301590Srgrimes comma = 0; 5311590Srgrimes len = strlen(np->n_name); 5321590Srgrimes col++; /* for the space */ 5331590Srgrimes if (col + len + comma > 72 && col > 4) { 5341590Srgrimes fputs("\n ", fo); 5351590Srgrimes col = 4; 5361590Srgrimes } else 5371590Srgrimes putc(' ', fo); 5381590Srgrimes fputs(np->n_name, fo); 5391590Srgrimes if (comma) 5401590Srgrimes putc(',', fo); 5411590Srgrimes col += len + comma; 5421590Srgrimes } 5431590Srgrimes putc('\n', fo); 5441590Srgrimes} 5451590Srgrimes 5461590Srgrimes/* 5471590Srgrimes * Save the outgoing mail on the passed file. 5481590Srgrimes */ 5491590Srgrimes 5501590Srgrimes/*ARGSUSED*/ 5511590Srgrimesint 5521590Srgrimessavemail(name, fi) 5531590Srgrimes char name[]; 5541590Srgrimes register FILE *fi; 5551590Srgrimes{ 5561590Srgrimes register FILE *fo; 5571590Srgrimes char buf[BUFSIZ]; 5581590Srgrimes register i; 5591590Srgrimes time_t now, time(); 5601590Srgrimes char *ctime(); 5611590Srgrimes 5621590Srgrimes if ((fo = Fopen(name, "a")) == NULL) { 56374769Smikeh warn("%s", name); 5641590Srgrimes return (-1); 5651590Srgrimes } 5661590Srgrimes (void) time(&now); 5671590Srgrimes fprintf(fo, "From %s %s", myname, ctime(&now)); 5681590Srgrimes while ((i = fread(buf, 1, sizeof buf, fi)) > 0) 5691590Srgrimes (void) fwrite(buf, 1, i, fo); 5701590Srgrimes (void) putc('\n', fo); 5711590Srgrimes (void) fflush(fo); 5721590Srgrimes if (ferror(fo)) 57374769Smikeh warn("%s", name); 5741590Srgrimes (void) Fclose(fo); 5751590Srgrimes rewind(fi); 5761590Srgrimes return (0); 5771590Srgrimes} 578