1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include "mail.h"
30 #include <sys/param.h>
31 /*
32 * Send mail - High level sending routine
33 */
34 void
sendmail(argc,argv)35 sendmail(argc, argv)
36 char **argv;
37 {
38 char **args;
39 char *tp, *zp;
40 char buf[2048], last1c;
41 FILE *input;
42 struct stat64 sbuf;
43 int aret;
44 int i, n;
45 int oldn = 1;
46 int ttyf = 0;
47 int pushrest = 0;
48 int hdrtyp = 0;
49 int ctf = FALSE;
50 int binflg = 0;
51 long count = 0L;
52 struct tm *bp;
53 struct hdrs *hptr;
54 static char pn[] = "sendmail";
55 reciplist list;
56
57 Dout(pn, 0, "entered\n");
58 new_reciplist(&list);
59 for (i = 1; i < argc; ++i) {
60 if (argv[i][0] == '-') {
61 if (argv[i][1] == '\0') {
62 errmsg(E_SYNTAX,
63 "Hyphens MAY NOT be followed by spaces");
64 }
65 if (i > 1) {
66 errmsg(E_SYNTAX,
67 "Options MUST PRECEDE persons");
68 }
69 done(0);
70 }
71 /*
72 * Ensure no NULL names in list
73 */
74 if (argv[i][0] == '\0' || argv[i][strlen(argv[i])-1] == '!') {
75 errmsg(E_SYNTAX, "Null names are not allowed");
76 done(0);
77 }
78 /* Don't check for duplication */
79 add_recip(&list, argv[i], FALSE);
80 }
81
82 mktmp();
83 /*
84 * Format time
85 */
86 time(&iop);
87 bp = localtime(&iop);
88 tp = asctime(bp);
89 zp = tzname[bp->tm_isdst];
90 sprintf(datestring, "%.16s %.3s %.5s", tp, zp, tp+20);
91 trimnl(datestring);
92 /* asctime: Fri Sep 30 00:00:00 1986\n */
93 /* 0123456789012345678901234 */
94 /* RFCtime: Fri, 28 Jul 89 10:30 EDT */
95 sprintf(RFC822datestring, "%.3s, %.2s %.3s %.4s %.5s %.3s",
96 tp, tp+8, tp+4, tp+20, tp+11, zp);
97
98 /*
99 * Write out the from line header for the letter
100 */
101 if (fromflag && deliverflag && from_user[0] != '\0') {
102 (void) snprintf(buf, sizeof (buf), "%s%s %s\n",
103 header[H_FROM].tag, from_user, datestring);
104 } else {
105 (void) snprintf(buf, sizeof (buf), "%s%s %s\n",
106 header[H_FROM].tag, my_name, datestring);
107 }
108 if (!wtmpf(buf, strlen(buf))) {
109 done(0);
110 }
111 savehdrs(buf, H_FROM);
112
113 /*
114 * Copy to list in mail entry?
115 */
116 if (flgt == 1 && argc > 1) {
117 aret = argc;
118 args = argv;
119 while (--aret > 0) {
120 (void) snprintf(buf, sizeof (buf),
121 "%s %s\n", header[H_TO].tag, *++args);
122 if (!wtmpf(buf, strlen(buf))) {
123 done(0);
124 }
125 savehdrs(buf, H_TO);
126 }
127 }
128
129 flgf = 1; /* reset when first read of message body succeeds */
130 /*
131 * Read mail message, allowing for lines of infinite
132 * length. This is tricky, have to watch for newlines.
133 */
134 saveint = setsig(SIGINT, savdead);
135 last1c = ' '; /* anything other than newline */
136 ttyf = isatty(fileno(stdin));
137 pushrest = 0;
138
139 /*
140 * scan header & save relevant info.
141 */
142 (void) strlcpy(fromU, my_name, sizeof (fromU));
143 fromS[0] = 0; /* set up for >From scan */
144 input = stdin;
145 /*
146 * Fifofs cannot handle if the inode number crosses
147 * 32-bit limit. This results in overflow, if the
148 * input steam is a pipe. Using 64-bit interface to
149 * take care of that.
150 */
151 if (fstat64(fileno(input), &sbuf) == 0) {
152 /* Also care if we could not handle large mail. */
153 if ((sbuf.st_size > MAXOFF_T) || (sbuf.st_blocks > LONG_MAX)) {
154 fprintf(stderr, "%s: stdin: %s\n", program,
155 strerror(EOVERFLOW));
156 exit(1);
157 }
158 }
159
160 while ((n = getaline(line, sizeof (line), stdin)) > 0) {
161 last1c = line[n-1];
162 if (pushrest) {
163 if (!wtmpf(line, n)) {
164 done(0);
165 }
166 pushrest = (last1c != '\n');
167 continue;
168 }
169 pushrest = (last1c != '\n');
170
171 if ((hdrtyp = isheader(line, &ctf)) == FALSE) {
172 break;
173 }
174 flgf = 0;
175 switch (hdrtyp) {
176 case H_RVERS:
177 /* Are we dealing with a delivery report? */
178 /* dflag = 9 ==> do not return on failure */
179 dflag = 9;
180 Dout(pn, 0, "dflag = 9\n");
181 break;
182 case H_FROM:
183 if (!wtmpf(">", 1)) {
184 done(0);
185 }
186 /* note dropthru */
187 hdrtyp = H_FROM1;
188 case H_FROM1:
189 if (substr(line, "forwarded by") > -1) {
190 break;
191 }
192 pickFrom(line);
193 if (Rpath[0] != '\0') {
194 strcat(Rpath, "!");
195 }
196 (void) strlcat(Rpath, fromS, sizeof (Rpath));
197 n = 0; /* don't copy remote from's into mesg. */
198 break;
199 case H_MIMEVERS:
200 case H_CLEN:
201 case H_CTYPE:
202 /* suppress it: only generated if needed */
203 n = 0; /* suppress */
204 break;
205 case H_TCOPY:
206 /* Write out placeholder for later */
207 (void) snprintf(buf, sizeof (buf), "%s \n",
208 header[H_TCOPY].tag);
209 if (!wtmpf(buf, strlen(buf))) {
210 done(0);
211 }
212 n = 0; /* suppress */
213 break;
214 case H_MTYPE:
215 if (flgm) {
216 /* suppress if message-type argument */
217 n = 0;
218 }
219 break;
220 case H_CONT:
221 if (oldn == 0) {
222 /* suppress continuation line also */
223 n = 0;
224 }
225 break;
226 }
227 oldn = n; /* remember if this line was suppressed */
228 if (n && !wtmpf(line, n)) {
229 done(0);
230 }
231 if (!n) savehdrs(line, hdrtyp);
232 }
233 if (Rpath[0] != '\0') {
234 strcat(Rpath, "!");
235 }
236 (void) strlcat(Rpath, fromU, sizeof (Rpath));
237
238 /* push out message type if so requested */
239 if (flgm) { /* message-type */
240 snprintf(buf, sizeof (buf), "%s%s\n",
241 header[H_MTYPE].tag, msgtype);
242 if (!wtmpf(buf, strlen(buf))) {
243 done(0);
244 }
245 }
246
247 memcpy(buf, line, n);
248 if (n == 0 || (ttyf && !strncmp(buf, ".\n", 2))) {
249 if (flgf) {
250 /* no input */
251 return;
252 } else {
253 /*
254 * no content: put mime-version, content-type
255 * and -length only if explicitly present.
256 * Write out 'place-holders' only. (see below....)
257 */
258 if ((hptr = hdrlines[H_MIMEVERS].head) !=
259 (struct hdrs *)NULL) {
260 (void) snprintf(line, sizeof (line), "%s \n",
261 header[H_MIMEVERS].tag);
262 if (!wtmpf(line, strlen(line))) {
263 done(0);
264 }
265 }
266 if ((hptr = hdrlines[H_CTYPE].head) !=
267 (struct hdrs *)NULL) {
268 (void) snprintf(line, sizeof (line), "%s \n",
269 header[H_CTYPE].tag);
270 if (!wtmpf(line, strlen(line))) {
271 done(0);
272 }
273 }
274 if ((hptr = hdrlines[H_CLEN].head) !=
275 (struct hdrs *)NULL) {
276 (void) snprintf(line, sizeof (line), "%s \n",
277 header[H_CLEN].tag);
278 if (!wtmpf(line, strlen(line))) {
279 done(0);
280 }
281 }
282 goto wrapsend;
283 }
284 }
285
286 if (n == 1 && last1c == '\n') { /* blank line -- suppress */
287 n = getaline(buf, sizeof (buf), stdin);
288 if (n == 0 || (ttyf && !strncmp(buf, ".\n", 2))) {
289 /*
290 * no content: put mime-version, content-type
291 * and -length only if explicitly present.
292 * Write out 'place-holders' only. (see below....)
293 */
294 if ((hptr = hdrlines[H_MIMEVERS].head) !=
295 (struct hdrs *)NULL) {
296 (void) snprintf(line, sizeof (line), "%s \n",
297 header[H_MIMEVERS].tag);
298 if (!wtmpf(line, strlen(line))) {
299 done(0);
300 }
301 }
302 if ((hptr = hdrlines[H_CTYPE].head) !=
303 (struct hdrs *)NULL) {
304 (void) snprintf(line, sizeof (line), "%s \n",
305 header[H_CTYPE].tag);
306 if (!wtmpf(line, strlen(line))) {
307 done(0);
308 }
309 }
310 if ((hptr = hdrlines[H_CLEN].head) !=
311 (struct hdrs *)NULL) {
312 (void) snprintf(line, sizeof (line), "%s \n",
313 header[H_CLEN].tag);
314 if (!wtmpf(line, strlen(line))) {
315 done(0);
316 }
317 }
318 goto wrapsend;
319 }
320 }
321
322 if (debug > 0) {
323 buf[n] = '\0';
324 Dout(pn, 0, "header scan complete, readahead %d = \"%s\"\n",
325 n, buf);
326 }
327
328 /*
329 * Write out H_MIMEVERS, H_CTYPE & H_CLEN lines. These are used only as
330 * placeholders in the tmp file. When the 'real' message is sent,
331 * the proper values will be put out by copylet().
332 */
333 (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag);
334 if (!wtmpf(line, strlen(line))) {
335 done(0);
336 }
337 if (hdrlines[H_MIMEVERS].head == (struct hdrs *)NULL) {
338 savehdrs(line, H_MIMEVERS);
339 }
340 (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag);
341 if (!wtmpf(line, strlen(line))) {
342 done(0);
343 }
344 if (hdrlines[H_CTYPE].head == (struct hdrs *)NULL) {
345 savehdrs(line, H_CTYPE);
346 }
347 (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag);
348 if (!wtmpf(line, strlen(line))) {
349 done(0);
350 }
351 if (hdrlines[H_CLEN].head == (struct hdrs *)NULL) {
352 savehdrs(line, H_CLEN);
353 }
354 /* and a blank line */
355 if (!wtmpf("\n", 1)) {
356 done(0);
357 }
358 Dout(pn, 0, "header out completed\n");
359
360 pushrest = 0;
361 count = 0L;
362 /*
363 * Are we returning mail from a delivery failure of an old-style
364 * (SVR3.1 or SVR3.0) rmail? If so, we won't return THIS on failure
365 * [This line should occur as the FIRST non-blank non-header line]
366 */
367 if (!strncmp("***** UNDELIVERABLE MAIL sent to", buf, 32)) {
368 dflag = 9; /* 9 says do not return on failure */
369 Dout(pn, 0, "found old-style UNDELIVERABLE line. dflag = 9\n");
370 }
371
372 /* scan body of message */
373 while (n > 0) {
374 if (ttyf && !strcmp(buf, ".\n"))
375 break;
376 if (!binflg) {
377 binflg = !istext((unsigned char *)buf, n);
378 }
379
380 if (!wtmpf(buf, n)) {
381 done(0);
382 }
383 count += n;
384 n = ttyf
385 ? getaline(buf, sizeof (buf), stdin)
386 : fread(buf, 1, sizeof (buf), stdin);
387 }
388 setsig(SIGINT, saveint);
389
390 wrapsend:
391 /*
392 * In order to use some of the subroutines that are used to
393 * read mail, the let array must be set up
394 */
395 nlet = 1;
396 let[0].adr = 0;
397 let[1].adr = ftell(tmpf);
398 let[0].text = (binflg == 1 ? FALSE : TRUE);
399 Dout(pn, 0, "body copy complete, count %ld\n", count);
400 /*
401 * Modify value of H_MIMEVERS if necessary.
402 */
403 if ((hptr = hdrlines[H_MIMEVERS].head) != (struct hdrs *)NULL) {
404 if (strlen(hptr->value) == 0) {
405 (void) strlcpy(hptr->value, "1.0",
406 sizeof (hptr->value));
407 }
408 }
409 /*
410 * Modify value of H_CTYPE if necessary.
411 */
412 if ((hptr = hdrlines[H_CTYPE].head) != (struct hdrs *)NULL) {
413 if (strlen(hptr->value) == 0) {
414 (void) strlcpy(hptr->value, "text/plain",
415 sizeof (hptr->value));
416 }
417 }
418 /*
419 * Set 'place-holder' value of content length to true value
420 */
421 if ((hptr = hdrlines[H_CLEN].head) != (struct hdrs *)NULL) {
422 (void) snprintf(hptr->value, sizeof (hptr->value),
423 "%ld", count);
424 }
425
426 if (fclose(tmpf) == EOF) {
427 tmperr();
428 done(0);
429 }
430
431 tmpf = doopen(lettmp, "r+", E_TMP);
432
433 /* Do not send mail on SIGINT */
434 if (dflag == 2) {
435 done(0);
436 }
437
438 sendlist(&list, 0, 0);
439 done(0);
440 }
441