/* $Id: ipop3d.c,v 0.1 2003/10/20 21:12:01 Matt Exp $
* (c) 2000-2002 IC&S, The Netherlands
* modified by Matthew Dickinson
* based upon pop3d.c
* ipop3d.c
*
* ipop3 daemon for use with (x)inetd
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include "imap4.h"
#include "server.h"
#include "debug.h"
#include "misc.h"
#include "dbmail.h"
#include "clientinfo.h"
#include "pop3.h"
#include "serverchild.h"
#include "db.h"
#include "auth.h"
#ifdef PROC_TITLES
#include "proctitleutils.h"
#endif


#define	MAXSOCKADDR  128	/* max socket address structure size */

#define PNAME "dbmail/ipop3d"

/* server timeout error */
#define POP_TIMEOUT_MSG "-ERR I'm leaving, you're tooo slow"

char *configFile = DEFAULT_CONFIG_FILE;

/* set up database login data */
extern field_t _db_host;
extern field_t _db_db;
extern field_t _db_user;
extern field_t _db_pass;

void SetConfigItems(serverConfig_t *config, struct list *items);
void Daemonize();
int SetMainSigHandler();
void MainSigHandler(int sig, siginfo_t *info, void *data);

int pop_before_smtp = 0;

PopSession_t session;
char *myhostname;
char *timeout_setting;

socklen_t len;
struct sockaddr *cliaddr;

static char str[128];

clientinfo_t myclientinfo;

#ifdef PROC_TITLES
int main(int argc, char *argv[], char **envp)
#else
     int main(int argc, char *argv[])
#endif
{
  serverConfig_t config;
  struct list popItems, sysItems;
  int result;
  pid_t pid;

  openlog(PNAME, LOG_PID, LOG_MAIL);

  if (argc >= 2 && (argv[1]))
  {
	  if (strcmp (argv[1],"-v") == 0)
	  {
		  printf ("\n*** DBMAIL: dbmail-ipop3d version $Revision: 0.1 $ %s\n\n",COPYRIGHT);
		  return 0;
	  }
	  else
		  if (strcmp(argv[1],"-f")==0 && (argv[2]))
				configFile = argv[2];
    }


      trace(TRACE_DEBUG, "main(): reading config");
      #ifdef PROC_TITLES
      init_set_proc_title(argc, argv, envp, PNAME);
      set_proc_title("%s", "Idle");
      #endif

      ReadConfig("POP", configFile, &popItems);
      ReadConfig("DBMAIL", configFile, &sysItems);
      SetConfigItems(&config, &popItems);
      SetTraceLevel(&popItems);
      GetDBParams(_db_host, _db_db, _db_user, _db_pass, &sysItems);

      config.ClientHandler = pop3_handle_connection;
      config.timeoutMsg = POP_TIMEOUT_MSG;

      trace(TRACE_DEBUG, "main(): getting socket");
      cliaddr = malloc(MAXSOCKADDR);
      len = MAXSOCKADDR;
      getpeername(0, cliaddr, &len);

      struct sockaddr_in *sin = (struct sockaddr_in*) cliaddr;
            
      trace (TRACE_MESSAGE,"main(): incoming connection from [%s]",
      inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)));
                               
      trace(TRACE_DEBUG, "main(): got socket, starting server");
      trace(TRACE_DEBUG, "main(): Connecting to Database.");
      if (db_connect() != 0)
    {
      trace(TRACE_ERROR, "main(): could not connect to database");
      return -1;
    }

  if (auth_connect() != 0)
    {
      trace(TRACE_ERROR, "main(): could not connect to authentication");
      return -1;
    }

switch ( (pid = fork()) )
	{
	case -1:
	  close(config.listenSocket);
	  trace(TRACE_FATAL, "main(): fork failed [%s]", strerror(errno));

	case 0:
	  /* child process */
	  drop_priviledges(config.serverUser, config.serverGroup);
    myclientinfo.tx = stdout;
    myclientinfo.rx = stdin;
    pop3_handle_connection (&myclientinfo);

	  trace(TRACE_INFO, "main(): server done, exit.");
	  exit(result);
   }

      list_freelist(&popItems.start);
      list_freelist(&sysItems.start);
      close(config.listenSocket);

 /* trace(TRACE_DEBUG, "main(): Disconnecting from Database.");
  db_disconnect();
  trace(TRACE_DEBUG, "main(): Disconnecting from Auth.");
  auth_disconnect();*/

  trace(TRACE_INFO, "main(): exit");
  return 0;
}

