/* ** ** Copyright (C) 1993 Swedish University Network (SUNET) ** ** ** This program is developed by UDAC, Uppsala University by commission ** of the Swedish University Network (SUNET). ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITTNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** ** Martin.Wendel@its.uu.se ** Torbjorn.Wictorin@its.uu.se ** ** ITS ** P.O. Box 887 ** S-751 08 Uppsala ** Sweden ** */ #include "emil.h" char *emilbase(char *); short det_sket_sig = FALSE; long alloc_total; struct message *rootmess = NULL; struct config_struct *source = NULL, *target = NULL; char **mailer = NULL; char * recipient = NULL, /* Recipient */ * sender = NULL; /* Sender */ char * rmx = NULL; /* Recipient's mx */ int want_unix_from = 0; #ifdef SMTP int smtp_client = 0; #endif #ifdef sun extern char * optarg; #elif defined(ultrix) || defined(_AUX_SOURCE) extern char * optarg; #endif #ifdef DEBUG int edebug = FALSE; #endif void fix_config_struct(struct config_struct *); int process; char ebuf[1024]; #ifndef ultrix int syslog_facility = LOG_FACILITY; #endif int header_logging = 0; int syslog_logging = 0; int spawn_mailer = 0; int pseudo_route = 0; int in_fd = 0; FILE * out_fd; FILE * char_fd = NULL; FILE * conf_fd = NULL; off_t pz; char * hostname = NULL; int main(int argc, char *argv[]) { struct data *d; int c; int no_run = FALSE; char *cmailer = NULL; char *member = NULL; out_fd = stdout; #ifdef HAVE_GETPAGESIZE pz = (off_t) getpagesize(); #elif defined(hpux) || defined(_AUX_SOURCE) pz = 4096; #else pz = sysconf(_SC_PAGESIZE); #endif if (strcmp(emilbase(argv[0]), "sendmail") == 0) { for (c = 1; c < argc; c++) { if (strncmp(argv[c], "-f", 2) == 0) { if (strlen(argv[c]) > 2) sender = NEWSTR(argv[c] + 2); else { c++; sender = NEWSTR(argv[c]); } } else { recipient = NEWSTR(argv[c]); } } rmx = NEWSTR("localhost"); cmailer = NEWSTR("sendmail"); if (sender == NULL || recipient == NULL) { fprintf(stderr, "USAGE: %s -f \n", argv[0]); exit(-1); } } else #ifdef ultrix while((c=getopt(argc, argv, "s:r:x:i:m:o:e:c:A:B:H:F:C:G:S:T:l:h:fpgduvn")) >= 0) { #else while((c=getopt(argc, argv, "s:r:x:l:i:m:o:e:c:A:B:H:F:C:G:S:T:h:f:pgduvn")) >= 0) { #endif switch (c) { case 's': /* Sender's name */ sender = optarg; break; case 'r': /* Recipient's name */ recipient = optarg; break; case 'x': /* Recipient's mail exchanger address */ rmx = optarg; break; case 'l': /* syslog level */ if (optarg == NULL) { /* Just increment */ syslog_logging++; break; } else switch(*optarg) { case '1': syslog_logging = 1; break; case '2': syslog_logging = 2; break; case '3': syslog_logging = 3; break; case '4': syslog_logging = 4; break; case '5': syslog_logging = 5; break; default: syslog_logging++ ; break; } break; case 'f': #ifndef ultrix if (optarg == NULL) { /* Just increment */ syslog_logging++; break; } *optarg = tolower(*optarg); if (optarg) switch (*optarg) { case 'm': syslog_facility = LOG_MAIL; break; case 'd': syslog_facility = LOG_DAEMON; break; case '0': syslog_facility = LOG_LOCAL0; break; case '1': syslog_facility = LOG_LOCAL1; break; case '2': syslog_facility = LOG_LOCAL2; break; case '3': syslog_facility = LOG_LOCAL3; break; case '4': syslog_facility = LOG_LOCAL4; break; case '5': syslog_facility = LOG_LOCAL5; break; case '6': syslog_facility = LOG_LOCAL6; break; case '7': syslog_facility = LOG_LOCAL7; break; default: sprintf(ebuf,"Invalid parameter to -f: %s",optarg); #ifdef DEBUG if (edebug) fprintf(stderr, "%s", ebuf); #endif logger(LOG_WARNING,ebuf); } #endif break; case 'h': /* Log in header */ if (optarg == NULL) { /* Just increment */ header_logging++; break; } else switch(*optarg) { case '1': header_logging = 1; break; case '2': header_logging = 2; break; case '3': header_logging = 3; break; case '4': header_logging = 4; break; case '5': header_logging = 5; break; default: header_logging++ ; break; } break; case 'm': cmailer = NEWSTR(optarg); break; #ifdef SMTP case 'n': /* SMTP Client */ smtp_client = 1; break; #endif case 'p': /* Add loop back pseudo route */ pseudo_route = 1; break; case 'g': /* Just return group */ no_run = TRUE; break; #ifdef DEBUG case 'd': /* Switch on debugging on stderr */ fprintf(stderr, "*** Emil version %s ***\n", EMIL_VERSION); fprintf(stderr, "Processing with debug switched on.\n"); fprintf(stderr, "(This might produce voluminous output.)\n\n"); edebug = TRUE; break; #endif case 'i': /* Input file */ in_fd = open(optarg,O_RDONLY,0); if (in_fd < 0) { logger(LOG_ERR,"Cannot open input file"); fprintf(stderr, "Emil: Cannot open input file\n"); exit(EX_NOINPUT); } break; case 'o': /* Output file */ out_fd = fopen(optarg,"w"); if (out_fd == NULL) { logger(LOG_ERR,"Cannot open output file"); fprintf(stderr, "Emil: Cannot open output file\n"); exit(EX_CANTCREAT); } break; case 'e': /* Main configuration file */ conf_fd = fopen(optarg,"r"); if (conf_fd == NULL) { logger(LOG_ERR,"Cannot open emil.cf"); fprintf(stderr, "Emil: Cannot open emil.cf\n"); exit(EX_OSFILE); } break; case 'c': /* charsets file */ char_fd = fopen(optarg,"r"); if (char_fd == NULL) { logger(LOG_ERR,"Cannot open charsets file"); fprintf(stderr, "Emil: Cannot open charsets file\n"); exit(EX_OSFILE); } break; case 'A': /* applefile encoding */ if (target == NULL) target = (struct config_struct *)Yalloc(sizeof(struct config_struct)); target->appletype = NEWSTR(optarg); break; case 'B': /* binary encoding */ if (target == NULL) target = (struct config_struct *)Yalloc(sizeof(struct config_struct)); target->bin = NEWSTR(optarg); break; case 'H': /* target header encoding */ if (target == NULL) target = (struct config_struct *)Yalloc(sizeof(struct config_struct)); target->header = NEWSTR(optarg); break; case 'T': /* target text encoding */ if (target == NULL) target = (struct config_struct *)Yalloc(sizeof(struct config_struct)); target->text = NEWSTR(optarg); break; case 'F': /* target format */ if (target == NULL) target = (struct config_struct *)Yalloc(sizeof(struct config_struct)); target->format = NEWSTR(optarg); break; case 'C': /* recipient charset */ if (target == NULL) target = (struct config_struct *)Yalloc(sizeof(struct config_struct)); target->charset = NEWSTR(optarg); break; case 'G': /* Target group */ member = NEWSTR(optarg); break; case 'S': /* source charsets */ if (source == NULL) source = (struct config_struct *)Yalloc(sizeof(struct config_struct)); source->charset = NEWSTR(optarg); break; case 'u': want_unix_from = 1; break; case 'v': printf("emil version %s at your service\n", EMIL_VERSION); fflush(stdout); exit(EX_OK); break; default: sprintf(ebuf,"Invalid flag: -%c",c); #ifdef DEBUG if (edebug) fprintf(stderr, "%s", ebuf); #endif logger(LOG_WARNING,ebuf); } } if (sender == NULL && source == NULL) { #ifdef DEBUG if (edebug) fprintf(stderr, "*** No sender, No source: Check arguments.\n"); #endif sender = NULL; } if (sender == NULL) { #ifdef DEBUG if (edebug) fprintf(stderr, "Missing -s"); #endif logger(LOG_DEBUG,"Missing -s"); sender = "unknown@unknown"; } if (recipient == NULL && target == NULL) { #ifdef DEBUG if (edebug) fprintf(stderr, "*** No recipient, No target: Check arguments.\n"); #endif recipient = NULL; } if (recipient == NULL) { #ifdef DEBUG if (edebug) fprintf(stderr, "Missing -r"); #endif logger(LOG_DEBUG,"Missing -r"); recipient = "unknown@unknown"; } if (rmx == NULL) { #ifdef DEBUG if (edebug) fprintf(stderr, "*** No recipient host: don't worry.\n"); #endif logger(LOG_DEBUG,"Missing -x"); rmx = "unknown"; } if (cmailer != NULL) { mailer = get_mailer(cmailer); if (mailer == NULL) { sprintf(ebuf, "Invalid mailer specification %s", optarg); #ifdef DEBUG if (edebug) fprintf(stderr, "%s", ebuf); #endif logger(LOG_ERR, ebuf); fprintf(stderr, "Emil: %s\n", ebuf); exit(EX_USAGE); } spawn_mailer = 1; } #ifdef SMTP if (smtp_client) { if (sender == NULL) { fprintf(stderr, "Emil: Need sender to use SMTP.\n"); exit(EX_USAGE); } if (recipient == NULL) { fprintf(stderr, "Emil: Need recipient to use SMTP.\n"); exit(EX_USAGE); } if (rmx == NULL) { fprintf(stderr, "Emil: Need relay to use SMTP.\n"); exit(EX_USAGE); } spawn_mailer = 0; smtp_open(rmx); } #endif sprintf(ebuf,"mail from %s to %s via %s",sender,recipient,rmx); logger(LOG_DEBUG,ebuf); #ifdef DEBUG if (edebug) fprintf(stderr, "Processing message from %s to %s via %s.\n", sender, recipient, rmx); #endif if (target == NULL) { if (member == NULL) { #ifdef DEBUG if (edebug) fprintf(stderr, "Using getoption(%s, %s, %s) to get target structure.\n", recipient, sender, rmx); #endif target = (struct config_struct *) getoption(recipient, sender, rmx); } else { #ifdef DEBUG if (edebug) fprintf(stderr, "Using getmember(%s) to get target structure.\n", member); #endif target = (struct config_struct *) getmember(member); } } if (no_run == TRUE) { #ifdef DEBUG if (edebug) fprintf(stderr, "\nResolving target group.\n"); #endif if (target == NULL || target->name == NULL) { #ifdef DEBUG if (edebug) fprintf(stderr, "*** ERROR, unable to resolve target group\n"); #endif target = NULL; } else fprintf(stdout, "%s\n", target->name); fflush(stderr); exit(EX_OK); } if (target == NULL) target = (struct config_struct *)Yalloc(sizeof(struct config_struct)); fix_config_struct(target); if (source == NULL) source = (struct config_struct *) getoption(sender, recipient, rmx); /* rmx?? smx */ sprintf(ebuf,"sender group = %s, recipient group = %s", source ? (source->name ? source->name : "unknown") : "Unknown", target ? (target->name ? target->name : "unknown") : "Unknown" ); #ifdef DEBUG if (edebug) fprintf(stderr, "%s", ebuf); #endif logger(LOG_DEBUG,ebuf); if (source == NULL) source = (struct config_struct *)Yalloc(sizeof(struct config_struct)); d = (struct data *)load_data(); #ifdef DEBUG if (edebug) fprintf(stderr, "Data loaded\n"); fflush(stderr); #endif logger(LOG_DEBUG,"Data loaded"); rootmess = (struct message *)Yalloc(sizeof(struct message)); rootmess->sd = d; rootmess->sdl = d; rootmess->td = d; process = 0; #ifdef DEBUG if (edebug) fprintf(stderr, "\n* Parsing message.\n"); #endif if (target->iformat == TRANSPARENT || parse_message(rootmess) == NOK) { #ifdef DEBUG if (edebug) { if (target->iformat == TRANSPARENT) fprintf(stderr, "*** TRANSPARENT Delivery ***.\n"); else fprintf(stderr, "*** Parse message failed.\n"); } #endif det_sket_sig = TRUE; if (target->iformat != TRANSPARENT) logger(LOG_WARNING,"Parsing failed"); d->offset = 0; if (spawn_mailer) do_fork(); print_log(); out_message(rootmess); if (spawn_mailer) end_fork(); closelog(); #ifdef SMTP if (smtp_client) smtp_close(rmx); #endif exit(EX_OK); } process = 1; rootmess = fix_structure(rootmess); #ifdef DEBUG if (edebug) fprintf(stderr, "\n* Processing message.\n"); #endif convert_applefile(rootmess); if (convert_data(rootmess) == NOK) { #ifdef DEBUG if (edebug) fprintf(stderr, "*** Convert data failed.\n"); #endif det_sket_sig = TRUE; logger(LOG_WARNING, "Conversion failed"); d->offset = 0; if (spawn_mailer) do_fork(); print_log(); out_message(rootmess); if (spawn_mailer) end_fork(); closelog(); #ifdef SMTP if (smtp_client) smtp_close(rmx); #endif exit(EX_OK); } if (spawn_mailer) do_fork(); print_log(); #ifdef DEBUG if (edebug) fprintf(stderr, "\n* Output message.\n"); #endif if (rootmess->sd->format == RFC822) multipart_kludge(rootmess); out_message(rootmess); #ifdef SMTP if (smtp_client) smtp_close(rmx); #endif if (spawn_mailer) end_fork(); /* end_fork returns here if not spawning: */ closelog(); #ifdef DEBUG if (edebug) fprintf(stderr, "Exit OK.\n"); #endif return EX_OK; } void fix_config_struct(struct config_struct *c) { if (c == NULL) return; #ifdef DEBUG if (edebug) fprintf(stderr, "Fix target structure, format - "); #endif if (c->format != NULL) { if (cmatch(c->format, "mime") == TRUE) { c->iformat = MIME; #ifdef DEBUG if (edebug) fprintf(stderr, "mime"); #endif } else if (cmatch(c->format, "mailtool") == TRUE) { c->iformat = MAILTOOL; #ifdef DEBUG if (edebug) fprintf(stderr, "mailtool"); #endif } else if (cmatch(c->format, "transparent") == TRUE) { c->iformat = TRANSPARENT; #ifdef DEBUG if (edebug) fprintf(stderr, "TRANSPARENT"); #endif } else { c->iformat = RFC822; #ifdef DEBUG if (edebug) fprintf(stderr, "other (rfc822)"); #endif } } else { c->iformat = RFC822; #ifdef DEBUG if (edebug) fprintf(stderr, "unspecified (rfc822)"); #endif } #ifdef DEBUG if (edebug) fprintf(stderr, ", binary - "); #endif if (c->bin != NULL) { if (strncasecmp(c->bin, "ba", 2) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "base64"); #endif c->ibin = EBASE64; } else { if (strncasecmp(c->bin, "bi", 2) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "binhex"); #endif c->ibin = EBINHEX; } else { if (strncasecmp(c->bin, "u", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "uuencode"); #endif c->ibin = EUUENCODE; } else { if (strncasecmp(c->bin, "q", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "quoted-printable"); #endif c->ibin = EQP; } else { if (strncasecmp(c->bin, "8", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "8bit"); #endif c->ibin = E8BIT; } else { #ifdef DEBUG if (edebug) fprintf(stderr, "other (7bit)"); #endif c->ibin = E7BIT; }}}}} } else { #ifdef DEBUG if (edebug) fprintf(stderr, "unspecified (7bit)"); #endif c->ibin = E7BIT; } #ifdef DEBUG if (edebug) fprintf(stderr, ", text - "); #endif if (c->text != NULL) { if (strncasecmp(c->text, "ba", 2) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "base64"); #endif c->itext = EBASE64; } else { if (strncasecmp(c->text, "bi", 2) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "binhex"); #endif c->itext = EBINHEX; } else { if (strncasecmp(c->text, "u", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "uuencode"); #endif c->itext = EUUENCODE; } else { if (strncasecmp(c->text, "q", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "quoted-printable"); #endif c->itext = EQP; } else { if (strncasecmp(c->text, "8", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "8bit"); #endif c->itext = E8BIT; } else { if (strncasecmp(c->text, "s", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "SE"); #endif c->itext = ESE; } else { #ifdef DEBUG if (edebug) fprintf(stderr, "other (7bit)"); #endif c->itext = E7BIT; }}}}}} } else { #ifdef DEBUG if (edebug) fprintf(stderr, "unspecified (7bit)"); #endif c->itext = E7BIT; } #ifdef DEBUG if (edebug) fprintf(stderr, ", appletype - "); #endif if (c->appletype != NULL) { if (strncasecmp(c->appletype, "s", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "applesingle"); #endif c->iapple = ASINGLE; } else { if (strncasecmp(c->appletype, "b", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "binhex"); #endif c->iapple = ABINHEX; } else { if (strncasecmp(c->appletype, "d", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "appledouble"); #endif c->iapple = ADOUBLE; } else { #ifdef DEBUG if (edebug) fprintf(stderr, "other (unknown)"); #endif }}} } else { if (c->ibin == EBINHEX) { c->iapple = ABINHEX; #ifdef DEBUG if (edebug) fprintf(stderr, "unspecified (using BinHex)"); #endif } #ifdef DEBUG if (edebug) fprintf(stderr, "unspecified (unknown)"); #endif } #ifdef DEBUG if (edebug) fprintf(stderr, ", header - "); #endif if (c->header != NULL) { if (strncasecmp(c->header, "ba", 2) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "base64.\n"); #endif c->htext = EBASE64; } else { if (strncasecmp(c->header, "q", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "quoted-printable.\n"); #endif c->htext = EQP; } else { if (strncasecmp(c->header, "8", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "8bit.\n"); #endif c->htext = E8BIT; } else { if (strncasecmp(c->header, "s", 1) == 0) { #ifdef DEBUG if (edebug) fprintf(stderr, "SE.\n"); #endif c->htext = ESE; } else { #ifdef DEBUG if (edebug) fprintf(stderr, "other (7bit).\n"); #endif c->htext = E7BIT; }}}} } else { #ifdef DEBUG if (edebug) fprintf(stderr, "unspecified (7bit).\n"); #endif c->htext = E7BIT; } } char * emilbase(char *string) { char *c; if ((c = rindex(string, '/')) != NULL) c++; else c = string; return(c); }