/* 
Acidblood IRC Bot 
Copyright (C) 1997-2000 Bryan Schwab
bryan@darkice.com 

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 1, 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 FITNESS 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.

*/

#include "acidblood.h"
#include <sys/types.h>
#include <sys/times.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <ctype.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>


/* Global state variables */
int main_pid;          /* pid of main program */
int state=0;           /* bot state 0-normal 1-gather 2-massdeop 3-kick ban */
int logging=1;         /* logging is off when 0, on when 1 */
int pong_init=0;
int alarm_called=0;
int alarm_returned=1;

/* amount of times alarm was called */
int globalthingy=0;
  
/* had to make these global for the signal handler */
char *pong_out;  /* pong string */
int s;           /* network socket */
char *pong;      /* pong data */
/* end globals for signal handler */

/* signal handler */
void
handler(
int signal)
{
   exit(0);
}

/* alarm signal handler */
void
timeout(
int signal)
{
   printf("Network timeout. Exiting.\n");
   exit(0);
}

/* The signal handler just clears the flag and re-enables itself. */
void
catch_alarm (int sig)
{
  globalthingy++;
  alarm_called--;
  alarm_returned++;
  #ifdef DEBUG
     printf("alarm called %d times\n", globalthingy);
  #endif
  signal(sig, catch_alarm);

  /* if we know the pong data, better to get it from network */
  if (pong_init) {
     #ifdef DEBUG
        printf("sending %s",pong_out);
     #endif
     if ((send(s,pong_out,strlen(pong_out),0))==-1) {
	printf("network error in signal handler, exiting\n");
	exit(-1);
     }
  }
}


/* initialize all the important log & config files */
int
initialize(
FILE **fp_log, 
FILE **fp_debug, 
FILE **fp_config,
FILE **fp_line) 
{

   if ((*fp_log=fopen("../logs/acid.log","a"))==NULL) {
      fprintf(stderr,"Cannot open log file [logs/acid.log]!\n");
      return(-1);
   }

   #ifdef DEBUG
   if ((*fp_debug=fopen("../logs/acid.debug","a"))==NULL) {
      fprintf(stderr,"Cannot open debug file [logs/acid.debug]!\n");
      return(-1);
   }
   else {
      fprintf(*fp_debug,"\n");
   }

   if ((*fp_line=fopen("../logs/acid.lines","a"))==NULL) {
      fprintf(stderr,"Cannot open [logs/acid.logs]!\n");
      return(-1);
   }
   #endif

   if ((*fp_config=fopen("../conf/acid.conf","r"))==NULL) {
      fprintf(stderr,"Cannot open config file [conf/acid.conf]!\n");
      return(-1);
   }

   return (0);
}


/* signal handler */
void
handler_hup(
int signal)
{
   read_user_data();
   return;
}

