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