/* Read in and grok the various administrative files.
   Copyright (C) 1993 Free Software Foundation, Inc.
   Contributed by Tim Wicinski (wicinski@barn.com).

This file is part of GNU GNATS.

GNU GNATS 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.

GNU GNATS 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 GNU GNATS; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "config.h"

#include <stdio.h>
#include <sys/types.h>

#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include <pwd.h>

#include "gnats.h"
#include "pathmax.h"
#include "globals.h"

Responsible *responsible_chain;

static int get_adm_record		PARAMS((char*, char**, char*));
static Responsible *find_responsible	PARAMS((char *));
static int next_record			PARAMS((char*, char**));

/* Find SITE in the submitters list, copying it into CPTR.  */
int 
find_submitter (cptr, site)
     Submitter *cptr;
     char *site;
{
  char *path = (char *) xmalloc (PATH_MAX);
  char **array = (char **) xmalloc (NUM_SUBMITTER_FIELDS * sizeof (char *));
  int err;

  if (site == NULL)
    return -1;

  sprintf (path, "%s/gnats-adm/%s", gnats_root, SUBMITTERS);
  err = get_adm_record (path, array, site);

  if (err == -1) 
    return err;

  memset (cptr, 0, sizeof (Submitter));

  if (err >= 5)
    cptr->notify = array[5];
  if (err >= 4)
    cptr->contact = array[4];
  if (err >= 3)
    {
      if (*array[3])
	cptr->rtime = atoi (array[3]);
      else
	cptr->rtime = -1;	/* -1 => no response time specified */
    }
  if (err >= 2)
    cptr->type = array[2];
  if (err >= 1)
    cptr->fullname = array[1];
  if (err >= 0)
    cptr->key = array[0];

  if (cptr->contact == NULL)
    {
      log_msg (LOG_INFO, 1, "contact person not defined, setting to:",
	       gnats_admin);
      cptr->contact = gnats_admin;
    }

  return err;
}

int 
find_categories (cptr, category)
     Category *cptr;
     char *category;
{
  char *path = (char *) xmalloc (PATH_MAX);
  char **array = (char **) xmalloc (NUM_CATEGORY_FIELDS * sizeof (char *));
  int err;

  sprintf (path, "%s/gnats-adm/%s", gnats_root, CATEGORIES);
  err = get_adm_record (path, array, category);

  if (err == -1)
    return err;
  
  if (err >= 3)
    cptr->notify = array[3];
  if (err >= 2)
    cptr->person = array[2];
  if (err >= 1)
    cptr->fullname = array[1];
  if (err >= 0)
    cptr->key = array[0];

  return err;
}

static Responsible*
find_responsible (person)
     char *person;
{
  Responsible *r;

  if (person == NULL)
    return NULL;

  /* If the chain has worked, then search it. Otherwise, do the 'file
     thing'. */
  if (responsible_chain != NULL)
    {
      for (r = responsible_chain; r; r = r->next)
        if (strcmp (r->key, person) == 0)
          return r;
    }
  else
    {
      char *path = (char *) xmalloc (PATH_MAX);
      char **array = (char **) xmalloc (NUM_SUBMITTER_FIELDS * sizeof (char *));
      int err;

      sprintf (path, "%s/gnats-adm/%s", gnats_root, RESPONSIBLE_FILE);
      err = get_adm_record (path, array, person);

      if (err == -1)
        return NULL;

      r = (Responsible *) xmalloc (sizeof (Responsible));
      memset (r, 0, sizeof (Responsible));

      r->alias = array[2];
      r->fullname = array[1];
      r->key = array[0];

      return r;
    }

  return NULL;
}

/* Read through the adm files, finding the line that matches the
   variable key.  Return the number of fields in PTR (the ones that matched
   KEY.  */
