8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / mail / sendmail.c
blob9bd6444b6a9b3f6d8a9c798a8eb221eab3e4e62a
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) !=
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);
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);
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);
282 goto wrapsend;
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))) {
290 * no content: put mime-version, content-type
291 * and -length only if explicitly present.
292 * Write out 'place-holders' only. (see below....)
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);
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);
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);
318 goto wrapsend;
322 if (debug > 0) {
323 buf[n] = '\0';
324 Dout(pn, 0, "header scan complete, readahead %d = \"%s\"\n",
325 n, buf);
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().
333 (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag);
334 if (!wtmpf(line, strlen(line))) {
335 done(0);
337 if (hdrlines[H_MIMEVERS].head == (struct hdrs *)NULL) {
338 savehdrs(line, H_MIMEVERS);
340 (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag);
341 if (!wtmpf(line, strlen(line))) {
342 done(0);
344 if (hdrlines[H_CTYPE].head == (struct hdrs *)NULL) {
345 savehdrs(line, H_CTYPE);
347 (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag);
348 if (!wtmpf(line, strlen(line))) {
349 done(0);
351 if (hdrlines[H_CLEN].head == (struct hdrs *)NULL) {
352 savehdrs(line, H_CLEN);
354 /* and a blank line */
355 if (!wtmpf("\n", 1)) {
356 done(0);
358 Dout(pn, 0, "header out completed\n");
360 pushrest = 0;
361 count = 0L;
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]
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");
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);
380 if (!wtmpf(buf, n)) {
381 done(0);
383 count += n;
384 n = ttyf
385 ? getaline(buf, sizeof (buf), stdin)
386 : fread(buf, 1, sizeof (buf), stdin);
388 setsig(SIGINT, saveint);
390 wrapsend:
392 * In order to use some of the subroutines that are used to
393 * read mail, the let array must be set up
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);
401 * Modify value of H_MIMEVERS if necessary.
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));
410 * Modify value of H_CTYPE if necessary.
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));
419 * Set 'place-holder' value of content length to true value
421 if ((hptr = hdrlines[H_CLEN].head) != (struct hdrs *)NULL) {
422 (void) snprintf(hptr->value, sizeof (hptr->value),
423 "%ld", count);
426 if (fclose(tmpf) == EOF) {
427 tmperr();
428 done(0);
431 tmpf = doopen(lettmp, "r+", E_TMP);
433 /* Do not send mail on SIGINT */
434 if (dflag == 2) {
435 done(0);
438 sendlist(&list, 0, 0);
439 done(0);