/** * \file main.c * Main program. */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H #include #endif #include "main.h" #include "message.h" #include "smtp.h" #include "local.h" #include "rcfile.h" static void drop_sgids( void ) { gid_t real_gid, effective_gid; real_gid = getgid(); effective_gid = getegid(); if( setregid(real_gid,real_gid) != 0 ) { fprintf (stderr, "Could not drop setgid: %s\n", strerror(errno)); exit(EX_DROPPERM); } } /** Modes of operation. */ typedef enum { ENQUEUE, /**< delivery mode */ NEWALIAS, /**< initialize alias database */ MAILQ, /**< list mail queue */ FLUSHQ /**< flush the mail queue */ } opmode_t; int verbose = 0; FILE *log_fp = NULL; static void message_send(message_t *message) { int local, remote; identity_t *identity; /* Lookup the identity already here */ identity = identity_lookup(message->reverse_path); assert(identity); if( identity->qualifydomain ) { local = 0; remote = 1; } else { local = !list_empty(&message->local_recipients); remote = !list_empty(&message->remote_recipients); } if(remote && !local) smtp_send(message,identity); else if(!remote && local) { local_init(message); local_flush(message); } else { local_init(message); smtp_send(message,identity); local_flush(message); } local_cleanup(); } int main (int argc, char **argv) { int c; message_t *message; int parse_headers = 0; opmode_t mode; char *rcfile = NULL; message = message_new(); /* Set the default mode of operation. */ if (!strcmp(argv[0], "mailq")) { mode = MAILQ; } else if (!strcmp(argv[0], "newaliases")) { mode = NEWALIAS; } else { mode = ENQUEUE; } while ((c = getopt (argc, argv, "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:")) != EOF) switch (c) { case 'A': /* Use alternate sendmail/submit.cf */ break; case 'B': /* Body type */ if (!strcmp (optarg, "7BIT")) message->body = E8bitmime_7BIT; else if (!strcmp (optarg, "8BITMIME")) message->body = E8bitmime_8BITMIME; else { fprintf (stderr, "Unsupported body type %s\n", optarg); exit (EX_USAGE); } break; case 'C': /* Select configuration file */ rcfile = optarg; break; case 'F': /* Set full name */ break; case 'G': /* Relay (gateway) submission */ break; case 'I': /* Initialize alias database */ mode = NEWALIAS; break; case 'L': /* Program label */ break; case 'M': /* Define macro */ break; case 'N': /* Delivery status notifications */ if (!strcmp (optarg, "never")) message->notify = Notify_NEVER; else { if (strstr (optarg, "failure")) message->notify |= Notify_FAILURE; if (strstr (optarg, "delay")) message->notify |= Notify_DELAY; if (strstr (optarg, "success")) message->notify |= Notify_SUCCESS; } break; case 'R': /* What to return */ if (!strcmp (optarg, "full")) message->ret |= Ret_FULL; if (!strcmp (optarg, "hdrs")) message->ret |= Ret_HDRS; break; case 'T': /* Set timeout interval */ break; case 'X': /* Traffic log file */ if (log_fp) fclose(log_fp); log_fp = fopen(optarg, "a"); break; case 'V': /* Set original envelope id */ message_set_envid(message, optarg); case 'b': /* Operations mode */ c = (optarg == NULL) ? ' ' : *optarg; switch (c) { case 'm': /* Deliver mail in the usual way */ mode = ENQUEUE; break; case 'i': /* Initialize the alias database */ mode = NEWALIAS; break; case 'p': /* Print a listing of the queue(s) */ mode = MAILQ; break; case 'a': /* Go into ARPANET mode */ case 'd': /* Run as a daemon */ case 'D': /* Run as a daemon in foreground */ case 'h': /* Print the persistent host status database */ case 'H': /* Purge expired entries from the persistent host * status database */ case 'P': /* Print number of entries in the queue(s) */ case 's': /* Use the SMTP protocol as described in RFC821 * on standard input and output */ case 't': /* Run in address test mode */ case 'v': /* Verify names only */ fprintf (stderr, "Unsupported operation mode %c\n", c); exit (EX_USAGE); break; default: fprintf (stderr, "Invalid operation mode %c\n", c); exit (EX_USAGE); break; } break; case 'c': /* Connect to non-local mailers */ break; case 'd': /* Debugging */ break; case 'e': /* Error message disposition */ break; case 'f': /* From address */ case 'r': /* Obsolete -f flag */ message_set_reverse_path(message, optarg); break; case 'h': /* Hop count */ break; case 'i': /* Don't let dot stop me */ break; case 'm': /* Send to me too */ break; case 'n': /* don't alias */ break; case 'o': /* Set option */ break; case 'p': /* Set protocol */ break; case 'q': /* Run queue files at intervals */ mode = FLUSHQ; if (optarg[0] == '!') { /* Negate the meaning of pattern match */ optarg++; } switch (optarg[0]) { case 'G': /* Limit by queue group name */ break; case 'I': /* Limit by ID */ break; case 'R': /* Limit by recipient */ break; case 'S': /* Limit by sender */ break; case 'f': /* Foreground queue run */ break; case 'p': /* Persistent queue */ if (optarg[1] == '\0') break; ++optarg; default: break; } break; case 's': /* Save From lines in headers */ break; case 't': /* Read recipients from message */ parse_headers = 1; break; case 'v': /* Verbose */ verbose = 1; break; default: fprintf (stderr, "Invalid option %c\n", c); exit (EX_USAGE); } switch (mode) { case ENQUEUE: break; case MAILQ: printf ("Mail queue is empty\n"); case NEWALIAS: case FLUSHQ: goto done; } /* At least one more argument is needed. */ if (optind > argc - 1 && !parse_headers) { fprintf(stderr, "Recipient names must be specified\n"); exit (EX_USAGE); } /* Parse the rc file. * * Do this before message_add_recipient; to enable the force_mda recipient */ rcfile_parse(rcfile); /* Read recipients from message */ if (parse_headers) { if (!message_parse_headers(message)) { fprintf(stderr, "No recipients found\n"); exit(EX_DATAERR); } } /* Add remaining program arguments as message recipients. */ while (optind < argc) message_add_recipient(message, argv[optind++]); identities_init(); drop_sgids(); message_send(message); identities_cleanup(); done: if(log_fp) fclose(log_fp); message_free(message); exit(EX_OK); }