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. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 349b50d902SRodney W. Grimes #ifndef lint 350c3a8314SMike Heffner #if 0 369b50d902SRodney W. Grimes static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; 370c3a8314SMike Heffner #endif 380c3a8314SMike Heffner static const char rcsid[] = 390c3a8314SMike Heffner "$FreeBSD$"; 409b50d902SRodney W. Grimes #endif /* not lint */ 419b50d902SRodney W. Grimes 429b50d902SRodney W. Grimes #include "rcv.h" 439b50d902SRodney W. Grimes #include "extern.h" 449b50d902SRodney W. Grimes 459b50d902SRodney W. Grimes /* 469b50d902SRodney W. Grimes * Mail -- a mail program 479b50d902SRodney W. Grimes * 489b50d902SRodney W. Grimes * Mail to others. 499b50d902SRodney W. Grimes */ 509b50d902SRodney W. Grimes 519b50d902SRodney W. Grimes /* 529b50d902SRodney W. Grimes * Send message described by the passed pointer to the 539b50d902SRodney W. Grimes * passed output buffer. Return -1 on error. 549b50d902SRodney W. Grimes * Adjust the status: field if need be. 559b50d902SRodney W. Grimes * If doign is given, suppress ignored header fields. 569b50d902SRodney W. Grimes * prefix is a string to prepend to each output line. 579b50d902SRodney W. Grimes */ 589b50d902SRodney W. Grimes int 590c3a8314SMike Heffner sendmessage(mp, obuf, doign, prefix) 609ce73e90SMike Heffner struct message *mp; 619b50d902SRodney W. Grimes FILE *obuf; 629b50d902SRodney W. Grimes struct ignoretab *doign; 639b50d902SRodney W. Grimes char *prefix; 649b50d902SRodney W. Grimes { 659b50d902SRodney W. Grimes long count; 669ce73e90SMike Heffner FILE *ibuf; 679ce73e90SMike Heffner char *cp, *cp2, line[LINESIZE]; 689b50d902SRodney W. Grimes int ishead, infld, ignoring, dostat, firstline; 699ce73e90SMike Heffner int c, length, prefixlen; 709b50d902SRodney W. Grimes 719b50d902SRodney W. Grimes /* 729b50d902SRodney W. Grimes * Compute the prefix string, without trailing whitespace 739b50d902SRodney W. Grimes */ 749ce73e90SMike Heffner if (prefix != NULL) { 759b50d902SRodney W. Grimes cp2 = 0; 769ce73e90SMike Heffner for (cp = prefix; *cp != '\0'; cp++) 779b50d902SRodney W. Grimes if (*cp != ' ' && *cp != '\t') 789b50d902SRodney W. Grimes cp2 = cp; 799ce73e90SMike Heffner prefixlen = cp2 == NULL ? 0 : cp2 - prefix + 1; 809b50d902SRodney W. Grimes } 819b50d902SRodney W. Grimes ibuf = setinput(mp); 829b50d902SRodney W. Grimes count = mp->m_size; 839b50d902SRodney W. Grimes ishead = 1; 849b50d902SRodney W. Grimes dostat = doign == 0 || !isign("status", doign); 859b50d902SRodney W. Grimes infld = 0; 869b50d902SRodney W. Grimes firstline = 1; 879b50d902SRodney W. Grimes /* 889b50d902SRodney W. Grimes * Process headers first 899b50d902SRodney W. Grimes */ 909b50d902SRodney W. Grimes while (count > 0 && ishead) { 910c3a8314SMike Heffner if (fgets(line, sizeof(line), ibuf) == NULL) 929b50d902SRodney W. Grimes break; 939b50d902SRodney W. Grimes count -= length = strlen(line); 949b50d902SRodney W. Grimes if (firstline) { 959b50d902SRodney W. Grimes /* 969b50d902SRodney W. Grimes * First line is the From line, so no headers 979b50d902SRodney W. Grimes * there to worry about 989b50d902SRodney W. Grimes */ 999b50d902SRodney W. Grimes firstline = 0; 1009b50d902SRodney W. Grimes ignoring = doign == ignoreall; 1019b50d902SRodney W. Grimes } else if (line[0] == '\n') { 1029b50d902SRodney W. Grimes /* 1039b50d902SRodney W. Grimes * If line is blank, we've reached end of 1049b50d902SRodney W. Grimes * headers, so force out status: field 1059b50d902SRodney W. Grimes * and note that we are no longer in header 1069b50d902SRodney W. Grimes * fields 1079b50d902SRodney W. Grimes */ 1089b50d902SRodney W. Grimes if (dostat) { 1099b50d902SRodney W. Grimes statusput(mp, obuf, prefix); 1109b50d902SRodney W. Grimes dostat = 0; 1119b50d902SRodney W. Grimes } 1129b50d902SRodney W. Grimes ishead = 0; 1139b50d902SRodney W. Grimes ignoring = doign == ignoreall; 1149b50d902SRodney W. Grimes } else if (infld && (line[0] == ' ' || line[0] == '\t')) { 1159b50d902SRodney W. Grimes /* 1169b50d902SRodney W. Grimes * If this line is a continuation (via space or tab) 1179b50d902SRodney W. Grimes * of a previous header field, just echo it 1189b50d902SRodney W. Grimes * (unless the field should be ignored). 1199b50d902SRodney W. Grimes * In other words, nothing to do. 1209b50d902SRodney W. Grimes */ 1219b50d902SRodney W. Grimes } else { 1229b50d902SRodney W. Grimes /* 1239b50d902SRodney W. Grimes * Pick up the header field if we have one. 1249b50d902SRodney W. Grimes */ 1259ce73e90SMike Heffner for (cp = line; (c = *cp++) != '\0' && c != ':' && 1269ce73e90SMike Heffner !isspace(c);) 1279b50d902SRodney W. Grimes ; 1289b50d902SRodney W. Grimes cp2 = --cp; 1299b50d902SRodney W. Grimes while (isspace(*cp++)) 1309b50d902SRodney W. Grimes ; 1319b50d902SRodney W. Grimes if (cp[-1] != ':') { 1329b50d902SRodney W. Grimes /* 1339b50d902SRodney W. Grimes * Not a header line, force out status: 1349b50d902SRodney W. Grimes * This happens in uucp style mail where 1359b50d902SRodney W. Grimes * there are no headers at all. 1369b50d902SRodney W. Grimes */ 1379b50d902SRodney W. Grimes if (dostat) { 1389b50d902SRodney W. Grimes statusput(mp, obuf, prefix); 1399b50d902SRodney W. Grimes dostat = 0; 1409b50d902SRodney W. Grimes } 1419b50d902SRodney W. Grimes if (doign != ignoreall) 1429b50d902SRodney W. Grimes /* add blank line */ 1439b50d902SRodney W. Grimes (void)putc('\n', obuf); 1449b50d902SRodney W. Grimes ishead = 0; 1459b50d902SRodney W. Grimes ignoring = 0; 1469b50d902SRodney W. Grimes } else { 1479b50d902SRodney W. Grimes /* 1489b50d902SRodney W. Grimes * If it is an ignored field and 1499b50d902SRodney W. Grimes * we care about such things, skip it. 1509b50d902SRodney W. Grimes */ 1519ce73e90SMike Heffner *cp2 = '\0'; /* temporarily null terminate */ 1529b50d902SRodney W. Grimes if (doign && isign(line, doign)) 1539b50d902SRodney W. Grimes ignoring = 1; 1549b50d902SRodney W. Grimes else if ((line[0] == 's' || line[0] == 'S') && 1559b50d902SRodney W. Grimes strcasecmp(line, "status") == 0) { 1569b50d902SRodney W. Grimes /* 1579b50d902SRodney W. Grimes * If the field is "status," go compute 1589b50d902SRodney W. Grimes * and print the real Status: field 1599b50d902SRodney W. Grimes */ 1609b50d902SRodney W. Grimes if (dostat) { 1619b50d902SRodney W. Grimes statusput(mp, obuf, prefix); 1629b50d902SRodney W. Grimes dostat = 0; 1639b50d902SRodney W. Grimes } 1649b50d902SRodney W. Grimes ignoring = 1; 1659b50d902SRodney W. Grimes } else { 1669b50d902SRodney W. Grimes ignoring = 0; 1679b50d902SRodney W. Grimes *cp2 = c; /* restore */ 1689b50d902SRodney W. Grimes } 1699b50d902SRodney W. Grimes infld = 1; 1709b50d902SRodney W. Grimes } 1719b50d902SRodney W. Grimes } 1729b50d902SRodney W. Grimes if (!ignoring) { 1739b50d902SRodney W. Grimes /* 1749b50d902SRodney W. Grimes * Strip trailing whitespace from prefix 1759b50d902SRodney W. Grimes * if line is blank. 1769b50d902SRodney W. Grimes */ 1779ce73e90SMike Heffner if (prefix != NULL) { 1789b50d902SRodney W. Grimes if (length > 1) 1799b50d902SRodney W. Grimes fputs(prefix, obuf); 1809b50d902SRodney W. Grimes else 1819ce73e90SMike Heffner (void)fwrite(prefix, sizeof(*prefix), 1829b50d902SRodney W. Grimes prefixlen, obuf); 1830c3a8314SMike Heffner } 1849ce73e90SMike Heffner (void)fwrite(line, sizeof(*line), length, obuf); 1859b50d902SRodney W. Grimes if (ferror(obuf)) 1869ce73e90SMike Heffner return (-1); 1879b50d902SRodney W. Grimes } 1889b50d902SRodney W. Grimes } 1899b50d902SRodney W. Grimes /* 1909b50d902SRodney W. Grimes * Copy out message body 1919b50d902SRodney W. Grimes */ 1929b50d902SRodney W. Grimes if (doign == ignoreall) 1939b50d902SRodney W. Grimes count--; /* skip final blank line */ 1949ce73e90SMike Heffner if (prefix != NULL) 1959b50d902SRodney W. Grimes while (count > 0) { 1960c3a8314SMike Heffner if (fgets(line, sizeof(line), ibuf) == NULL) { 1979b50d902SRodney W. Grimes c = 0; 1989b50d902SRodney W. Grimes break; 1999b50d902SRodney W. Grimes } 2009b50d902SRodney W. Grimes count -= c = strlen(line); 2019b50d902SRodney W. Grimes /* 2029b50d902SRodney W. Grimes * Strip trailing whitespace from prefix 2039b50d902SRodney W. Grimes * if line is blank. 2049b50d902SRodney W. Grimes */ 2059b50d902SRodney W. Grimes if (c > 1) 2069b50d902SRodney W. Grimes fputs(prefix, obuf); 2079b50d902SRodney W. Grimes else 2089ce73e90SMike Heffner (void)fwrite(prefix, sizeof(*prefix), 2099b50d902SRodney W. Grimes prefixlen, obuf); 2109ce73e90SMike Heffner (void)fwrite(line, sizeof(*line), c, obuf); 2119b50d902SRodney W. Grimes if (ferror(obuf)) 2129ce73e90SMike Heffner return (-1); 2139b50d902SRodney W. Grimes } 2149b50d902SRodney W. Grimes else 2159b50d902SRodney W. Grimes while (count > 0) { 2169b50d902SRodney W. Grimes c = count < LINESIZE ? count : LINESIZE; 2179ce73e90SMike Heffner if ((c = fread(line, sizeof(*line), c, ibuf)) <= 0) 2189b50d902SRodney W. Grimes break; 2199b50d902SRodney W. Grimes count -= c; 2209ce73e90SMike Heffner if (fwrite(line, sizeof(*line), c, obuf) != c) 2219ce73e90SMike Heffner return (-1); 2229b50d902SRodney W. Grimes } 2239b50d902SRodney W. Grimes if (doign == ignoreall && c > 0 && line[c - 1] != '\n') 2249b50d902SRodney W. Grimes /* no final blank line */ 2259b50d902SRodney W. Grimes if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) 2269ce73e90SMike Heffner return (-1); 2279ce73e90SMike Heffner return (0); 2289b50d902SRodney W. Grimes } 2299b50d902SRodney W. Grimes 2309b50d902SRodney W. Grimes /* 2319b50d902SRodney W. Grimes * Output a reasonable looking status field. 2329b50d902SRodney W. Grimes */ 2339b50d902SRodney W. Grimes void 2349b50d902SRodney W. Grimes statusput(mp, obuf, prefix) 2359ce73e90SMike Heffner struct message *mp; 2369b50d902SRodney W. Grimes FILE *obuf; 2379b50d902SRodney W. Grimes char *prefix; 2389b50d902SRodney W. Grimes { 2399b50d902SRodney W. Grimes char statout[3]; 2409ce73e90SMike Heffner char *cp = statout; 2419b50d902SRodney W. Grimes 2429b50d902SRodney W. Grimes if (mp->m_flag & MREAD) 2439b50d902SRodney W. Grimes *cp++ = 'R'; 2449b50d902SRodney W. Grimes if ((mp->m_flag & MNEW) == 0) 2459b50d902SRodney W. Grimes *cp++ = 'O'; 2469ce73e90SMike Heffner *cp = '\0'; 2479ce73e90SMike Heffner if (statout[0] != '\0') 2489b50d902SRodney W. Grimes fprintf(obuf, "%sStatus: %s\n", 2499ce73e90SMike Heffner prefix == NULL ? "" : prefix, statout); 2509b50d902SRodney W. Grimes } 2519b50d902SRodney W. Grimes 2529b50d902SRodney W. Grimes /* 2539b50d902SRodney W. Grimes * Interface between the argument list and the mail1 routine 2549b50d902SRodney W. Grimes * which does all the dirty work. 2559b50d902SRodney W. Grimes */ 2569b50d902SRodney W. Grimes int 25799bd6601SJoerg Wunsch mail(to, cc, bcc, smopts, subject, replyto) 2589b50d902SRodney W. Grimes struct name *to, *cc, *bcc, *smopts; 25999bd6601SJoerg Wunsch char *subject, *replyto; 2609b50d902SRodney W. Grimes { 2619b50d902SRodney W. Grimes struct header head; 2629b50d902SRodney W. Grimes 2639b50d902SRodney W. Grimes head.h_to = to; 2649b50d902SRodney W. Grimes head.h_subject = subject; 2659b50d902SRodney W. Grimes head.h_cc = cc; 2669b50d902SRodney W. Grimes head.h_bcc = bcc; 2679b50d902SRodney W. Grimes head.h_smopts = smopts; 26899bd6601SJoerg Wunsch head.h_replyto = replyto; 2699ce73e90SMike Heffner head.h_inreplyto = NULL; 2709b50d902SRodney W. Grimes mail1(&head, 0); 2719b50d902SRodney W. Grimes return (0); 2729b50d902SRodney W. Grimes } 2739b50d902SRodney W. Grimes 2749b50d902SRodney W. Grimes 2759b50d902SRodney W. Grimes /* 2769b50d902SRodney W. Grimes * Send mail to a bunch of user names. The interface is through 2779b50d902SRodney W. Grimes * the mail routine below. 2789b50d902SRodney W. Grimes */ 2799b50d902SRodney W. Grimes int 2809b50d902SRodney W. Grimes sendmail(str) 2819b50d902SRodney W. Grimes char *str; 2829b50d902SRodney W. Grimes { 2839b50d902SRodney W. Grimes struct header head; 2849b50d902SRodney W. Grimes 2859b50d902SRodney W. Grimes head.h_to = extract(str, GTO); 2869ce73e90SMike Heffner head.h_subject = NULL; 2879ce73e90SMike Heffner head.h_cc = NULL; 2889ce73e90SMike Heffner head.h_bcc = NULL; 2899ce73e90SMike Heffner head.h_smopts = NULL; 29099bd6601SJoerg Wunsch if ((head.h_replyto = getenv("REPLYTO")) == NULL) 2919ce73e90SMike Heffner head.h_replyto = NULL; 2929ce73e90SMike Heffner head.h_inreplyto = NULL; 2939b50d902SRodney W. Grimes mail1(&head, 0); 2949b50d902SRodney W. Grimes return (0); 2959b50d902SRodney W. Grimes } 2969b50d902SRodney W. Grimes 2979b50d902SRodney W. Grimes /* 2989b50d902SRodney W. Grimes * Mail a message on standard input to the people indicated 2999b50d902SRodney W. Grimes * in the passed header. (Internal interface). 3009b50d902SRodney W. Grimes */ 3019b50d902SRodney W. Grimes void 3029b50d902SRodney W. Grimes mail1(hp, printheaders) 3039b50d902SRodney W. Grimes struct header *hp; 3049b50d902SRodney W. Grimes int printheaders; 3059b50d902SRodney W. Grimes { 3069b50d902SRodney W. Grimes char *cp; 3079b50d902SRodney W. Grimes int pid; 3089b50d902SRodney W. Grimes char **namelist; 3099b50d902SRodney W. Grimes struct name *to; 3109b50d902SRodney W. Grimes FILE *mtf; 3119b50d902SRodney W. Grimes 3129b50d902SRodney W. Grimes /* 3139b50d902SRodney W. Grimes * Collect user's mail from standard input. 3149b50d902SRodney W. Grimes * Get the result as mtf. 3159b50d902SRodney W. Grimes */ 3169b50d902SRodney W. Grimes if ((mtf = collect(hp, printheaders)) == NULL) 3179b50d902SRodney W. Grimes return; 3189ce73e90SMike Heffner if (value("interactive") != NULL) { 3199ce73e90SMike Heffner if (value("askcc") != NULL) 3209b50d902SRodney W. Grimes grabh(hp, GCC); 3219b50d902SRodney W. Grimes else { 3229b50d902SRodney W. Grimes printf("EOT\n"); 3239b50d902SRodney W. Grimes (void)fflush(stdout); 3249b50d902SRodney W. Grimes } 3250c3a8314SMike Heffner } 3260c3a8314SMike Heffner if (fsize(mtf) == 0) { 3279ce73e90SMike Heffner if (hp->h_subject == NULL) 3289b50d902SRodney W. Grimes printf("No message, no subject; hope that's ok\n"); 3299b50d902SRodney W. Grimes else 3309b50d902SRodney W. Grimes printf("Null message body; hope that's ok\n"); 3310c3a8314SMike Heffner } 3329b50d902SRodney W. Grimes /* 3339b50d902SRodney W. Grimes * Now, take the user names from the combined 3349b50d902SRodney W. Grimes * to and cc lists and do all the alias 3359b50d902SRodney W. Grimes * processing. 3369b50d902SRodney W. Grimes */ 3379b50d902SRodney W. Grimes senderr = 0; 3389b50d902SRodney W. Grimes to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); 3399ce73e90SMike Heffner if (to == NULL) { 3409b50d902SRodney W. Grimes printf("No recipients specified\n"); 3419b50d902SRodney W. Grimes senderr++; 3429b50d902SRodney W. Grimes } 3439b50d902SRodney W. Grimes /* 3449b50d902SRodney W. Grimes * Look through the recipient list for names with /'s 3459b50d902SRodney W. Grimes * in them which we write to as files directly. 3469b50d902SRodney W. Grimes */ 3479b50d902SRodney W. Grimes to = outof(to, mtf, hp); 3489b50d902SRodney W. Grimes if (senderr) 3499b50d902SRodney W. Grimes savedeadletter(mtf); 3509b50d902SRodney W. Grimes to = elide(to); 3519b50d902SRodney W. Grimes if (count(to) == 0) 3529b50d902SRodney W. Grimes goto out; 3539b50d902SRodney W. Grimes fixhead(hp, to); 3549b50d902SRodney W. Grimes if ((mtf = infix(hp, mtf)) == NULL) { 3559b50d902SRodney W. Grimes fprintf(stderr, ". . . message lost, sorry.\n"); 3569b50d902SRodney W. Grimes return; 3579b50d902SRodney W. Grimes } 3589b50d902SRodney W. Grimes namelist = unpack(cat(hp->h_smopts, to)); 3599b50d902SRodney W. Grimes if (debug) { 3609b50d902SRodney W. Grimes char **t; 3619b50d902SRodney W. Grimes 3629b50d902SRodney W. Grimes printf("Sendmail arguments:"); 3639ce73e90SMike Heffner for (t = namelist; *t != NULL; t++) 3649b50d902SRodney W. Grimes printf(" \"%s\"", *t); 3659b50d902SRodney W. Grimes printf("\n"); 3669b50d902SRodney W. Grimes goto out; 3679b50d902SRodney W. Grimes } 3689ce73e90SMike Heffner if ((cp = value("record")) != NULL) 3699b50d902SRodney W. Grimes (void)savemail(expand(cp), mtf); 3709b50d902SRodney W. Grimes /* 3719b50d902SRodney W. Grimes * Fork, set up the temporary mail file as standard 3729b50d902SRodney W. Grimes * input for "mail", and exec with the user list we generated 3739b50d902SRodney W. Grimes * far above. 3749b50d902SRodney W. Grimes */ 3759b50d902SRodney W. Grimes pid = fork(); 3769b50d902SRodney W. Grimes if (pid == -1) { 3770c3a8314SMike Heffner warn("fork"); 3789b50d902SRodney W. Grimes savedeadletter(mtf); 3799b50d902SRodney W. Grimes goto out; 3809b50d902SRodney W. Grimes } 3819b50d902SRodney W. Grimes if (pid == 0) { 3829b50d902SRodney W. Grimes prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)| 3839b50d902SRodney W. Grimes sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU), 3849b50d902SRodney W. Grimes fileno(mtf), -1); 3859ce73e90SMike Heffner if ((cp = value("sendmail")) != NULL) 3869b50d902SRodney W. Grimes cp = expand(cp); 3879b50d902SRodney W. Grimes else 3889b50d902SRodney W. Grimes cp = _PATH_SENDMAIL; 3899b50d902SRodney W. Grimes execv(cp, namelist); 3900c3a8314SMike Heffner warn("%s", cp); 3919b50d902SRodney W. Grimes _exit(1); 3929b50d902SRodney W. Grimes } 3939ce73e90SMike Heffner if (value("verbose") != NULL) 3949b50d902SRodney W. Grimes (void)wait_child(pid); 3959b50d902SRodney W. Grimes else 3969b50d902SRodney W. Grimes free_child(pid); 3979b50d902SRodney W. Grimes out: 3989b50d902SRodney W. Grimes (void)Fclose(mtf); 3999b50d902SRodney W. Grimes } 4009b50d902SRodney W. Grimes 4019b50d902SRodney W. Grimes /* 4029b50d902SRodney W. Grimes * Fix the header by glopping all of the expanded names from 4039b50d902SRodney W. Grimes * the distribution list into the appropriate fields. 4049b50d902SRodney W. Grimes */ 4059b50d902SRodney W. Grimes void 4069b50d902SRodney W. Grimes fixhead(hp, tolist) 4079b50d902SRodney W. Grimes struct header *hp; 4089b50d902SRodney W. Grimes struct name *tolist; 4099b50d902SRodney W. Grimes { 4109ce73e90SMike Heffner struct name *np; 4119b50d902SRodney W. Grimes 4129ce73e90SMike Heffner hp->h_to = NULL; 4139ce73e90SMike Heffner hp->h_cc = NULL; 4149ce73e90SMike Heffner hp->h_bcc = NULL; 4159ce73e90SMike Heffner for (np = tolist; np != NULL; np = np->n_flink) 4169b50d902SRodney W. Grimes if ((np->n_type & GMASK) == GTO) 4179b50d902SRodney W. Grimes hp->h_to = 4189b50d902SRodney W. Grimes cat(hp->h_to, nalloc(np->n_name, np->n_type)); 4199b50d902SRodney W. Grimes else if ((np->n_type & GMASK) == GCC) 4209b50d902SRodney W. Grimes hp->h_cc = 4219b50d902SRodney W. Grimes cat(hp->h_cc, nalloc(np->n_name, np->n_type)); 4229b50d902SRodney W. Grimes else if ((np->n_type & GMASK) == GBCC) 4239b50d902SRodney W. Grimes hp->h_bcc = 4249b50d902SRodney W. Grimes cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); 4259b50d902SRodney W. Grimes } 4269b50d902SRodney W. Grimes 4279b50d902SRodney W. Grimes /* 4289b50d902SRodney W. Grimes * Prepend a header in front of the collected stuff 4299b50d902SRodney W. Grimes * and return the new file. 4309b50d902SRodney W. Grimes */ 4319b50d902SRodney W. Grimes FILE * 4329b50d902SRodney W. Grimes infix(hp, fi) 4339b50d902SRodney W. Grimes struct header *hp; 4349b50d902SRodney W. Grimes FILE *fi; 4359b50d902SRodney W. Grimes { 4369ce73e90SMike Heffner FILE *nfo, *nfi; 4379ce73e90SMike Heffner int c, fd; 4380c3a8314SMike Heffner char tempname[PATHSIZE]; 4399b50d902SRodney W. Grimes 4409ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 4419ce73e90SMike Heffner "%s/mail.RsXXXXXXXXXX", tmpdir); 4420c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 4430c3a8314SMike Heffner (nfo = Fdopen(fd, "w")) == NULL) { 4440c3a8314SMike Heffner warn("%s", tempname); 4459b50d902SRodney W. Grimes return (fi); 4469b50d902SRodney W. Grimes } 4470c3a8314SMike Heffner if ((nfi = Fopen(tempname, "r")) == NULL) { 4480c3a8314SMike Heffner warn("%s", tempname); 4499b50d902SRodney W. Grimes (void)Fclose(nfo); 4500c3a8314SMike Heffner (void)rm(tempname); 4519b50d902SRodney W. Grimes return (fi); 4529b50d902SRodney W. Grimes } 4530c3a8314SMike Heffner (void)rm(tempname); 45457392071SJoerg Wunsch (void)puthead(hp, nfo, 45557392071SJoerg Wunsch GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA); 4569b50d902SRodney W. Grimes c = getc(fi); 4579b50d902SRodney W. Grimes while (c != EOF) { 4589b50d902SRodney W. Grimes (void)putc(c, nfo); 4599b50d902SRodney W. Grimes c = getc(fi); 4609b50d902SRodney W. Grimes } 4619b50d902SRodney W. Grimes if (ferror(fi)) { 4620c3a8314SMike Heffner warnx("read"); 4639b50d902SRodney W. Grimes rewind(fi); 4649b50d902SRodney W. Grimes return (fi); 4659b50d902SRodney W. Grimes } 4669b50d902SRodney W. Grimes (void)fflush(nfo); 4679b50d902SRodney W. Grimes if (ferror(nfo)) { 4680c3a8314SMike Heffner warn("%s", tempname); 4699b50d902SRodney W. Grimes (void)Fclose(nfo); 4709b50d902SRodney W. Grimes (void)Fclose(nfi); 4719b50d902SRodney W. Grimes rewind(fi); 4729b50d902SRodney W. Grimes return (fi); 4739b50d902SRodney W. Grimes } 4749b50d902SRodney W. Grimes (void)Fclose(nfo); 4759b50d902SRodney W. Grimes (void)Fclose(fi); 4769b50d902SRodney W. Grimes rewind(nfi); 4779b50d902SRodney W. Grimes return (nfi); 4789b50d902SRodney W. Grimes } 4799b50d902SRodney W. Grimes 4809b50d902SRodney W. Grimes /* 4819b50d902SRodney W. Grimes * Dump the to, subject, cc header on the 4829b50d902SRodney W. Grimes * passed file buffer. 4839b50d902SRodney W. Grimes */ 4849b50d902SRodney W. Grimes int 4859b50d902SRodney W. Grimes puthead(hp, fo, w) 4869b50d902SRodney W. Grimes struct header *hp; 4879b50d902SRodney W. Grimes FILE *fo; 4889b50d902SRodney W. Grimes int w; 4899b50d902SRodney W. Grimes { 4909ce73e90SMike Heffner int gotcha; 4919b50d902SRodney W. Grimes 4929b50d902SRodney W. Grimes gotcha = 0; 4939ce73e90SMike Heffner if (hp->h_to != NULL && w & GTO) 4949b50d902SRodney W. Grimes fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; 4959ce73e90SMike Heffner if (hp->h_subject != NULL && w & GSUBJECT) 4969b50d902SRodney W. Grimes fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 4979ce73e90SMike Heffner if (hp->h_cc != NULL && w & GCC) 4989b50d902SRodney W. Grimes fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; 4999ce73e90SMike Heffner if (hp->h_bcc != NULL && w & GBCC) 5009b50d902SRodney W. Grimes fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; 5019ce73e90SMike Heffner if (hp->h_replyto != NULL && w & GREPLYTO) 50299bd6601SJoerg Wunsch fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++; 5039ce73e90SMike Heffner if (hp->h_inreplyto != NULL && w & GINREPLYTO) 50499bd6601SJoerg Wunsch fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++; 5059b50d902SRodney W. Grimes if (gotcha && w & GNL) 5069b50d902SRodney W. Grimes (void)putc('\n', fo); 5079b50d902SRodney W. Grimes return (0); 5089b50d902SRodney W. Grimes } 5099b50d902SRodney W. Grimes 5109b50d902SRodney W. Grimes /* 5119b50d902SRodney W. Grimes * Format the given header line to not exceed 72 characters. 5129b50d902SRodney W. Grimes */ 5139b50d902SRodney W. Grimes void 5149b50d902SRodney W. Grimes fmt(str, np, fo, comma) 5159ce73e90SMike Heffner const char *str; 5169ce73e90SMike Heffner struct name *np; 5179b50d902SRodney W. Grimes FILE *fo; 5189b50d902SRodney W. Grimes int comma; 5199b50d902SRodney W. Grimes { 5209ce73e90SMike Heffner int col, len; 5219b50d902SRodney W. Grimes 5229b50d902SRodney W. Grimes comma = comma ? 1 : 0; 5239b50d902SRodney W. Grimes col = strlen(str); 5249b50d902SRodney W. Grimes if (col) 5259b50d902SRodney W. Grimes fputs(str, fo); 5269ce73e90SMike Heffner for (; np != NULL; np = np->n_flink) { 5279ce73e90SMike Heffner if (np->n_flink == NULL) 5289b50d902SRodney W. Grimes comma = 0; 5299b50d902SRodney W. Grimes len = strlen(np->n_name); 5309b50d902SRodney W. Grimes col++; /* for the space */ 5319b50d902SRodney W. Grimes if (col + len + comma > 72 && col > 4) { 5329ce73e90SMike Heffner fprintf(fo, "\n "); 5339b50d902SRodney W. Grimes col = 4; 5349b50d902SRodney W. Grimes } else 5359ce73e90SMike Heffner fprintf(fo, " "); 5369b50d902SRodney W. Grimes fputs(np->n_name, fo); 5379b50d902SRodney W. Grimes if (comma) 5389ce73e90SMike Heffner fprintf(fo, ","); 5399b50d902SRodney W. Grimes col += len + comma; 5409b50d902SRodney W. Grimes } 5419ce73e90SMike Heffner fprintf(fo, "\n"); 5429b50d902SRodney W. Grimes } 5439b50d902SRodney W. Grimes 5449b50d902SRodney W. Grimes /* 5459b50d902SRodney W. Grimes * Save the outgoing mail on the passed file. 5469b50d902SRodney W. Grimes */ 5479b50d902SRodney W. Grimes 5489b50d902SRodney W. Grimes /*ARGSUSED*/ 5499b50d902SRodney W. Grimes int 5509b50d902SRodney W. Grimes savemail(name, fi) 5519b50d902SRodney W. Grimes char name[]; 5529ce73e90SMike Heffner FILE *fi; 5539b50d902SRodney W. Grimes { 5549ce73e90SMike Heffner FILE *fo; 5559b50d902SRodney W. Grimes char buf[BUFSIZ]; 5569ce73e90SMike Heffner int i; 5579ce73e90SMike Heffner time_t now; 5589b50d902SRodney W. Grimes 5599b50d902SRodney W. Grimes if ((fo = Fopen(name, "a")) == NULL) { 5600c3a8314SMike Heffner warn("%s", name); 5619b50d902SRodney W. Grimes return (-1); 5629b50d902SRodney W. Grimes } 5639b50d902SRodney W. Grimes (void)time(&now); 5649b50d902SRodney W. Grimes fprintf(fo, "From %s %s", myname, ctime(&now)); 5659ce73e90SMike Heffner while ((i = fread(buf, 1, sizeof(buf), fi)) > 0) 5669b50d902SRodney W. Grimes (void)fwrite(buf, 1, i, fo); 5679ce73e90SMike Heffner fprintf(fo, "\n"); 5689b50d902SRodney W. Grimes (void)fflush(fo); 5699b50d902SRodney W. Grimes if (ferror(fo)) 5700c3a8314SMike Heffner warn("%s", name); 5719b50d902SRodney W. Grimes (void)Fclose(fo); 5729b50d902SRodney W. Grimes rewind(fi); 5739b50d902SRodney W. Grimes return (0); 5749b50d902SRodney W. Grimes } 575