int
main(
int argc,
char *argv[])
{
   /* non-global variables */
   FILE *fp_log;    /* file pointer for log file */
   FILE *fp_line;    /* file pointer for line file */
   FILE *fp_debug;  /* file pointer for debug file */
   FILE *fp_config; /* file pointer for config file */
   FILE *fp_socket; /* file pointer for socket */
   FILE *fp_pid;    /* file pointer for pid file */
   time_t currtime;
   time_t starttime;
   char timestr[50];
   struct tm *logtime;
   int result;
   int not_connected=1;
   int retry=0;

   totalbytes=0;
   time(&starttime);

   /* globals */
   globalx=0;
   globalint=0;

   /* signals to watch out for */
   signal(SIGINT,handler);
   signal(SIGQUIT,handler);
   signal(SIGTERM,handler);
   signal(SIGALRM,timeout);


   printf("Acidblood %s\n", VERSION);

   if ((botinfo=malloc(sizeof(struct botstruct)))==NULL) {
      fprintf(stderr,"main: Malloc error!\n");
      exit(-1);
   }

   if ((serverdata=malloc(sizeof(struct serverstruct)))==NULL) {
      fprintf(stderr,"main: Malloc error!\n");
      exit(-1);
   }

   if ((channeldata=malloc(sizeof(struct channels)))==NULL) {
      fprintf(stderr,"main: Malloc error!\n");
      exit(-1);
   }

   if ((input=malloc(1000))==NULL) {
      fprintf(stderr,"main: Malloc error!\n");
      exit(-1);
   }

   if ((pong_out=malloc(100))==NULL) {
      fprintf(stderr,"main: Malloc error!\n");
      exit(-1);
   }


   if ((pong=malloc(50))==NULL) {
      fprintf(stderr,"main: Malloc error!\n");
      exit(-1);
   }


   /* initialize file system */
   if (initialize(&fp_log, &fp_debug, &fp_config, &fp_line) < 0) {
      fprintf(stderr, "Initialization failed.\n");
      exit(-1);
   }

   /* read in config file */
   if (read_config(botinfo, &fp_config, &fp_debug) < 0 ) {
      fprintf(stderr,"Error loading users.\n"); 
      exit(-1);
   }

   memset(argv[0],0,strlen(argv[0]));
   strncpy(argv[0], botinfo->image, strlen(botinfo->image));
 
   /* load user data */
   if ((read_user_data()) < 0 ) {
      fprintf(stderr,"Error reading in user file.\n");
      exit(-1);
   }

   printf("Connecting to %s\n",botinfo->server);


   /* connect to server */
   while(not_connected) {
      if (retry > 1) {
         fprintf(stderr,"Exiting.\n");
         exit(-1);
      }
      result=connect_to_server(botinfo, &fp_socket, &fp_log, &s);

      if (result==-5) {
	 fprintf(stderr, "Error, server closed link\n");
         exit(-1);
      }

      if (result==-4) {
	 fprintf(stderr,"Sorry, you must have identd installed to connect to this server.\n");
	 exit(-1);
      }

      if (result==-3) {
         fprintf(stderr,"No more connections.\n");
         fprintf(stderr,"Retrying...\n");
	 retry++;
      }
      else if (result==-2) {
         fprintf(stderr,"No Auth, please install identd or set the USER variable to be your login name.\n");
         fprintf(stderr,"Retrying...\n");
	 retry++;
      }
      else if (result==-1) {
         fprintf(stderr,"Cannot connect to server.\n");
         fprintf(stderr,"Retrying...\n");
	 retry++;
      }

      else if (result==0) {
         fprintf(stderr,"Connected!\n");
         not_connected=0;
      }

      
   }

   time(&currtime);
   logtime=localtime(&currtime);
   strftime(timestr,sizeof(timestr),"%a %b %d %H:%M:%Y",logtime);
   fprintf(fp_log,"Connection complete : %s\n",timestr);
   fflush(fp_log);

   /* timeout routine */
   signal(SIGALRM, catch_alarm);


   /* main loop */
   if (!(main_pid=fork())) {
      /* FIX */
      /* signal(SIGHUP,handler_hup); */
      if ((fp_pid=fopen("../logs/acid.pid","w"))==NULL) {
         fprintf(fp_log,"Cannot open pid file.\n");
         exit(-1);
      }
      fprintf(fp_pid,"%d",(main_pid=getpid()));
      fclose(fp_pid);

      while (1) {

        if (!alarm_called) {
           alarm(botinfo->timer);
           alarm_called++;
	   alarm_returned--;
        }

        /* the alarm is going to wait on this function */
        result=getline_from_server(botinfo,input,s);

         #ifdef DEBUG
           if (strlen(input) > 0) {
	      printf("line> %s\n",input);
           }
         #endif

        /* got data in the buffer */
        if (result > 0 ) {
         #ifdef DEBUG
 	    fprintf(fp_line,"%s\n",input);
	    fflush(fp_line);
         #endif
         time(&currtime);
         logtime=localtime(&currtime);
         strftime(timestr,sizeof(timestr),"%a %b %d %H:%M:%Y",logtime);
      
         if (!strncmp("PING",input,4)) {

            if (!pong_init) {
               pong=strtok(input,":");
               pong=strtok(NULL,"\n");
               snprintf(pong_out,100,"PONG :%s\n",pong);
               printf("initial: %s", pong_out);
            }

            if ((send(s,pong_out,strlen(pong_out),0))==-1) {
               exit(-1);
            }

            if ((send(s,pong_out,strlen(pong_out),0))==-1) {
               exit(-1);
            }

	    pong_init=1;
         }

         if (parse_server(input,serverdata,&fp_debug,&fp_log) < 0) {
	    break;
         }
         if (no_parse!=1) {
            if (execute(serverdata,botinfo,&fp_debug,&fp_socket,&fp_log,&s,timestr,starttime) < 0) {
	       break;
            }
         }
      
       }

      else if (alarm_returned) {
         /* just wait for more data */
      }
      /* hmmm got a zero */
      else if (result==0) {
	/* wont be able to get to here */
      }
      /* error doing network calls */
      else if (result==-1) {
        fprintf(fp_log,"Timeout from server. Exiting %s\n",timestr);
        fflush(fp_log);
        break;
      }
      else if (result==-2) {
        fprintf(fp_log,"Error from server. Exiting %s\n",timestr);
	fflush(fp_log);
	break;
      }
      /* no data in the buffer, problem */
      else {
        printf("unexpected result\n");
      }
     }
     printf("about to exit\n");
     exit(0);
   }

   fclose(fp_config);
   fclose(fp_log);
   #ifdef DEBUG
      fclose(fp_line);
      fclose(fp_debug);
   #endif
   fclose(fp_socket);

   return (1);
}
