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