Mercurial > hg > Applications > mh
view uip/sendmail.c @ 12:441a2190cfae
Lion fix
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Sat, 21 Apr 2012 13:10:49 +0900 |
parents | bce86c4163a3 |
children |
line wrap: on
line source
/* sendmail.c - */ #ifndef lint static char Id[] = "$Id: sendmail.c,v 1.1.1.1 2005/04/18 14:46:07 kono Exp $"; #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); }