/* sigit.c -- an auto signature creating tool.. 

   Copyright (C) Kenneth 'Redhead' Nielsen <redhead@diku.dk>

   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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

/* $Id: sigit.c,v 0.9 2001/08/13 16:43:00 redhead Exp $ */

#include "sigit.h" // #include "config.h"
#include "files.h"
#include "deamoninit.h"


int print_help(void)
{
 /* should we have nothing to give here, we better just try not to use the parameter */
  printf("\n");
  printf("The normal use of this program would be:\n");   
  printf(PACKAGE " [-a file] [-l file] [-r file] [-u ident] [-cdevV] \n");   
  printf("\t-a  <file>\n");
  printf("\t   This is used, when you want to add a\n");
  printf("\t   signature to your database.\n");
  printf("\t   The desired signature is stored in the\n");
  printf("\t   file parsed with this flag.\n");
  printf("\t-c\n");
  printf("\t   This is used, when the program is to be\n");
  printf("\t   run as a cron job.\n");
  printf("\t-d\n");
  printf("\t   This will launch " PACKAGE " into the background,\n");
  printf("\t   and thereby create a deamon, which will run even\n");
  printf("\t   after you are loged out.\n");
  printf("\t-e\n");
  printf("\t   This will retrieve all signatures from the\n");
  printf("\t   data file, and load them into your $EDITOR\n");
  printf("\t   where you can edit them all.\n");
  printf("\t   Upon exit the program will rebuild the data file\n");
  printf("\t   with the new updated signatures.\n");
  printf("\t-l  <file> \n");
  printf("\t   This will write any signatures in the data file\n");
  printf("\t   to the given file. If the file exist, it will\n");
  printf("\t   overwrite the file.\n");
  printf("\t-r  <file> \n");
  printf("\t   This is used to rebuild the sigs database\n");
  printf("\t   it will erase every former entry in the\n");
  printf("\t   data_file defined in .sigitrc and build a\n");
  printf("\t   new one with every signatures found in the\n");
  printf("\t   file parsed to the program.\n");
  printf("\t   If your using the globaly placed data file,\n");
  printf("\t   then you must be root to use this feature.\n");
  printf("\t-u  <ident> \n");
  printf("\t   This will make sure the signature, with the identifyer\n");
  printf("\t   matching ident, will be removed from the data file.\n");
  printf("\t-v\n");
  printf("\t   This is used, to produce verbose output.\n");
  printf("\t-vv\n");
  printf("\t   produces very verbose output, good for debugging.\n");
  printf("\t   Throw in a couple more -v's and you get a real treat.\n");
  printf("\t-V\n");
  printf("\t   This will print info about the program version.\n\n");
  return SUCCESS;
}


/* Lets fire this baby up.. */


