/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include "mail.h" #include /* * Send mail - High level sending routine */ void sendmail(argc, argv) char **argv; { char **args; char *tp, *zp; char buf[2048], last1c; FILE *input; struct stat64 sbuf; int aret; int i, n; int oldn = 1; int ttyf = 0; int pushrest = 0; int hdrtyp = 0; int ctf = FALSE; int binflg = 0; long count = 0L; struct tm *bp; struct hdrs *hptr; static char pn[] = "sendmail"; reciplist list; Dout(pn, 0, "entered\n"); new_reciplist(&list); for (i = 1; i < argc; ++i) { if (argv[i][0] == '-') { if (argv[i][1] == '\0') { errmsg(E_SYNTAX, "Hyphens MAY NOT be followed by spaces"); } if (i > 1) { errmsg(E_SYNTAX, "Options MUST PRECEDE persons"); } done(0); } /* * Ensure no NULL names in list */ if (argv[i][0] == '\0' || argv[i][strlen(argv[i])-1] == '!') { errmsg(E_SYNTAX, "Null names are not allowed"); done(0); } /* Don't check for duplication */ add_recip(&list, argv[i], FALSE); } mktmp(); /* * Format time */ time(&iop); bp = localtime(&iop); tp = asctime(bp); zp = tzname[bp->tm_isdst]; sprintf(datestring, "%.16s %.3s %.5s", tp, zp, tp+20); trimnl(datestring); /* asctime: Fri Sep 30 00:00:00 1986\n */ /* 0123456789012345678901234 */ /* RFCtime: Fri, 28 Jul 89 10:30 EDT */ sprintf(RFC822datestring, "%.3s, %.2s %.3s %.4s %.5s %.3s", tp, tp+8, tp+4, tp+20, tp+11, zp); /* * Write out the from line header for the letter */ if (fromflag && deliverflag && from_user[0] != '\0') { (void) snprintf(buf, sizeof (buf), "%s%s %s\n", header[H_FROM].tag, from_user, datestring); } else { (void) snprintf(buf, sizeof (buf), "%s%s %s\n", header[H_FROM].tag, my_name, datestring); } if (!wtmpf(buf, strlen(buf))) { done(0); } savehdrs(buf, H_FROM); /* * Copy to list in mail entry? */ if (flgt == 1 && argc > 1) { aret = argc; args = argv; while (--aret > 0) { (void) snprintf(buf, sizeof (buf), "%s %s\n", header[H_TO].tag, *++args); if (!wtmpf(buf, strlen(buf))) { done(0); } savehdrs(buf, H_TO); } } flgf = 1; /* reset when first read of message body succeeds */ /* * Read mail message, allowing for lines of infinite * length. This is tricky, have to watch for newlines. */ saveint = setsig(SIGINT, savdead); last1c = ' '; /* anything other than newline */ ttyf = isatty(fileno(stdin)); pushrest = 0; /* * scan header & save relevant info. */ (void) strlcpy(fromU, my_name, sizeof (fromU)); fromS[0] = 0; /* set up for >From scan */ input = stdin; /* * Fifofs cannot handle if the inode number crosses * 32-bit limit. This results in overflow, if the * input steam is a pipe. Using 64-bit interface to * take care of that. */ if (fstat64(fileno(input), &sbuf) == 0) { /* Also care if we could not handle large mail. */ if ((sbuf.st_size > MAXOFF_T) || (sbuf.st_blocks > LONG_MAX)) { fprintf(stderr, "%s: stdin: %s\n", program, strerror(EOVERFLOW)); exit(1); } } while ((n = getline(line, sizeof (line), stdin)) > 0) { last1c = line[n-1]; if (pushrest) { if (!wtmpf(line, n)) { done(0); } pushrest = (last1c != '\n'); continue; } pushrest = (last1c != '\n'); if ((hdrtyp = isheader(line, &ctf)) == FALSE) { break; } flgf = 0; switch (hdrtyp) { case H_RVERS: /* Are we dealing with a delivery report? */ /* dflag = 9 ==> do not return on failure */ dflag = 9; Dout(pn, 0, "dflag = 9\n"); break; case H_FROM: if (!wtmpf(">", 1)) { done(0); } /* note dropthru */ hdrtyp = H_FROM1; case H_FROM1: if (substr(line, "forwarded by") > -1) { break; } pickFrom(line); if (Rpath[0] != '\0') { strcat(Rpath, "!"); } (void) strlcat(Rpath, fromS, sizeof (Rpath)); n = 0; /* don't copy remote from's into mesg. */ break; case H_MIMEVERS: case H_CLEN: case H_CTYPE: /* suppress it: only generated if needed */ n = 0; /* suppress */ break; case H_TCOPY: /* Write out placeholder for later */ (void) snprintf(buf, sizeof (buf), "%s \n", header[H_TCOPY].tag); if (!wtmpf(buf, strlen(buf))) { done(0); } n = 0; /* suppress */ break; case H_MTYPE: if (flgm) { /* suppress if message-type argument */ n = 0; } break; case H_CONT: if (oldn == 0) { /* suppress continuation line also */ n = 0; } break; } oldn = n; /* remember if this line was suppressed */ if (n && !wtmpf(line, n)) { done(0); } if (!n) savehdrs(line, hdrtyp); } if (Rpath[0] != '\0') { strcat(Rpath, "!"); } (void) strlcat(Rpath, fromU, sizeof (Rpath)); /* push out message type if so requested */ if (flgm) { /* message-type */ snprintf(buf, sizeof (buf), "%s%s\n", header[H_MTYPE].tag, msgtype); if (!wtmpf(buf, strlen(buf))) { done(0); } } memcpy(buf, line, n); if (n == 0 || (ttyf && !strncmp(buf, ".\n", 2))) { if (flgf) { /* no input */ return; } else { /* * no content: put mime-version, content-type * and -length only if explicitly present. * Write out 'place-holders' only. (see below....) */ if ((hptr = hdrlines[H_MIMEVERS].head) != (struct hdrs *)NULL) { (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag); if (!wtmpf(line, strlen(line))) { done(0); } } if ((hptr = hdrlines[H_CTYPE].head) != (struct hdrs *)NULL) { (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag); if (!wtmpf(line, strlen(line))) { done(0); } } if ((hptr = hdrlines[H_CLEN].head) != (struct hdrs *)NULL) { (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag); if (!wtmpf(line, strlen(line))) { done(0); } } goto wrapsend; } } if (n == 1 && last1c == '\n') { /* blank line -- suppress */ n = getline(buf, sizeof (buf), stdin); if (n == 0 || (ttyf && !strncmp(buf, ".\n", 2))) { /* * no content: put mime-version, content-type * and -length only if explicitly present. * Write out 'place-holders' only. (see below....) */ if ((hptr = hdrlines[H_MIMEVERS].head) != (struct hdrs *)NULL) { (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag); if (!wtmpf(line, strlen(line))) { done(0); } } if ((hptr = hdrlines[H_CTYPE].head) != (struct hdrs *)NULL) { (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag); if (!wtmpf(line, strlen(line))) { done(0); } } if ((hptr = hdrlines[H_CLEN].head) != (struct hdrs *)NULL) { (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag); if (!wtmpf(line, strlen(line))) { done(0); } } goto wrapsend; } } if (debug > 0) { buf[n] = '\0'; Dout(pn, 0, "header scan complete, readahead %d = \"%s\"\n", n, buf); } /* * Write out H_MIMEVERS, H_CTYPE & H_CLEN lines. These are used only as * placeholders in the tmp file. When the 'real' message is sent, * the proper values will be put out by copylet(). */ (void) snprintf(line, sizeof (line), "%s \n", header[H_MIMEVERS].tag); if (!wtmpf(line, strlen(line))) { done(0); } if (hdrlines[H_MIMEVERS].head == (struct hdrs *)NULL) { savehdrs(line, H_MIMEVERS); } (void) snprintf(line, sizeof (line), "%s \n", header[H_CTYPE].tag); if (!wtmpf(line, strlen(line))) { done(0); } if (hdrlines[H_CTYPE].head == (struct hdrs *)NULL) { savehdrs(line, H_CTYPE); } (void) snprintf(line, sizeof (line), "%s \n", header[H_CLEN].tag); if (!wtmpf(line, strlen(line))) { done(0); } if (hdrlines[H_CLEN].head == (struct hdrs *)NULL) { savehdrs(line, H_CLEN); } /* and a blank line */ if (!wtmpf("\n", 1)) { done(0); } Dout(pn, 0, "header out completed\n"); pushrest = 0; count = 0L; /* * Are we returning mail from a delivery failure of an old-style * (SVR3.1 or SVR3.0) rmail? If so, we won't return THIS on failure * [This line should occur as the FIRST non-blank non-header line] */ if (!strncmp("***** UNDELIVERABLE MAIL sent to", buf, 32)) { dflag = 9; /* 9 says do not return on failure */ Dout(pn, 0, "found old-style UNDELIVERABLE line. dflag = 9\n"); } /* scan body of message */ while (n > 0) { if (ttyf && !strcmp(buf, ".\n")) break; if (!binflg) { binflg = !istext((unsigned char *)buf, n); } if (!wtmpf(buf, n)) { done(0); } count += n; n = ttyf ? getline(buf, sizeof (buf), stdin) : fread(buf, 1, sizeof (buf), stdin); } setsig(SIGINT, saveint); wrapsend: /* * In order to use some of the subroutines that are used to * read mail, the let array must be set up */ nlet = 1; let[0].adr = 0; let[1].adr = ftell(tmpf); let[0].text = (binflg == 1 ? FALSE : TRUE); Dout(pn, 0, "body copy complete, count %ld\n", count); /* * Modify value of H_MIMEVERS if necessary. */ if ((hptr = hdrlines[H_MIMEVERS].head) != (struct hdrs *)NULL) { if (strlen(hptr->value) == 0) { (void) strlcpy(hptr->value, "1.0", sizeof (hptr->value)); } } /* * Modify value of H_CTYPE if necessary. */ if ((hptr = hdrlines[H_CTYPE].head) != (struct hdrs *)NULL) { if (strlen(hptr->value) == 0) { (void) strlcpy(hptr->value, "text/plain", sizeof (hptr->value)); } } /* * Set 'place-holder' value of content length to true value */ if ((hptr = hdrlines[H_CLEN].head) != (struct hdrs *)NULL) { (void) snprintf(hptr->value, sizeof (hptr->value), "%ld", count); } if (fclose(tmpf) == EOF) { tmperr(); done(0); } tmpf = doopen(lettmp, "r+", E_TMP); /* Do not send mail on SIGINT */ if (dflag == 2) { done(0); } sendlist(&list, 0, 0); done(0); }