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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 321590Srgrimesstatic char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include "extern.h" 401590Srgrimes 411590Srgrimes/* 421590Srgrimes * Mail -- a mail program 431590Srgrimes * 441590Srgrimes * Mail to others. 451590Srgrimes */ 461590Srgrimes 471590Srgrimes/* 481590Srgrimes * Send message described by the passed pointer to the 491590Srgrimes * passed output buffer. Return -1 on error. 501590Srgrimes * Adjust the status: field if need be. 511590Srgrimes * If doign is given, suppress ignored header fields. 521590Srgrimes * prefix is a string to prepend to each output line. 531590Srgrimes */ 541590Srgrimesint 55216564Scharniersendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, 56216564Scharnier char *prefix) 571590Srgrimes{ 581590Srgrimes long count; 5977274Smikeh FILE *ibuf; 6077274Smikeh char *cp, *cp2, line[LINESIZE]; 611590Srgrimes int ishead, infld, ignoring, dostat, firstline; 6277274Smikeh int c, length, prefixlen; 631590Srgrimes 641590Srgrimes /* 651590Srgrimes * Compute the prefix string, without trailing whitespace 661590Srgrimes */ 6777274Smikeh if (prefix != NULL) { 681590Srgrimes cp2 = 0; 6977274Smikeh for (cp = prefix; *cp != '\0'; cp++) 701590Srgrimes if (*cp != ' ' && *cp != '\t') 711590Srgrimes cp2 = cp; 7277274Smikeh prefixlen = cp2 == NULL ? 0 : cp2 - prefix + 1; 731590Srgrimes } 741590Srgrimes ibuf = setinput(mp); 751590Srgrimes count = mp->m_size; 761590Srgrimes ishead = 1; 771590Srgrimes dostat = doign == 0 || !isign("status", doign); 781590Srgrimes infld = 0; 791590Srgrimes firstline = 1; 801590Srgrimes /* 811590Srgrimes * Process headers first 821590Srgrimes */ 831590Srgrimes while (count > 0 && ishead) { 8474769Smikeh if (fgets(line, sizeof(line), ibuf) == NULL) 851590Srgrimes break; 861590Srgrimes count -= length = strlen(line); 871590Srgrimes if (firstline) { 888874Srgrimes /* 891590Srgrimes * First line is the From line, so no headers 901590Srgrimes * there to worry about 911590Srgrimes */ 921590Srgrimes firstline = 0; 931590Srgrimes ignoring = doign == ignoreall; 941590Srgrimes } else if (line[0] == '\n') { 951590Srgrimes /* 961590Srgrimes * If line is blank, we've reached end of 971590Srgrimes * headers, so force out status: field 981590Srgrimes * and note that we are no longer in header 991590Srgrimes * fields 1001590Srgrimes */ 1011590Srgrimes if (dostat) { 1021590Srgrimes statusput(mp, obuf, prefix); 1031590Srgrimes dostat = 0; 1041590Srgrimes } 1051590Srgrimes ishead = 0; 1061590Srgrimes ignoring = doign == ignoreall; 1071590Srgrimes } else if (infld && (line[0] == ' ' || line[0] == '\t')) { 1081590Srgrimes /* 1091590Srgrimes * If this line is a continuation (via space or tab) 1101590Srgrimes * of a previous header field, just echo it 1111590Srgrimes * (unless the field should be ignored). 1121590Srgrimes * In other words, nothing to do. 1131590Srgrimes */ 1141590Srgrimes } else { 1151590Srgrimes /* 1161590Srgrimes * Pick up the header field if we have one. 1171590Srgrimes */ 11877274Smikeh for (cp = line; (c = *cp++) != '\0' && c != ':' && 11988227Sache !isspace((unsigned char)c);) 1201590Srgrimes ; 1211590Srgrimes cp2 = --cp; 12288227Sache while (isspace((unsigned char)*cp++)) 1231590Srgrimes ; 1241590Srgrimes if (cp[-1] != ':') { 1251590Srgrimes /* 1261590Srgrimes * Not a header line, force out status: 1271590Srgrimes * This happens in uucp style mail where 1281590Srgrimes * there are no headers at all. 1291590Srgrimes */ 1301590Srgrimes if (dostat) { 1311590Srgrimes statusput(mp, obuf, prefix); 1321590Srgrimes dostat = 0; 1331590Srgrimes } 1341590Srgrimes if (doign != ignoreall) 1351590Srgrimes /* add blank line */ 13677274Smikeh (void)putc('\n', obuf); 1371590Srgrimes ishead = 0; 1381590Srgrimes ignoring = 0; 1391590Srgrimes } else { 1401590Srgrimes /* 1411590Srgrimes * If it is an ignored field and 1421590Srgrimes * we care about such things, skip it. 1431590Srgrimes */ 14477274Smikeh *cp2 = '\0'; /* temporarily null terminate */ 1451590Srgrimes if (doign && isign(line, doign)) 1461590Srgrimes ignoring = 1; 1471590Srgrimes else if ((line[0] == 's' || line[0] == 'S') && 1481590Srgrimes strcasecmp(line, "status") == 0) { 1491590Srgrimes /* 1501590Srgrimes * If the field is "status," go compute 1511590Srgrimes * and print the real Status: field 1521590Srgrimes */ 1531590Srgrimes if (dostat) { 1541590Srgrimes statusput(mp, obuf, prefix); 1551590Srgrimes dostat = 0; 1561590Srgrimes } 1571590Srgrimes ignoring = 1; 1581590Srgrimes } else { 1591590Srgrimes ignoring = 0; 1601590Srgrimes *cp2 = c; /* restore */ 1611590Srgrimes } 1621590Srgrimes infld = 1; 1631590Srgrimes } 1641590Srgrimes } 1651590Srgrimes if (!ignoring) { 1661590Srgrimes /* 1671590Srgrimes * Strip trailing whitespace from prefix 1681590Srgrimes * if line is blank. 1691590Srgrimes */ 17077274Smikeh if (prefix != NULL) { 1711590Srgrimes if (length > 1) 1721590Srgrimes fputs(prefix, obuf); 1731590Srgrimes else 17477274Smikeh (void)fwrite(prefix, sizeof(*prefix), 17577274Smikeh prefixlen, obuf); 17674769Smikeh } 17777274Smikeh (void)fwrite(line, sizeof(*line), length, obuf); 1781590Srgrimes if (ferror(obuf)) 17977274Smikeh return (-1); 1801590Srgrimes } 1811590Srgrimes } 1821590Srgrimes /* 1831590Srgrimes * Copy out message body 1841590Srgrimes */ 1851590Srgrimes if (doign == ignoreall) 1861590Srgrimes count--; /* skip final blank line */ 18777274Smikeh if (prefix != NULL) 1881590Srgrimes while (count > 0) { 18974769Smikeh if (fgets(line, sizeof(line), ibuf) == NULL) { 1901590Srgrimes c = 0; 1911590Srgrimes break; 1921590Srgrimes } 1931590Srgrimes count -= c = strlen(line); 1941590Srgrimes /* 1951590Srgrimes * Strip trailing whitespace from prefix 1961590Srgrimes * if line is blank. 1971590Srgrimes */ 1981590Srgrimes if (c > 1) 1991590Srgrimes fputs(prefix, obuf); 2001590Srgrimes else 20177274Smikeh (void)fwrite(prefix, sizeof(*prefix), 20277274Smikeh prefixlen, obuf); 20377274Smikeh (void)fwrite(line, sizeof(*line), c, obuf); 2041590Srgrimes if (ferror(obuf)) 20577274Smikeh return (-1); 2061590Srgrimes } 2071590Srgrimes else 2081590Srgrimes while (count > 0) { 2091590Srgrimes c = count < LINESIZE ? count : LINESIZE; 21077274Smikeh if ((c = fread(line, sizeof(*line), c, ibuf)) <= 0) 2111590Srgrimes break; 2121590Srgrimes count -= c; 21377274Smikeh if (fwrite(line, sizeof(*line), c, obuf) != c) 21477274Smikeh return (-1); 2151590Srgrimes } 2161590Srgrimes if (doign == ignoreall && c > 0 && line[c - 1] != '\n') 2171590Srgrimes /* no final blank line */ 2181590Srgrimes if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) 21977274Smikeh return (-1); 22077274Smikeh return (0); 2211590Srgrimes} 2221590Srgrimes 2231590Srgrimes/* 2241590Srgrimes * Output a reasonable looking status field. 2251590Srgrimes */ 2261590Srgrimesvoid 227216564Scharnierstatusput(struct message *mp, FILE *obuf, char *prefix) 2281590Srgrimes{ 2291590Srgrimes char statout[3]; 23077274Smikeh char *cp = statout; 2311590Srgrimes 2321590Srgrimes if (mp->m_flag & MREAD) 2331590Srgrimes *cp++ = 'R'; 2341590Srgrimes if ((mp->m_flag & MNEW) == 0) 2351590Srgrimes *cp++ = 'O'; 23677274Smikeh *cp = '\0'; 23777274Smikeh if (statout[0] != '\0') 2381590Srgrimes fprintf(obuf, "%sStatus: %s\n", 23977274Smikeh prefix == NULL ? "" : prefix, statout); 2401590Srgrimes} 2411590Srgrimes 2421590Srgrimes/* 2431590Srgrimes * Interface between the argument list and the mail1 routine 2441590Srgrimes * which does all the dirty work. 2451590Srgrimes */ 2461590Srgrimesint 247216564Scharniermail(struct name *to, struct name *cc, struct name *bcc, struct name *smopts, 248216564Scharnier char *subject, char *replyto) 2491590Srgrimes{ 2501590Srgrimes struct header head; 2511590Srgrimes 2521590Srgrimes head.h_to = to; 2531590Srgrimes head.h_subject = subject; 2541590Srgrimes head.h_cc = cc; 2551590Srgrimes head.h_bcc = bcc; 2561590Srgrimes head.h_smopts = smopts; 25732189Sjoerg head.h_replyto = replyto; 25877274Smikeh head.h_inreplyto = NULL; 2591590Srgrimes mail1(&head, 0); 26077274Smikeh return (0); 2611590Srgrimes} 2621590Srgrimes 2631590Srgrimes 2641590Srgrimes/* 2651590Srgrimes * Send mail to a bunch of user names. The interface is through 2661590Srgrimes * the mail routine below. 2671590Srgrimes */ 2681590Srgrimesint 269216564Scharniersendmail(char *str) 2701590Srgrimes{ 2711590Srgrimes struct header head; 2721590Srgrimes 2731590Srgrimes head.h_to = extract(str, GTO); 27477274Smikeh head.h_subject = NULL; 27577274Smikeh head.h_cc = NULL; 27677274Smikeh head.h_bcc = NULL; 27777274Smikeh head.h_smopts = NULL; 27878193Smikeh head.h_replyto = value("REPLYTO"); 27977274Smikeh head.h_inreplyto = NULL; 2801590Srgrimes mail1(&head, 0); 28177274Smikeh return (0); 2821590Srgrimes} 2831590Srgrimes 2841590Srgrimes/* 2851590Srgrimes * Mail a message on standard input to the people indicated 2861590Srgrimes * in the passed header. (Internal interface). 2871590Srgrimes */ 2881590Srgrimesvoid 289216564Scharniermail1(struct header *hp, int printheaders) 2901590Srgrimes{ 2911590Srgrimes char *cp; 292126415Smikeh char *nbuf; 2931590Srgrimes int pid; 2941590Srgrimes char **namelist; 295126415Smikeh struct name *to, *nsto; 2961590Srgrimes FILE *mtf; 2971590Srgrimes 2981590Srgrimes /* 2991590Srgrimes * Collect user's mail from standard input. 3001590Srgrimes * Get the result as mtf. 3011590Srgrimes */ 3021590Srgrimes if ((mtf = collect(hp, printheaders)) == NULL) 3031590Srgrimes return; 30477274Smikeh if (value("interactive") != NULL) { 30588150Smikeh if (value("askcc") != NULL || value("askbcc") != NULL) { 30688150Smikeh if (value("askcc") != NULL) 30788150Smikeh grabh(hp, GCC); 30888150Smikeh if (value("askbcc") != NULL) 30988150Smikeh grabh(hp, GBCC); 31088150Smikeh } else { 3111590Srgrimes printf("EOT\n"); 31277274Smikeh (void)fflush(stdout); 3131590Srgrimes } 31474769Smikeh } 31574769Smikeh if (fsize(mtf) == 0) { 31678904Smikeh if (value("dontsendempty") != NULL) 31778904Smikeh goto out; 31877274Smikeh if (hp->h_subject == NULL) 3191590Srgrimes printf("No message, no subject; hope that's ok\n"); 3201590Srgrimes else 3211590Srgrimes printf("Null message body; hope that's ok\n"); 32274769Smikeh } 3231590Srgrimes /* 3241590Srgrimes * Now, take the user names from the combined 3251590Srgrimes * to and cc lists and do all the alias 3261590Srgrimes * processing. 3271590Srgrimes */ 3281590Srgrimes senderr = 0; 3291590Srgrimes to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); 33077274Smikeh if (to == NULL) { 3311590Srgrimes printf("No recipients specified\n"); 3321590Srgrimes senderr++; 3331590Srgrimes } 3341590Srgrimes /* 3351590Srgrimes * Look through the recipient list for names with /'s 3361590Srgrimes * in them which we write to as files directly. 3371590Srgrimes */ 3381590Srgrimes to = outof(to, mtf, hp); 3391590Srgrimes if (senderr) 3401590Srgrimes savedeadletter(mtf); 3411590Srgrimes to = elide(to); 3421590Srgrimes if (count(to) == 0) 3431590Srgrimes goto out; 344126415Smikeh if (value("recordrecip") != NULL) { 345126415Smikeh /* 346126415Smikeh * Before fixing the header, save old To:. 347126415Smikeh * We do this because elide above has sorted To: list, and 348126415Smikeh * we would like to save message in a file named by the first 349126415Smikeh * recipient the user has entered, not the one being the first 350126415Smikeh * after sorting happened. 351126415Smikeh */ 352126415Smikeh if ((nsto = malloc(sizeof(struct name))) == NULL) 353126415Smikeh err(1, "Out of memory"); 354126415Smikeh bcopy(hp->h_to, nsto, sizeof(struct name)); 355126415Smikeh } 3561590Srgrimes fixhead(hp, to); 3571590Srgrimes if ((mtf = infix(hp, mtf)) == NULL) { 3581590Srgrimes fprintf(stderr, ". . . message lost, sorry.\n"); 3591590Srgrimes return; 3601590Srgrimes } 3611590Srgrimes namelist = unpack(cat(hp->h_smopts, to)); 3621590Srgrimes if (debug) { 3631590Srgrimes char **t; 3641590Srgrimes 3651590Srgrimes printf("Sendmail arguments:"); 36677274Smikeh for (t = namelist; *t != NULL; t++) 3671590Srgrimes printf(" \"%s\"", *t); 3681590Srgrimes printf("\n"); 3691590Srgrimes goto out; 3701590Srgrimes } 371126415Smikeh if (value("recordrecip") != NULL) { 372126415Smikeh /* 373126415Smikeh * Extract first recipient username from saved To: and use it 374126415Smikeh * as a filename. 375126415Smikeh */ 376126415Smikeh if ((nbuf = malloc(strlen(detract(nsto, 0)) + 1)) == NULL) 377126415Smikeh err(1, "Out of memory"); 378126415Smikeh if ((cp = yanklogin(detract(nsto, 0), nbuf)) != NULL) 379126415Smikeh (void)savemail(expand(nbuf), mtf); 380126415Smikeh free(nbuf); 381126415Smikeh free(nsto); 382126415Smikeh } else if ((cp = value("record")) != NULL) 38377274Smikeh (void)savemail(expand(cp), mtf); 3841590Srgrimes /* 3851590Srgrimes * Fork, set up the temporary mail file as standard 3861590Srgrimes * input for "mail", and exec with the user list we generated 3871590Srgrimes * far above. 3881590Srgrimes */ 3891590Srgrimes pid = fork(); 3901590Srgrimes if (pid == -1) { 39174769Smikeh warn("fork"); 3921590Srgrimes savedeadletter(mtf); 3931590Srgrimes goto out; 3941590Srgrimes } 3951590Srgrimes if (pid == 0) { 39688150Smikeh sigset_t nset; 39788150Smikeh (void)sigemptyset(&nset); 39888150Smikeh (void)sigaddset(&nset, SIGHUP); 39988150Smikeh (void)sigaddset(&nset, SIGINT); 40088150Smikeh (void)sigaddset(&nset, SIGQUIT); 40188150Smikeh (void)sigaddset(&nset, SIGTSTP); 40288150Smikeh (void)sigaddset(&nset, SIGTTIN); 40388150Smikeh (void)sigaddset(&nset, SIGTTOU); 40488150Smikeh prepare_child(&nset, fileno(mtf), -1); 40577274Smikeh if ((cp = value("sendmail")) != NULL) 4061590Srgrimes cp = expand(cp); 4071590Srgrimes else 4081590Srgrimes cp = _PATH_SENDMAIL; 4091590Srgrimes execv(cp, namelist); 41074769Smikeh warn("%s", cp); 4111590Srgrimes _exit(1); 4121590Srgrimes } 41377274Smikeh if (value("verbose") != NULL) 41477274Smikeh (void)wait_child(pid); 4151590Srgrimes else 4161590Srgrimes free_child(pid); 4171590Srgrimesout: 41877274Smikeh (void)Fclose(mtf); 4191590Srgrimes} 4201590Srgrimes 4211590Srgrimes/* 4221590Srgrimes * Fix the header by glopping all of the expanded names from 4231590Srgrimes * the distribution list into the appropriate fields. 4241590Srgrimes */ 4251590Srgrimesvoid 426216564Scharnierfixhead(struct header *hp, struct name *tolist) 4271590Srgrimes{ 42877274Smikeh struct name *np; 4291590Srgrimes 43077274Smikeh hp->h_to = NULL; 43177274Smikeh hp->h_cc = NULL; 43277274Smikeh hp->h_bcc = NULL; 43388229Sache for (np = tolist; np != NULL; np = np->n_flink) { 43488150Smikeh /* Don't copy deleted addresses to the header */ 43588150Smikeh if (np->n_type & GDEL) 43688150Smikeh continue; 4371590Srgrimes if ((np->n_type & GMASK) == GTO) 4381590Srgrimes hp->h_to = 43977274Smikeh cat(hp->h_to, nalloc(np->n_name, np->n_type)); 4401590Srgrimes else if ((np->n_type & GMASK) == GCC) 4411590Srgrimes hp->h_cc = 44277274Smikeh cat(hp->h_cc, nalloc(np->n_name, np->n_type)); 4431590Srgrimes else if ((np->n_type & GMASK) == GBCC) 4441590Srgrimes hp->h_bcc = 44577274Smikeh cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); 44688229Sache } 4471590Srgrimes} 4481590Srgrimes 4491590Srgrimes/* 4501590Srgrimes * Prepend a header in front of the collected stuff 4511590Srgrimes * and return the new file. 4521590Srgrimes */ 4531590SrgrimesFILE * 454216564Scharnierinfix(struct header *hp, FILE *fi) 4551590Srgrimes{ 45677274Smikeh FILE *nfo, *nfi; 45777274Smikeh int c, fd; 45874769Smikeh char tempname[PATHSIZE]; 4591590Srgrimes 46077274Smikeh (void)snprintf(tempname, sizeof(tempname), 46177274Smikeh "%s/mail.RsXXXXXXXXXX", tmpdir); 46274769Smikeh if ((fd = mkstemp(tempname)) == -1 || 46374769Smikeh (nfo = Fdopen(fd, "w")) == NULL) { 46474769Smikeh warn("%s", tempname); 46577274Smikeh return (fi); 4661590Srgrimes } 46774769Smikeh if ((nfi = Fopen(tempname, "r")) == NULL) { 46874769Smikeh warn("%s", tempname); 46977274Smikeh (void)Fclose(nfo); 47077274Smikeh (void)rm(tempname); 47177274Smikeh return (fi); 4721590Srgrimes } 47377274Smikeh (void)rm(tempname); 47477274Smikeh (void)puthead(hp, nfo, 47577274Smikeh GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA); 4761590Srgrimes c = getc(fi); 4771590Srgrimes while (c != EOF) { 47877274Smikeh (void)putc(c, nfo); 4791590Srgrimes c = getc(fi); 4801590Srgrimes } 4811590Srgrimes if (ferror(fi)) { 48274769Smikeh warnx("read"); 4831590Srgrimes rewind(fi); 48477274Smikeh return (fi); 4851590Srgrimes } 48677274Smikeh (void)fflush(nfo); 4871590Srgrimes if (ferror(nfo)) { 48874769Smikeh warn("%s", tempname); 48977274Smikeh (void)Fclose(nfo); 49077274Smikeh (void)Fclose(nfi); 4911590Srgrimes rewind(fi); 49277274Smikeh return (fi); 4931590Srgrimes } 49477274Smikeh (void)Fclose(nfo); 49577274Smikeh (void)Fclose(fi); 4961590Srgrimes rewind(nfi); 49777274Smikeh return (nfi); 4981590Srgrimes} 4991590Srgrimes 5001590Srgrimes/* 5011590Srgrimes * Dump the to, subject, cc header on the 5021590Srgrimes * passed file buffer. 5031590Srgrimes */ 5041590Srgrimesint 505216564Scharnierputhead(struct header *hp, FILE *fo, int w) 5061590Srgrimes{ 50777274Smikeh int gotcha; 5081590Srgrimes 5091590Srgrimes gotcha = 0; 51077274Smikeh if (hp->h_to != NULL && w & GTO) 5111590Srgrimes fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; 51277274Smikeh if (hp->h_subject != NULL && w & GSUBJECT) 5131590Srgrimes fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 51477274Smikeh if (hp->h_cc != NULL && w & GCC) 5151590Srgrimes fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; 51677274Smikeh if (hp->h_bcc != NULL && w & GBCC) 5171590Srgrimes fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; 51877274Smikeh if (hp->h_replyto != NULL && w & GREPLYTO) 51932189Sjoerg fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++; 52077274Smikeh if (hp->h_inreplyto != NULL && w & GINREPLYTO) 52132189Sjoerg fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++; 5221590Srgrimes if (gotcha && w & GNL) 52377274Smikeh (void)putc('\n', fo); 52477274Smikeh return (0); 5251590Srgrimes} 5261590Srgrimes 5271590Srgrimes/* 5281590Srgrimes * Format the given header line to not exceed 72 characters. 5291590Srgrimes */ 5301590Srgrimesvoid 531216564Scharnierfmt(const char *str, struct name *np, FILE *fo, 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 563216564Scharniersavemail(char name[], FILE *fi) 5641590Srgrimes{ 56577274Smikeh FILE *fo; 5661590Srgrimes char buf[BUFSIZ]; 56777274Smikeh int i; 56877274Smikeh time_t now; 5691590Srgrimes 5701590Srgrimes if ((fo = Fopen(name, "a")) == NULL) { 57174769Smikeh warn("%s", name); 5721590Srgrimes return (-1); 5731590Srgrimes } 57477274Smikeh (void)time(&now); 5751590Srgrimes fprintf(fo, "From %s %s", myname, ctime(&now)); 57677274Smikeh while ((i = fread(buf, 1, sizeof(buf), fi)) > 0) 57777274Smikeh (void)fwrite(buf, 1, i, fo); 57877274Smikeh fprintf(fo, "\n"); 57977274Smikeh (void)fflush(fo); 5801590Srgrimes if (ferror(fo)) 58174769Smikeh warn("%s", name); 58277274Smikeh (void)Fclose(fo); 5831590Srgrimes rewind(fi); 5841590Srgrimes return (0); 5851590Srgrimes} 586