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