/* ============================================================================
 * << File: log.c >>
 * -----------------
 *   Author: Emiliano Castagnari (aka Torian) <ecastag@fi.uba.ar>
 *           Diego Essaya <dessaya@fi.uba.ar>
 *     Date: 29/12/03
 *
 *  Description:
 *    Functions for server logging.
 * ============================================================================
 * ============================================================================
 *
 * ChangeLog: View Changelog
 *
 * ============================================================================
 * Copyright (C) 2003, 2004 Diego Essaya, Emiliano Castagnari
 * 
 * This file is part of gems.
 * 
 * gems 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 of the License, or
 * (at your option) any later version.
 *
 * gems 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 Library 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.
 * ============================================================================
 */

#include <stdarg.h>     /* variable parameter functions */
#include <time.h>       /* time_t */
#include <syslog.h>     /* syslog() */
#include <string.h>     /* strlen() */

#include "version_server.h"

#include "log.h"

/* Global variables defining where to log: */
log_opt_t logdest = G_LOG_NOLOG;
char *logfile = NULL;

t_log mesg_log[] = 
{
	{ERR_NOT_OPT,		LOG_ERR, 	N_("Invalid option: %s.")},
	{ERR_OPT_WO_ARG,	LOG_ERR, 	N_("Option %s requires an argument.")},
	{ERR_PORT, 			LOG_ERR, 	N_("Invalid TCP port.")},
	{ERR_MAXCONN,		LOG_ERR, 	N_("Invalid value for maximum number of"
									" connections.")},
	{ERR_WAIT,			LOG_ERR, 	N_("Invalid value for 'wait' option.")},
	{ERR_MEMORY, 		LOG_ERR, 	N_("Not enough memory.")},
	{ERR_LOCK,          LOG_ERR, 	N_("Cannot create lock file: %s\n"
		"  Maybe another instance of %s is running?")},
	{ERR_INTERNAL,		LOG_ERR, 	N_("Aaargh! Internal error -- sorry.")},
	{LOG_SOCK_C, 		LOG_INFO, 	N_("Accepting connections on port %d.")},
	{LOG_NEW_C, 		LOG_INFO, 	N_("New connection -- Client %i -- "
									"IP: %s.")}, 
	{LOG_CLOSE_C, 		LOG_INFO, 	N_("Client disconnection -- IP: %s.")},
	{LOG_CLOSING_ALL, 	LOG_INFO, 	N_("Closing all connections...")},
	{LOG_MAXCONN, 		LOG_INFO, 	N_("Connection refused: maximum number "
									"of connections reached.")},
	{LOG_SERVER_VERSION,LOG_INFO, 	N_("Connection refused: obsolete server "
									"version.")},
	{LOG_CLIENT_VERSION,LOG_INFO, 	N_("Connection refused: obsolete client "
									"version.")},
	{LOG_WINSIZE,		LOG_INFO, 	N_("Client disconnected: terminal size "
									"too small.")},
	{LOG_RUNSCRIPT,		LOG_INFO, 	N_("Running %s...")},
	{LOG_ENDSCRIPT,		LOG_INFO, 	N_("script terminated.")},

	{DEBUG_ADD_C, 		LOG_DEBUG, 	
" # DEBUG | add_client(): client->prev[%p] | client[%p] | client->next[%p]"},
	{DEBUG_DEL_C, 		LOG_DEBUG, 	
" # DEBUG | del_client(): client->prev[%p] | client[%p] | client->next[%p]"},
	{DEBUG_SEND_C, 		LOG_DEBUG, 	" # DEBUG | send_2client(): "}
};


/*****************************************************************************
 * g_set_logfile()
 *
 * Specifies where the logs wil be written to.
 * If _logdest == G_LOG_FILE, another argument is expected (filename).
 */
void g_set_logdest(log_opt_t _logdest, ...)
{
	va_list va;

	logdest = _logdest;

	va_start(va, _logdest);
	if (logdest == G_LOG_FILE) logfile = va_arg(va, char *);
	else logfile = NULL; 
	va_end(va);

	if (logdest == G_LOG_SYSLOG) openlog(APPNAME, LOG_PID, LOG_USER);
}


/*****************************************************************************
 * g_log()
 * 
 * Logging function.
 * In case of not writing to syslog, the format of the produced log is:
 * 
 *   APPNAME [DATE]: mesg_log[errno]
 *
 * where 'APPNAME' is the name of the program, 'DATE' is the value returned  
 * by the 'g_time()' function, and 'mesg_log[errno]' is the message string. 
 *
 * The extra arguments are passed to vsprintf(). */
void g_log(short int errno, ...)
{
	char string[255];	/* Container for the formatted message */
	va_list va;
	FILE *fd_log = NULL;

	/* Validation of the errno argument: */
	if (errno >= sizeof(mesg_log) || errno < 0)
		errno = ERR_INTERNAL;

	/* Format message string + variable arguments into the "string" array */
	va_start(va, errno);
	vsprintf(string, _(mesg_log[errno].log_str), va);
	va_end(va);

	if (logdest == G_LOG_SYSLOG) /* use syslog */
	{
		syslog(mesg_log[errno].priority, string);
	}
	else if (logdest != G_LOG_NOLOG) /* log to stderr or a file: */
	{
		if ((logdest == G_LOG_FILE) && (logfile))
		{
			fd_log = fopen(logfile, "a");
		}

		fprintf((fd_log == NULL) ? stderr : fd_log, APPNAME" [%s]: %s\n",
				g_time(), string);

		if (fd_log != NULL) fclose(fd_log);
	}
	
	/* If we have an error message, write it to stderr (if not done yet): */
	if ((mesg_log[errno].priority == LOG_ERR) && (logdest != G_LOG_STDERR))
	{
		fprintf(stderr, APPNAME": %s\n", string);
	}
}


/*****************************************************************************/
/* Return the actual time & date, in string format. */
char *g_time(void)
{
	time_t time_utc;			/* UTC formatted date */
	struct tm time_fmt;			/* Time data structure */
	char *time_str;

	time_utc = time(NULL);
	time_fmt = (*localtime(&time_utc));

	time_str = asctime(&time_fmt);
	time_str[strlen(time_str) - 1] = '\0';
	return time_str;
}

/* vim: set ts=4 sw=4: */
