send.c revision 32189
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) { 948874Srgrimes /* 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 25432189Sjoergmail(to, cc, bcc, smopts, subject, replyto) 2551590Srgrimes struct name *to, *cc, *bcc, *smopts; 25632189Sjoerg char *subject, *replyto; 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; 26532189Sjoerg head.h_replyto = replyto; 26632189Sjoerg head.h_inreplyto = NOSTR; 2671590Srgrimes mail1(&head, 0); 2681590Srgrimes return(0); 2691590Srgrimes} 2701590Srgrimes 2711590Srgrimes 2721590Srgrimes/* 2731590Srgrimes * Send mail to a bunch of user names. The interface is through 2741590Srgrimes * the mail routine below. 2751590Srgrimes */ 2761590Srgrimesint 2771590Srgrimessendmail(str) 2781590Srgrimes char *str; 2791590Srgrimes{ 2801590Srgrimes struct header head; 2811590Srgrimes 2821590Srgrimes head.h_to = extract(str, GTO); 2831590Srgrimes head.h_subject = NOSTR; 2841590Srgrimes head.h_cc = NIL; 2851590Srgrimes head.h_bcc = NIL; 2861590Srgrimes head.h_smopts = NIL; 28732189Sjoerg if ((head.h_replyto = getenv("REPLYTO")) == NULL) 28832189Sjoerg head.h_replyto = NOSTR; 28932189Sjoerg head.h_inreplyto = NOSTR; 2901590Srgrimes mail1(&head, 0); 2911590Srgrimes return(0); 2921590Srgrimes} 2931590Srgrimes 2941590Srgrimes/* 2951590Srgrimes * Mail a message on standard input to the people indicated 2961590Srgrimes * in the passed header. (Internal interface). 2971590Srgrimes */ 2981590Srgrimesvoid 2991590Srgrimesmail1(hp, printheaders) 3001590Srgrimes struct header *hp; 3011590Srgrimes int printheaders; 3021590Srgrimes{ 3031590Srgrimes char *cp; 3041590Srgrimes int pid; 3051590Srgrimes char **namelist; 3061590Srgrimes struct name *to; 3071590Srgrimes FILE *mtf; 3081590Srgrimes 3091590Srgrimes /* 3101590Srgrimes * Collect user's mail from standard input. 3111590Srgrimes * Get the result as mtf. 3121590Srgrimes */ 3131590Srgrimes if ((mtf = collect(hp, printheaders)) == NULL) 3141590Srgrimes return; 3151590Srgrimes if (value("interactive") != NOSTR) 3161590Srgrimes if (value("askcc") != NOSTR) 3171590Srgrimes grabh(hp, GCC); 3181590Srgrimes else { 3191590Srgrimes printf("EOT\n"); 3201590Srgrimes (void) fflush(stdout); 3211590Srgrimes } 3221590Srgrimes if (fsize(mtf) == 0) 3231590Srgrimes if (hp->h_subject == NOSTR) 3241590Srgrimes printf("No message, no subject; hope that's ok\n"); 3251590Srgrimes else 3261590Srgrimes printf("Null message body; hope that's ok\n"); 3271590Srgrimes /* 3281590Srgrimes * Now, take the user names from the combined 3291590Srgrimes * to and cc lists and do all the alias 3301590Srgrimes * processing. 3311590Srgrimes */ 3321590Srgrimes senderr = 0; 3331590Srgrimes to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); 3341590Srgrimes if (to == NIL) { 3351590Srgrimes printf("No recipients specified\n"); 3361590Srgrimes senderr++; 3371590Srgrimes } 3381590Srgrimes /* 3391590Srgrimes * Look through the recipient list for names with /'s 3401590Srgrimes * in them which we write to as files directly. 3411590Srgrimes */ 3421590Srgrimes to = outof(to, mtf, hp); 3431590Srgrimes if (senderr) 3441590Srgrimes savedeadletter(mtf); 3451590Srgrimes to = elide(to); 3461590Srgrimes if (count(to) == 0) 3471590Srgrimes goto out; 3481590Srgrimes fixhead(hp, to); 3491590Srgrimes if ((mtf = infix(hp, mtf)) == NULL) { 3501590Srgrimes fprintf(stderr, ". . . message lost, sorry.\n"); 3511590Srgrimes return; 3521590Srgrimes } 3531590Srgrimes namelist = unpack(cat(hp->h_smopts, to)); 3541590Srgrimes if (debug) { 3551590Srgrimes char **t; 3561590Srgrimes 3571590Srgrimes printf("Sendmail arguments:"); 3581590Srgrimes for (t = namelist; *t != NOSTR; t++) 3591590Srgrimes printf(" \"%s\"", *t); 3601590Srgrimes printf("\n"); 3611590Srgrimes goto out; 3621590Srgrimes } 3631590Srgrimes if ((cp = value("record")) != NOSTR) 3641590Srgrimes (void) savemail(expand(cp), mtf); 3651590Srgrimes /* 3661590Srgrimes * Fork, set up the temporary mail file as standard 3671590Srgrimes * input for "mail", and exec with the user list we generated 3681590Srgrimes * far above. 3691590Srgrimes */ 3701590Srgrimes pid = fork(); 3711590Srgrimes if (pid == -1) { 3721590Srgrimes perror("fork"); 3731590Srgrimes savedeadletter(mtf); 3741590Srgrimes goto out; 3751590Srgrimes } 3761590Srgrimes if (pid == 0) { 3771590Srgrimes prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)| 3781590Srgrimes sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU), 3791590Srgrimes fileno(mtf), -1); 3801590Srgrimes if ((cp = value("sendmail")) != NOSTR) 3811590Srgrimes cp = expand(cp); 3821590Srgrimes else 3831590Srgrimes cp = _PATH_SENDMAIL; 3841590Srgrimes execv(cp, namelist); 3851590Srgrimes perror(cp); 3861590Srgrimes _exit(1); 3871590Srgrimes } 3881590Srgrimes if (value("verbose") != NOSTR) 3891590Srgrimes (void) wait_child(pid); 3901590Srgrimes else 3911590Srgrimes free_child(pid); 3921590Srgrimesout: 3931590Srgrimes (void) Fclose(mtf); 3941590Srgrimes} 3951590Srgrimes 3961590Srgrimes/* 3971590Srgrimes * Fix the header by glopping all of the expanded names from 3981590Srgrimes * the distribution list into the appropriate fields. 3991590Srgrimes */ 4001590Srgrimesvoid 4011590Srgrimesfixhead(hp, tolist) 4021590Srgrimes struct header *hp; 4031590Srgrimes struct name *tolist; 4041590Srgrimes{ 4051590Srgrimes register struct name *np; 4061590Srgrimes 4071590Srgrimes hp->h_to = NIL; 4081590Srgrimes hp->h_cc = NIL; 4091590Srgrimes hp->h_bcc = NIL; 4101590Srgrimes for (np = tolist; np != NIL; np = np->n_flink) 4111590Srgrimes if ((np->n_type & GMASK) == GTO) 4121590Srgrimes hp->h_to = 4131590Srgrimes cat(hp->h_to, nalloc(np->n_name, np->n_type)); 4141590Srgrimes else if ((np->n_type & GMASK) == GCC) 4151590Srgrimes hp->h_cc = 4161590Srgrimes cat(hp->h_cc, nalloc(np->n_name, np->n_type)); 4171590Srgrimes else if ((np->n_type & GMASK) == GBCC) 4181590Srgrimes hp->h_bcc = 4191590Srgrimes cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); 4201590Srgrimes} 4211590Srgrimes 4221590Srgrimes/* 4231590Srgrimes * Prepend a header in front of the collected stuff 4241590Srgrimes * and return the new file. 4251590Srgrimes */ 4261590SrgrimesFILE * 4271590Srgrimesinfix(hp, fi) 4281590Srgrimes struct header *hp; 4291590Srgrimes FILE *fi; 4301590Srgrimes{ 4311590Srgrimes extern char tempMail[]; 4321590Srgrimes register FILE *nfo, *nfi; 4331590Srgrimes register int c; 4341590Srgrimes 4351590Srgrimes if ((nfo = Fopen(tempMail, "w")) == NULL) { 4361590Srgrimes perror(tempMail); 4371590Srgrimes return(fi); 4381590Srgrimes } 4391590Srgrimes if ((nfi = Fopen(tempMail, "r")) == NULL) { 4401590Srgrimes perror(tempMail); 4411590Srgrimes (void) Fclose(nfo); 4421590Srgrimes return(fi); 4431590Srgrimes } 4441590Srgrimes (void) rm(tempMail); 44532189Sjoerg (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA); 4461590Srgrimes c = getc(fi); 4471590Srgrimes while (c != EOF) { 4481590Srgrimes (void) putc(c, nfo); 4491590Srgrimes c = getc(fi); 4501590Srgrimes } 4511590Srgrimes if (ferror(fi)) { 4521590Srgrimes perror("read"); 4531590Srgrimes rewind(fi); 4541590Srgrimes return(fi); 4551590Srgrimes } 4561590Srgrimes (void) fflush(nfo); 4571590Srgrimes if (ferror(nfo)) { 4581590Srgrimes perror(tempMail); 4591590Srgrimes (void) Fclose(nfo); 4601590Srgrimes (void) Fclose(nfi); 4611590Srgrimes rewind(fi); 4621590Srgrimes return(fi); 4631590Srgrimes } 4641590Srgrimes (void) Fclose(nfo); 4651590Srgrimes (void) Fclose(fi); 4661590Srgrimes rewind(nfi); 4671590Srgrimes return(nfi); 4681590Srgrimes} 4691590Srgrimes 4701590Srgrimes/* 4711590Srgrimes * Dump the to, subject, cc header on the 4721590Srgrimes * passed file buffer. 4731590Srgrimes */ 4741590Srgrimesint 4751590Srgrimesputhead(hp, fo, w) 4761590Srgrimes struct header *hp; 4771590Srgrimes FILE *fo; 4781590Srgrimes int w; 4791590Srgrimes{ 4801590Srgrimes register int gotcha; 4811590Srgrimes 4821590Srgrimes gotcha = 0; 4831590Srgrimes if (hp->h_to != NIL && w & GTO) 4841590Srgrimes fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; 4851590Srgrimes if (hp->h_subject != NOSTR && w & GSUBJECT) 4861590Srgrimes fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 4871590Srgrimes if (hp->h_cc != NIL && w & GCC) 4881590Srgrimes fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; 4891590Srgrimes if (hp->h_bcc != NIL && w & GBCC) 4901590Srgrimes fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; 49132189Sjoerg if (hp->h_replyto != NOSTR && w && GREPLYTO) 49232189Sjoerg fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++; 49332189Sjoerg if (hp->h_inreplyto != NOSTR && w && GINREPLYTO) 49432189Sjoerg fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++; 4951590Srgrimes if (gotcha && w & GNL) 4961590Srgrimes (void) putc('\n', fo); 4971590Srgrimes return(0); 4981590Srgrimes} 4991590Srgrimes 5001590Srgrimes/* 5011590Srgrimes * Format the given header line to not exceed 72 characters. 5021590Srgrimes */ 5031590Srgrimesvoid 5041590Srgrimesfmt(str, np, fo, comma) 5051590Srgrimes char *str; 5061590Srgrimes register struct name *np; 5071590Srgrimes FILE *fo; 5081590Srgrimes int comma; 5091590Srgrimes{ 5101590Srgrimes register col, len; 5111590Srgrimes 5121590Srgrimes comma = comma ? 1 : 0; 5131590Srgrimes col = strlen(str); 5141590Srgrimes if (col) 5151590Srgrimes fputs(str, fo); 5161590Srgrimes for (; np != NIL; np = np->n_flink) { 5171590Srgrimes if (np->n_flink == NIL) 5181590Srgrimes comma = 0; 5191590Srgrimes len = strlen(np->n_name); 5201590Srgrimes col++; /* for the space */ 5211590Srgrimes if (col + len + comma > 72 && col > 4) { 5221590Srgrimes fputs("\n ", fo); 5231590Srgrimes col = 4; 5241590Srgrimes } else 5251590Srgrimes putc(' ', fo); 5261590Srgrimes fputs(np->n_name, fo); 5271590Srgrimes if (comma) 5281590Srgrimes putc(',', fo); 5291590Srgrimes col += len + comma; 5301590Srgrimes } 5311590Srgrimes putc('\n', fo); 5321590Srgrimes} 5331590Srgrimes 5341590Srgrimes/* 5351590Srgrimes * Save the outgoing mail on the passed file. 5361590Srgrimes */ 5371590Srgrimes 5381590Srgrimes/*ARGSUSED*/ 5391590Srgrimesint 5401590Srgrimessavemail(name, fi) 5411590Srgrimes char name[]; 5421590Srgrimes register FILE *fi; 5431590Srgrimes{ 5441590Srgrimes register FILE *fo; 5451590Srgrimes char buf[BUFSIZ]; 5461590Srgrimes register i; 5471590Srgrimes time_t now, time(); 5481590Srgrimes char *ctime(); 5491590Srgrimes 5501590Srgrimes if ((fo = Fopen(name, "a")) == NULL) { 5511590Srgrimes perror(name); 5521590Srgrimes return (-1); 5531590Srgrimes } 5541590Srgrimes (void) time(&now); 5551590Srgrimes fprintf(fo, "From %s %s", myname, ctime(&now)); 5561590Srgrimes while ((i = fread(buf, 1, sizeof buf, fi)) > 0) 5571590Srgrimes (void) fwrite(buf, 1, i, fo); 5581590Srgrimes (void) putc('\n', fo); 5591590Srgrimes (void) fflush(fo); 5601590Srgrimes if (ferror(fo)) 5611590Srgrimes perror(name); 5621590Srgrimes (void) Fclose(fo); 5631590Srgrimes rewind(fi); 5641590Srgrimes return (0); 5651590Srgrimes} 566