/* config.c  --  The file holding every overall needed info for the entire program.. 

   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: config.c,v 0.9 2001/08/13 16:43:00 redhead Exp $ */


#include "config.h" // #include <every_fucking_thing>


int create_pid_file(unsigned short int verbose, unsigned short int sys_log)
{
  int pid = -1, ppid = -1;
  char lockfile[LINE_SIZE +1]; /* should be enough for the user and /tmp and PACKAGE */
  FILE* lockfp;
  /* First findout who the user is.. */
  uid_t  original_real_uid = getuid();
  struct passwd* pw = getpwuid(original_real_uid);
  if (!pw)
    {
      logging(1, verbose, 0, sys_log, 1, "You don't exist, go away!\n");
      exit(1);
    }
  /* then test if theres a file called PACKAGE-USER */
  /* if found look into it, and decide the pid of the running program */
  /* send an alert, that there allready is a copy of PACKAGE running as PID  */
  /* and kill it, then start normaly */
#ifdef HPUX
  sprintf(lockfile, "%s/.%s-%s.lock", getenv("HOME"), PACKAGE, pw->pw_name);
#else
  snprintf(lockfile, LINE_SIZE, "%s/.%s-%s.lock", getenv("HOME"), PACKAGE, pw->pw_name);
#endif
  logging(1, verbose, 0, sys_log, 1, "Creating [%s] as lock file.\n", lockfile);
  if((lockfp = fopen(lockfile, "r")) != NULL )
    {
      fscanf(lockfp,"%d %d", &pid, &ppid);
      if(!kill(pid, 9)) { /* should be a kill-sig thats accepted even if its a suspended process */
	fclose(lockfp);	/* not checking should be safe, file mode was "r" */
	logging(1, verbose, 0, sys_log, 1, "Removing stale lockfile.\n");
	pid = -1;
	ppid = -1;
	unlink(lockfile);
      }
      else
	{
	  logging(1, verbose, 0, sys_log, 1, "Couldn't kill allready running process\n");      
	  unlink(lockfile);
	}
    }
  /* else start the program, and create the PID file. */
  pid = getpid();
  ppid = getppid();
  if((lockfp = fopen(lockfile, "w")) != NULL)
    fprintf(lockfp, "%d %d", pid, ppid);
  fclose(lockfp);
  logging(1, verbose, 0, sys_log, 1, "   DONE\n");
  return SUCCESS;
}


int remove_pid_file(unsigned short int verbose, unsigned short int sys_log)
{
  char lockfile[LINE_SIZE +1]; /* should be enough for the user and /tmp and PACKAGE */
  FILE* lockfp;
  /* First findout who the user is.. */
  uid_t  original_real_uid = getuid();
  struct passwd* pw = getpwuid(original_real_uid);
  if (!pw)
    {
      logging(1, verbose, 0, sys_log, 1, "You don't exist, go away!\n");
      exit(1);
    }
  /* then test if theres a file called PACKAGE-USER */
#ifdef HPUX
  sprintf(lockfile, "%s/.%s-%s.lock", getenv("HOME"), PACKAGE, pw->pw_name);
#else
  snprintf(lockfile, LINE_SIZE, "%s/.%s-%s.lock", getenv("HOME"),PACKAGE, pw->pw_name);
#endif
  if((lockfp = fopen(lockfile, "r")) != NULL )
    {
      logging(1, verbose, 0, sys_log, 1, "Removing [%s] as lock file.\n", lockfile);
      fclose(lockfp);	/* not checking should be safe, file mode was "r" */
      unlink(lockfile);
    }                               
  logging(1, verbose, 0, sys_log, 1, "   DONE\n");
  return SUCCESS;
}




int logging(int need_package_info, 
	    unsigned short int verbose, int level, 
	    unsigned short int sys_log, int sys_ready, const char* fmt, ...)
{
  va_list ap;
  int n, size = 100;
  char *p;
  if(verbose > 4 && level < 4)
    return SUCCESS;
  if(verbose > level)
    {
      if(!sys_log)
	{
	  if(need_package_info >= 1)
	    {
	      if(need_package_info > 1)
		printf("\n");
	      printf(PACKAGE ": ");
	    }
	  fflush(stdout);
	  va_start(ap, fmt);
	  vprintf(fmt, ap);
	  fflush(stdout);
	  va_end(ap);
	  return SUCCESS;
	}
      else
	{
	  if(sys_ready)
	    {
	      if ((p = malloc (size)) == NULL)
		{
		  free(p);
		  return FAILURE;
		}
	      while (1)
		{
		  /* Try to print in the allocated space. */
		  va_start(ap, fmt);
#ifdef LINUX
		  n = vsnprintf (p, size, fmt, ap);
#else
		  n = vsprintf(p, fmt, ap);
#endif
		  va_end(ap);
		  /* If that worked, log the string. */
		  if (n > -1 && n < size)
		    {
		      syslog(5, p);
		      free(p);
		      return SUCCESS;
		    }
		  /* Else try again with more space. */
		  if (n > -1)    /* glibc 2.1+ */
		    size = n+1; /* precisely what is needed */
		  else           /* glibc 2.0 */
		    size *= 2;  /* twice the old size */
		  if ((p = realloc (p, size)) == NULL)
		    {		
		      free(p);
		      return FAILURE;
		    }
		}
	    }
	}
    }
  return SUCCESS;
}





