Mercurial > hg > Applications > mh
diff uip/sendmail.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | 441a2190cfae |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uip/sendmail.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,578 @@ +/* sendmail.c - */ +#ifndef lint +static char Id[] = "$Id$"; +#endif +/* + ** A Sendmail fake. + * + * Contributed by Scott Erickson <erickson@ics.uci.edu> + */ +/* Include files glommed from post.c */ + +#include "../h/mh.h" +#include "../h/addrsbr.h" +#include "../h/aliasbr.h" +#include "../h/dropsbr.h" +#include "../zotnet/tws.h" +#ifndef MMDFMTS +#include <ctype.h> +#include <errno.h> +#include <setjmp.h> +#include <stdio.h> +#include <sys/types.h> +#else MMDFMTS +#include "../mts/mmdf/util.h" +#include "../mts/mmdf/mmdf.h" +#endif MMDFMTS +#include "../zotnet/mts.h" +#ifdef MHMTS +#ifndef V7 +#include <sys/ioctl.h> +#endif not V7 +#include <sys/stat.h> +#endif MHMTS +#ifdef SENDMTS +#include "../mts/sendmail/smail.h" +#undef MF +#endif SENDMTS +#include <signal.h> +#ifdef LOCALE +#include <locale.h> +#endif + +char *SMTPSRVR = "smtpsrvr"; + +char msgfname[50]; /* name of message file */ +char *FullName; /* sender's full name */ +char *from; /* sender's mail address */ +int verbose; +int verify; +int extract; +int dodist; +int rewritefrom; +int status; /* return value from procedures */ +static int childid; /* id from smtp child process */ +TYPESIG die(); +time_t lclock = 0L; /* the time we started (more or less) */ + + +FILE *fp; /* file pointer for message file */ +extern FILE *tmpfile(); + +static struct swit switches[] = { +#define ARPASW 0 + "ba", -2, +#define DAEMONSW 1 + "bd", -2, +#define INITALSW 2 + "bi", -2, +#define DELIVSW 3 + "bm", -2, +#define QSUMSW 4 + "bp", -2, +#define SMTPSW 5 + "bs", -2, +#define ADRTSTSW 6 + "bt", -2, +#define ADRVRFSW 7 + "bv", -2, +#define CFGFRZSW 8 + "bz", -2, +#define ALTCFGSW 9 + "C", -1, +#define DBGVALSW 10 + "d", -1, +#define FULLSW 11 + "F", -1, +#define FROMSW 12 + "f", -1, +#define HOPCNTSW 13 + "h", -1, +#define MSGIDSW 14 + "M", -1, +#define NOALISW 15 + "n", -1, +#define QTIMESW 16 + "q", -1, +#define OBSFRMSW 17 + "r", -1, +#define EXTHDRSW 18 + "t", -1, +#define VERBSW 19 + "v", -1, +#define ALTALISW 20 + "oA", -2, +#define NOCONSW 21 + "oc", -2, +#define DLVMODSW 22 + "od", -2, +#define NEWALISW 23 + "oD", -2, +#define ERRMODSW 24 + "oe", -2, +#define TMPMODSW 25 + "oF", -2, +#define UFROMSW 26 + "of", -2, +#define GIDSW 27 + "og", -2, +#define HLPFILSW 28 + "oH", -2, +#define NODOTSW 29 + "oi", -2, +#define LOGLEVSW 30 + "oL", -2, +#define MEOKSW 31 + "om", -2, +#define OLDHDRSW 32 + "oo", -2, +#define QDIRSW 33 + "oQ", -2, +#define RTMOUTSW 34 + "or", -2, +#define SFILESW 35 + "oS", -2, +#define QMSGSW 36 + "os", -2, +#define MTMOUTSW 37 + "oT", -2, +#define TZSW 38 + "ot", -2, +#define UIDSW 39 + "ou", -2, + + NULL, 0 + }; + +#if !defined(POSIX) && !defined(_POSIX_SOURCE) +extern char *mktemp(); +#endif + +static void removemsg(); +static int isheader(), sendfile(); + +/*ARGSUSED*/ +main (argc, argv) +int argc; +char **argv; +{ + register char *cp; + char **argp = argv + 1; + +#ifdef LOCALE + setlocale(LC_ALL, ""); +#endif +#ifdef JAPAN + ml_init(); +#endif /* JAPAN */ + invo_name = r1bindex (argv[0], '/'); + mts_init(argv[0]); + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + (void) signal(SIGINT, die); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + (void) signal(SIGHUP, die); + (void) signal(SIGTERM, die); + (void) signal(SIGPIPE, die); + + FullName = getfullname(); + from = adrsprintf(NULLCP,NULLCP); + (void) time (&lclock); + + while ( (cp = *argp) && *cp == '-' ) { + argp++; + switch (smatch ( ++cp, switches )) { + case ARPASW: /* smtp on stdin */ + case SMTPSW: /* smtp on stdin */ + smtp(); + exit(98); /* should never happen */ + + case DELIVSW: /* just send mail */ + continue; + + case ADRVRFSW: /* verify mode */ + verify = 1; + continue; + + case FROMSW: /* from address */ + case OBSFRMSW: /* obsolete -f flag */ + if (*(++cp) == '\0' && + (!(cp = *argp++) || *cp == '-')) + adios (NULLCP, "missing argument to %s", argp[-2]); + /* At this point, cp points to the from name */ + if (rewritefrom) { + adios (NULLCP, "More than one \"from\" person"); + continue; + } + from = cp; + rewritefrom = 1; + continue; + + case EXTHDRSW: /* read recipients from message */ + extract = 1; + continue; + + case VERBSW: /* give blow-by-blow description */ + verbose = 1; + continue; + + /* These switches have no args. */ + case QMSGSW: /* always queue the message */ + case DAEMONSW: /* run as a daemon & wait for SMTP */ + case INITALSW: /* initialize the alias database */ + case QSUMSW: /* print summary of mail queue */ + case ADRTSTSW: /* test the addresses to debug config file */ + case CFGFRZSW: /* create the configuration freeze file */ + case NOALISW: /* do not do aliasing */ + case NOCONSW: /* do not initiate immediate host connection */ + case NEWALISW: /* run newaliases to rebuild db */ + case UFROMSW: /* save UNIX-style From lines at front of msg*/ + case NODOTSW: /* dots on line are not msg terminators */ + case MEOKSW: /* ok to send to me if I'm in an alias */ + case OLDHDRSW: /* msg may have old-style headers */ + continue; + + /* These switches have string args. */ + case ALTALISW: /* use alternate alias file */ + case ALTCFGSW: /* use alternate configuration file */ + case DBGVALSW: /* set the debug value */ + case FULLSW: /* set full name */ + case MSGIDSW: /* try to deliver queued msg with msg-id */ + case QTIMESW: /* interval between queue passes */ + case DLVMODSW: /* set the delivery mode */ + case ERRMODSW: /* set the error mode */ + case TMPMODSW: /* the mode to use when creating tmp files */ + case HLPFILSW: /* the SMTP help file */ + case QDIRSW: /* directory into which to queue messages */ + case RTMOUTSW: /* timeout on reads */ + case SFILESW: /* save statistics in this file */ + case MTMOUTSW: /* timeout on messages in the queue */ + case TZSW: /* set the name of the timezone */ + if (*(++cp) == '\0' && + (!(cp = *argp++) || *cp == '-')) + adios (NULLCP, "missing argument to %s", argp[-2]); + /* At this point, cp points to the argument */ + continue; /* Ignore */ + + /* These switches have numeric args. */ + case HOPCNTSW: /* hop count */ + case GIDSW: /* gid when calling mailers */ + case LOGLEVSW: /* the log level */ + case UIDSW: /* uid when calling mailers */ + if (*(++cp) == '\0' && + (!(cp = *argp++) || *cp == '-')) + adios (NULLCP, "missing argument to %s", argp[-2]); + /* At this point, cp points to the numeric arg */ + if (!isdigit(*cp)) + adios (NULLCP, "non-numeric argument to %s", argp[-2]); + continue; /* Ignore */ + } + } + + (void) setuid(getuid()); + + if (verify && extract) + adios (NULLCP, "mode not supported on header components"); + + if (*argp == NULL && !extract) + adios (NULLCP, "usage: ", sendmail, " [flags] addr..."); + + strcpy (msgfname, "/tmp/sendmhXXXXXX"); + if ( mktemp(msgfname) == NULL ) + adios (msgfname, "can't create msg file "); + + if ( (fp = fopen(msgfname,"w") ) == NULL ) { + adios (msgfname, "error opening "); + } + + doheader(argp); + if ( verify ) { + (void) fclose(fp); + status = doverify(); + removemsg(); + exit ( status ) ; + } + dobody(); + status = sendfile(); + removemsg(); + exit ( status ); +} + +static void removemsg() +{ + if ( unlink(msgfname) != 0 ) + perror("unlink"); +} + +doheader(argp) +char **argp; +{ + char line[BUFSIZ]; + int gotdate, gotfrom, gotsender, gotto; + + /* if we're not extracting the headers from the message, then we + * need to check to see if we need to do a "send" or a "dist". + */ + + if ( !extract ) { + /* If we're doing a verify, just create a "To:" header. */ + if ( ! verify ) { + gotdate = gotfrom = gotto = gotsender = dodist = 0; + while (fgets (line, BUFSIZ, stdin) != NULL) { + if (line[0] == '\n') /* end of header */ + break; + if ( !isheader(line) ) + break; + + /* if any of the following headers are present, then we + * want to do a dist. + */ + if ( !gotdate && uprf(line, "date") ) + gotdate = dodist = 1; + + else if ( !gotto && (uprf(line, "to") || uprf(line, "cc")) ) + gotto = dodist = 1; + + else if ( uprf(line, "message-id") ) + dodist = 1; + + else if ( !gotsender && uprf(line, "sender") ) + gotsender = dodist = 1; + + else if ( uprf ( line, "resent-" ) ) { + dodist = 1; + (void) fputs("Prev-", fp); + } + + /* See if we are re-writing the from line */ + if ( uprf(line, "from") ) { + gotfrom = 1; + if ( rewritefrom ) + dofrom(); + else + (void) fputs(line,fp); + } + else + (void) fputs(line,fp); + } + } + /* Now, generate a "to" line. The first line is easy. + * Write the rest of the lines with a newline/tab so that we + * don't accidentally write a line that's too long to be parsed + * by post. + */ + (void) fprintf (fp, "%sTo: %s", (dodist ? "Resent-" : "" ), *argp++); + while ( *argp ) + (void) fprintf ( fp, ",\n\t%s", *argp++ ); + (void) fputs("\n",fp); + + /* If we're doing a dist, we must have a "Date:" and "From:" field. + */ + if ( dodist ) { + if ( !gotdate ) + (void) fprintf (fp, "Date: %s\n", dtime (&lclock)); + if ( !gotfrom ) + dofrom(); + } +#ifdef MMDFI /* sigh */ + if ( !gotsender ) + (void) fprintf (fp, "Sender: %s\n", from); +#endif MMDFI + } else { /* we're verifying, so just pass everything through */ + while (fgets (line, BUFSIZ, stdin) != NULL) { + if (line[0] == '\n') /* end of header */ + break; + + if ( rewritefrom && uprf(line, "from")) + dofrom(); + else + (void) fputs(line,fp); + } + } + /* At this point, line is either a newline (end of header) or the + * first line of the body (poorly formatted message). If line + * contains a line of body from a poorly formatted message, then + * print a newline to separate the header correctly, then print + * the body line. + */ + if ( line[0] != '\n' ) /* i.e. a "body" line */ + (void) fputc('\n', fp); + (void) fputs(line, fp); +} + +static int isheader(s) +char *s; +{ + register char *cp; + + /* If the first character is a space, assume a continuation of a header */ + if ( isspace(*s) ) + return 1; + + /* If there's no ':', it's not a header */ + if ( (cp = index(s,':')) == NULL ) + return 0; + + /* If there's a space between BOL and ':', it's not a header */ + while ( s < cp ) { + if ( isspace(*s) ) + return 0; + s++; + } + return 1; +} + +/* This procedure does the verify and returns the status */ +doverify() { + char *command, buf[BUFSIZ], *bp; + FILE *verfp, *popen(); + + /* set up the command line for post */ + if ( (command = (char *)malloc((strlen(postproc) + + strlen(" -whom -check -verbose ") + + strlen(msgfname) + 1 )*sizeof(char))) + == NULL ) { + perror("malloc"); + return NOTOK; + } + + (void) strcpy(command,postproc); + (void) strcat(command," -whom -check "); + if ( verbose ) + (void) strcat(command, "-verbose " ); + (void) strcat(command, msgfname); + + /* open up the pipe */ + if ( (verfp = popen(command,"r")) == NULL ) + return NOTOK; + + while ( fgets(buf, BUFSIZ, verfp) != NULL ) + /* sendmail returns: + * address: result + * so we need to strip the extra post headers. + */ + if ( verbose ) { + bp = buf; + while (isspace(*bp)) + bp++; + if ( *bp != '-' ) + (void) fputs(bp,stdout); + } + + /* return the error status of post */ + return( pclose(verfp) >> 8 ); +} + +static int sendfile() +{ + char *command, buf[BUFSIZ]; + FILE *verfp, *popen(); + + /* set up the command line for post */ + if ( (command = (char *)malloc((strlen(postproc) + + strlen(" -dist -verbose ") + + strlen(msgfname) + 1 )*sizeof(char))) + == NULL ) { + perror("malloc"); + return NOTOK; + } + + (void) strcpy(command,postproc); + (void) strcat(command," "); + if ( verbose ) + (void) strcat(command, "-verbose " ); + if ( dodist ) + (void) strcat(command, "-dist " ); + (void) strcat(command, msgfname); + + /* open up the pipe */ + if ( (verfp = popen(command,"r")) == NULL ) + return NOTOK; + + while ( fgets(buf, BUFSIZ, verfp) != NULL ) + (void) fputs(buf,stdout); + + /* return the error status of post */ + return( pclose(verfp) >> 8 ); +} + +dofrom() { + char line[128]; + + if (FullName) + (void) sprintf(line, "From: %s <%s>\n", FullName, from); + else + (void) sprintf(line, "From: %s\n", from); + (void) fputs(line, fp); +} + +dobody() { + register int i; + char buffer[BUFSIZ]; + + while (!feof (stdin) && !ferror (stdin) && + (i = fread (buffer, sizeof (char), sizeof (buffer), stdin)) > 0) + if (fwrite (buffer, sizeof (char), i , fp) != i ) + adios (NULLCP, "Problem writing body"); + + if (ferror (stdin)) + adios (NULLCP, "Problem reading body"); + + if ( fclose(fp) != 0 ) + adios (NULLCP, "problem ending submission"); +} + +TYPESIG silentdie(); + +smtp() +{ + int sd,len; + char buf[BUFSIZ], response[BUFSIZ]; + + if ((sd = client(NULLCP, "tcp", "smtp", 0, response)) == NOTOK) + adios (NULLCP, "cannot open smtp client process"); + + (void) signal(SIGCHLD, silentdie); + + switch ((childid = fork())) { + case NOTOK: + adios (NULLCP, "unable to fork smtp process"); + + case OK: /* i.e. child */ + (void) dup2(sd,0); + break; + + default: /* i.e. parent */ + (void) dup2(sd,1); + break; + } + while ( (len = read(0, buf, BUFSIZ)) > 0) + (void) write (1, buf, len); + + if (childid) + (void) kill(childid, SIGHUP); + + exit(9); +} + +/* ARGSUSED */ +TYPESIG die(sig) +int sig; +{ + if (fp) { + (void) fclose(fp); + (void) unlink(msgfname); + } + if (sig != SIGHUP) + (void) fprintf(stderr, "sendmail: dying from signal %d\n", sig); + exit(99); +} + +/* ARGSUSED */ + +TYPESIG silentdie(sig) +int sig; +{ + pidwait (childid, OK); + exit(0); +}