/* Acidblood parsing routines */
/*
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>


#define CTCP_DELIM_CHAR '\001'


/* parse a line from the config file */
void parse_line(
char *line,
char *data)
{
         data[0]='\0';

         while (*line!='=') {
              line++;
         }

         line++;

         while (*line!='\n') {
              *data++=*line++;
         }
         *data='\0';
}

/* get action from server line */
void get_action(
char *line,
char *data)
{
         while (*line!=' ') {
              line++;
         }

         line++;

         while (*line!=' ') {
              *data++=*line++;
         }
         *data='\0';
}


/* parse channels from the config file */
void parse_channels(
char *line,
char *data)
{
         char temp[100];
	 char key[100];
         int x=0;
         int y=0;
	 int keyflag=0;

         while (*line!='=') {
              line++;
         }

         line++;

         while (*line!='\n') {


	    /* beginning of a key */
	    if (*line=='(') {
		keyflag=1;
		line++;
		continue;
	    }
		
	    /* ending of a key */
	    if (*line==')') {
	       keyflag=0;
	       key[y]='\0';
		line++;
		continue;
	    }

	    /* we are processing a key */
	    if (keyflag) {
	       key[y++]=*line;
	       line++;
	       continue;
	    }
	
	    /* end of a channel */
            if (*line==',') {
               temp[x]='\0';
               insert_channels(temp,key);
	       y=0;
	       key[y]='\0';
               x=0;
            }

            else {
              temp[x++]=*line;
            } 
              *data++=*line++;
         }
         *data='\0';

         temp[x]='\0';
         insert_channels(temp,key);
}

void
strip_colon(
char *data)
{
  char *c;

  /* look for comma */
     if (strchr(data,':')!=NULL) {   

     if ((c=malloc(strlen(data)+1))==NULL) {
	printf("strip_colon: Malloc error!\n");
	exit(-1);
     }
     strncpy(c, &data[1],strlen(data)+1);
     strncpy(data, c, strlen(data)+1);

     free(c);
  }
  else {
	/* do nothing, no comma exists */
  }
}


void
strip_delim(
char *data)
{
  char *c;

  /* look for delim */
     if (strchr(data,CTCP_DELIM_CHAR)!=NULL) {

     if ((c=malloc(strlen(data)+1))==NULL) {
        printf("strip_delim: Malloc error!\n");
        exit(-1);
     }
     strncpy(c, &data[1],strlen(data)+1);
     strncpy(data, c, strlen(data)+1);

     free(c);
  }
  else { 
        /* do nothing, no comma exists */
  }      
}             

void
strip_return(
char *unstripped)
{ 
  char *c;
  char *d;

  /* look for return */
  if (strchr(unstripped,'\r')!=NULL) { 


     if ((c=malloc(strlen(unstripped)+1))==NULL) {
	printf("strip_return: Malloc error!\n");
	exit(-1);
     }
     strncpy(c, unstripped,strlen(unstripped)+1);
     d=strtok(c,"\r");
     strncpy(unstripped,d,strlen(unstripped)+1);

     /* sometimes cores here, FIX */
     if (c!=NULL) {
     	free(c);
     }
  }
  else {
	/* do nothing, doesnt have a return to strip */
  }
}

void 
strip_newline(
char *unstripped)
{
  char *c;
  char *d;
         
  if ((c=malloc(strlen(unstripped)+1))==NULL) {
	printf("strip_newline: Malloc error!\n");
	exit(-1);
  }
  strncpy(c, unstripped,strlen(unstripped)+1);
  d=strtok(c,"\n");
  strncpy(unstripped,d,strlen(unstripped)+1);

  free(c);
}             


int
match_ip(
char *listip, /* curr->userip */
char *serverip) /* serverdata->ip */
{  
   int size1,size2;

   size1=strlen(listip);
   size2=strlen(serverip);
   size1--;
   size2--;

   for (;size1>=0 && size2>=0; size1--,size2--)
   {
    if (listip[size1]==serverip[size2]) {}
    else {
         if (listip[size1]=='*') { return(1); }
         else if (listip[size1]=='?') {}
         else { return(0); }
         }
   }

   return 1;
}

