#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include "vars.h"


/***************************************
 ********** Start MAIN function ********/
 int main(int argc, char* argv[])
{

  int z;
  char etmp[ML_ETMP],str[ML_URL];
  int flag;

    //Init some vars
    init_vars();

    // Load config file
    if (argc!=2) {get_opt(DEFAULT_CONFIG);}
    else {
          if (!strcmp(argv[1],"-V"))
           {
            printf("Redirector %s\n",VERSION);
            exit(0);
           }
           get_opt(argv[1]);
         }

    // Run make-cahe
    if (argc!=2) {run_make_cache(DEFAULT_CONFIG);}
    else {run_make_cache(argv[1]);}

    // Load allow urls cache
    sprintf(etmp,"%s/allow_urls.cache",redir[0]->ban_dir);
    load_cache(&allow_urls,&allow_urls_count,etmp);  

    // Prepare section data
    for (z=0;z<sections_count; z++)
	{
         // Prepare new_url
	 prepare_new_url(z);
	 // Load urls cache
	 sprintf(etmp,"%s/urls.cache",redir[z]->ban_dir);
         load_cache(&redir[z]->ban_urls,&redir[z]->ban_urls_count,etmp);
	 // Load pcre lists
	 load_pcre_file(z);
	}
  

    //Open log file
    if (chg_log)
    for (z=0;z<sections_count; z++)
     {
       if (!redir[z]->log_flag)
        {
	    if ((change_log=fopen(chg_log,"a"))==NULL)
    	    {
             sprintf(etmp,"ERROR: Can't make chg_log file %s: %s\n",chg_log,strerror(errno));
             err_mes(etmp);
	     exit(-1);
    	    }

	#ifdef DEBUG_CYCLE
	 fprintf (stderr,"\nOpen log file: %s\n",chg_log);
	#endif
	break;
	}
     }

      sprintf(etmp,"Redirector start and working (%s)",VERSION);
      err_mes(etmp);

/***********************
 ****** Work cycle *****/        
    // Get input string
    while (fgets(str,ML_URL,stdin)!=NULL)
    {   
        // convert input string to input structure->(url,who,ident,method)
        if(parse_input(str)) 
	   {
	   
	    // If error in convert
	    printf ("%s",str);
	    fflush(stdout);
	    sprintf(etmp,"Error convert input string to input structure str=%s",str);
	    err_mes(etmp);
	    continue;
	   };

	  // Check to work_id
	  if (work_id_count && !check_id(work_id,work_id_count)) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," -->Skiping by not hit in work_id in global section\n");
	    #endif
	    pass();
	    continue;
	   }

	  // Check to allow_id
	  if (allow_id_count && check_id(allow_id,allow_id_count)) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," -->Skiping by allow_id in global section\n");
	    #endif
	    pass();
	    continue;
	   }
	  
	  // Check ip to "work_ip" option
	  if (work_ip_count && !check_ip(work_ip,work_ip_count)) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," --> Skiping by not wokr_ip in global section\n");
	    #endif
	    pass();
	    continue;
	   }
	 
	  // Check ip to "allow_ip" option
	  if (allow_ip_count && check_ip(allow_ip,allow_ip_count)) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," --> Skiping by allow_ip in global section\n");
	    #endif
	    pass();
	    continue;
	   }
	   // Check for allow_urls
	   #ifdef CASE_INDEPENDENT
	   z=parse_urls(i_url,input_url_uc);
           if (z<0)
           {
            sprintf(etmp, "REDIRECTOR: WARNING: Can't parse url: %s. Pass.",input_url_uc);
            err_mes(etmp);
	    pass();
            continue;
           }
           #else
	   z=parse_urls(i_url,input_url_un);	   
           if (z<0)
           {
            sprintf(etmp, "REDIRECTOR: WARNING: Can't parse url: %s. Pass.",input_url_un);
            err_mes(etmp);
	    pass();
            continue;
           }
           #endif

										       
										       

	  if (check_url(allow_urls,allow_urls_count)) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," --> Skiping by allow_urls in global section\n");
	    #endif
	    pass();
	    continue;
	   }
	   
    flag=0;

  /***** Check sections rules *****/
    for (z=0;z<sections_count; z++)
    {

	  // Check for work_id
	  if ((!redir[z]->work_id_count && redir[z]->work_id_flag) || (redir[z]->work_id_count && !check_id(redir[z]->work_id,redir[z]->work_id_count))) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," -->Skiping by not hit in work_id in \"%s\" section\n",redir[z]->name);
	    #endif
	    continue;
	   }

          // Check for allow_id
	  if (redir[z]->allow_id_count && check_id(redir[z]->allow_id,redir[z]->allow_id_count)) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," -->Skiping by allow_id in \"%s\" section\n",redir[z]->name);
	    #endif
	    continue;
	   }

	  // Check for work_ip
	  if ((!redir[z]->work_ip_count && redir[z]->work_ip_flag) || (redir[z]->work_ip_count && !check_ip(redir[z]->work_ip,redir[z]->work_ip_count))) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," --> Skiping by not work_ip in \"%s\" section\n",redir[z]->name);
	    #endif
	    continue;
	   }
	 
	  // Check for allow_ip
	  if (redir[z]->allow_ip_count && check_ip(redir[z]->allow_ip,redir[z]->allow_ip_count)) 
	   {
	    #ifdef DEBUG_CYCLE
	    fprintf (stderr," --> Skiping by allow_ip in \"%s\" section\n",redir[z]->name);
	    #endif
	    continue;
	   }

  //Check for BAN URLS
  if (redir[z]->ban_urls_count)
    {
       flag=check_url(redir[z]->ban_urls,redir[z]->ban_urls_count);
       if ((flag && !redir[z]->revers) || (!flag && redir[z]->revers))    
        {
	 flag=1;
	 redirect(z);
	 break;
        }
    }
  else flag=0;

  //Check for BAN PCRE
  if (redir[z]->ban_pcre_count)
    {
       flag=check_pcre(z);
       if ((flag && !redir[z]->revers) || (!flag && redir[z]->revers))
        {
	 flag=1;
	 redirect(z);
	 break;
        }
    }
  else flag=0;
  
  }// sections rules 
      if (!flag)
      {
	#ifdef DEBUG_CYCLE

	 fprintf(stderr,"\n=== URL NOT FOUND IN BLACK LIST ========\n");
	 fprintf(stderr,"str\t:%s",str);
	 fprintf(stderr,"url\t:%s:\n",input_url);
	 fprintf(stderr,"url_un\t:%s:\n",input_url_un);	 
	 fprintf(stderr,"ip\t:%d.%d.%d.%d:\n",(unsigned char)input_ip[0],(unsigned char)input_ip[1],(unsigned char)input_ip[2],(unsigned char)input_ip[3]);
	 fprintf(stderr,"host\t:%s:\n",input_host);
	 fprintf(stderr,"ident\t:%s:\n",input_ident);
	 fprintf(stderr,"ident_un:%s:\n",input_ident_un);
	 fprintf(stderr,"method\t:%s:\n\n",input_method);	
	#endif
	
	pass();
      }
    }//work cycle

 exit(0);
}
