#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_PRINTF_H

#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#include <stdlib.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif

#include <wchar.h>

#include "sigparams.h"
#include "util.h"


/*
  signature parameters: custom printf conversion codes that can be
  used to add computed information to a signature block

  by MAtteo HCE Valsasna <valsasna@uninsubria.it>

*/

extern int debug;

/*
  add to this array the conversion functions to be registered */

static struct param_info {
  int conv_specifier;
  int (*print_fun) (FILE *stream,
		    const struct printf_info *info,
		    const void *const *args);
}  conversions[] =
{
  {'R', print_count }, 
  {'D', print_delta },
  {'T', print_time }, 
  {'Y', print_daycount }, 
  {'H', print_first_in_day }, 
  /* terminator ;) */
  {'0', NULL }
};


/* global vars used to create a process status informations an user
   could find useful
*/

/* process fire count*/
int count;

/* daily fire count */
int day_count;
int first_in_day;

time_t current_time, last_eval_time, process_start_time;

/* used to detect day change */
int last_eval_day;
int last_eval_month;

char * first_in_day_msg;

#define init_sigparams_BUFSIZE 256

/* module initialization */
void init_sigparams()
{
  int rv = 0;
  char errmsg[init_sigparams_BUFSIZE];
  int ii;

  count = 0;
  day_count = 0;
  /* TODO: should be customizable */
  first_in_day_msg = 
    "you are my first mail recipient of the day, congratulations!\n";
  first_in_day = 1;

  time(& process_start_time);
  current_time = process_start_time;


  /* register conversion functions */
  for (ii = 0; conversions[ii].print_fun; ii ++)
    {
      rv = register_printf_function (conversions[ii].conv_specifier,
				     conversions[ii].print_fun,
				     print_arginfo);
      if (rv != 0) {
	snprintf(errmsg, init_sigparams_BUFSIZE,
		 "sigparams.c: initializing %c (%d) conversion", 
		 conversions[ii].conv_specifier,		 
		 conversions[ii].conv_specifier);
	perror(errmsg);
	exit(1);
      }
    }
}

/* 
   this function gets called at every read of .signature, before the
   actual signature printig happens.
   
   all status collecting code should go here - NOT in print_*
   functions - so that if conversion specifiers are added or removed
   from .signature.tmpl without restarting gensig, status is still
   computed correctly

*/

void foreach_sigparams()
{
  int current_day, current_month;

  count ++;
  day_count ++;

  last_eval_time = current_time;
  time(& current_time);
  current_day = localtime(& current_time) -> tm_mday;
  current_month = localtime(& current_time) -> tm_mon;
  
  /* see if this is the first run in a new day, taking care of
     februaries (if we just compared days, an user reading a signature
     on the Nth of february and doing the next read on the Nth of
     march would not get the first_in_day message) */
  if (current_day != last_eval_day ||
      current_month != last_eval_month)
    {
      last_eval_day = current_day;
      last_eval_month = current_month;
      day_count = 1;
      first_in_day = 1;
    }
  else first_in_day = 0;
  

  /* we are computing time differencies, a good position to detect
     clock skews */

  if (difftime(current_time, last_eval_time) < 0)
    {
      if (debug) 
	{
	  fprintf(stderr, "time warp? wonderful!\n");
	  fprintf(stderr, "last time run: %s\n", ctime(&last_eval_time));
	  fprintf(stderr, "current time: %s\n", ctime(&current_time));
	}
      else
	{
	  openlog("gensig", LOG_PID, LOG_USER);
	  syslog(LOG_WARNING, "time warp? wonderful!");
	  syslog(LOG_WARNING, "last time run: %s", ctime(&last_eval_time));
	  syslog(LOG_WARNING, "current time: %s", ctime(&current_time));
	}
    }
}

/* 
   print_arginfo: 

   this is called by *printf to know how many arguments to pass to
   print_* when a %? conversion specifier is found in the format
   string

   since we are printing values that depend on program state and not
   on user input, we always return 0 

*/

int print_arginfo (const struct printf_info *info, size_t n,
		   int *argtypes)
{
  return 0;
}

/*
  TODO: print_* functions could consider the info parameter they
  receive (it contains formatting instructions)
*/

/* count: number of times .signature was read in process life */

int print_count(FILE *stream,
		const struct printf_info *info,
		const void *const *args)
{
  return fprintf(stream, "%d", count);
}


/* delta: time elapsed since last read */

int print_delta(FILE *stream,
		const struct printf_info *info,
		const void *const *args)
{
  int seconds = (int) difftime(current_time, last_eval_time);

  return fprint_delta(stream, seconds);
}

/* time: time elapsed since process start */

int print_time(FILE *stream,
		const struct printf_info *info,
		const void *const *args)
{
  int seconds = (int) difftime(current_time, process_start_time);

  return fprint_delta(stream, seconds);
}



/* day count: number of reads in a day */

int print_daycount(FILE *stream,
		const struct printf_info *info,
		const void *const *args)
{
  return fprintf(stream, "%d", day_count);
}


/* first in day: pring a message for the first read in a day */

int print_first_in_day(FILE *stream,
		const struct printf_info *info,
		const void *const *args)
{
  if (first_in_day)
    {
      return fprintf(stream, "%s", first_in_day_msg);
    }
  else return 0;
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1