/*
 * btscanner - Displays the output of Bluetooth scans
 * Copyright (C) 2003 Pentest Limited
 * 
 * Written 2003 by Tim Hurman <timh at pentest.co.uk>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
 * RIGHTS.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE
 * FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 * 
 * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
 * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE
 * IS DISCLAIMED.
 */

/*
 * log.c: btscanner logging
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif

#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

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

#include <stdio.h>
#include <errno.h>
#include <pthread.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

#include <log.h>
#include <cfg.h>

static FILE *log_fp = NULL;
static int log_fd = -1;
static FILE *log_sum_fp = NULL;
static int log_sum_fd = -1;
static pthread_mutex_t log_smux = PTHREAD_MUTEX_INITIALIZER;

/* initalise the logging, to a new file. */
int log_init(void)
{
	const char *s;

	/* sort out the filename */
	s = cfg_log_filename();
	if (!s) {
		fprintf(stderr, "%s(): NULL logfile\n", __FUNCTION__);
		return 1;
	}

	/* open the logfile */
	log_fd = open(s, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
	if (-1 == log_fd) {
		fprintf(stderr, "%s::open(): %s\n", __FUNCTION__, strerror(errno));
		return 1;
	}

	/* open it as a pointer */
	log_fp = fdopen(log_fd, "w");
	if (NULL == log_fp) {
		fprintf(stderr, "%s::open(): %s\n", __FUNCTION__, strerror(errno));
		return 1;
	}

	applog(LOG_INFO, "btscanner starting");
	return 0;
}


/* open the summary log */
int log_sum_open(const char *filename)
{
	/* sort out the filename */
	if (!filename) {
/*		fprintf(stderr, "%s(): NULL logfile\n", __FUNCTION__);*/
		return 1;
	}

	/* open the logfile */
	log_sum_fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
	if (-1 == log_sum_fd) {
/*		fprintf(stderr, "%s::open(): %s\n", __FUNCTION__,
 *		strerror(errno));*/
		return 1;
	}

	/* open it as a pointer */
	log_sum_fp = fdopen(log_sum_fd, "w");
	if (NULL == log_sum_fp) {
/*		fprintf(stderr, "%s::open(): %s\n", __FUNCTION__,
 *		strerror(errno));*/
		return 1;
	}
	return 0;
}


/* cease logging */
int log_close(void)
{
	if (log_fp) {
		applog(LOG_INFO, "btscanner shutting down");
		fflush(log_fp);
		fclose(log_fp);
		log_fp = NULL;
		log_fd = -1;
	}
	return 0;
}
int log_sum_close(void)
{
	if (log_sum_fp) {
		fflush(log_sum_fp);
		fclose(log_sum_fp);
		log_sum_fp = NULL;
		log_sum_fd = -1;
	}
	return 0;
}


/* log an error */
int applog(int level, const char *fmt, ...)
{
	va_list ap;
	struct tm now;
	time_t tnow;
	char *s;

	if(!log_fp) return 1;

	/* serialise the function */
	pthread_mutex_lock(&log_smux);

	/* firstly print out the date/time */
	time(&tnow);
	localtime_r(&tnow, &now);
	now.tm_year += 1900;
	now.tm_mon ++;

	switch(level) {
	case LOG_INFO:
		s="info";
		break;
	case LOG_WARNING:
		s="warning";
		break;
	case LOG_ERR:
		s="error";
		break;
	default:
		s="unknown";
		break;
	}

	fprintf(log_fp, "%04d/%02d/%02d %02d:%02d:%02d: %s: ", 
	  now.tm_year, now.tm_mon, now.tm_mday,
	  now.tm_hour, now.tm_min, now.tm_sec, s);
	va_start(ap, fmt);
	vfprintf(log_fp, fmt, ap);
	va_end(ap);
	fprintf(log_fp, "\n");
	fflush(log_fp);

	/* unserialise */
	pthread_mutex_unlock(&log_smux);

	return 0;
}


/* print a line into the summary log */
int summary(const char *fmt, ...)
{
	va_list ap;

	if(!log_sum_fp) return 1;

	/* serialise the function */
	pthread_mutex_lock(&log_smux);

	va_start(ap, fmt);
	vfprintf(log_sum_fp, fmt, ap);
	va_end(ap);
	fprintf(log_sum_fp, "\n");
	fflush(log_sum_fp);

	/* unserialise */
	pthread_mutex_unlock(&log_smux);

	return 0;
}

