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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include "mail.h" 34 /* 35 Send mail - High level sending routine 36 */ 37 void sendmail(argc, argv) 38 char **argv; 39 { 40 char **args; 41 char *tp, *zp; 42 char buf[2048],last1c; 43 FILE *input; 44 struct stat sbuf; 45 int aret; 46 int i, n; 47 int oldn = 1; 48 int ttyf = 0; 49 int pushrest = 0; 50 int hdrtyp = 0; 51 int ctf = FALSE; 52 int binflg = 0; 53 long count = 0L; 54 struct tm *bp; 55 struct hdrs *hptr; 56 static char pn[] = "sendmail"; 57 reciplist list; 58 59 Dout(pn, 0, "entered\n"); 60 new_reciplist(&list); 61 for (i = 1; i < argc; ++i) { 62 if (argv[i][0] == '-') { 63 if (argv[i][1] == '\0') { 64 errmsg(E_SYNTAX,"Hyphens MAY NOT be followed by spaces"); 65 } 66 if (i > 1) { 67 errmsg(E_SYNTAX,"Options MUST PRECEDE persons"); 68 } 69 done(0); 70 } 71 /* 72 Ensure no NULL names in list 73 */ 74 if (argv[i][0] == '\0' || argv[i][strlen(argv[i])-1] == '!') { 75 errmsg(E_SYNTAX,"Null names are not allowed"); 76 done(0); 77 } 78 add_recip(&list, argv[i], FALSE); /* Don't check for duplication */ 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), "%s %s\n", header[H_TO].tag, *++args); 120 if (!wtmpf(buf, strlen(buf))) { 121 done(0); 122 } 123 savehdrs(buf, H_TO); 124 } 125 } 126 127 flgf = 1; /* reset when first read of message body succeeds */ 128 /* 129 Read mail message, allowing for lines of infinite 130 length. This is tricky, have to watch for newlines. 131 */ 132 saveint = setsig(SIGINT, savdead); 133 last1c = ' '; /* anything other than newline */ 134 ttyf = isatty (fileno(stdin)); 135 pushrest = 0; 136 137 /* 138 * scan header & save relevant info. 139 */ 140 (void) strlcpy(fromU, my_name, sizeof (fromU)); 141 fromS[0] = 0; /* set up for >From scan */ 142 input = stdin; 143 if (fstat(fileno(input), &sbuf) < 0) { 144 if (errno == EOVERFLOW) { 145 perror("stdin"); 146 exit(1); 147 } 148 } 149 150 while ((n = getline (line, sizeof line, stdin)) > 0) { 151 last1c = line[n-1]; 152 if (pushrest) { 153 if (!wtmpf(line,n)) { 154 done(0); 155 } 156 pushrest = (last1c != '\n'); 157 continue; 158 } 159 pushrest = (last1c != '\n'); 160 161 if ((hdrtyp = isheader (line, &ctf)) == FALSE) { 162 break; 163 } 164 flgf = 0; 165 switch (hdrtyp) { 166 case H_RVERS: 167 /* Are we dealing with a delivery report? */ 168 /* dflag = 9 ==> do not return on failure */ 169 dflag = 9; 170 Dout(pn, 0, "dflag = 9\n"); 171 break; 172 case H_FROM: 173 if (!wtmpf(">", 1)) { 174 done(0); 175 } 176 /* note dropthru */ 177 hdrtyp = H_FROM1; 178 case H_FROM1: 179 if (substr(line, "forwarded by") > -1) { 180 break; 181 } 182 pickFrom (line); 183 if (Rpath[0] != '\0') { 184 strcat(Rpath, "!"); 185 } 186 (void) strlcat(Rpath, fromS, sizeof (Rpath)); 187 n = 0; /* don't copy remote from's into mesg. */ 188 break; 189 case H_MIMEVERS: 190 case H_CLEN: 191 case H_CTYPE: 192 /* suppress it: only generated if needed */ 193 n = 0; /* suppress */ 194 break; 195 case H_TCOPY: 196 /* Write out placeholder for later */ 197 (void) snprintf(buf, sizeof (buf), "%s \n", header[H_TCOPY].tag); 198 if (!wtmpf(buf, strlen(buf))) { 199 done(0); 200 } 201 n = 0; /* suppress */ 202 break; 203 case H_MTYPE: 204 if (flgm) { 205 /* suppress if message-type argument */ 206 n = 0; 207 } 208 break; 209 case H_CONT: 210 if (oldn == 0) { 211 /* suppress continuation line also */ 212 n = 0; 213 } 214 break; 215 } 216 oldn = n; /* remember if this line was suppressed */ 217 if (n && !wtmpf(line,n)) { 218 done(0); 219 } 220 if (!n) savehdrs(line, hdrtyp); 221 } 222 if (Rpath[0] != '\0') { 223 strcat(Rpath, "!"); 224 } 225 (void) strlcat(Rpath, fromU, sizeof (Rpath)); 226 227 /* push out message type if so requested */ 228 if (flgm) { /* message-type */ 229 snprintf(buf, sizeof(buf), "%s%s\n", header[H_MTYPE].tag, msgtype); 230 if (!wtmpf(buf, strlen(buf))) { 231 done(0); 232 } 233 } 234 235 memcpy (buf, line, n); 236 if (n == 0 || (ttyf && !strncmp (buf, ".\n", 2)) ) { 237 if (flgf) { 238 /* no input */ 239 return; 240 } else { 241 /* 242 * no content: put mime-version, content-type 243 * and -length only if explicitly present. 244 * Write out 'place-holders' only. (see below....) 245 */ 246 if ((hptr = hdrlines[H_MIMEVERS].head) != 247 (struct hdrs *)NULL) { 248 (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag); 249 if (!wtmpf(line, strlen(line))) { 250 done(0); 251 } 252 } 253 if ((hptr = hdrlines[H_CTYPE].head) != 254 (struct hdrs *)NULL) { 255 (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag); 256 if (!wtmpf(line, strlen(line))) { 257 done(0); 258 } 259 } 260 if ((hptr = hdrlines[H_CLEN].head) != 261 (struct hdrs *)NULL) { 262 (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag); 263 if (!wtmpf(line, strlen(line))) { 264 done(0); 265 } 266 } 267 goto wrapsend; 268 } 269 } 270 271 if (n == 1 && last1c == '\n') { /* blank line -- suppress */ 272 n = getline (buf, sizeof buf, stdin); 273 if (n == 0 || (ttyf && !strncmp (buf, ".\n", 2)) ) { 274 /* 275 * no content: put mime-version, content-type 276 * and -length only if explicitly present. 277 * Write out 'place-holders' only. (see below....) 278 */ 279 if ((hptr = hdrlines[H_MIMEVERS].head) != 280 (struct hdrs *)NULL) { 281 (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag); 282 if (!wtmpf(line, strlen(line))) { 283 done(0); 284 } 285 } 286 if ((hptr = hdrlines[H_CTYPE].head) != 287 (struct hdrs *)NULL) { 288 (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag); 289 if (!wtmpf(line, strlen(line))) { 290 done(0); 291 } 292 } 293 if ((hptr = hdrlines[H_CLEN].head) != 294 (struct hdrs *)NULL) { 295 (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag); 296 if (!wtmpf(line, strlen(line))) { 297 done(0); 298 } 299 } 300 goto wrapsend; 301 } 302 } 303 304 if (debug > 0) { 305 buf[n] = '\0'; 306 Dout(pn, 0, "header scan complete, readahead %d = \"%s\"\n", n, buf); 307 } 308 309 /* 310 * Write out H_MIMEVERS, H_CTYPE & H_CLEN lines. These are used only as 311 * placeholders in the tmp file. When the 'real' message is sent, 312 * the proper values will be put out by copylet(). 313 */ 314 (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag); 315 if (!wtmpf(line, strlen(line))) { 316 done(0); 317 } 318 if (hdrlines[H_MIMEVERS].head == (struct hdrs *)NULL) { 319 savehdrs(line, H_MIMEVERS); 320 } 321 (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag); 322 if (!wtmpf(line, strlen(line))) { 323 done(0); 324 } 325 if (hdrlines[H_CTYPE].head == (struct hdrs *)NULL) { 326 savehdrs(line,H_CTYPE); 327 } 328 (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag); 329 if (!wtmpf(line, strlen(line))) { 330 done(0); 331 } 332 if (hdrlines[H_CLEN].head == (struct hdrs *)NULL) { 333 savehdrs(line,H_CLEN); 334 } 335 /* and a blank line */ 336 if (!wtmpf("\n", 1)) { 337 done(0); 338 } 339 Dout(pn, 0, "header out completed\n"); 340 341 pushrest = 0; 342 count = 0L; 343 /* 344 * Are we returning mail from a delivery failure of an old-style 345 * (SVR3.1 or SVR3.0) rmail? If so, we won't return THIS on failure 346 * [This line should occur as the FIRST non-blank non-header line] 347 */ 348 if (!strncmp("***** UNDELIVERABLE MAIL sent to",buf,32)) { 349 dflag = 9; /* 9 says do not return on failure */ 350 Dout(pn, 0, "found old-style UNDELIVERABLE line. dflag = 9\n"); 351 } 352 353 /* scan body of message */ 354 while (n > 0) { 355 if (ttyf && !strcmp (buf, ".\n")) 356 break; 357 if (!binflg) { 358 binflg = !istext ((unsigned char *)buf, n); 359 } 360 361 if (!wtmpf(buf, n)) { 362 done(0); 363 } 364 count += n; 365 n = ttyf 366 ? getline (buf, sizeof buf, stdin) 367 : fread (buf, 1, sizeof buf, stdin); 368 } 369 setsig(SIGINT, saveint); 370 371 wrapsend: 372 /* 373 * In order to use some of the subroutines that are used to 374 * read mail, the let array must be set up 375 */ 376 nlet = 1; 377 let[0].adr = 0; 378 let[1].adr = ftell(tmpf); 379 let[0].text = (binflg == 1 ? FALSE : TRUE); 380 Dout(pn, 0, "body copy complete, count %ld\n", count); 381 /* 382 * Modify value of H_MIMEVERS if necessary. 383 */ 384 if ((hptr = hdrlines[H_MIMEVERS].head) != (struct hdrs *)NULL) { 385 if (strlen(hptr->value) == 0) { 386 (void) strlcpy(hptr->value, "1.0", 387 sizeof (hptr->value)); 388 } 389 } 390 /* 391 * Modify value of H_CTYPE if necessary. 392 */ 393 if ((hptr = hdrlines[H_CTYPE].head) != (struct hdrs *)NULL) { 394 if (strlen(hptr->value) == 0) { 395 (void) strlcpy(hptr->value, "text/plain", 396 sizeof (hptr->value)); 397 } 398 } 399 /* 400 * Set 'place-holder' value of content length to true value 401 */ 402 if ((hptr = hdrlines[H_CLEN].head) != (struct hdrs *)NULL) { 403 (void) snprintf(hptr->value, sizeof (hptr->value), 404 "%ld", count); 405 } 406 407 if (fclose(tmpf) == EOF) { 408 tmperr(); 409 done(0); 410 } 411 412 tmpf = doopen(lettmp,"r+",E_TMP); 413 414 /* Do not send mail on SIGINT */ 415 if (dflag == 2) { 416 done(0); 417 } 418 419 sendlist(&list, 0, 0); 420 done(0); 421 } 422