static int
get_adm_record (fname, ptr, key)
     char *fname;
     char **ptr;
     char *key;
{
  FILE *fp;
  char line[STR_MAX], temp[STR_MAX];
  char *l;
  char *keyed;
  int err = -1, i, keyedlen;

  /* append a delimiting ':' to the end of sting to make sure the match
     is fully correct.  */
  keyed = (char *) xmalloc (strlen(key) + 2);
  /* which is slower - strcpy/strcat or sprintf? */
  sprintf (keyed, "%s:", key);
  keyedlen = strlen(keyed); 

  fp = fopen (fname,"r");
  if (fp == NULL)
    return -1;

  while (read_string (line, fp) > 0)
    if (line[0] != '#' && line[0] != ' ' && line[0] != '\n') 
      {
        i = strncmp (line, keyed, keyedlen);
        if (i == 0)
          { 
            /* We found a match, now get the whole line.  */
            l = line;
            while (*l != '\0') 
              {
                l = get_next_field (l, temp, ':');
                if (temp != NULL)
		  {
		    /* We got something.  */
		    i = strlen (temp);
		    if (temp[i - 1] == '\n')
		      temp[i - 1] = '\0';
		    ptr[++err] = (char *) strdup (temp);
		    temp[0] = '\0';
		  }
	      }
	    break;
          }
      }

  fclose (fp);

  return err;
}

/* get_responsible_address - dredges the responsible party out of the
     appropriate places.  This routine should be NIS Correct, but it isn't.  */

Responsible *
get_responsible_address (person)
     char *person;
{
  Responsible* responsible = NULL;
  struct passwd *passwd;
  char *p;

  /* First check the responsible file; if there's no entry, try the
     passwd file.  */
  responsible = find_responsible (person);
  if (responsible)
    {
      if (responsible->alias[0] == '\0')
	responsible->alias = responsible->key;
    }
  else if ((passwd = getpwnam (person)) != 0)
    {
      responsible = (Responsible*) xmalloc (sizeof (Responsible));
      responsible->key = responsible->alias = (char *) strdup (person);

      /* Some passwd entries have commas for finger programs that
	 understand office phone numbers, etc.  Chop 'em off.  */
      p = (char *) strchr (passwd->pw_gecos, ',');
      if (p != NULL)
	*p = '\0';
      responsible->fullname = (char *) strdup (passwd->pw_gecos);
    } 

  return responsible;
}

/*  init_responsibles - reads and parses the whole responsibles file
      into a big linked list.  */

int
init_responsibles ()
{

  Responsible *r, *r_start = NULL, *r_end = NULL;
  FILE *fp;

  char line[STR_MAX];
  char **array = (char **) xmalloc (NUM_RESPONSIBLE_FIELDS * sizeof (char *));
  char *path = xmalloc (PATH_MAX);

  sprintf (path, "%s/gnats-adm/%s", gnats_root, RESPONSIBLE_FILE);
  fp = fopen (path, "r");
  if (fp == NULL)
    return 0;

  while (read_string (line, fp) > 0)
    if (line[0] != '#' && line[0] != ' ' && line[0] != '\n')
      {
	next_record (line, array);
	r = (Responsible *) xmalloc (sizeof (Responsible));
	r->key = array[0];
	r->fullname = array[1];
	r->alias = array[2];

	if (!*r->alias)
          r->alias = r->key;

	if (r_end == NULL)
	  r_start = r_end = r;
	else
	  {
	    r_end->next = r;
	    r_end = r;
	  }

	r->next = NULL;
     }

  if (r_start != NULL)
    responsible_chain = r_start;

  fclose (fp);

  if (responsible_chain)
    return 1;
  else
    return 0;
}

/* next_record - straight from get_adm_record, but w/out the searching
     for the right record. This builds up an array at a time.  */

static int
next_record (line, ptr)
   char *line;
   char **ptr;
{
  char *l;
  int i, err = 0;
  char temp[STR_MAX];

  l = line;
  while (*l != '\0')
    {
      l = get_next_field (l, temp, ':');
      if (temp != NULL)
        {
          /* We got something.  */
          i = strlen (temp);
          if (temp[i - 1] == '\n')
            temp[i - 1] = '\0';
          ptr[err++] = (char *) strdup (temp);
          temp[0] = '\0';
        }
    }

  return err;
}