/*
 * Get a config file entry. The file must be open, and space must be allocated.
 * Return 0 if an entry was found - or non-zero on error or EOF.
 */


/* 
 * This function shouldn't have any debug printing inside it.. 
 * its all taken care of in read_config_file()
 * If there should be one, it should be checking for verbose of 2 and greater
 */


int get_config_entry (char entry[], char value[], FILE* fp, 
		      unsigned short int verbose, unsigned short int sys_log)
{ 
  char* ptr;
  char buffer[BUFF_SIZE+1];
  char strbuff[NUM_LINES*LINE_SIZE+1] = "";
  while (1)
    {
      if (feof(fp))
	return FAILURE;
      fgets(buffer, BUFF_SIZE, fp);
   /* Sort out lines starting with # (comments) and blank lines */
      if ((buffer[0] == '#') || (buffer[0] == '\0'))
	continue;
      if (!strncmp(buffer, "@@", 2))
	{
	  fgets(buffer, BUFF_SIZE, fp);
	  while(strncmp(buffer, "\\@@", 3))
	    {
	      logging(0, verbose, 1, sys_log, 0, "++++");
	      
	      strcat(buffer, "\n");
	      strncat(strbuff, buffer, strlen(buffer));
	      fgets(buffer, BUFF_SIZE, fp);
	    }
	    strncpy (entry, "pritty", LINE_SIZE);
	    strncpy (value,  strbuff, NUM_LINES*LINE_SIZE);
	    return SUCCESS;
	}
      /* Now find the delimiter and split up in var/value-pairs */
      for (ptr = buffer; *ptr != '\0'; ptr++)
	if (*ptr == '=')
	  {
	    logging(0, verbose, 1, sys_log, 0, "|");
	    *ptr = '\0';
	    strncpy (entry, buffer, LINE_SIZE);
	    strncpy (value, ptr+1, LINE_SIZE);
	    return SUCCESS;
	  }
      /* Hmmm... An invalid line? Ignore it. */
    }
  return FAILURE;
}

/* 
 * to read the config file for all its entries..
 */