int
get_channel(
struct channels *channeldata,
char *data,
char *key)
{

   if (curr3==NULL) {
      return(-1);
   }
   else {

      strncpy(data,curr3->channel,50);

      /* if a key exists, copy it */
      if (curr3->key!=NULL) {
         strncpy(key,curr3->key,50);
      }

     if (prev3->next!=NULL) {
      curr3=prev3->next;
      prev3=curr3;
     }
     else {
      curr3=NULL;
     }
   }
   return (1);
}

/* read bot configuration file */
int
read_config(
struct botstruct *botinfo,
FILE **fp_config,
FILE **fp_debug)
{
   char *line;
   char *data;
   int size;

   if ((line=malloc(1000))==NULL) {
      fprintf(stderr,"read_config: Malloc error!\n");
      return(-1);
   }

   if ((data=malloc(1000))==NULL) {
      fprintf(stderr,"read_config: Malloc error!\n");
      return(-1);
   }

   while ((fgets(line,1000,*fp_config))!=NULL) {
      size=strlen(line);
      if (*line=='\n' || *line=='\0' || *line=='/' || *line=='#' || size < 1) {
          /* ignore this line */
      }
      else {
         if (strstr(line,"USER")!=NULL) {
            parse_line(line,data);
            if ((botinfo->user=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->user,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot username=%s\n",botinfo->user);
            #endif
         }

         if (strstr(line,"NICK")!=NULL) {
            parse_line(line,data);
            if ((botinfo->nick=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->nick,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot nick=%s\n",botinfo->nick);
            #endif
         }


         if (strstr(line,"ALT")!=NULL) {
            parse_line(line,data);
            if ((botinfo->altnick=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->altnick,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot nick=%s\n",botinfo->nick);
            #endif
         }

         if (strstr(line,"FULLNAME")!=NULL) {
            parse_line(line,data);
            if ((botinfo->fname=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->fname,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot fullname=%s\n",botinfo->fname);
            #endif
         }

         if (strstr(line,"CHANNELS")!=NULL) {
            /*
            parse_line(line,data);
            if ((botinfo->channel=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->channel,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot channel=%s\n",botinfo->channel);
            #endif
            */
            parse_channels(line,data);
         }

         if (strstr(line,"SERVER")!=NULL) {
            parse_line(line,data);
            if ((botinfo->server=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->server,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot server=%s\n",botinfo->server);
            #endif
         }


         if (strstr(line,"AWAYMSG")!=NULL) {
            parse_line(line,data);
            if ((botinfo->awaymsg=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->awaymsg,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot away message=%s\n",botinfo->awaymsg);
            #endif
         }


         if (strstr(line,"CTCP")!=NULL) {
            parse_line(line,data);
	    if (!strncmp("ON",data,2)) {
		botinfo->ctcp=1;
	    }
            #ifdef DEBUG
              fprintf(*fp_debug,"CTCP response=%s\n",data);
            #endif
         }


         if (strstr(line,"PORT")!=NULL) {
            parse_line(line,data);
            botinfo->port=atoi(data);
            #ifdef DEBUG
              fprintf(*fp_debug,"Bot port=%d\n",botinfo->port);
            #endif
         }

	  if (strstr(line,"VERSION")!=NULL) {
            parse_line(line,data); 
            if ((botinfo->ver=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->ver,data,strlen(data)+1); 
            #ifdef DEBUG 
              fprintf(*fp_debug,"Bot ver=%s\n",botinfo->ver);
            #endif
         }

         if (strstr(line,"NSERV")!=NULL) {
            parse_line(line,data);
            if (!strncmp("ON",data,2)) {
                botinfo->ns=1;
            }
            #ifdef DEBUG
              fprintf(*fp_debug,"NickServ routines=%s\n",data);
            #endif
         }


          if (strstr(line,"NSPASS")!=NULL) {
            parse_line(line,data);
            if ((botinfo->nspass=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->nspass,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Nickserv Pass=%s\n",botinfo->nspass);
            #endif
          }

  	  if (strstr(line,"IMAGE")!=NULL) {
            parse_line(line,data);
            if ((botinfo->image=malloc(strlen(data)+1))==NULL) {
              fprintf(stderr,"read_config: Malloc error!\n");
              return(-1);
            }
            memcpy(botinfo->image,data,strlen(data)+1);
            #ifdef DEBUG
              fprintf(*fp_debug,"Image=%s\n",botinfo->image);
            #endif
         }

	 if (strstr(line,"AUTOOP")!=NULL) {
            parse_line(line,data);

	    if (!strncmp(data, "ON", 2)) {
               botinfo->autoop=1;
               #ifdef DEBUG
                 fprintf(*fp_debug,"Auto-op is ON\n");
               #endif
	    }
 	    else {
               botinfo->autoop=0;
            }
         }

	 /* set passwords */
	 if (strstr(line,"REQPASS")!=NULL) {
            parse_line(line,data);
	    if (!strncmp(data, "ON", 2)) {
               botinfo->reqpass=1;
               #ifdef DEBUG
                 fprintf(*fp_debug,"Passwords are ON\n");
               #endif
	    }
	    else {
	       botinfo->reqpass=0;
	    }
         }

         /* set keep alive */
         if (strstr(line,"KEEPALIVE")!=NULL) {
            parse_line(line,data);

               botinfo->timer=atoi(data);
               #ifdef DEBUG
                 fprintf(*fp_debug,"Keepalive is %d sec(s)\n", botinfo->timer);
               #endif
         
         }


         /* set server timeout */
         if (strstr(line,"TIMEOUT")!=NULL) {
            parse_line(line,data);
   
               botinfo->timeout=atoi(data);
               #ifdef DEBUG
                 fprintf(*fp_debug,"Timeout is %d min(s)\n", botinfo->timeout);
               #endif
     
         }

      }
   }


   return (0);
}


/* read in user file */
int
read_user_data()
{
   FILE *fp_users;
   char *data;
   char *servernick;
   char *serverip;
   char *statustemp;
   char *channels;
   char *password;

   if (free_list() < 0 ) {
      return (-1);
   }

   if ((data=malloc(1000))==NULL) {
      fprintf(stderr,"read_user_data: Malloc Error!\n");
      return(-1);
   }

   if ((fp_users=fopen("../conf/acid.users","r")) == NULL) {
      return(-1);
   }

   fgets(data,1000,fp_users);
   while (!feof(fp_users)) {
      if (*data!='#' && (strlen(data) > 1)) {
      /* if (!strchr(data,'#') > 0 && (strlen(data) > 1)) { */
      /* new format with password */
      /* subcube:63.197.85.162:0:all:testpass */

         servernick=strtok(data,":");
         serverip=strtok(NULL,":");
         statustemp=strtok(NULL,":");
         channels=strtok(NULL,":");
         password=strtok(NULL,"\n");

  	 strip_newline(channels);

         if ((insert_users(servernick,serverip,statustemp,channels,password)) < 0) {
            return(-1);
         }
      }
      fgets(data,80,fp_users);
   }

   fclose(fp_users);
   return (0);
}

int
parse_server (
char *input,
struct serverstruct *serverdata,
FILE **fp_debug,
FILE **fp_log)
{
  int x=0;
  char temp;
  int parsed=0;
  char *action;
  char *a;
  char *b;
  int size;


  no_parse=0;

  if(!strncmp(input,"ERROR",5)) {
      fprintf(*fp_log,"%s\n",input); 
      fflush(*fp_log); 
      return(-1);
  }

  if ((action=malloc(100))==NULL) {
      fprintf(stderr,"parse_server: Malloc error!\n");
      return(-1);
   }

  get_action(input,action);

  #ifdef DEBUG
     fprintf(stderr,"Action=%s\n",action);
  #endif

  /* subcube_!subcube_@borg.hotwired.com JOIN :#acidblood */
  if (!strncmp(action,"JOIN",4)) {
     serverdata->nick=strtok(input,"!");
     serverdata->username=strtok(NULL,"@");
     serverdata->ip=strtok(NULL," ");
     serverdata->action=strtok(NULL," ");
     serverdata->message=strtok(NULL," ");
     serverdata->extra=strtok(NULL,"");

     strip_colon(serverdata->nick);
     strip_colon(serverdata->message);
     strip_return(serverdata->message);

     parsed=1;
 }

 /* subcube_!subcube_@borg.hotwired.com PART #acidblood */
 if (!strncmp(action,"PART",4)) {
     serverdata->nick=strtok(input,"!");
     serverdata->username=strtok(NULL,"@");
     serverdata->ip=strtok(NULL," ");
     serverdata->action=strtok(NULL," ");
     serverdata->message=strtok(NULL," ");
     serverdata->extra=strtok(NULL,"");

     strip_colon(serverdata->nick);
     strip_return(serverdata->message);

     fprintf(*fp_log,"%s PART %s\n",serverdata->message,serverdata->nick); 
     fflush(*fp_log); 

 }


  if (!strncmp(action,"PRIVMSG",7)) {
     serverdata->nick=strtok(input,"!");
     serverdata->username=strtok(NULL,"@");
     serverdata->ip=strtok(NULL," ");
     serverdata->action=strtok(NULL," ");
     serverdata->message=strtok(NULL," ");
     serverdata->extra=strtok(NULL,"");

     strip_colon(serverdata->nick);
     strip_colon(serverdata->extra);
     strip_return(serverdata->extra);

     fprintf(*fp_log,"%s %s :%s\n",serverdata->message,serverdata->nick,serverdata->extra); 
     fflush(*fp_log); 
     
     parsed=1;

  }

/* :StLouis.MO.US.UnderNet.org NOTICE acidbot :on 3 ca 1(2) ft 9(10) tr */
 if (!strncmp(action,"NOTICE",6)) {
    if(strchr(b,'!')!=NULL) {
     serverdata->nick=strtok(input,"!"); /* nick */
     serverdata->username=strtok(NULL,"@"); /* username */
     serverdata->ip=strtok(NULL," "); /* ip */
     serverdata->action=strtok(NULL," "); /* action */
     serverdata->message=strtok(NULL," "); /* message */
     serverdata->extra=strtok(NULL,""); /* extra */

     strip_colon(serverdata->nick);
     strip_colon(serverdata->extra);
     strip_return(serverdata->extra);

     fprintf(*fp_log,"NOTICE from %s :%s\n",serverdata->nick,serverdata->extra);
     fflush(*fp_log);

     parsed=1;
    }

    else {
	/* notice from server, ignore for now */
    }

  }


 /* subcube_!subcube_@borg.hotwired.com TOPIC #acidblood :test2 */
 /* Banjo!mrwilson@pm0-aur-1.dialnet.net TOPIC #funfactory : */
 /* :hebron.in.us.dal.net TOPIC #pakistan :http://hashe.com  & http://mandviwallamauser.com (Bhoot) */
 /* extra will be size of 2 if empty */
 if (!strncmp(action,"TOPIC",5)) {

    if ((a=malloc(strlen(input)+1))==NULL) {
        return(-1);
    }
    strncpy(a,input,strlen(input)+1);
    b=strtok(a," ");
    if (a!=NULL) {
        free(a);
    }

    /* if there is a bang in the first part, its from a user */
    if(strchr(b,'!')!=NULL) {
     serverdata->nick=strtok(input,"!"); /* nickname */
     serverdata->username=strtok(NULL,"@"); /* username */
     serverdata->ip=strtok(NULL," "); /* ip */
     serverdata->action=strtok(NULL," "); /* action */
     serverdata->message=strtok(NULL," "); /* channel */
     serverdata->extra=strtok(NULL,""); /* topic */
    }
    else {
     /* dont have username or ip */
     serverdata->nick=strtok(input," "); /* nickname */
     serverdata->action=strtok(NULL," "); /* action */
     serverdata->message=strtok(NULL," "); /* channel */
     serverdata->extra=strtok(NULL,""); /* topic */
    }
     
     strip_colon(serverdata->nick);

     size=strlen(serverdata->extra);
     if (size <= 2) {}
     else {
        strip_colon(serverdata->extra);
        strip_return(serverdata->extra);
        fprintf(*fp_log,"%s TOPIC %s by %s\n",serverdata->message,serverdata->extra,serverdata->nick);
        fflush(*fp_log);
     }


  }


 /* subcube_!subcube_@borg.hotwired.com QUIT :Leaving */
 if (!strncmp(action,"QUIT",4)) {
     serverdata->nick=strtok(input,"!"); /* nick */
     serverdata->username=strtok(NULL,"@"); /* username */
     serverdata->ip=strtok(NULL," "); /* ip */
     serverdata->action=strtok(NULL,""); /* action */
     /* we dont care about the reason */

     strip_colon(serverdata->nick);

     fprintf(*fp_log,"QUIT by %s\n",serverdata->nick);
     fflush(*fp_log);

  }

 /* d3spise!subcube@207.238.141.237 MODE #acidblood +o subcube_ */
 /* Vancouver.BC.CA.Undernet.Org MODE #warez666 +bb *!*@cr484851-a.hnsn1.on.wave.home.com *!*@*.videotron.net */
 if (!strncmp(action,"MODE",4)) {

    if ((a=malloc(strlen(input)+1))==NULL) {
	return(-1);
    }
    strncpy(a,input,strlen(input)+1);
    b=strtok(a," ");
    if (a!=NULL) {
    	free(a);
    }

    /* if there is a bang in the first part, its from a user */
    if(strchr(b,'!')!=NULL) {
     serverdata->nick=strtok(input,"!"); /* nick name */
     serverdata->username=strtok(NULL,"@"); /* username */
     serverdata->ip=strtok(NULL," "); /* ip address */
     serverdata->action=strtok(NULL," "); /* action */
     serverdata->message=strtok(NULL," "); /* channel */
     serverdata->extra=strtok(NULL,""); /* mode string */

     strip_colon(serverdata->nick);
     strip_return(serverdata->extra);

     fprintf(*fp_log,"%s MODE %s by %s\n",serverdata->message,serverdata->extra,serverdata->nick);
     fflush(*fp_log);
    }
    /* otherwise it is from a server */
    else {
     /* sometimes the server performs MODEs on users in channel, not sure if it sets channel modes */
     /* lulea-r.se.eu.undernet.org MODE #mp3 +v MP3LAND */
     serverdata->nick=strtok(input," "); /* server */
     serverdata->action=strtok(NULL," "); /* action */
     serverdata->message=strtok(NULL," "); /* channel */
     serverdata->ip=strtok(NULL," "); /* flags */
     serverdata->extra=strtok(NULL,""); /* other */

     strip_colon(serverdata->nick);
      
     fprintf(*fp_log,"%s MODE %s %s by %s\n",serverdata->message,serverdata->ip,serverdata->extra,serverdata->nick);
     fflush(*fp_log);
    }

 }

 /* subcube_!subcube_@borg.hotwired.com KICK #acidblood m3chanml :subcube_ */
 /* Uworld.undernet.org KICK #california lipe_-Rj :see ya */
 /* Y-Wing!~ywing@130.14.36.31 KICK #chatzone Coelho :Banned for channel attacks and/or advertising */
  if (!strncmp(action,"KICK",4)) {

   if ((a=malloc(strlen(input)+1))==NULL) {
        return(-1);
    }
    strncpy(a,input,strlen(input)+1);
    b=strtok(a," ");
    free(a);

   /* if there is a bang in the first part, its from a user */
    if(strchr(b,'!')!=NULL) {
     serverdata->nick=strtok(input,"!");      /* nick */
     serverdata->username=strtok(NULL,"@");   /* username */
     serverdata->ip=strtok(NULL," ");         /* ip */
     serverdata->action=strtok(NULL," ");     /* action, should be KICK */
     serverdata->message=strtok(NULL," ");    /* channel */
     serverdata->extra=strtok(NULL,":");      /* nick */
     /* we dont care about the extra, will use that field for the nickname */
   }
   /* otherwise it is from a server */
    else {
     serverdata->nick=strtok(input," "); /* server */
     serverdata->action=strtok(NULL," "); /* action */
     serverdata->message=strtok(NULL," "); /* channel */
     serverdata->ip=strtok(NULL," "); /* nickname */
     serverdata->extra=strtok(NULL,""); /* reason */
    }
    
     parsed=1;
  }

  if (action!=NULL) {
     free(action);
  }
     
 if (parsed) {
   while (serverdata->ip[x]) {
     if (isalpha(serverdata->ip[x])) {
        temp=serverdata->ip[x];
        serverdata->ip[x]=tolower(temp);
     }
     x++;
   }
 }

 else {
   no_parse=1;
 }

     #ifdef DEBUG
      if (parsed) {
        fprintf(*fp_debug,"Nick=%s\n",serverdata->nick);
        fprintf(*fp_debug,"Username=%s\n",serverdata->username);
        fprintf(*fp_debug,"IP=%s\n",serverdata->ip);
        fprintf(*fp_debug,"Action=%s\n",serverdata->action);
        fprintf(*fp_debug,"Message=%s\n",serverdata->message);
       if (serverdata->extra!=NULL) {
        fprintf(*fp_debug,"extra=%s\n",serverdata->extra);
       }
        fprintf(*fp_debug,"\n");
        fflush(*fp_debug);
      }
     #endif


  return (0);
}




