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
) !=
259 (struct hdrs
*)NULL
) {
260 (void) snprintf(line
, sizeof (line
), "%s \n",
261 header
[H_MIMEVERS
].tag
);
262 if (!wtmpf(line
, strlen(line
))) {
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
))) {
274 if ((hptr
= hdrlines
[H_CLEN
].head
) !=
275 (struct hdrs
*)NULL
) {
276 (void) snprintf(line
, sizeof (line
), "%s \n",
278 if (!wtmpf(line
, strlen(line
))) {
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
))) {
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
))) {
310 if ((hptr
= hdrlines
[H_CLEN
].head
) !=
311 (struct hdrs
*)NULL
) {
312 (void) snprintf(line
, sizeof (line
), "%s \n",
314 if (!wtmpf(line
, strlen(line
))) {
324 Dout(pn
, 0, "header scan complete, readahead %d = \"%s\"\n",
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
))) {
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
))) {
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
))) {
351 if (hdrlines
[H_CLEN
].head
== (struct hdrs
*)NULL
) {
352 savehdrs(line
, H_CLEN
);
354 /* and a blank line */
355 if (!wtmpf("\n", 1)) {
358 Dout(pn
, 0, "header out completed\n");
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 */
374 if (ttyf
&& !strcmp(buf
, ".\n"))
377 binflg
= !istext((unsigned char *)buf
, n
);
380 if (!wtmpf(buf
, n
)) {
385 ? getaline(buf
, sizeof (buf
), stdin
)
386 : fread(buf
, 1, sizeof (buf
), stdin
);
388 setsig(SIGINT
, saveint
);
392 * In order to use some of the subroutines that are used to
393 * read mail, the let array must be set up
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
),
426 if (fclose(tmpf
) == EOF
) {
431 tmpf
= doopen(lettmp
, "r+", E_TMP
);
433 /* Do not send mail on SIGINT */
438 sendlist(&list
, 0, 0);