19b50d902SRodney W. Grimes /* 29b50d902SRodney W. Grimes * Copyright (c) 1980, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 13*fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 149b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 159b50d902SRodney W. Grimes * without specific prior written permission. 169b50d902SRodney W. Grimes * 179b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 189b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 199b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 209b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 219b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 229b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 239b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 249b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 259b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 269b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 279b50d902SRodney W. Grimes * SUCH DAMAGE. 289b50d902SRodney W. Grimes */ 299b50d902SRodney W. Grimes 309b50d902SRodney W. Grimes #ifndef lint 310c3a8314SMike Heffner #if 0 329b50d902SRodney W. Grimes static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; 330c3a8314SMike Heffner #endif 349b50d902SRodney W. Grimes #endif /* not lint */ 35e026a48cSDavid E. O'Brien #include <sys/cdefs.h> 36e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 379b50d902SRodney W. Grimes 389b50d902SRodney W. Grimes #include "rcv.h" 399b50d902SRodney W. Grimes #include "extern.h" 409b50d902SRodney W. Grimes 419b50d902SRodney W. Grimes /* 429b50d902SRodney W. Grimes * Mail -- a mail program 439b50d902SRodney W. Grimes * 449b50d902SRodney W. Grimes * Mail to others. 459b50d902SRodney W. Grimes */ 469b50d902SRodney W. Grimes 479b50d902SRodney W. Grimes /* 489b50d902SRodney W. Grimes * Send message described by the passed pointer to the 499b50d902SRodney W. Grimes * passed output buffer. Return -1 on error. 509b50d902SRodney W. Grimes * Adjust the status: field if need be. 519b50d902SRodney W. Grimes * If doign is given, suppress ignored header fields. 529b50d902SRodney W. Grimes * prefix is a string to prepend to each output line. 539b50d902SRodney W. Grimes */ 549b50d902SRodney W. Grimes int 556d8484b0SPhilippe Charnier sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, 566d8484b0SPhilippe Charnier char *prefix) 579b50d902SRodney W. Grimes { 589b50d902SRodney W. Grimes long count; 599ce73e90SMike Heffner FILE *ibuf; 609ce73e90SMike Heffner char *cp, *cp2, line[LINESIZE]; 619b50d902SRodney W. Grimes int ishead, infld, ignoring, dostat, firstline; 624994a9b8SXin LI int c = 0, length, prefixlen; 639b50d902SRodney W. Grimes 649b50d902SRodney W. Grimes /* 659b50d902SRodney W. Grimes * Compute the prefix string, without trailing whitespace 669b50d902SRodney W. Grimes */ 679ce73e90SMike Heffner if (prefix != NULL) { 689b50d902SRodney W. Grimes cp2 = 0; 699ce73e90SMike Heffner for (cp = prefix; *cp != '\0'; cp++) 709b50d902SRodney W. Grimes if (*cp != ' ' && *cp != '\t') 719b50d902SRodney W. Grimes cp2 = cp; 729ce73e90SMike Heffner prefixlen = cp2 == NULL ? 0 : cp2 - prefix + 1; 739b50d902SRodney W. Grimes } 749b50d902SRodney W. Grimes ibuf = setinput(mp); 759b50d902SRodney W. Grimes count = mp->m_size; 769b50d902SRodney W. Grimes ishead = 1; 779b50d902SRodney W. Grimes dostat = doign == 0 || !isign("status", doign); 789b50d902SRodney W. Grimes infld = 0; 799b50d902SRodney W. Grimes firstline = 1; 809b50d902SRodney W. Grimes /* 819b50d902SRodney W. Grimes * Process headers first 829b50d902SRodney W. Grimes */ 839b50d902SRodney W. Grimes while (count > 0 && ishead) { 840c3a8314SMike Heffner if (fgets(line, sizeof(line), ibuf) == NULL) 859b50d902SRodney W. Grimes break; 869b50d902SRodney W. Grimes count -= length = strlen(line); 879b50d902SRodney W. Grimes if (firstline) { 889b50d902SRodney W. Grimes /* 899b50d902SRodney W. Grimes * First line is the From line, so no headers 909b50d902SRodney W. Grimes * there to worry about 919b50d902SRodney W. Grimes */ 929b50d902SRodney W. Grimes firstline = 0; 939b50d902SRodney W. Grimes ignoring = doign == ignoreall; 949b50d902SRodney W. Grimes } else if (line[0] == '\n') { 959b50d902SRodney W. Grimes /* 969b50d902SRodney W. Grimes * If line is blank, we've reached end of 979b50d902SRodney W. Grimes * headers, so force out status: field 989b50d902SRodney W. Grimes * and note that we are no longer in header 999b50d902SRodney W. Grimes * fields 1009b50d902SRodney W. Grimes */ 1019b50d902SRodney W. Grimes if (dostat) { 1029b50d902SRodney W. Grimes statusput(mp, obuf, prefix); 1039b50d902SRodney W. Grimes dostat = 0; 1049b50d902SRodney W. Grimes } 1059b50d902SRodney W. Grimes ishead = 0; 1069b50d902SRodney W. Grimes ignoring = doign == ignoreall; 1079b50d902SRodney W. Grimes } else if (infld && (line[0] == ' ' || line[0] == '\t')) { 1089b50d902SRodney W. Grimes /* 1099b50d902SRodney W. Grimes * If this line is a continuation (via space or tab) 1109b50d902SRodney W. Grimes * of a previous header field, just echo it 1119b50d902SRodney W. Grimes * (unless the field should be ignored). 1129b50d902SRodney W. Grimes * In other words, nothing to do. 1139b50d902SRodney W. Grimes */ 1149b50d902SRodney W. Grimes } else { 1159b50d902SRodney W. Grimes /* 1169b50d902SRodney W. Grimes * Pick up the header field if we have one. 1179b50d902SRodney W. Grimes */ 1189ce73e90SMike Heffner for (cp = line; (c = *cp++) != '\0' && c != ':' && 1196d48fa43SAndrey A. Chernov !isspace((unsigned char)c);) 1209b50d902SRodney W. Grimes ; 1219b50d902SRodney W. Grimes cp2 = --cp; 1226d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp++)) 1239b50d902SRodney W. Grimes ; 1249b50d902SRodney W. Grimes if (cp[-1] != ':') { 1259b50d902SRodney W. Grimes /* 1269b50d902SRodney W. Grimes * Not a header line, force out status: 1279b50d902SRodney W. Grimes * This happens in uucp style mail where 1289b50d902SRodney W. Grimes * there are no headers at all. 1299b50d902SRodney W. Grimes */ 1309b50d902SRodney W. Grimes if (dostat) { 1319b50d902SRodney W. Grimes statusput(mp, obuf, prefix); 1329b50d902SRodney W. Grimes dostat = 0; 1339b50d902SRodney W. Grimes } 1349b50d902SRodney W. Grimes if (doign != ignoreall) 1359b50d902SRodney W. Grimes /* add blank line */ 1369b50d902SRodney W. Grimes (void)putc('\n', obuf); 1379b50d902SRodney W. Grimes ishead = 0; 1389b50d902SRodney W. Grimes ignoring = 0; 1399b50d902SRodney W. Grimes } else { 1409b50d902SRodney W. Grimes /* 1419b50d902SRodney W. Grimes * If it is an ignored field and 1429b50d902SRodney W. Grimes * we care about such things, skip it. 1439b50d902SRodney W. Grimes */ 1449ce73e90SMike Heffner *cp2 = '\0'; /* temporarily null terminate */ 1459b50d902SRodney W. Grimes if (doign && isign(line, doign)) 1469b50d902SRodney W. Grimes ignoring = 1; 1479b50d902SRodney W. Grimes else if ((line[0] == 's' || line[0] == 'S') && 1489b50d902SRodney W. Grimes strcasecmp(line, "status") == 0) { 1499b50d902SRodney W. Grimes /* 1509b50d902SRodney W. Grimes * If the field is "status," go compute 1519b50d902SRodney W. Grimes * and print the real Status: field 1529b50d902SRodney W. Grimes */ 1539b50d902SRodney W. Grimes if (dostat) { 1549b50d902SRodney W. Grimes statusput(mp, obuf, prefix); 1559b50d902SRodney W. Grimes dostat = 0; 1569b50d902SRodney W. Grimes } 1579b50d902SRodney W. Grimes ignoring = 1; 1589b50d902SRodney W. Grimes } else { 1599b50d902SRodney W. Grimes ignoring = 0; 1609b50d902SRodney W. Grimes *cp2 = c; /* restore */ 1619b50d902SRodney W. Grimes } 1629b50d902SRodney W. Grimes infld = 1; 1639b50d902SRodney W. Grimes } 1649b50d902SRodney W. Grimes } 1659b50d902SRodney W. Grimes if (!ignoring) { 1669b50d902SRodney W. Grimes /* 1679b50d902SRodney W. Grimes * Strip trailing whitespace from prefix 1689b50d902SRodney W. Grimes * if line is blank. 1699b50d902SRodney W. Grimes */ 1709ce73e90SMike Heffner if (prefix != NULL) { 1719b50d902SRodney W. Grimes if (length > 1) 1729b50d902SRodney W. Grimes fputs(prefix, obuf); 1739b50d902SRodney W. Grimes else 1749ce73e90SMike Heffner (void)fwrite(prefix, sizeof(*prefix), 1759b50d902SRodney W. Grimes prefixlen, obuf); 1760c3a8314SMike Heffner } 1779ce73e90SMike Heffner (void)fwrite(line, sizeof(*line), length, obuf); 1789b50d902SRodney W. Grimes if (ferror(obuf)) 1799ce73e90SMike Heffner return (-1); 1809b50d902SRodney W. Grimes } 1819b50d902SRodney W. Grimes } 1829b50d902SRodney W. Grimes /* 1839b50d902SRodney W. Grimes * Copy out message body 1849b50d902SRodney W. Grimes */ 1859b50d902SRodney W. Grimes if (doign == ignoreall) 1869b50d902SRodney W. Grimes count--; /* skip final blank line */ 1879ce73e90SMike Heffner if (prefix != NULL) 1889b50d902SRodney W. Grimes while (count > 0) { 1890c3a8314SMike Heffner if (fgets(line, sizeof(line), ibuf) == NULL) { 1909b50d902SRodney W. Grimes c = 0; 1919b50d902SRodney W. Grimes break; 1929b50d902SRodney W. Grimes } 1939b50d902SRodney W. Grimes count -= c = strlen(line); 1949b50d902SRodney W. Grimes /* 1959b50d902SRodney W. Grimes * Strip trailing whitespace from prefix 1969b50d902SRodney W. Grimes * if line is blank. 1979b50d902SRodney W. Grimes */ 1989b50d902SRodney W. Grimes if (c > 1) 1999b50d902SRodney W. Grimes fputs(prefix, obuf); 2009b50d902SRodney W. Grimes else 2019ce73e90SMike Heffner (void)fwrite(prefix, sizeof(*prefix), 2029b50d902SRodney W. Grimes prefixlen, obuf); 2039ce73e90SMike Heffner (void)fwrite(line, sizeof(*line), c, obuf); 2049b50d902SRodney W. Grimes if (ferror(obuf)) 2059ce73e90SMike Heffner return (-1); 2069b50d902SRodney W. Grimes } 2079b50d902SRodney W. Grimes else 2089b50d902SRodney W. Grimes while (count > 0) { 2099b50d902SRodney W. Grimes c = count < LINESIZE ? count : LINESIZE; 2109ce73e90SMike Heffner if ((c = fread(line, sizeof(*line), c, ibuf)) <= 0) 2119b50d902SRodney W. Grimes break; 2129b50d902SRodney W. Grimes count -= c; 2139ce73e90SMike Heffner if (fwrite(line, sizeof(*line), c, obuf) != c) 2149ce73e90SMike Heffner return (-1); 2159b50d902SRodney W. Grimes } 2169b50d902SRodney W. Grimes if (doign == ignoreall && c > 0 && line[c - 1] != '\n') 2179b50d902SRodney W. Grimes /* no final blank line */ 2189b50d902SRodney W. Grimes if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) 2199ce73e90SMike Heffner return (-1); 2209ce73e90SMike Heffner return (0); 2219b50d902SRodney W. Grimes } 2229b50d902SRodney W. Grimes 2239b50d902SRodney W. Grimes /* 2249b50d902SRodney W. Grimes * Output a reasonable looking status field. 2259b50d902SRodney W. Grimes */ 2269b50d902SRodney W. Grimes void 2276d8484b0SPhilippe Charnier statusput(struct message *mp, FILE *obuf, char *prefix) 2289b50d902SRodney W. Grimes { 2299b50d902SRodney W. Grimes char statout[3]; 2309ce73e90SMike Heffner char *cp = statout; 2319b50d902SRodney W. Grimes 2329b50d902SRodney W. Grimes if (mp->m_flag & MREAD) 2339b50d902SRodney W. Grimes *cp++ = 'R'; 2349b50d902SRodney W. Grimes if ((mp->m_flag & MNEW) == 0) 2359b50d902SRodney W. Grimes *cp++ = 'O'; 2369ce73e90SMike Heffner *cp = '\0'; 2379ce73e90SMike Heffner if (statout[0] != '\0') 2389b50d902SRodney W. Grimes fprintf(obuf, "%sStatus: %s\n", 2399ce73e90SMike Heffner prefix == NULL ? "" : prefix, statout); 2409b50d902SRodney W. Grimes } 2419b50d902SRodney W. Grimes 2429b50d902SRodney W. Grimes /* 2439b50d902SRodney W. Grimes * Interface between the argument list and the mail1 routine 2449b50d902SRodney W. Grimes * which does all the dirty work. 2459b50d902SRodney W. Grimes */ 2469b50d902SRodney W. Grimes int 2476d8484b0SPhilippe Charnier mail(struct name *to, struct name *cc, struct name *bcc, struct name *smopts, 2486d8484b0SPhilippe Charnier char *subject, char *replyto) 2499b50d902SRodney W. Grimes { 2509b50d902SRodney W. Grimes struct header head; 2519b50d902SRodney W. Grimes 2529b50d902SRodney W. Grimes head.h_to = to; 2539b50d902SRodney W. Grimes head.h_subject = subject; 2549b50d902SRodney W. Grimes head.h_cc = cc; 2559b50d902SRodney W. Grimes head.h_bcc = bcc; 2569b50d902SRodney W. Grimes head.h_smopts = smopts; 25799bd6601SJoerg Wunsch head.h_replyto = replyto; 2589ce73e90SMike Heffner head.h_inreplyto = NULL; 2599b50d902SRodney W. Grimes mail1(&head, 0); 2609b50d902SRodney W. Grimes return (0); 2619b50d902SRodney W. Grimes } 2629b50d902SRodney W. Grimes 2639b50d902SRodney W. Grimes 2649b50d902SRodney W. Grimes /* 2659b50d902SRodney W. Grimes * Send mail to a bunch of user names. The interface is through 2669b50d902SRodney W. Grimes * the mail routine below. 2679b50d902SRodney W. Grimes */ 2689b50d902SRodney W. Grimes int 2696d8484b0SPhilippe Charnier sendmail(char *str) 2709b50d902SRodney W. Grimes { 2719b50d902SRodney W. Grimes struct header head; 2729b50d902SRodney W. Grimes 2739b50d902SRodney W. Grimes head.h_to = extract(str, GTO); 2749ce73e90SMike Heffner head.h_subject = NULL; 2759ce73e90SMike Heffner head.h_cc = NULL; 2769ce73e90SMike Heffner head.h_bcc = NULL; 2779ce73e90SMike Heffner head.h_smopts = NULL; 27859c3f4f7SMike Heffner head.h_replyto = value("REPLYTO"); 2799ce73e90SMike Heffner head.h_inreplyto = NULL; 2809b50d902SRodney W. Grimes mail1(&head, 0); 2819b50d902SRodney W. Grimes return (0); 2829b50d902SRodney W. Grimes } 2839b50d902SRodney W. Grimes 2849b50d902SRodney W. Grimes /* 2859b50d902SRodney W. Grimes * Mail a message on standard input to the people indicated 2869b50d902SRodney W. Grimes * in the passed header. (Internal interface). 2879b50d902SRodney W. Grimes */ 2889b50d902SRodney W. Grimes void 2896d8484b0SPhilippe Charnier mail1(struct header *hp, int printheaders) 2909b50d902SRodney W. Grimes { 2919b50d902SRodney W. Grimes char *cp; 292c92dfc23SMike Heffner char *nbuf; 2939b50d902SRodney W. Grimes int pid; 2949b50d902SRodney W. Grimes char **namelist; 295c92dfc23SMike Heffner struct name *to, *nsto; 2969b50d902SRodney W. Grimes FILE *mtf; 2979b50d902SRodney W. Grimes 2989b50d902SRodney W. Grimes /* 2999b50d902SRodney W. Grimes * Collect user's mail from standard input. 3009b50d902SRodney W. Grimes * Get the result as mtf. 3019b50d902SRodney W. Grimes */ 3029b50d902SRodney W. Grimes if ((mtf = collect(hp, printheaders)) == NULL) 3039b50d902SRodney W. Grimes return; 3049ce73e90SMike Heffner if (value("interactive") != NULL) { 305856f23edSMike Heffner if (value("askcc") != NULL || value("askbcc") != NULL) { 3069ce73e90SMike Heffner if (value("askcc") != NULL) 3079b50d902SRodney W. Grimes grabh(hp, GCC); 308856f23edSMike Heffner if (value("askbcc") != NULL) 309856f23edSMike Heffner grabh(hp, GBCC); 310856f23edSMike Heffner } else { 3119b50d902SRodney W. Grimes printf("EOT\n"); 3129b50d902SRodney W. Grimes (void)fflush(stdout); 3139b50d902SRodney W. Grimes } 3140c3a8314SMike Heffner } 3150c3a8314SMike Heffner if (fsize(mtf) == 0) { 316dcd24e27SMike Heffner if (value("dontsendempty") != NULL) 317dcd24e27SMike Heffner goto out; 3189ce73e90SMike Heffner if (hp->h_subject == NULL) 3199b50d902SRodney W. Grimes printf("No message, no subject; hope that's ok\n"); 3209b50d902SRodney W. Grimes else 3219b50d902SRodney W. Grimes printf("Null message body; hope that's ok\n"); 3220c3a8314SMike Heffner } 3239b50d902SRodney W. Grimes /* 3249b50d902SRodney W. Grimes * Now, take the user names from the combined 3259b50d902SRodney W. Grimes * to and cc lists and do all the alias 3269b50d902SRodney W. Grimes * processing. 3279b50d902SRodney W. Grimes */ 3289b50d902SRodney W. Grimes senderr = 0; 3299b50d902SRodney W. Grimes to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); 3309ce73e90SMike Heffner if (to == NULL) { 3319b50d902SRodney W. Grimes printf("No recipients specified\n"); 3329b50d902SRodney W. Grimes senderr++; 3339b50d902SRodney W. Grimes } 3349b50d902SRodney W. Grimes /* 3359b50d902SRodney W. Grimes * Look through the recipient list for names with /'s 3369b50d902SRodney W. Grimes * in them which we write to as files directly. 3379b50d902SRodney W. Grimes */ 3389b50d902SRodney W. Grimes to = outof(to, mtf, hp); 3399b50d902SRodney W. Grimes if (senderr) 3409b50d902SRodney W. Grimes savedeadletter(mtf); 3419b50d902SRodney W. Grimes to = elide(to); 3429b50d902SRodney W. Grimes if (count(to) == 0) 3439b50d902SRodney W. Grimes goto out; 344c92dfc23SMike Heffner if (value("recordrecip") != NULL) { 345c92dfc23SMike Heffner /* 346c92dfc23SMike Heffner * Before fixing the header, save old To:. 347c92dfc23SMike Heffner * We do this because elide above has sorted To: list, and 348c92dfc23SMike Heffner * we would like to save message in a file named by the first 349c92dfc23SMike Heffner * recipient the user has entered, not the one being the first 350c92dfc23SMike Heffner * after sorting happened. 351c92dfc23SMike Heffner */ 352c92dfc23SMike Heffner if ((nsto = malloc(sizeof(struct name))) == NULL) 353c92dfc23SMike Heffner err(1, "Out of memory"); 354c92dfc23SMike Heffner bcopy(hp->h_to, nsto, sizeof(struct name)); 355c92dfc23SMike Heffner } 3569b50d902SRodney W. Grimes fixhead(hp, to); 3579b50d902SRodney W. Grimes if ((mtf = infix(hp, mtf)) == NULL) { 3589b50d902SRodney W. Grimes fprintf(stderr, ". . . message lost, sorry.\n"); 3599b50d902SRodney W. Grimes return; 3609b50d902SRodney W. Grimes } 3619b50d902SRodney W. Grimes namelist = unpack(cat(hp->h_smopts, to)); 3629b50d902SRodney W. Grimes if (debug) { 3639b50d902SRodney W. Grimes char **t; 3649b50d902SRodney W. Grimes 3659b50d902SRodney W. Grimes printf("Sendmail arguments:"); 3669ce73e90SMike Heffner for (t = namelist; *t != NULL; t++) 3679b50d902SRodney W. Grimes printf(" \"%s\"", *t); 3689b50d902SRodney W. Grimes printf("\n"); 3699b50d902SRodney W. Grimes goto out; 3709b50d902SRodney W. Grimes } 371c92dfc23SMike Heffner if (value("recordrecip") != NULL) { 372c92dfc23SMike Heffner /* 373c92dfc23SMike Heffner * Extract first recipient username from saved To: and use it 374c92dfc23SMike Heffner * as a filename. 375c92dfc23SMike Heffner */ 376c92dfc23SMike Heffner if ((nbuf = malloc(strlen(detract(nsto, 0)) + 1)) == NULL) 377c92dfc23SMike Heffner err(1, "Out of memory"); 378c92dfc23SMike Heffner if ((cp = yanklogin(detract(nsto, 0), nbuf)) != NULL) 379c92dfc23SMike Heffner (void)savemail(expand(nbuf), mtf); 380c92dfc23SMike Heffner free(nbuf); 381c92dfc23SMike Heffner free(nsto); 382c92dfc23SMike Heffner } else if ((cp = value("record")) != NULL) 3839b50d902SRodney W. Grimes (void)savemail(expand(cp), mtf); 3849b50d902SRodney W. Grimes /* 3859b50d902SRodney W. Grimes * Fork, set up the temporary mail file as standard 3869b50d902SRodney W. Grimes * input for "mail", and exec with the user list we generated 3879b50d902SRodney W. Grimes * far above. 3889b50d902SRodney W. Grimes */ 3899b50d902SRodney W. Grimes pid = fork(); 3909b50d902SRodney W. Grimes if (pid == -1) { 3910c3a8314SMike Heffner warn("fork"); 3929b50d902SRodney W. Grimes savedeadletter(mtf); 3939b50d902SRodney W. Grimes goto out; 3949b50d902SRodney W. Grimes } 3959b50d902SRodney W. Grimes if (pid == 0) { 396856f23edSMike Heffner sigset_t nset; 397856f23edSMike Heffner (void)sigemptyset(&nset); 398856f23edSMike Heffner (void)sigaddset(&nset, SIGHUP); 399856f23edSMike Heffner (void)sigaddset(&nset, SIGINT); 400856f23edSMike Heffner (void)sigaddset(&nset, SIGQUIT); 401856f23edSMike Heffner (void)sigaddset(&nset, SIGTSTP); 402856f23edSMike Heffner (void)sigaddset(&nset, SIGTTIN); 403856f23edSMike Heffner (void)sigaddset(&nset, SIGTTOU); 404856f23edSMike Heffner prepare_child(&nset, fileno(mtf), -1); 4059ce73e90SMike Heffner if ((cp = value("sendmail")) != NULL) 4069b50d902SRodney W. Grimes cp = expand(cp); 4079b50d902SRodney W. Grimes else 4089b50d902SRodney W. Grimes cp = _PATH_SENDMAIL; 4099b50d902SRodney W. Grimes execv(cp, namelist); 4100c3a8314SMike Heffner warn("%s", cp); 4119b50d902SRodney W. Grimes _exit(1); 4129b50d902SRodney W. Grimes } 4139ce73e90SMike Heffner if (value("verbose") != NULL) 4149b50d902SRodney W. Grimes (void)wait_child(pid); 4159b50d902SRodney W. Grimes else 4169b50d902SRodney W. Grimes free_child(pid); 4179b50d902SRodney W. Grimes out: 4189b50d902SRodney W. Grimes (void)Fclose(mtf); 4199b50d902SRodney W. Grimes } 4209b50d902SRodney W. Grimes 4219b50d902SRodney W. Grimes /* 4229b50d902SRodney W. Grimes * Fix the header by glopping all of the expanded names from 4239b50d902SRodney W. Grimes * the distribution list into the appropriate fields. 4249b50d902SRodney W. Grimes */ 4259b50d902SRodney W. Grimes void 4266d8484b0SPhilippe Charnier fixhead(struct header *hp, struct name *tolist) 4279b50d902SRodney W. Grimes { 4289ce73e90SMike Heffner struct name *np; 4299b50d902SRodney W. Grimes 4309ce73e90SMike Heffner hp->h_to = NULL; 4319ce73e90SMike Heffner hp->h_cc = NULL; 4329ce73e90SMike Heffner hp->h_bcc = NULL; 43350892679SAndrey A. Chernov for (np = tolist; np != NULL; np = np->n_flink) { 434856f23edSMike Heffner /* Don't copy deleted addresses to the header */ 435856f23edSMike Heffner if (np->n_type & GDEL) 436856f23edSMike Heffner continue; 4379b50d902SRodney W. Grimes if ((np->n_type & GMASK) == GTO) 4389b50d902SRodney W. Grimes hp->h_to = 4399b50d902SRodney W. Grimes cat(hp->h_to, nalloc(np->n_name, np->n_type)); 4409b50d902SRodney W. Grimes else if ((np->n_type & GMASK) == GCC) 4419b50d902SRodney W. Grimes hp->h_cc = 4429b50d902SRodney W. Grimes cat(hp->h_cc, nalloc(np->n_name, np->n_type)); 4439b50d902SRodney W. Grimes else if ((np->n_type & GMASK) == GBCC) 4449b50d902SRodney W. Grimes hp->h_bcc = 4459b50d902SRodney W. Grimes cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); 4469b50d902SRodney W. Grimes } 44750892679SAndrey A. Chernov } 4489b50d902SRodney W. Grimes 4499b50d902SRodney W. Grimes /* 4509b50d902SRodney W. Grimes * Prepend a header in front of the collected stuff 4519b50d902SRodney W. Grimes * and return the new file. 4529b50d902SRodney W. Grimes */ 4539b50d902SRodney W. Grimes FILE * 4546d8484b0SPhilippe Charnier infix(struct header *hp, FILE *fi) 4559b50d902SRodney W. Grimes { 4569ce73e90SMike Heffner FILE *nfo, *nfi; 4579ce73e90SMike Heffner int c, fd; 4580c3a8314SMike Heffner char tempname[PATHSIZE]; 4599b50d902SRodney W. Grimes 4609ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 4619ce73e90SMike Heffner "%s/mail.RsXXXXXXXXXX", tmpdir); 4620c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 4630c3a8314SMike Heffner (nfo = Fdopen(fd, "w")) == NULL) { 4640c3a8314SMike Heffner warn("%s", tempname); 4659b50d902SRodney W. Grimes return (fi); 4669b50d902SRodney W. Grimes } 4670c3a8314SMike Heffner if ((nfi = Fopen(tempname, "r")) == NULL) { 4680c3a8314SMike Heffner warn("%s", tempname); 4699b50d902SRodney W. Grimes (void)Fclose(nfo); 4700c3a8314SMike Heffner (void)rm(tempname); 4719b50d902SRodney W. Grimes return (fi); 4729b50d902SRodney W. Grimes } 4730c3a8314SMike Heffner (void)rm(tempname); 47457392071SJoerg Wunsch (void)puthead(hp, nfo, 47557392071SJoerg Wunsch GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA); 4769b50d902SRodney W. Grimes c = getc(fi); 4779b50d902SRodney W. Grimes while (c != EOF) { 4789b50d902SRodney W. Grimes (void)putc(c, nfo); 4799b50d902SRodney W. Grimes c = getc(fi); 4809b50d902SRodney W. Grimes } 4819b50d902SRodney W. Grimes if (ferror(fi)) { 4820c3a8314SMike Heffner warnx("read"); 4839b50d902SRodney W. Grimes rewind(fi); 4849b50d902SRodney W. Grimes return (fi); 4859b50d902SRodney W. Grimes } 4869b50d902SRodney W. Grimes (void)fflush(nfo); 4879b50d902SRodney W. Grimes if (ferror(nfo)) { 4880c3a8314SMike Heffner warn("%s", tempname); 4899b50d902SRodney W. Grimes (void)Fclose(nfo); 4909b50d902SRodney W. Grimes (void)Fclose(nfi); 4919b50d902SRodney W. Grimes rewind(fi); 4929b50d902SRodney W. Grimes return (fi); 4939b50d902SRodney W. Grimes } 4949b50d902SRodney W. Grimes (void)Fclose(nfo); 4959b50d902SRodney W. Grimes (void)Fclose(fi); 4969b50d902SRodney W. Grimes rewind(nfi); 4979b50d902SRodney W. Grimes return (nfi); 4989b50d902SRodney W. Grimes } 4999b50d902SRodney W. Grimes 5009b50d902SRodney W. Grimes /* 5019b50d902SRodney W. Grimes * Dump the to, subject, cc header on the 5029b50d902SRodney W. Grimes * passed file buffer. 5039b50d902SRodney W. Grimes */ 5049b50d902SRodney W. Grimes int 5056d8484b0SPhilippe Charnier puthead(struct header *hp, FILE *fo, int w) 5069b50d902SRodney W. Grimes { 5079ce73e90SMike Heffner int gotcha; 5089b50d902SRodney W. Grimes 5099b50d902SRodney W. Grimes gotcha = 0; 5109ce73e90SMike Heffner if (hp->h_to != NULL && w & GTO) 5119b50d902SRodney W. Grimes fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; 5129ce73e90SMike Heffner if (hp->h_subject != NULL && w & GSUBJECT) 5139b50d902SRodney W. Grimes fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 5149ce73e90SMike Heffner if (hp->h_cc != NULL && w & GCC) 5159b50d902SRodney W. Grimes fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; 5169ce73e90SMike Heffner if (hp->h_bcc != NULL && w & GBCC) 5179b50d902SRodney W. Grimes fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; 5189ce73e90SMike Heffner if (hp->h_replyto != NULL && w & GREPLYTO) 51999bd6601SJoerg Wunsch fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++; 5209ce73e90SMike Heffner if (hp->h_inreplyto != NULL && w & GINREPLYTO) 52199bd6601SJoerg Wunsch fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++; 5229b50d902SRodney W. Grimes if (gotcha && w & GNL) 5239b50d902SRodney W. Grimes (void)putc('\n', fo); 5249b50d902SRodney W. Grimes return (0); 5259b50d902SRodney W. Grimes } 5269b50d902SRodney W. Grimes 5279b50d902SRodney W. Grimes /* 5289b50d902SRodney W. Grimes * Format the given header line to not exceed 72 characters. 5299b50d902SRodney W. Grimes */ 5309b50d902SRodney W. Grimes void 5316d8484b0SPhilippe Charnier fmt(const char *str, struct name *np, FILE *fo, int comma) 5329b50d902SRodney W. Grimes { 5339ce73e90SMike Heffner int col, len; 5349b50d902SRodney W. Grimes 5359b50d902SRodney W. Grimes comma = comma ? 1 : 0; 5369b50d902SRodney W. Grimes col = strlen(str); 5379b50d902SRodney W. Grimes if (col) 5389b50d902SRodney W. Grimes fputs(str, fo); 5399ce73e90SMike Heffner for (; np != NULL; np = np->n_flink) { 5409ce73e90SMike Heffner if (np->n_flink == NULL) 5419b50d902SRodney W. Grimes comma = 0; 5429b50d902SRodney W. Grimes len = strlen(np->n_name); 5439b50d902SRodney W. Grimes col++; /* for the space */ 5449b50d902SRodney W. Grimes if (col + len + comma > 72 && col > 4) { 5459ce73e90SMike Heffner fprintf(fo, "\n "); 5469b50d902SRodney W. Grimes col = 4; 5479b50d902SRodney W. Grimes } else 5489ce73e90SMike Heffner fprintf(fo, " "); 5499b50d902SRodney W. Grimes fputs(np->n_name, fo); 5509b50d902SRodney W. Grimes if (comma) 5519ce73e90SMike Heffner fprintf(fo, ","); 5529b50d902SRodney W. Grimes col += len + comma; 5539b50d902SRodney W. Grimes } 5549ce73e90SMike Heffner fprintf(fo, "\n"); 5559b50d902SRodney W. Grimes } 5569b50d902SRodney W. Grimes 5579b50d902SRodney W. Grimes /* 5589b50d902SRodney W. Grimes * Save the outgoing mail on the passed file. 5599b50d902SRodney W. Grimes */ 5609b50d902SRodney W. Grimes 5619b50d902SRodney W. Grimes /*ARGSUSED*/ 5629b50d902SRodney W. Grimes int 5636d8484b0SPhilippe Charnier savemail(char name[], FILE *fi) 5649b50d902SRodney W. Grimes { 5659ce73e90SMike Heffner FILE *fo; 5669b50d902SRodney W. Grimes char buf[BUFSIZ]; 5679ce73e90SMike Heffner int i; 5689ce73e90SMike Heffner time_t now; 569c0d0b766SXin LI mode_t saved_umask; 5709b50d902SRodney W. Grimes 571c0d0b766SXin LI saved_umask = umask(077); 572c0d0b766SXin LI fo = Fopen(name, "a"); 573c0d0b766SXin LI umask(saved_umask); 574c0d0b766SXin LI 575c0d0b766SXin LI if (fo == NULL) { 5760c3a8314SMike Heffner warn("%s", name); 5779b50d902SRodney W. Grimes return (-1); 5789b50d902SRodney W. Grimes } 5799b50d902SRodney W. Grimes (void)time(&now); 5809b50d902SRodney W. Grimes fprintf(fo, "From %s %s", myname, ctime(&now)); 5819ce73e90SMike Heffner while ((i = fread(buf, 1, sizeof(buf), fi)) > 0) 5829b50d902SRodney W. Grimes (void)fwrite(buf, 1, i, fo); 5839ce73e90SMike Heffner fprintf(fo, "\n"); 5849b50d902SRodney W. Grimes (void)fflush(fo); 5859b50d902SRodney W. Grimes if (ferror(fo)) 5860c3a8314SMike Heffner warn("%s", name); 5879b50d902SRodney W. Grimes (void)Fclose(fo); 5889b50d902SRodney W. Grimes rewind(fi); 5899b50d902SRodney W. Grimes return (0); 5909b50d902SRodney W. Grimes } 591