// Copyright, 2001-2003, Astra Network Inc.  All Rights Reserved

// This source code has been published by Astra Network Inc. However, any
// use, reproduction, modification, distribution or transfer of this
// software, or any software which includes or is based upon any of this
// code, is only permitted if expressly authorized by a written license
// agreement from Astra. Contact your Astra representative directly for
// more information.


#include <olmod.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>

typedef struct log_data_s
{
  pid_t process;
  int logtype;
  FILE *fp;
  int facility;
  int debug_level;		/* level at which we stop recording errors */
}
log_data_t;

typedef struct name_fact_s
{
  const char *name;
  const int facility;
}
name_fact_t;

static name_fact_t syslognames[] = {
  {"LOG_AUTH", LOG_AUTH},
#ifndef sun
  {"LOG_AUTHPRIV", LOG_AUTHPRIV},
#endif
  {"LOG_CRON", LOG_CRON},
  {"LOG_DAEMON", LOG_DAEMON},
  {"LOG_KERN", LOG_KERN},
  {"LOG_LOCAL0", LOG_LOCAL0},
  {"LOG_LOCAL1", LOG_LOCAL1},
  {"LOG_LOCAL2", LOG_LOCAL2},
  {"LOG_LOCAL3", LOG_LOCAL3},
  {"LOG_LOCAL4", LOG_LOCAL4},
  {"LOG_LOCAL5", LOG_LOCAL5},
  {"LOG_LOCAL6", LOG_LOCAL6},
  {"LOG_LOCAL7", LOG_LOCAL7},
  {"LOG_LPR", LOG_LPR},
  {"LOG_MAIL", LOG_MAIL},
  {"LOG_NEWS", LOG_NEWS},
  {"LOG_SYSLOG", LOG_SYSLOG},
  {"LOG_USER", LOG_USER},
  {"LOG_UUCP", LOG_UUCP}
};

static int
name_cmp (const void *p1, const void *p2)
{
  const char *p1c = (const char *) p1;
  const char **p2c = (const char **) p2;

  return strcmp (p1c, *p2c);
}

olmod_error_t
log_module_init ()
{
  return kMod_OK;
}

olmod_blackbox_t /*@null@ */  * log_module_inst (pid_t process,
						 olmod_arglist_t *
						 static_args)
{
  log_data_t *blackbox;
  name_fact_t *fac;

  if (!(blackbox = (log_data_t *) malloc (sizeof (log_data_t))))
    {
      printf ("mod_log: malloc failed\n");
      return NULL;
    }
  blackbox->process = process;
  blackbox->logtype = QTOL (*(int64_t *) static_args[0]);
  switch (blackbox->logtype)
    {
    case 0:
      blackbox->fp = stderr;
      break;
    case 1:
      blackbox->fp = fopen ((char *) static_args[1], "a+");
      if (blackbox->fp == NULL)
	blackbox->fp = stderr;
      break;
    case 2:
      blackbox->fp = NULL;
      fac = (name_fact_t *) bsearch (static_args[1], syslognames,
				     sizeof (syslognames) /
				     sizeof (syslognames[0]),
				     sizeof (syslognames[0]), name_cmp);
      if (fac == NULL)
	{
	  free (blackbox);
	  printf ("mod_log: Invalid facility type\n");
	  return NULL;
	}
      openlog ("olrt", LOG_CONS, fac->facility);
      break;
    default:
      blackbox->fp = stderr;
    }

  /* FIXME: highest level, change this to something dynamic later */
  blackbox->debug_level = 10;

  return (olmod_blackbox_t *) blackbox;
}

olmod_error_t
log_module_set (olmod_blackbox_t /*@unused@ */  * data,
		int64_t /*@unused@ */ var)
{
  return kMod_OK;
}

int64_t
log_module_get (olmod_blackbox_t * data, olmod_arglist_t * dynamic_args)
{
  log_data_t *blackbox = (log_data_t *) data;
  int severity = *(int *) dynamic_args[0];

  if (data == NULL)
    return LTOQ (0L);

  /* Only record log message of a severity greater than the debug level */
  if (severity > blackbox->debug_level)
    return (LTOQ (0l));

  switch (blackbox->logtype)
    {
    case 0:
    case 1:
      fprintf (blackbox->fp, "%ld:%d:%s\n", (long int) blackbox->process,	/* pid (or 0 for global context) */
	       severity,	/* severity level */
	       (char *) dynamic_args[1]);	/* log message */
      break;
    case 2:
      syslog (severity, "%ld:%s",
	      (long int) blackbox->process, (char *) dynamic_args[1]);
      break;
    default:
      fprintf (stderr, "mod_log: logtype not supported\n");
    }

  return (LTOQ (0l));
}

void
log_module_deinst (olmod_blackbox_t * data)
{
  log_data_t *blackbox = (log_data_t *) data;

  if (data != NULL)
    {
      if (blackbox->fp && blackbox->fp != stderr)
	fclose (blackbox->fp);
      if (blackbox->logtype == 2)
	closelog ();
      free (data);
    }
}

void
log_module_deinit ()
{
}
