10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate 230Sstevel@tonic-gate /* 240Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 28*18Srobbin /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29*18Srobbin /* All Rights Reserved */ 30*18Srobbin 310Sstevel@tonic-gate /* 320Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 330Sstevel@tonic-gate * The Regents of the University of California 340Sstevel@tonic-gate * All Rights Reserved 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 370Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 380Sstevel@tonic-gate * contributors. 390Sstevel@tonic-gate */ 400Sstevel@tonic-gate 410Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include "rcv.h" 440Sstevel@tonic-gate #include <locale.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * mailx -- a modified version of a University of California at Berkeley 480Sstevel@tonic-gate * mail program 490Sstevel@tonic-gate * 500Sstevel@tonic-gate * Mail to others. 510Sstevel@tonic-gate */ 520Sstevel@tonic-gate 530Sstevel@tonic-gate static void fmt(register char *str, register FILE *fo); 540Sstevel@tonic-gate static FILE *infix(struct header *hp, FILE *fi); 550Sstevel@tonic-gate static void statusput(register struct message *mp, register FILE *obuf, int doign, int (*fp)(const char *, FILE *)); 560Sstevel@tonic-gate static int savemail(char name[], struct header *hp, FILE *fi); 570Sstevel@tonic-gate static int sendmail(char *str); 580Sstevel@tonic-gate static int Sendmail(char *str); 590Sstevel@tonic-gate 600Sstevel@tonic-gate static off_t textpos; 610Sstevel@tonic-gate 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * Send message described by the passed pointer to the 640Sstevel@tonic-gate * passed output buffer. Return -1 on error, but normally 650Sstevel@tonic-gate * the number of lines written. Adjust the status: field 660Sstevel@tonic-gate * if need be. If doign is set, suppress ignored header fields. 670Sstevel@tonic-gate * Call (*fp)(line, obuf) to print the line. 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate long 700Sstevel@tonic-gate msend( 710Sstevel@tonic-gate struct message *mailp, 720Sstevel@tonic-gate FILE *obuf, 730Sstevel@tonic-gate int flag, 740Sstevel@tonic-gate int (*fp)(const char *, FILE *)) 750Sstevel@tonic-gate { 760Sstevel@tonic-gate register struct message *mp; 770Sstevel@tonic-gate long clen, n, c; 780Sstevel@tonic-gate FILE *ibuf; 790Sstevel@tonic-gate char line[LINESIZE], field[BUFSIZ]; 800Sstevel@tonic-gate int ishead, infld, fline, dostat, doclen, nread, unused; 810Sstevel@tonic-gate char *cp, *cp2; 820Sstevel@tonic-gate int doign = flag & M_IGNORE; 830Sstevel@tonic-gate int oldign = 0; /* previous line was ignored */ 840Sstevel@tonic-gate long lc; 850Sstevel@tonic-gate 860Sstevel@tonic-gate mp = mailp; 870Sstevel@tonic-gate if (mp->m_clen == 0) 880Sstevel@tonic-gate setclen(mp); 890Sstevel@tonic-gate ibuf = setinput(mp); 900Sstevel@tonic-gate c = mp->m_size; 910Sstevel@tonic-gate ishead = 1; 920Sstevel@tonic-gate dostat = 1; 930Sstevel@tonic-gate doclen = 1; 940Sstevel@tonic-gate infld = 0; 950Sstevel@tonic-gate fline = 1; 960Sstevel@tonic-gate lc = 0; 970Sstevel@tonic-gate clearerr(obuf); 980Sstevel@tonic-gate while (c > 0L) { 990Sstevel@tonic-gate nread = getline(line, LINESIZE, ibuf, &unused); 1000Sstevel@tonic-gate c -= nread; 1010Sstevel@tonic-gate lc++; 1020Sstevel@tonic-gate if (ishead) { 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * First line is the From line, so no headers 1050Sstevel@tonic-gate * there to worry about 1060Sstevel@tonic-gate */ 1070Sstevel@tonic-gate if (fline) { 1080Sstevel@tonic-gate fline = 0; 1090Sstevel@tonic-gate goto writeit; 1100Sstevel@tonic-gate } 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * If line is blank, we've reached end of 1130Sstevel@tonic-gate * headers, so force out status: field 1140Sstevel@tonic-gate * and note that we are no longer in header 1150Sstevel@tonic-gate * fields. Also force out Content-Length: field. 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate if (line[0] == '\n') { 1180Sstevel@tonic-gate if (dostat) { 1190Sstevel@tonic-gate statusput(mailp, obuf, doign, fp); 1200Sstevel@tonic-gate dostat = 0; 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate if (doclen && 1230Sstevel@tonic-gate !isign("content-length", flag&M_SAVING)) { 1240Sstevel@tonic-gate snprintf(field, sizeof (field), 1250Sstevel@tonic-gate "Content-Length: %ld\n", 1260Sstevel@tonic-gate mp->m_clen - 1); 1270Sstevel@tonic-gate (*fp)(field, obuf); 1280Sstevel@tonic-gate if (ferror(obuf)) 1290Sstevel@tonic-gate return(-1); 1300Sstevel@tonic-gate doclen = 0; 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate ishead = 0; 1330Sstevel@tonic-gate goto writeit; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate /* 1360Sstevel@tonic-gate * If this line is a continuation 1370Sstevel@tonic-gate * of a previous header field, just echo it. 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate if (isspace(line[0]) && infld) 1400Sstevel@tonic-gate if (oldign) 1410Sstevel@tonic-gate continue; 1420Sstevel@tonic-gate else 1430Sstevel@tonic-gate goto writeit; 1440Sstevel@tonic-gate infld = 0; 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * If we are no longer looking at real 1470Sstevel@tonic-gate * header lines, force out status: 1480Sstevel@tonic-gate * This happens in uucp style mail where 1490Sstevel@tonic-gate * there are no headers at all. 1500Sstevel@tonic-gate */ 1510Sstevel@tonic-gate if (!headerp(line)) { 1520Sstevel@tonic-gate if (dostat) { 1530Sstevel@tonic-gate statusput(mailp, obuf, doign, fp); 1540Sstevel@tonic-gate dostat = 0; 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate (*fp)("\n", obuf); 1570Sstevel@tonic-gate ishead = 0; 1580Sstevel@tonic-gate goto writeit; 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate infld++; 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * Pick up the header field. 1630Sstevel@tonic-gate * If it is an ignored field and 1640Sstevel@tonic-gate * we care about such things, skip it. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate cp = line; 1670Sstevel@tonic-gate cp2 = field; 1680Sstevel@tonic-gate while (*cp && *cp != ':' && !isspace(*cp)) 1690Sstevel@tonic-gate *cp2++ = *cp++; 1700Sstevel@tonic-gate *cp2 = 0; 1710Sstevel@tonic-gate oldign = doign && isign(field, flag&M_SAVING); 1720Sstevel@tonic-gate if (oldign) 1730Sstevel@tonic-gate continue; 1740Sstevel@tonic-gate /* 1750Sstevel@tonic-gate * If the field is "status," go compute and print the 1760Sstevel@tonic-gate * real Status: field 1770Sstevel@tonic-gate */ 1780Sstevel@tonic-gate if (icequal(field, "status")) { 1790Sstevel@tonic-gate if (dostat) { 1800Sstevel@tonic-gate statusput(mailp, obuf, doign, fp); 1810Sstevel@tonic-gate dostat = 0; 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate continue; 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate if (icequal(field, "content-length")) { 1860Sstevel@tonic-gate if (doclen) { 1870Sstevel@tonic-gate snprintf(line, sizeof (line), 1880Sstevel@tonic-gate "Content-Length: %ld\n", 1890Sstevel@tonic-gate mp->m_clen - 1); 1900Sstevel@tonic-gate (*fp)(line, obuf); 1910Sstevel@tonic-gate if (ferror(obuf)) 1920Sstevel@tonic-gate return(-1); 1930Sstevel@tonic-gate doclen = 0; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate continue; 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate writeit: 1990Sstevel@tonic-gate if (!ishead && !mp->m_text && mp->m_clen != 0) { 2000Sstevel@tonic-gate if (line[0] == '\n') 2010Sstevel@tonic-gate putc('\n', obuf); 2020Sstevel@tonic-gate clen = mp->m_clen-1; 2030Sstevel@tonic-gate for (;;) { 2040Sstevel@tonic-gate n = clen < sizeof line ? clen : sizeof line; 2050Sstevel@tonic-gate if ((n = fread(line, 1, (int)n, ibuf)) <= 0) { 2060Sstevel@tonic-gate fprintf(stderr, gettext( 2070Sstevel@tonic-gate "\t(Unexpected end-of-file).\n")); 2080Sstevel@tonic-gate clen = 0; 2090Sstevel@tonic-gate } else { 2100Sstevel@tonic-gate if (fwrite(line, 1, (int)n, obuf) != n) { 2110Sstevel@tonic-gate fprintf(stderr, gettext( 2120Sstevel@tonic-gate "\tError writing to the new file.\n")); 2130Sstevel@tonic-gate fflush(obuf); 2140Sstevel@tonic-gate if (fferror(obuf)) 2150Sstevel@tonic-gate return (-1); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate clen -= n; 2190Sstevel@tonic-gate if (clen <= 0) { 2200Sstevel@tonic-gate break; 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate c = 0L; 2240Sstevel@tonic-gate } else { 2250Sstevel@tonic-gate (*fp)(line, obuf); 2260Sstevel@tonic-gate if (ferror(obuf)) 2270Sstevel@tonic-gate return(-1); 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate fflush(obuf); 2310Sstevel@tonic-gate if (ferror(obuf)) 2320Sstevel@tonic-gate return(-1); 2330Sstevel@tonic-gate if (ishead && (mailp->m_flag & MSTATUS)) 2340Sstevel@tonic-gate printf(gettext("failed to fix up status field\n")); 2350Sstevel@tonic-gate return(lc); 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate /* 2390Sstevel@tonic-gate * Test if the passed line is a header line, RFC 822 style. 2400Sstevel@tonic-gate */ 2410Sstevel@tonic-gate int 2420Sstevel@tonic-gate headerp(register char *line) 2430Sstevel@tonic-gate { 2440Sstevel@tonic-gate register char *cp = line; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate while (*cp && *cp != ' ' && *cp != '\t' && *cp != ':') 2470Sstevel@tonic-gate cp++; 2480Sstevel@tonic-gate return(*cp == ':'); 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * Output a reasonable looking status field. 2530Sstevel@tonic-gate * But if "status" is ignored and doign, forget it. 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate static void 2560Sstevel@tonic-gate statusput( 2570Sstevel@tonic-gate register struct message *mp, 2580Sstevel@tonic-gate register FILE *obuf, 2590Sstevel@tonic-gate int doign, 2600Sstevel@tonic-gate int (*fp)(const char *, FILE *)) 2610Sstevel@tonic-gate { 2620Sstevel@tonic-gate char statout[12]; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if (doign && isign("status", 0)) 2650Sstevel@tonic-gate return; 2660Sstevel@tonic-gate if ((mp->m_flag & (MNEW|MREAD)) == MNEW) 2670Sstevel@tonic-gate return; 2680Sstevel@tonic-gate strcpy(statout, "Status: "); 2690Sstevel@tonic-gate if (mp->m_flag & MREAD) 2700Sstevel@tonic-gate strcat(statout, "R"); 2710Sstevel@tonic-gate if ((mp->m_flag & MNEW) == 0) 2720Sstevel@tonic-gate strcat(statout, "O"); 2730Sstevel@tonic-gate strcat(statout, "\n"); 2740Sstevel@tonic-gate (*fp)(statout, obuf); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* 2780Sstevel@tonic-gate * Interface between the argument list and the mail1 routine 2790Sstevel@tonic-gate * which does all the dirty work. 2800Sstevel@tonic-gate */ 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate int 2830Sstevel@tonic-gate mail(char **people) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate register char *cp2, *cp3; 2860Sstevel@tonic-gate register int s; 2870Sstevel@tonic-gate char *buf, **ap; 2880Sstevel@tonic-gate struct header head; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate for (s = 0, ap = people; *ap; ap++) 2910Sstevel@tonic-gate s += strlen(*ap) + 2; 2920Sstevel@tonic-gate buf = (char *)salloc((unsigned)(s+1)); 2930Sstevel@tonic-gate cp2 = buf; 2940Sstevel@tonic-gate for (ap = people; *ap; ap++) { 2950Sstevel@tonic-gate for (cp3 = *ap; *cp3; ) { 2960Sstevel@tonic-gate if (*cp3 == ' ' || *cp3 == '\t') { 2970Sstevel@tonic-gate *cp3++ = ','; 2980Sstevel@tonic-gate while (*cp3 == ' ' || *cp3 == '\t') 2990Sstevel@tonic-gate cp3++; 3000Sstevel@tonic-gate } else 3010Sstevel@tonic-gate cp3++; 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate cp2 = copy(*ap, cp2); 3040Sstevel@tonic-gate *cp2++ = ','; 3050Sstevel@tonic-gate *cp2++ = ' '; 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate *cp2 = '\0'; 3080Sstevel@tonic-gate head.h_to = buf; 3090Sstevel@tonic-gate head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR; 3100Sstevel@tonic-gate head.h_others = NOSTRPTR; 3110Sstevel@tonic-gate head.h_seq = 0; 3120Sstevel@tonic-gate mail1(&head, Fflag, NOSTR); 3130Sstevel@tonic-gate return(0); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate int 3170Sstevel@tonic-gate sendm(char *str) 3180Sstevel@tonic-gate { 3190Sstevel@tonic-gate if (value("flipm") != NOSTR) 3200Sstevel@tonic-gate return(Sendmail(str)); 3210Sstevel@tonic-gate else return(sendmail(str)); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate int 3250Sstevel@tonic-gate Sendm(char *str) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate if (value("flipm") != NOSTR) 3280Sstevel@tonic-gate return(sendmail(str)); 3290Sstevel@tonic-gate else return(Sendmail(str)); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * Interface to the mail1 routine for the -t flag 3340Sstevel@tonic-gate * (read headers from text). 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate int 3370Sstevel@tonic-gate tmail(void) 3380Sstevel@tonic-gate { 3390Sstevel@tonic-gate struct header head; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate head.h_to = NOSTR; 3420Sstevel@tonic-gate head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR; 3430Sstevel@tonic-gate head.h_others = NOSTRPTR; 3440Sstevel@tonic-gate head.h_seq = 0; 3450Sstevel@tonic-gate mail1(&head, Fflag, NOSTR); 3460Sstevel@tonic-gate return(0); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * Send mail to a bunch of user names. The interface is through 3510Sstevel@tonic-gate * the mail routine below. 3520Sstevel@tonic-gate */ 3530Sstevel@tonic-gate static int 3540Sstevel@tonic-gate sendmail(char *str) 3550Sstevel@tonic-gate { 3560Sstevel@tonic-gate struct header head; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate if (blankline(str)) 3590Sstevel@tonic-gate head.h_to = NOSTR; 3600Sstevel@tonic-gate else 3610Sstevel@tonic-gate head.h_to = addto(NOSTR, str); 3620Sstevel@tonic-gate head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR; 3630Sstevel@tonic-gate head.h_others = NOSTRPTR; 3640Sstevel@tonic-gate head.h_seq = 0; 3650Sstevel@tonic-gate mail1(&head, 0, NOSTR); 3660Sstevel@tonic-gate return(0); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * Send mail to a bunch of user names. The interface is through 3710Sstevel@tonic-gate * the mail routine below. 3720Sstevel@tonic-gate * save a copy of the letter 3730Sstevel@tonic-gate */ 3740Sstevel@tonic-gate static int 3750Sstevel@tonic-gate Sendmail(char *str) 3760Sstevel@tonic-gate { 3770Sstevel@tonic-gate struct header head; 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate if (blankline(str)) 3800Sstevel@tonic-gate head.h_to = NOSTR; 3810Sstevel@tonic-gate else 3820Sstevel@tonic-gate head.h_to = addto(NOSTR, str); 3830Sstevel@tonic-gate head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR; 3840Sstevel@tonic-gate head.h_others = NOSTRPTR; 3850Sstevel@tonic-gate head.h_seq = 0; 3860Sstevel@tonic-gate mail1(&head, 1, NOSTR); 3870Sstevel@tonic-gate return(0); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate /* 3910Sstevel@tonic-gate * Walk the list of fds, closing all but one. 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate static int 3940Sstevel@tonic-gate closefd_walk(void *special_fd, int fd) 3950Sstevel@tonic-gate { 3960Sstevel@tonic-gate if (fd > STDERR_FILENO && fd != *(int *)special_fd) 3970Sstevel@tonic-gate (void) close(fd); 3980Sstevel@tonic-gate return (0); 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate /* 4020Sstevel@tonic-gate * Mail a message on standard input to the people indicated 4030Sstevel@tonic-gate * in the passed header. (Internal interface). 4040Sstevel@tonic-gate */ 4050Sstevel@tonic-gate void 4060Sstevel@tonic-gate mail1(struct header *hp, int use_to, char *orig_to) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate pid_t p, pid; 4090Sstevel@tonic-gate int i, s, gotcha; 4100Sstevel@tonic-gate char **namelist, *deliver; 4110Sstevel@tonic-gate struct name *to, *np; 4120Sstevel@tonic-gate FILE *mtf, *fp; 4130Sstevel@tonic-gate int remote = rflag != NOSTR || rmail; 4140Sstevel@tonic-gate char **t; 4150Sstevel@tonic-gate char *deadletter; 4160Sstevel@tonic-gate char recfile[PATHSIZE]; 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate /* 4190Sstevel@tonic-gate * Collect user's mail from standard input. 4200Sstevel@tonic-gate * Get the result as mtf. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate pid = (pid_t)-1; 4240Sstevel@tonic-gate if ((mtf = collect(hp)) == NULL) 4250Sstevel@tonic-gate return; 4260Sstevel@tonic-gate hp->h_seq = 1; 4270Sstevel@tonic-gate if (hp->h_subject == NOSTR) 4280Sstevel@tonic-gate hp->h_subject = sflag; 4290Sstevel@tonic-gate if (fsize(mtf) == 0 && hp->h_subject == NOSTR) { 4300Sstevel@tonic-gate printf(gettext("No message !?!\n")); 4310Sstevel@tonic-gate goto out; 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate if (intty) { 4340Sstevel@tonic-gate printf(gettext("EOT\n")); 4350Sstevel@tonic-gate flush(); 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * If we need to use the To: line to determine the record 4400Sstevel@tonic-gate * file, save a copy of it before it's sorted below. 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate if (use_to && orig_to == NOSTR && hp->h_to != NOSTR) 4440Sstevel@tonic-gate orig_to = strcpy((char *)salloc(strlen(hp->h_to)+1), hp->h_to); 4450Sstevel@tonic-gate else if (orig_to == NOSTR) 4460Sstevel@tonic-gate orig_to = ""; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate /* 4490Sstevel@tonic-gate * Now, take the user names from the combined 4500Sstevel@tonic-gate * to and cc lists and do all the alias 4510Sstevel@tonic-gate * processing. 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate senderr = 0; 4550Sstevel@tonic-gate to = cat(extract(hp->h_bcc, GBCC), 4560Sstevel@tonic-gate cat(extract(hp->h_to, GTO), 4570Sstevel@tonic-gate extract(hp->h_cc, GCC))); 4580Sstevel@tonic-gate to = translate(outpre(elide(usermap(to)))); 4590Sstevel@tonic-gate if (!senderr) 4600Sstevel@tonic-gate mapf(to, myname); 4610Sstevel@tonic-gate mechk(to); 4620Sstevel@tonic-gate for (gotcha = 0, np = to; np != NIL; np = np->n_flink) 4630Sstevel@tonic-gate if ((np->n_type & GDEL) == 0) 4640Sstevel@tonic-gate gotcha++; 4650Sstevel@tonic-gate hp->h_to = detract(to, GTO); 4660Sstevel@tonic-gate hp->h_cc = detract(to, GCC); 4670Sstevel@tonic-gate hp->h_bcc = detract(to, GBCC); 4680Sstevel@tonic-gate if ((mtf = infix(hp, mtf)) == NULL) { 4690Sstevel@tonic-gate fprintf(stderr, gettext(". . . message lost, sorry.\n")); 4700Sstevel@tonic-gate return; 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate rewind(mtf); 4730Sstevel@tonic-gate if (askme && isatty(0)) { 4740Sstevel@tonic-gate char ans[64]; 4750Sstevel@tonic-gate puthead(hp, stdout, GTO|GCC|GBCC, 0); 4760Sstevel@tonic-gate printf(gettext("Send? ")); 4770Sstevel@tonic-gate printf("[yes] "); 4780Sstevel@tonic-gate if (fgets(ans, sizeof(ans), stdin) && ans[0] && 4790Sstevel@tonic-gate (tolower(ans[0]) != 'y' && ans[0] != '\n')) 4800Sstevel@tonic-gate goto dead; 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate if (senderr) 4830Sstevel@tonic-gate goto dead; 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * Look through the recipient list for names with /'s 4860Sstevel@tonic-gate * in them which we write to as files directly. 4870Sstevel@tonic-gate */ 4880Sstevel@tonic-gate i = outof(to, mtf); 4890Sstevel@tonic-gate rewind(mtf); 4900Sstevel@tonic-gate if (!gotcha && !i) { 4910Sstevel@tonic-gate printf(gettext("No recipients specified\n")); 4920Sstevel@tonic-gate goto dead; 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate if (senderr) 4950Sstevel@tonic-gate goto dead; 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate getrecf(orig_to, recfile, use_to, sizeof (recfile)); 4980Sstevel@tonic-gate if (recfile != NOSTR && *recfile) 4990Sstevel@tonic-gate savemail(safeexpand(recfile), hp, mtf); 5000Sstevel@tonic-gate if (!gotcha) 5010Sstevel@tonic-gate goto out; 5020Sstevel@tonic-gate namelist = unpack(to); 5030Sstevel@tonic-gate if (debug) { 5040Sstevel@tonic-gate fprintf(stderr, "Recipients of message:\n"); 5050Sstevel@tonic-gate for (t = namelist; *t != NOSTR; t++) 5060Sstevel@tonic-gate fprintf(stderr, " \"%s\"", *t); 5070Sstevel@tonic-gate fprintf(stderr, "\n"); 5080Sstevel@tonic-gate return; 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Wait, to absorb a potential zombie, then 5130Sstevel@tonic-gate * fork, set up the temporary mail file as standard 5140Sstevel@tonic-gate * input for "mail" and exec with the user list we generated 5150Sstevel@tonic-gate * far above. Return the process id to caller in case he 5160Sstevel@tonic-gate * wants to await the completion of mail. 5170Sstevel@tonic-gate */ 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate #ifdef VMUNIX 5200Sstevel@tonic-gate while (wait3((int *)0, WNOHANG, (struct rusage *)0) > 0) 5210Sstevel@tonic-gate ; 5220Sstevel@tonic-gate #else 5230Sstevel@tonic-gate #ifdef preSVr4 5240Sstevel@tonic-gate wait((int *)0); 5250Sstevel@tonic-gate #else 5260Sstevel@tonic-gate while (waitpid((pid_t)-1, (int *)0, WNOHANG) > 0) 5270Sstevel@tonic-gate ; 5280Sstevel@tonic-gate #endif 5290Sstevel@tonic-gate #endif 5300Sstevel@tonic-gate rewind(mtf); 5310Sstevel@tonic-gate pid = fork(); 5320Sstevel@tonic-gate if (pid == (pid_t)-1) { 5330Sstevel@tonic-gate perror("fork"); 5340Sstevel@tonic-gate dead: 5350Sstevel@tonic-gate deadletter = Getf("DEAD"); 5360Sstevel@tonic-gate if (fp = fopen(deadletter, 5370Sstevel@tonic-gate value("appenddeadletter") == NOSTR ? "w" : "a")) { 5380Sstevel@tonic-gate chmod(deadletter, DEADPERM); 5390Sstevel@tonic-gate puthead(hp, fp, GMASK|GCLEN, fsize(mtf) - textpos); 5400Sstevel@tonic-gate fseek(mtf, textpos, 0); 5410Sstevel@tonic-gate lcwrite(deadletter, mtf, fp, 5420Sstevel@tonic-gate value("appenddeadletter") != NOSTR); 5430Sstevel@tonic-gate fclose(fp); 5440Sstevel@tonic-gate } else 5450Sstevel@tonic-gate perror(deadletter); 5460Sstevel@tonic-gate goto out; 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate if (pid == 0) { 5490Sstevel@tonic-gate sigchild(); 5500Sstevel@tonic-gate #ifdef SIGTSTP 5510Sstevel@tonic-gate if (remote == 0) { 5520Sstevel@tonic-gate sigset(SIGTSTP, SIG_IGN); 5530Sstevel@tonic-gate sigset(SIGTTIN, SIG_IGN); 5540Sstevel@tonic-gate sigset(SIGTTOU, SIG_IGN); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate #endif 5570Sstevel@tonic-gate sigset(SIGHUP, SIG_IGN); 5580Sstevel@tonic-gate sigset(SIGINT, SIG_IGN); 5590Sstevel@tonic-gate sigset(SIGQUIT, SIG_IGN); 5600Sstevel@tonic-gate s = fileno(mtf); 5610Sstevel@tonic-gate (void) fdwalk(closefd_walk, &s); 5620Sstevel@tonic-gate close(0); 5630Sstevel@tonic-gate dup(s); 5640Sstevel@tonic-gate close(s); 5650Sstevel@tonic-gate #ifdef CC 5660Sstevel@tonic-gate submit(getpid()); 5670Sstevel@tonic-gate #endif /* CC */ 5680Sstevel@tonic-gate if ((deliver = value("sendmail")) == NOSTR) 5690Sstevel@tonic-gate #ifdef SENDMAIL 5700Sstevel@tonic-gate deliver = SENDMAIL; 5710Sstevel@tonic-gate #else 5720Sstevel@tonic-gate deliver = MAIL; 5730Sstevel@tonic-gate #endif 5740Sstevel@tonic-gate execvp(safeexpand(deliver), namelist); 5750Sstevel@tonic-gate perror(deliver); 5760Sstevel@tonic-gate exit(1); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate if (value("sendwait")!=NOSTR) 5800Sstevel@tonic-gate remote++; 5810Sstevel@tonic-gate out: 5820Sstevel@tonic-gate if (remote) { 5830Sstevel@tonic-gate while ((p = wait(&s)) != pid && p != (pid_t)-1) 5840Sstevel@tonic-gate ; 5850Sstevel@tonic-gate if (s != 0) 5860Sstevel@tonic-gate senderr++; 5870Sstevel@tonic-gate pid = 0; 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate fclose(mtf); 5900Sstevel@tonic-gate return; 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate /* 5940Sstevel@tonic-gate * Prepend a header in front of the collected stuff 5950Sstevel@tonic-gate * and return the new file. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate static FILE * 5990Sstevel@tonic-gate infix(struct header *hp, FILE *fi) 6000Sstevel@tonic-gate { 6010Sstevel@tonic-gate register FILE *nfo, *nfi; 6020Sstevel@tonic-gate register int c; 6030Sstevel@tonic-gate char *postmark, *returnaddr; 6040Sstevel@tonic-gate int fd = -1; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate rewind(fi); 6070Sstevel@tonic-gate if ((fd = open(tempMail, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 || 6080Sstevel@tonic-gate (nfo = fdopen(fd, "w")) == NULL) { 6090Sstevel@tonic-gate perror(tempMail); 6100Sstevel@tonic-gate return(fi); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate if ((nfi = fopen(tempMail, "r")) == NULL) { 6130Sstevel@tonic-gate perror(tempMail); 6140Sstevel@tonic-gate fclose(nfo); 6150Sstevel@tonic-gate return(fi); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate removefile(tempMail); 6180Sstevel@tonic-gate postmark = value("postmark"); 6190Sstevel@tonic-gate returnaddr = value("returnaddr"); 6200Sstevel@tonic-gate if ((postmark != NOSTR) || (returnaddr != NOSTR)) { 6210Sstevel@tonic-gate if (returnaddr && *returnaddr) 6220Sstevel@tonic-gate fprintf(nfo, "From: %s", returnaddr); 6230Sstevel@tonic-gate else 6240Sstevel@tonic-gate fprintf(nfo, "From: %s@%s", myname, host); 6250Sstevel@tonic-gate if (postmark && *postmark) 6260Sstevel@tonic-gate fprintf(nfo, " (%s)", postmark); 6270Sstevel@tonic-gate putc('\n', nfo); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate puthead(hp, nfo, (GMASK & ~GBCC) | GCLEN, fsize(fi)); 6300Sstevel@tonic-gate textpos = ftell(nfo); 6310Sstevel@tonic-gate while ((c = getc(fi)) != EOF) 6320Sstevel@tonic-gate putc(c, nfo); 6330Sstevel@tonic-gate if (ferror(fi)) { 6340Sstevel@tonic-gate perror("read"); 6350Sstevel@tonic-gate return(fi); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate fflush(nfo); 6380Sstevel@tonic-gate if (fferror(nfo)) { 6390Sstevel@tonic-gate perror(tempMail); 6400Sstevel@tonic-gate fclose(nfo); 6410Sstevel@tonic-gate fclose(nfi); 6420Sstevel@tonic-gate return(fi); 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate fclose(nfo); 6450Sstevel@tonic-gate fclose(fi); 6460Sstevel@tonic-gate rewind(nfi); 6470Sstevel@tonic-gate return(nfi); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate /* 6510Sstevel@tonic-gate * Dump the message header on the 6520Sstevel@tonic-gate * passed file buffer. 6530Sstevel@tonic-gate */ 6540Sstevel@tonic-gate 655*18Srobbin int 6560Sstevel@tonic-gate puthead(struct header *hp, FILE *fo, int w, long clen) 6570Sstevel@tonic-gate { 6580Sstevel@tonic-gate register int gotcha; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate gotcha = 0; 6610Sstevel@tonic-gate if (hp->h_to != NOSTR && (w & GTO)) 6620Sstevel@tonic-gate fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++; 6630Sstevel@tonic-gate if ((w & GSUBJECT) && (int)value("bsdcompat")) 6640Sstevel@tonic-gate if (hp->h_subject != NOSTR && *hp->h_subject) 6650Sstevel@tonic-gate fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 6660Sstevel@tonic-gate else 6670Sstevel@tonic-gate if (sflag && *sflag) 6680Sstevel@tonic-gate fprintf(fo, "Subject: %s\n", sflag), gotcha++; 6690Sstevel@tonic-gate if (hp->h_cc != NOSTR && (w & GCC)) 6700Sstevel@tonic-gate fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++; 6710Sstevel@tonic-gate if (hp->h_bcc != NOSTR && (w & GBCC)) 6720Sstevel@tonic-gate fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++; 6730Sstevel@tonic-gate if (hp->h_defopt != NOSTR && (w & GDEFOPT)) 6740Sstevel@tonic-gate if (receipt_flg) 6750Sstevel@tonic-gate fprintf(fo, "Return-Receipt-To: %s\n", 6760Sstevel@tonic-gate hp->h_defopt), gotcha++; 6770Sstevel@tonic-gate else 6780Sstevel@tonic-gate fprintf(fo, "Default-Options: %s\n", hp->h_defopt), gotcha++; 6790Sstevel@tonic-gate if ((w & GSUBJECT) && !(int)value("bsdcompat")) 6800Sstevel@tonic-gate if (hp->h_subject != NOSTR && *hp->h_subject) 6810Sstevel@tonic-gate fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 6820Sstevel@tonic-gate else 6830Sstevel@tonic-gate if (sflag && *sflag) 6840Sstevel@tonic-gate fprintf(fo, "Subject: %s\n", sflag), gotcha++; 6850Sstevel@tonic-gate if (hp->h_others != NOSTRPTR && (w & GOTHER)) { 6860Sstevel@tonic-gate char **p; 6870Sstevel@tonic-gate for (p = hp->h_others; *p; p++) 6880Sstevel@tonic-gate fprintf(fo, "%s\n", *p); 6890Sstevel@tonic-gate gotcha++; 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate #ifndef preSVr4 6920Sstevel@tonic-gate if (w & GCLEN) 6930Sstevel@tonic-gate fprintf(fo, "Content-Length: %ld\n", clen), gotcha++; 6940Sstevel@tonic-gate #endif 6950Sstevel@tonic-gate if (gotcha && (w & GNL)) 6960Sstevel@tonic-gate putc('\n', fo); 6970Sstevel@tonic-gate return(0); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Format the given text to not exceed 78 characters. 7020Sstevel@tonic-gate */ 7030Sstevel@tonic-gate static void 7040Sstevel@tonic-gate fmt(register char *str, register FILE *fo) 7050Sstevel@tonic-gate { 7060Sstevel@tonic-gate register int col = 4; 7070Sstevel@tonic-gate char name[256]; 7080Sstevel@tonic-gate int len; 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate str = strcpy((char *)salloc(strlen(str)+1), str); 7110Sstevel@tonic-gate while (str = yankword(str, name, sizeof (name), 1)) { 7120Sstevel@tonic-gate len = strlen(name); 7130Sstevel@tonic-gate if (col > 4) { 7140Sstevel@tonic-gate if (col + len > 76) { 7150Sstevel@tonic-gate fputs(",\n ", fo); 7160Sstevel@tonic-gate col = 4; 7170Sstevel@tonic-gate } else { 7180Sstevel@tonic-gate fputs(", ", fo); 7190Sstevel@tonic-gate col += 2; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate fputs(name, fo); 7230Sstevel@tonic-gate col += len; 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate putc('\n', fo); 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate /* 7290Sstevel@tonic-gate * Save the outgoing mail on the passed file. 7300Sstevel@tonic-gate */ 7310Sstevel@tonic-gate static int 7320Sstevel@tonic-gate savemail(char name[], struct header *hp, FILE *fi) 7330Sstevel@tonic-gate { 7340Sstevel@tonic-gate register FILE *fo; 7350Sstevel@tonic-gate time_t now; 7360Sstevel@tonic-gate char *n; 7370Sstevel@tonic-gate #ifdef preSVr4 7380Sstevel@tonic-gate char line[BUFSIZ]; 7390Sstevel@tonic-gate #else 7400Sstevel@tonic-gate int c; 7410Sstevel@tonic-gate #endif 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate if (debug) 7440Sstevel@tonic-gate fprintf(stderr, gettext("save in '%s'\n"), name); 7450Sstevel@tonic-gate if ((fo = fopen(name, "a")) == NULL) { 7460Sstevel@tonic-gate perror(name); 7470Sstevel@tonic-gate return(-1); 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate time(&now); 7500Sstevel@tonic-gate n = rflag; 7510Sstevel@tonic-gate if (n == NOSTR) 7520Sstevel@tonic-gate n = myname; 7530Sstevel@tonic-gate fprintf(fo, "From %s %s", n, ctime(&now)); 7540Sstevel@tonic-gate puthead(hp, fo, GMASK|GCLEN, fsize(fi) - textpos); 7550Sstevel@tonic-gate fseek(fi, textpos, 0); 7560Sstevel@tonic-gate #ifdef preSVr4 7570Sstevel@tonic-gate while (fgets(line, sizeof line, fi)) { 7580Sstevel@tonic-gate if (!strncmp(line, "From ", 5)) 7590Sstevel@tonic-gate putc('>', fo); 7600Sstevel@tonic-gate fputs(line, fo); 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate #else 7630Sstevel@tonic-gate while ((c = getc(fi)) != EOF) 7640Sstevel@tonic-gate putc(c, fo); 7650Sstevel@tonic-gate #endif 7660Sstevel@tonic-gate putc('\n', fo); 7670Sstevel@tonic-gate fflush(fo); 7680Sstevel@tonic-gate if (fferror(fo)) 7690Sstevel@tonic-gate perror(name); 7700Sstevel@tonic-gate fclose(fo); 7710Sstevel@tonic-gate return(0); 7720Sstevel@tonic-gate } 773