dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / mail / sendmail.c
blob5b1b45debb92c192e64c6495851c62364a9bacf7
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
29 #include "mail.h"
30 #include <sys/param.h>
32 * Send mail - High level sending routine
34 void
35 sendmail(argc, argv)
36 char **argv;
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;
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");
65 if (i > 1) {
66 errmsg(E_SYNTAX,
67 "Options MUST PRECEDE persons");
69 done(0);
72 * Ensure no NULL names in list
74 if (argv[i][0] == '\0' || argv[i][strlen(argv[i])-1] == '!') {
75 errmsg(E_SYNTAX, "Null names are not allowed");
76 done(0);
78 /* Don't check for duplication */
79 add_recip(&list, argv[i], FALSE);
82 mktmp();
84 * Format time
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);
99 * Write out the from line header for the letter
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);
108 if (!wtmpf(buf, strlen(buf))) {
109 done(0);
111 savehdrs(buf, H_FROM);
114 * Copy to list in mail entry?
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);
125 savehdrs(buf, H_TO);
129 flgf = 1; /* reset when first read of message body succeeds */
131 * Read mail message, allowing for lines of infinite
132 * length. This is tricky, have to watch for newlines.
134 saveint = setsig(SIGINT, savdead);
135 last1c = ' '; /* anything other than newline */
136 ttyf = isatty(fileno(stdin));
137 pushrest = 0;
140 * scan header & save relevant info.
142 (void) strlcpy(fromU, my_name, sizeof (fromU));
143 fromS[0] = 0; /* set up for >From scan */
144 input = stdin;
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.
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);
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);
166 pushrest = (last1c != '\n');
167 continue;
169 pushrest = (last1c != '\n');
171 if ((hdrtyp = isheader(line, &ctf)) == FALSE) {
172 break;
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);
186 /* note dropthru */
187 hdrtyp = H_FROM1;
188 case H_FROM1:
189 if (substr(line, "forwarded by") > -1) {
190 break;
192 pickFrom(line);
193 if (Rpath[0] != '\0') {
194 strcat(Rpath, "!");
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);
212 n = 0; /* suppress */
213 break;
214 case H_MTYPE:
215 if (flgm) {
216 /* suppress if message-type argument */
217 n = 0;
219 break;
220 case H_CONT:
221 if (oldn == 0) {
222 /* suppress continuation line also */
223 n = 0;
225 break;
227 oldn = n; /* remember if this line was suppressed */
228 if (n && !wtmpf(line, n)) {
229 done(0);
231 if (!n) savehdrs(line, hdrtyp);
233 if (Rpath[0] != '\0') {
234 strcat(Rpath, "!");
236 (void) strlcat(Rpath, fromU, sizeof (Rpath));
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);
247 memcpy(buf, line, n);
248 if (n == 0 || (ttyf && !strncmp(buf, ".\n", 2))) {
249 if (flgf) {
250 /* no input */
251 return;
252 } else {
254 * no content: put mime-version, content-type
255 * and -length only if explicitly present.
256 * Write out 'place-holders' only. (see below....)
258 if ((hptr = hdrlines[H_MIMEVERS].head) != NULL) {
259 (void) snprintf(line, sizeof (line), "%s \n",
260 header[H_MIMEVERS].tag);
261 if (!wtmpf(line, strlen(line))) {
262 done(0);
265 if ((hptr = hdrlines[H_CTYPE].head) != NULL) {
266 (void) snprintf(line, sizeof (line), "%s \n",
267 header[H_CTYPE].tag);
268 if (!wtmpf(line, strlen(line))) {
269 done(0);
272 if ((hptr = hdrlines[H_CLEN].head) != NULL) {
273 (void) snprintf(line, sizeof (line), "%s \n",
274 header[H_CLEN].tag);
275 if (!wtmpf(line, strlen(line))) {
276 done(0);
279 goto wrapsend;
283 if (n == 1 && last1c == '\n') { /* blank line -- suppress */
284 n = getaline(buf, sizeof (buf), stdin);
285 if (n == 0 || (ttyf && !strncmp(buf, ".\n", 2))) {
287 * no content: put mime-version, content-type
288 * and -length only if explicitly present.
289 * Write out 'place-holders' only. (see below....)
291 if ((hptr = hdrlines[H_MIMEVERS].head) != NULL) {
292 (void) snprintf(line, sizeof (line), "%s \n",
293 header[H_MIMEVERS].tag);
294 if (!wtmpf(line, strlen(line))) {
295 done(0);
298 if ((hptr = hdrlines[H_CTYPE].head) != NULL) {
299 (void) snprintf(line, sizeof (line), "%s \n",
300 header[H_CTYPE].tag);
301 if (!wtmpf(line, strlen(line))) {
302 done(0);
305 if ((hptr = hdrlines[H_CLEN].head) != NULL) {
306 (void) snprintf(line, sizeof (line), "%s \n",
307 header[H_CLEN].tag);
308 if (!wtmpf(line, strlen(line))) {
309 done(0);
312 goto wrapsend;
316 if (debug > 0) {
317 buf[n] = '\0';
318 Dout(pn, 0, "header scan complete, readahead %d = \"%s\"\n",
319 n, buf);
323 * Write out H_MIMEVERS, H_CTYPE & H_CLEN lines. These are used only as
324 * placeholders in the tmp file. When the 'real' message is sent,
325 * the proper values will be put out by copylet().
327 (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag);
328 if (!wtmpf(line, strlen(line))) {
329 done(0);
331 if (hdrlines[H_MIMEVERS].head == NULL) {
332 savehdrs(line, H_MIMEVERS);
334 (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag);
335 if (!wtmpf(line, strlen(line))) {
336 done(0);
338 if (hdrlines[H_CTYPE].head == NULL) {
339 savehdrs(line, H_CTYPE);
341 (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag);
342 if (!wtmpf(line, strlen(line))) {
343 done(0);
345 if (hdrlines[H_CLEN].head == NULL) {
346 savehdrs(line, H_CLEN);
348 /* and a blank line */
349 if (!wtmpf("\n", 1)) {
350 done(0);
352 Dout(pn, 0, "header out completed\n");
354 pushrest = 0;
355 count = 0L;
357 * Are we returning mail from a delivery failure of an old-style
358 * (SVR3.1 or SVR3.0) rmail? If so, we won't return THIS on failure
359 * [This line should occur as the FIRST non-blank non-header line]
361 if (!strncmp("***** UNDELIVERABLE MAIL sent to", buf, 32)) {
362 dflag = 9; /* 9 says do not return on failure */
363 Dout(pn, 0, "found old-style UNDELIVERABLE line. dflag = 9\n");
366 /* scan body of message */
367 while (n > 0) {
368 if (ttyf && !strcmp(buf, ".\n"))
369 break;
370 if (!binflg) {
371 binflg = !istext((unsigned char *)buf, n);
374 if (!wtmpf(buf, n)) {
375 done(0);
377 count += n;
378 n = ttyf
379 ? getaline(buf, sizeof (buf), stdin)
380 : fread(buf, 1, sizeof (buf), stdin);
382 setsig(SIGINT, saveint);
384 wrapsend:
386 * In order to use some of the subroutines that are used to
387 * read mail, the let array must be set up
389 nlet = 1;
390 let[0].adr = 0;
391 let[1].adr = ftell(tmpf);
392 let[0].text = (binflg == 1 ? FALSE : TRUE);
393 Dout(pn, 0, "body copy complete, count %ld\n", count);
395 * Modify value of H_MIMEVERS if necessary.
397 if ((hptr = hdrlines[H_MIMEVERS].head) != NULL) {
398 if (strlen(hptr->value) == 0) {
399 (void) strlcpy(hptr->value, "1.0",
400 sizeof (hptr->value));
404 * Modify value of H_CTYPE if necessary.
406 if ((hptr = hdrlines[H_CTYPE].head) != NULL) {
407 if (strlen(hptr->value) == 0) {
408 (void) strlcpy(hptr->value, "text/plain",
409 sizeof (hptr->value));
413 * Set 'place-holder' value of content length to true value
415 if ((hptr = hdrlines[H_CLEN].head) != NULL) {
416 (void) snprintf(hptr->value, sizeof (hptr->value),
417 "%ld", count);
420 if (fclose(tmpf) == EOF) {
421 tmperr();
422 done(0);
425 tmpf = doopen(lettmp, "r+", E_TMP);
427 /* Do not send mail on SIGINT */
428 if (dflag == 2) {
429 done(0);
432 sendlist(&list, 0, 0);
433 done(0);