int main(int argc, char* argv[])
{
  struct setting config;
  unsigned short int add = 0, cron = 0, edit = 0, rebuild = 0, deamon = 0;
  int opt; /* to determain which options we are given in argv */
  char edit_f[LINE_SIZE +1]; /* shoudl be enough for ht efile placed in home dir */
  char optarg_element[LINE_SIZE+1 ]; /* to take the sig file for adding.. */
 
  /*
   * to make sure theres no errors here.. 
   * due to any garbage placed in the memory from previus. 
   */
  config.sig_file[0] = '\0';
  config.data_file[0] = '\0';
  config.pritty[0] = '\0';
  config.t_line[0] = '\0';
  config.b_line[0] = '\0';
  config.optarg_element[0] = '\0';
  config.config_file[0] = '\0';
  config.delete_sig[0] = '\0';

  config.sig_n.sig[0] = '\0';
  config.sig_n.ident[0] = '\0';
  config.sig_n.count = htonl(0);

  config.cnt.ver[0] = '\0';
  config.cnt.count = htonl(0);
 
  config.delete = 0;
  config.list = 0;
  config.slash = 0;
  config.deamon_proc = 0;
  config.create_sig = 0;
  config.sys_log = 0;
  config.verbose = 0;
  config.c_num = 0;
  config.date = 0;  

  if(argc > 1)
    { /* if we were run with an argument, lets findout what that was.. */
      while( (opt = getopt(argc, argv, "a:cdehl:r:u:vV")) > 0)
	{
	  switch ((char)opt) 
	    {
	    case 'V':
	      printf(PACKAGE "-" VERSION " (" CALLSIGN ") ["
		     __DATE__ " " __TIME__ "]\n\n"
		     "Copyright (C) 2000-2001 Kenneth 'Redhead' Nielsen <redhead@diku.dk>\n"
		     "This is free software; see the source for copying conditions.\n"
		     "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
		     "FOR A PARTICULAR PURPOSE, to the extent permitted by law.\n"
		     "Latest version can be obtained from: <" HOMEPAGE ">\n");
  	      return SUCCESS;
	    case 'h':
	      print_help();
	      return SUCCESS;
	    case 'a':
	      strcpy(config.optarg_element, optarg);
	      add = 1;
	      break;
	    case 'c':
	      cron = 1;
	      break;
	    case 'd':
	      deamon = 1;
	      break;
	    case 'l':
	      strcpy(config.optarg_element, optarg);
	      config.list = 1;
	    case 'e':
	      edit = 1;
	      break;
	    case 'r':
	      strcpy(config.optarg_element, optarg);
	      rebuild = 1;
	      break;
	    case 'u':
	      config.delete = 1;
	      strcpy(config.delete_sig, optarg);
	      edit = 1;
	      break;
	    case 'v':
	      config.verbose++;
	      break;
	    default:
	      print_help();
	      return FAILURE;	
	    } 
	}
    }
  if(config.verbose > 5) /* only loones want this much verbose */
    return(_shine_on_you_crazy_diamond_());
  /* lets read what is to be read. */
  if(read_config_file(&config))
    return FAILURE;
  if(!add && !edit && !rebuild && !deamon && cron)
    {
      if(!get_sig(&config))
	{
	  if(!pretty_print(&config))
	    {/* no need to unlink if there is a sigit running in the background */
	      return SUCCESS;
	    }
	  else
	    {
	      return FAILURE;
	    }
	}
      else
	{
	  return FAILURE;
	}
      return SUCCESS;
    } /* or perhaps they want to add a sig */
  if(add && !edit && !rebuild && !deamon && !cron)
    {
      if(access(config.optarg_element, F_OK))
	{
	  logging(1, config.verbose, 0, config.sys_log, 1, "[ERROR] :Cant locate file: %s\n", config.optarg_element);
	  return FAILURE;
	}
      if(add_sig(&config))
	{/* no need to unlink if there is a sigit running in the background */
	  return FAILURE;
	}
      return SUCCESS;
    } /* if not adding, could it be the editing part ? */
  if(!add && edit && !rebuild && !deamon && !cron)
    {
      if(!config.list)
	{
            /* just create the edit file from the normal signature database */
#ifdef LINUX
	  snprintf(config.optarg_element, LINE_SIZE, "/tmp/%s-%d", PACKAGE, getpid());
#else
	  sprintf(config.optarg_element, "/tmp/%s-%d", PACKAGE, getpid());
#endif
	}
      if(edit_data_file(&config))
	{/* no need to unlink if there is a sigit running in the background */
	  logging(1, config.verbose, 0, config.sys_log, 1,  "[ERROR] : There was an error trying to load your desired editor.\n");
	  logging(0, config.verbose, 0, config.sys_log, 1, "\tHave you set the correct $EDITOR environment. ?\n");	  logging(0, config.verbose, 0, config.sys_log, 1, "\tOr is it due to the fact, that [%s] is missing. ?\n", config.data_file);
	  if(!config.list)
	    unlink(config.optarg_element);
	  return FAILURE;
	}
      if(config.list)
	return SUCCESS;
      if(!access(config.data_file, R_OK)) /* atleast the edit file must be pressent.. */
	{
	  /* erase the previus database.. */
	  unlink(config.data_file);
	  /* check if it was removed correct.. */
	  if(!access(config.data_file, F_OK))
	    {
	      logging(1, config.verbose, 0, config.sys_log, 1, ": [ERROR] : The database file couldnt be removed..\n");
	      logging(0, config.verbose, 0, config.sys_log, 1, "\tCould this be due to the fact that you dont have write access to the file ?\n");
	      logging(0, config.verbose, 0, config.sys_log, 1, "\tOr that your a normal user, who is trying to remove the standard data file ?\n");
	      /* no need to unlink the fifo, when were just rebuilding the data file */
	      unlink(config.optarg_element);
	      return FAILURE;
	    }
	  if(!add_sig(&config))
	    {
	      unlink(config.optarg_element);
	      return SUCCESS;
	    }
	  else
	    {
	      unlink(edit_f);
	      return FAILURE;
	    }
	}
      else
	{
	  logging(1, config.verbose, 0, config.sys_log, 1, "[ERROR] : There was an error while updating the data file with\n");
	  logging(0, config.verbose, 0, config.sys_log, 1, "\the changes made, could this be because you havn't got write access to teh data file?\n");
	  unlink(config.optarg_element);
	  return FAILURE;
	}
      
    } /* or perhaps they are rebuilding it */
  if(!add && !edit && rebuild && !deamon && !cron)
    {
      if(!access(config.optarg_element, R_OK)) /* atleast the file must be pressent.. */
	{
	  /* erase the previus database.. */
	  unlink(config.data_file);
	  /* check if it was removed correct.. */
	  if(!access(config.data_file, F_OK))
	    {
	      logging(1, config.verbose, 0, config.sys_log, 1, "[ERROR] : The database file couldnt be removed..\n");
	      logging(0, config.verbose, 0, config.sys_log, 1, "\tCould this be due to the fact that you dont have write access to the file ?\n");
	      logging(0, config.verbose, 0, config.sys_log, 1, "\tOr that your a normal user, who is trying to remove the standard data file ?\n");
	      /* no need to unlink the fifo, when were just rebuilding the data file */
	      return FAILURE;
	    }
	  if(add_sig(&config))
	    return FAILURE;
	}
      else 
	{
	  logging(1, config.verbose, 0, config.sys_log, 1, "[ERROR] : The files needed to rebuild the database couldn't be found.\n");
	  logging(0, config.verbose, 0, config.sys_log, 1, "\tCheck if the '%s' file exist.\n", optarg_element);
	  return FAILURE;
	}
      return SUCCESS;
    }
  if(!add && !edit && !rebuild && !cron)
    {
      /* it must be the trivial case.. we just run as a normal process */
      
      /* initializing the fifo, 
       * it will lock till someone opens 
       * it from the other end for reading
       */

      init_fifo(&config);

      /* install signal handler */
      install_sig_handler(config.verbose, config.sys_log);
      if(deamon)
	{ /* at this point it better be the deamon version poeple want.. */
	  logging(0, config.verbose, 0, config.sys_log, 0, "\n\tLauching " PACKAGE " into the background."
		 "\n\tAll verbose output will be syslog'ed.\n\n");
	  config.sys_log = 1;
	  deamon_init(argv[0], 0);
	}
      create_pid_file(config.verbose, config.sys_log); /* lets hope its the right PID thats written to it.. */
      /*
	At this point we must have been called regularly, with no arguments. 
	Meaning we should just be run like a deamon..
      */
      while(1)
	{
	  if(!get_sig(&config))
	    {
	      if(pretty_print(&config))
		{
		  unlink_fifo(&config);
		  return FAILURE;
		}
	    }
	  else
	    {
	      unlink_fifo(&config);
	      return FAILURE;
	    }
	  /*
	   * no need to sleep the delay, 
	   * now that the fifo will lock the process. 
	   *
	   * sleep(config.delay);
	   *	  
	   * Instead we only sleep for a brief moment.	   
	   * to make sure the process reading the fifo will 
	   * empty it, befor we take hold of it again.
	   */
	  
	  sleep(1);
	  /* if the user has made changes to the configuration,
	   * while we were waiting for the fifo to be activated.
	   * we better reread it.
	   */
	  if(read_config_file(&config))
	    {
	            unlink_fifo(&config);
		    return FAILURE;
	    }
	}
      unlink_fifo(&config);
      return SUCCESS;
    } 
  else
    { /* there must have been a failure. And we better let folks know.. */
      logging(1, config.verbose, 0, config.sys_log, 1, "[ERROR] : The program can't do multiple things at the same time.\n");
      logging(1, config.verbose, 0, config.sys_log, 1, "[ERROR] : When adding, editing, rebuilding signatures, or running as a cron job.\n");
      return FAILURE;
    } 
  return SUCCESS;
}








syntax highlighted by Code2HTML, v. 0.9.1