void SetConfigItems(serverConfig_t *config, struct list *items)
{
  field_t val;

  /* read items: NCHILDREN */
  GetConfigValue("NCHILDREN", items, val);
  if (strlen(val) == 0)
    trace(TRACE_FATAL, "SetConfigItems(): no value for NCHILDREN in config file");

  if ( (config->nChildren = atoi(val)) <= 0)
    trace(TRACE_FATAL, "SetConfigItems(): value for NCHILDREN is invalid: [%d]", config->nChildren);

  trace(TRACE_DEBUG, "SetConfigItems(): server will create  [%d] children", config->nChildren);


  /* read items: MAXCONNECTS */
  GetConfigValue("MAXCONNECTS", items, val);
  if (strlen(val) == 0)
    trace(TRACE_FATAL, "SetConfigItems(): no value for MAXCONNECTS in config file");

  if ( (config->childMaxConnect = atoi(val)) <= 0)
    trace(TRACE_FATAL, "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", config->childMaxConnect);

  trace(TRACE_DEBUG, "SetConfigItems(): children will make max. [%d] connections", config->childMaxConnect);


  /* read items: TIMEOUT */
  GetConfigValue("TIMEOUT", items, val);
  if (strlen(val) == 0)
    {
      trace(TRACE_DEBUG, "SetConfigItems(): no value for TIMEOUT in config file");
      config->timeout = 0;
    }
  else if ( (config->timeout = atoi(val)) <= 30)
    trace(TRACE_FATAL, "SetConfigItems(): value for TIMEOUT is invalid: [%d]", config->timeout);

  trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", config->timeout);


  /* read items: PORT */
  GetConfigValue("PORT", items, val);
  if (strlen(val) == 0)
    trace(TRACE_FATAL, "SetConfigItems(): no value for PORT in config file");

  if ( (config->port = atoi(val)) <= 0)
    trace(TRACE_FATAL, "SetConfigItems(): value for PORT is invalid: [%d]", config->port);

  trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", config->port);


  /* read items: BINDIP */
  GetConfigValue("BINDIP", items, val);
  if (strlen(val) == 0)
    trace(TRACE_FATAL, "SetConfigItems(): no value for BINDIP in config file");

  strncpy(config->ip, val, IPLEN);
  config->ip[IPLEN-1] = '\0';

  trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", config->ip);


  /* read items: RESOLVE_IP */
  GetConfigValue("RESOLVE_IP", items, val);
  if (strlen(val) == 0)
    trace(TRACE_DEBUG, "SetConfigItems(): no value for RESOLVE_IP in config file");

  config->resolveIP = (strcasecmp(val, "yes") == 0);

  trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", config->resolveIP ? "" : "not ");


  /* read items: IMAP-BEFORE-SMTP */
  GetConfigValue("POP_BEFORE_SMTP", items, val);
  if (strlen(val) == 0)
    trace(TRACE_DEBUG, "SetConfigItems(): no value for POP_BEFORE_SMTP  in config file");

  pop_before_smtp = (strcasecmp(val, "yes") == 0);

  trace(TRACE_DEBUG, "SetConfigItems(): %s POP-before-SMTP",
	pop_before_smtp ? "Enabling" : "Disabling");


  /* read items: EFFECTIVE-USER */
  GetConfigValue("EFFECTIVE_USER", items, val);
  if (strlen(val) == 0)
    trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_USER in config file");

  strncpy(config->serverUser, val, FIELDLEN);
  config->serverUser[FIELDLEN-1] = '\0';

  trace(TRACE_DEBUG, "SetConfigItems(): effective user shall be [%s]", config->serverUser);


  /* read items: EFFECTIVE-GROUP */
  GetConfigValue("EFFECTIVE_GROUP", items, val);
  if (strlen(val) == 0)
    trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_GROUP in config file");

  strncpy(config->serverGroup, val, FIELDLEN);
  config->serverGroup[FIELDLEN-1] = '\0';

  trace(TRACE_DEBUG, "SetConfigItems(): effective group shall be [%s]", config->serverGroup);



}
