/*
**
** Copyright (C) 1994 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@udac.uu.se
**                                        Torbjorn.Wictorin@udac.uu.se
**
**                                        UDAC	
**                                        P.O. Box 174
**                                        S-751 04 Uppsala
**                                        Sweden
**
*/


#include "emil.h"
short det_sket_sig = FALSE;
struct message *rootmess;
struct config_struct *source = NULL, 
                     *target = NULL;

char	* recipient   = NULL,		/* Recipient	*/
	* sender      = NULL;		/* Sender 	*/
static char * rmx     = NULL;		/* Recipient's mx */

#ifdef	sun
extern	char	* optarg;
#elif	ultrix
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_sendmail	= 0;
int     pseudo_route    = 0;

int	in_fd		= 0;
FILE	* out_fd	= stdout;
FILE	* char_fd	= NULL;
FILE	* conf_fd	= NULL;

int	main(int argc, char *argv[])
{
  
  struct data *d;
  int	c;
  int   no_run = FALSE;

#ifdef	ultrix
  while((c=getopt(argc, argv, "s:r:x:i:o:e:c:B:H:F:C:S:T:lhfpgd")) >= 0) {
#else
  while((c=getopt(argc, argv, "s:r:x:l:i:o:e:c:B:H:F:C:S:T:hfpgd")) >= 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 facility */
#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 -l: %s",optarg);
			logger(LOG_WARNING,ebuf);
		}
#endif
		syslog_logging++;
		break;
	case	'h':	/* Log in header */
		header_logging++;
		break;
	case	'f':	/* Fork mode (sendmail spawning) */
		spawn_sendmail	= 1;
		break;
        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");
			exit(EX_NOINPUT);
		}
		break;
	case	'o':	/* Output file */
		out_fd	= fopen(optarg,"w");
		if (out_fd == NULL) {
			logger(LOG_ERR,"Cannot open output file");
			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");
			exit(EX_OSFILE);
		}
		break;
	case	'c':	/* charsets file */
		char_fd	= fopen(optarg,"r");
		if (char_fd == NULL) {
			logger(LOG_ERR,"Cannot open charsets file");
			exit(EX_OSFILE);
		}
		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	'S':	/* source charsets */
		if (source == NULL)
		  source = (struct config_struct *)Yalloc(sizeof(struct config_struct));
		source->charset = NEWSTR(optarg);
		break;
	default:
		sprintf(ebuf,"Invalid flag: -%c",c);
		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)
    {
      logger(LOG_ERR,"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)
    {
      logger(LOG_ERR,"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";         
    }
  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)
    target = (struct config_struct *) getoption(recipient, sender, rmx);

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

  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"
		);
  logger(LOG_DEBUG,ebuf);
 
  d = (struct data *)load_data();
  logger(LOG_DEBUG,"Data loaded");
  rootmess = (struct message *)Yalloc(sizeof(struct message));
  rootmess->sd = d;
  rootmess->td = d;
  process = 0;
#ifdef DEBUG
  if (edebug)
    fprintf(stderr, "\n* Parsing message.\n");
#endif
  if (parse_message(rootmess) == NOK)
    {
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, "*** Parse message failed.\n");
#endif
      det_sket_sig = TRUE;
      logger(LOG_WARNING,"Parsing failed");
      d->offset = 0;
      if (spawn_sendmail) do_fork();
      	print_log();
      	print_body(d);
      if (spawn_sendmail) end_fork();
      closelog();
      exit(EX_OK);
    }
  process = 1;
#ifdef DEBUG
  if (edebug)
    fprintf(stderr, "\n* Processing message.\n");
#endif
  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_sendmail) do_fork();
  	print_log();
      	print_body(d);
      if (spawn_sendmail) end_fork();
      closelog();
      exit(EX_OK);
    }
  if (spawn_sendmail) do_fork();
  print_log();
#ifdef DEBUG
  if (edebug)
    fprintf(stderr, "\n* Output message.\n");
#endif

  out_message(rootmess);
  if (spawn_sendmail) 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
	  {
	    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
	{
#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, ", 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
	{
#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;
    }
}
