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]
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 */
30 #include <sys/param.h>
32 * Send mail - High level sending routine
40 char buf
[2048], last1c
;
54 static char pn
[] = "sendmail";
57 Dout(pn
, 0, "entered\n");
59 for (i
= 1; i
< argc
; ++i
) {
60 if (argv
[i
][0] == '-') {
61 if (argv
[i
][1] == '\0') {
63 "Hyphens MAY NOT be followed by spaces");
67 "Options MUST PRECEDE persons");
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");
78 /* Don't check for duplication */
79 add_recip(&list
, argv
[i
], FALSE
);
89 zp
= tzname
[bp
->tm_isdst
];
90 sprintf(datestring
, "%.16s %.3s %.5s", tp
, zp
, tp
+20);
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
);
105 (void) snprintf(buf
, sizeof (buf
), "%s%s %s\n",
106 header
[H_FROM
].tag
, my_name
, datestring
);
108 if (!wtmpf(buf
, strlen(buf
))) {
111 savehdrs(buf
, H_FROM
);
114 * Copy to list in mail entry?
116 if (flgt
== 1 && argc
> 1) {
120 (void) snprintf(buf
, sizeof (buf
),
121 "%s %s\n", header
[H_TO
].tag
, *++args
);
122 if (!wtmpf(buf
, strlen(buf
))) {
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
));
140 * scan header & save relevant info.
142 (void) strlcpy(fromU
, my_name
, sizeof (fromU
));
143 fromS
[0] = 0; /* set up for >From scan */
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
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
));
160 while ((n
= getaline(line
, sizeof (line
), stdin
)) > 0) {
163 if (!wtmpf(line
, n
)) {
166 pushrest
= (last1c
!= '\n');
169 pushrest
= (last1c
!= '\n');
171 if ((hdrtyp
= isheader(line
, &ctf
)) == FALSE
) {
177 /* Are we dealing with a delivery report? */
178 /* dflag = 9 ==> do not return on failure */
180 Dout(pn
, 0, "dflag = 9\n");
183 if (!wtmpf(">", 1)) {
189 if (substr(line
, "forwarded by") > -1) {
193 if (Rpath
[0] != '\0') {
196 (void) strlcat(Rpath
, fromS
, sizeof (Rpath
));
197 n
= 0; /* don't copy remote from's into mesg. */
202 /* suppress it: only generated if needed */
203 n
= 0; /* suppress */
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
))) {
212 n
= 0; /* suppress */
216 /* suppress if message-type argument */
222 /* suppress continuation line also */
227 oldn
= n
; /* remember if this line was suppressed */
228 if (n
&& !wtmpf(line
, n
)) {
231 if (!n
) savehdrs(line
, hdrtyp
);
233 if (Rpath
[0] != '\0') {
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
))) {
247 memcpy(buf
, line
, n
);
248 if (n
== 0 || (ttyf
&& !strncmp(buf
, ".\n", 2))) {
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
))) {
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
))) {
272 if ((hptr
= hdrlines
[H_CLEN
].head
) != NULL
) {
273 (void) snprintf(line
, sizeof (line
), "%s \n",
275 if (!wtmpf(line
, strlen(line
))) {
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
))) {
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
))) {
305 if ((hptr
= hdrlines
[H_CLEN
].head
) != NULL
) {
306 (void) snprintf(line
, sizeof (line
), "%s \n",
308 if (!wtmpf(line
, strlen(line
))) {
318 Dout(pn
, 0, "header scan complete, readahead %d = \"%s\"\n",
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
))) {
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
))) {
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
))) {
345 if (hdrlines
[H_CLEN
].head
== NULL
) {
346 savehdrs(line
, H_CLEN
);
348 /* and a blank line */
349 if (!wtmpf("\n", 1)) {
352 Dout(pn
, 0, "header out completed\n");
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 */
368 if (ttyf
&& !strcmp(buf
, ".\n"))
371 binflg
= !istext((unsigned char *)buf
, n
);
374 if (!wtmpf(buf
, n
)) {
379 ? getaline(buf
, sizeof (buf
), stdin
)
380 : fread(buf
, 1, sizeof (buf
), stdin
);
382 setsig(SIGINT
, saveint
);
386 * In order to use some of the subroutines that are used to
387 * read mail, the let array must be set up
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
),
420 if (fclose(tmpf
) == EOF
) {
425 tmpf
= doopen(lettmp
, "r+", E_TMP
);
427 /* Do not send mail on SIGINT */
432 sendlist(&list
, 0, 0);