/**
 * \file main.c
 * Main program.
 */


#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#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;

	real_gid = getgid();

	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);
}
