/* Miscellaneous utility routines for GNATS.
   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>
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif

#if defined(__STDC__) || defined(_AIX)
#include <stdarg.h>
#define VA_START(args, lastarg) va_start(args, lastarg)
#else
#include <varargs.h>
#define VA_START(args, lastarg) va_start(args)
#endif

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

#include <signal.h>

/* Debugging level.  */
int debug_level = LOG_ERR; 

/* File to log all messages to.  */
FILE *gnats_logfile = NULL;

/* Current logging method.  */
Logging_Methods log_method = STDERR;

/* Table to tell if a char c is whitespace.  */
unsigned char is_space[256];

void
init_gnats ()
{
  init_space ();
  init_pr ();
  init_header ();
}

/* VARARGS */
void 
#if defined(__STDC__) || defined(_AIX)
log_msg (int severity, int has_arg, ...)
#else
log_msg (severity, has_arg, va_alist)
     int severity, has_arg;
     va_dcl
#endif
{
  va_list args;
  char buf[STR_MAX], *message, *message2;

  VA_START (args, has_arg);
  message = va_arg (args, char *);
  if (has_arg)
    message2 = va_arg (args, char *);

  if (has_arg)
    sprintf (buf, "%s: %s %s\n", program_name, message, message2);
  else
    sprintf (buf, "%s: %s\n", program_name, message);

  if (debug_level >= severity)
    {
#ifdef HAVE_SYSLOG_H
      if (log_method == SYSLOG)
	syslog (severity, buf);
      else
#endif
      if (gnats_logfile != (FILE *) NULL)
	fprintf (gnats_logfile, "%s", buf);
      else
	fprintf (stderr, "%s", buf);
    }

  va_end (args);

  if (severity == LOG_ERR)
    exit (2);
}

/* Open the file (actually the pipe) to which the mail message will
   be written.  */
FILE *
open_mail_file (recipients)
     char *recipients;
{
  FILE *fp;
  char *buffer;

  if (recipients != NULL)
    buffer = (char *) xmalloc (strlen (mail_agent) + strlen (recipients) + 2);
  else
    buffer = (char *) xmalloc (strlen (mail_agent) + 1);

  /* Can't use log_msg here, since gnats_logfile is being set by this first
     thing.  */

#ifdef USE_BIN_MAIL
  sprintf (buffer, "%s %s", mail_agent,
	   (debug_mode ? gnats_admin : recipients));
#else
  sprintf (buffer, "%s", mail_agent);
#endif
  fp = popen (buffer, "w");

  if (debug_mode)
    {
      fprintf (fp, "From: gnats (GNATS Management)\n");
#ifndef USE_BIN_MAIL
      fprintf (fp, "To: %s\n", gnats_admin);
#endif
      fprintf (fp, "Subject: mail output from %s\n", program_name);
      fprintf (fp, "\n\n");
    }

  return fp;
}

void
close_mail_file (fp)
     FILE *fp;
{

#ifdef USE_BIN_MAIL
  fprintf (fp, ".\n");
#endif
 
  if (fp)
    {
      fflush (fp);
      pclose (fp);
    }
}

/* Initialize the `is_space' array.  */
void
init_space ()
{
  is_space[' '] = 1;
  is_space['\t'] = 1;
  is_space['\v'] = 1;
  is_space['\f'] = 1;
  is_space['\n'] = 1;
  is_space['\r'] = 1;
}

/* Scan down LINE, returning the next token.  We can't use strtok, since
   we often deal with constant strings like "foo | bar" for the default
   values for a PR.  */
char *
get_next_field (line, token, delim)
     char *line, *token;
     int delim;
{
  char *t = token;

  while (*line != delim && *line != '\0')
    *t++ = *line++;

  /* *line++; 	skip over delimiter */
  /* skip over any white space after delim */
  while (*line != '\0' && *++line == ' ')
    /* Nothing */ ;

  while (*--t == ' ')
    /* Nothing */ ;

  t[1] = '\0';

  return line;
}

/* Read in the next line using fgets, and return its length.  */
int
read_string (line, fp)
     char *line;
     FILE *fp;
{
  if (fgets (line, STR_MAX, fp) == NULL)
    return -1;

  if (*line == '\n')
    return 1;

  return strlen (line);
}

/* GetToken grabs a token, and returns both the token and the shortened
   string. */
char *
get_token (line, token)
     char *line;
     char *token;
{
  char *t = token;

  if (*line == ' ')
    return line;

  /* Check for quote. if we see if, read everything up to the next quote
     as the token.  */
  if (*line == '"')
    {
      line++; /* ignore the first quote */
      while (*line != '"' && *line != '\0')
	*t++ = *line++;

      line++; /*  ignore the last quote */
      SKIP_WHITE_SPACE (line);
    }
  else
    {
      /* If not quote, then just regular strings for now.  */
      while (*line != ' ' && *line != '\t' && *line != '\n' && *line != '\0')
	*t++ = *line++;
    }

  /* I want to make sure this happens.  */
  *t = '\0';

  SKIP_WHITE_SPACE (line);
  return line;
}

#ifndef HAVE_MKDIR
/* mkdir and rmdir adapted from GNU tar.  */

/* Make directory DPATH, with permission mode DMODE.

   Written by Robert Rother, Mariah Corporation, August 1985
   (sdcsvax!rmr or rmr@@uscd).  If you want it, it's yours.

   Severely hacked over by John Gilmore to make a 4.2BSD compatible
   subroutine.	11Mar86; hoptoad!gnu

   Modified by rmtodd@@uokmax 6-28-87 -- when making an already existing dir,
   subroutine didn't return EEXIST.  It does now.  */

int
mkdir (dpath, dmode)
     char *dpath;
     int dmode;
{
  int cpid, status;
  struct stat statbuf;

  if (stat (dpath, &statbuf) == 0)
    {
      errno = EEXIST;		/* stat worked, so it already exists.  */
      return -1;
    }

  /* If stat fails for a reason other than non-existence, return error.  */
  if (errno != ENOENT)
    return -1;

  cpid = fork ();
  switch (cpid)
    {
    case -1:			/* Cannot fork.  */
      return -1;		/* errno is set already.  */

    case 0:			/* Child process.  */
      /* Cheap hack to set mode of new directory.  Since this child
	 process is going away anyway, we zap its umask.
	 This won't suffice to set SUID, SGID, etc. on this
	 directory, so the parent process calls chmod afterward.  */
      status = umask (0);	/* Get current umask.  */
      umask (status | (0777 & ~dmode));	/* Set for mkdir.  */
      execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
      _exit (1);

    default:			/* Parent process.  */
      while (wait (&status) != cpid) /* Wait for kid to finish.  */
	/* Do nothing.  */ ;

      if (status & 0xFFFF)
	{
	  errno = EIO;		/* /bin/mkdir failed.  */
	  return -1;
	}
      return chmod (dpath, dmode);
    }
}
#endif /* HAVE_MKDIR */
