/*
**
** 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 <sender> <recipient>\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);
}
syntax highlighted by Code2HTML, v. 0.9.1