int read_config_file(struct setting *conf)
{
  FILE* infile;
  char value[NUM_LINES*LINE_SIZE +2];/* should be enough if the user has alot of spaces befor the '=' */
  char entry[LINE_SIZE +1]; /* should be enough if theres alot of things to say to the argument*/
  struct stat file_stat;
  int tmp;
  logging(1, conf->verbose, 0, conf->sys_log, 1, "Configuring the run of the program.\n");
  /* if this is the first run we better see what file to use */
  if(conf->config_file[0] == '\0')
    {
#ifdef LINUX
      snprintf(conf->config_file, LINE_SIZE -1, "%s/.sigitrc", getenv("HOME"));
#else
      sprintf(conf->config_file, "%s/.sigitrc", getenv("HOME"));
#endif
      stat(conf->config_file, &file_stat);
      conf->date = file_stat.st_ctime;
     
      if (!access(conf->config_file, F_OK))
	{ /* WOW the user had made his own.. */
	  logging(1, conf->verbose, 0, conf->sys_log, 1, "The user had made his own .sigitrc file.\n");
	  if (!access(conf->config_file, R_OK))
	    { /* Lets see if we have read access to it.. */
	      infile = fopen (conf->config_file, "r");
	      if(feof(infile))
		{
		  logging(1, conf->verbose, 0, conf->sys_log, 1, "But theres nothing to read from it.\n");
		  return CONF_ER;
		}
	    }	 
	  else
	    {
	      logging(1, conf->verbose, 0, conf->sys_log, 1, "But there's no read access to it.\n");
	      return CONF_HR;
	    }
	} 
      else
	{ /* DOH we have to read the lame default settings.. */
	      logging(1, conf->verbose, 0, conf->sys_log, 1, "The lUSER havn't made a configuration file.\n");
	  if (!access(DEFAULT_CONF_FILE, F_OK))
	    { /* well then we just use the standard one */
	      strncpy(conf->config_file, DEFAULT_CONF_FILE, LINE_SIZE -1);
	      logging(1, conf->verbose, 0, conf->sys_log, 1, "So we will have to read from the standard.\n");
	      
	      if (!access(DEFAULT_CONF_FILE, R_OK))
		{
		  /* Lets see if we have read access to it.. */
		  infile = fopen (DEFAULT_CONF_FILE, "r");
		  if(feof(infile))
		    {
		      logging(1, conf->verbose, 0, conf->sys_log, 1, "That lame SysAdmin havn't made a standard one.\n");
		      return CONF_ER;
		    }
		}
	      else
		{
		  logging(1, conf->verbose, 0, conf->sys_log, 1, "That lame SysAdmin havn't provided read access to the file.\n");
		  return CONF_ER;
		}
	    }
	  else /* if none of the files exist we must alarm */
	    {
	      logging(1, conf->verbose, 0, conf->sys_log, 1, "That lame SysAdmin havn't made a configuration file.\n");
	      return CONF_MI;
	    }
	}
    }
  else
    {
      /* ###### make som testing to see ####### */
      /* ###### if the .sigitrc file is ####### */
      /* ###### changed, might save the ####### */
      /* ###### time spend here with io ####### */
      stat(conf->config_file, &file_stat);
      /* lets hope st_ctime is the correct value for changes in the file */
      if(file_stat.st_ctime <= conf->date)
	{
	  logging(1, conf->verbose, 0, conf->sys_log, 1, "The config file hasn't changed since last.\n");
	  logging(1, conf->verbose, 0, conf->sys_log, 1, "   DONE\n");
	  return SUCCESS;
	}
      else
	{
	  logging(1, conf->verbose, 0, conf->sys_log, 1, "The config file has been altered since last.\n");
	  conf->date = file_stat.st_ctime;
	  infile = fopen (conf->config_file, "r");
	}
    }
  logging(1, conf->verbose, 0, conf->sys_log, 1, "Reading config.\n");
  logging(0, conf->verbose, 1, conf->sys_log, 0, "\t[+");
  while (SUCCESS == get_config_entry (entry, value, infile, conf->verbose, conf->sys_log))
    {
      /* Go through all configurable variables - sigh */
      if (!strcmp(entry, "sig_file"))
	{
	  if(strlen(value) <= 1)
	    {
#ifdef LINUX
	      snprintf(conf->sig_file, LINE_SIZE -1, "%s/%s", getenv("HOME"), DEFAULT_SIG_FILE);
#else
	      sprintf(conf->sig_file, "%s/%s", getenv("HOME"), DEFAULT_SIG_FILE);
#endif
	    }
	  else
	    {
#ifdef LINUX
	      snprintf(conf->sig_file, LINE_SIZE -1, "%s/%s", getenv("HOME"), value);
#else
	      sprintf(conf->sig_file, "%s/%s", getenv("HOME"), value);
#endif
	    }
	  logging(0, conf->verbose, 1, conf->sys_log, 0,"++++");
	  if(conf->sig_file[strlen(conf->sig_file) -1] == '\n')
	    conf->sig_file[strlen(conf->sig_file) -1] = '\0'; /* to make sure the \n is removed */
	  continue;
	}
      if (!strcmp(entry, "data_file"))
	{
	  if(strlen(value) <= 1)
	    strncpy(conf->data_file, DEFAULT_DATA_FILE, LINE_SIZE -1);
	  else
	    strncpy (conf->data_file, value, LINE_SIZE -1);
    	  logging(0, conf->verbose, 1, conf->sys_log, 0,"++++");
	  if(conf->data_file[strlen(value) -1] == '\n')
	    conf->data_file[strlen(value) -1] = '\0'; /* to make sure the \n is removed */
	  continue;
	}
      if (!strcmp(entry, "--"))
	{
	  tmp = atoi (value);
	  if (tmp > 0)
	    conf->slash = tmp;
	  logging(0, conf->verbose, 1, conf->sys_log, 0,"++++");
	  continue;
	}
      if (!strcmp(entry, "pritty"))
	{
	  if(strlen(value) <= 1)
	    conf->pritty[0] = '\0';
	  else
	    strncpy(conf->pritty, value, NUM_LINES*LINE_SIZE);
	  logging(0, conf->verbose, 1, conf->sys_log, 0,"++++");
	  continue;
	}
      if (!strcmp(entry, "t_line"))
	{
	  strncpy (conf->t_line, value, LINE_SIZE);	  
	  conf->t_line[strlen(value)] = '\0';
	  logging(0, conf->verbose, 1, conf->sys_log, 0,"++++");
	  continue;
	}
      if (!strcmp(entry, "b_line"))
	{
	  strncpy (conf->b_line, value, LINE_SIZE);
	  conf->b_line[strlen(value)]  = '\0';
	  logging(0, conf->verbose, 1, conf->sys_log, 0,"++++");
	  continue;
	}
      /* normaly you would be alarmed, when this happened */
      /* but i decided to continue since its not a big NONO */
      /* to have unknown entries in the configuration, could */
      /* be an error from a previus version, so we tell the user. */
      logging(2, conf->verbose, 0, conf->sys_log, 1, "There was an error while reading config file.\n");
      logging(1, conf->verbose, 0, conf->sys_log, 1, "The entry [%s] is unknown.\n", entry);
      logging(1, conf->verbose, 0, conf->sys_log, 1, "In order to satisfy our listeners, we continue.\n\t");
    }
  fclose(infile);
  logging(0, conf->verbose, 1, conf->sys_log, 0, "+]\n");
  logging(1, conf->verbose, 0, conf->sys_log, 1, "   DONE\n");
  return SUCCESS;
}



syntax highlighted by Code2HTML, v. 0.9.1