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