/* syslog.c - log an event to a system log file
 */

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "viewfile.h"
#include "viewmenu.h"
#include "terminal.h"
#include "mstring.h"
#include "lock.h"
#include "hook.h"
#include "bbs.h"

extern char current_keypath[];
extern int log_truncate(int, int, long, long, int);
extern time_t start_time;


/* Perform logging of data "t", auxiliary information "a", to file "key".
 */
void hook_do_syslog(char *key, char *a, char *t)
{
	char fbuf[1024];
	char buf[1024];
	struct tm *z;
	time_t n;
	int fd;
	int i;
	int l = 0;
	long s;

	n = time(0);
	z = localtime(&n);
	if (!z)
		return;

	if (!t)
		t = "";

	strcpy(fbuf, cf_str("logdir"));
	strcat(fbuf, "/");
	strcat(fbuf, cf_str(key));

	fd = open(fbuf, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	if (fd < 0)
		return;
	fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);

	t_bored(0);
	for (i = 0; i < 10; i++) {	    /* wait for file lock */
		if (!my_flock(fbuf, fd, LOCK_EX | LOCK_NB)) {
			l = 1;
			break;
		}
		t_bored(1);
		sleep(1);		    /* don't bother with lock after 10s */
	}
	t_bored(0);

	lseek(fd, 0, SEEK_END);		    /* go to end of file */

	if (a) {
		sprintf(buf,
			"%02d/%02d/%02d %2d:%02d %9s %9s <\035B%s\035b> %s\n",
			z->tm_year % 100, z->tm_mon + 1, z->tm_mday,
			z->tm_hour, z->tm_min, current_user, a,
			current_keypath, t);
	} else {
		sprintf(buf,
			"%02d/%02d/%02d %2d:%02d %9s <\035B%s\035b> %s\n",
			z->tm_year % 100, z->tm_mon + 1, z->tm_mday,
			z->tm_hour, z->tm_min, current_user,
			current_keypath, t);
	}

	write(fd, buf, strlen(buf));
	fsync(fd);

	s = cf_int("logsize") * 1024;

	if (l)
		log_truncate(fd, -1, s, (long) (s / 10), 0);	/* trunc if locked */

	my_flock(fbuf, fd, LOCK_UN);
	close(fd);
}


/* Log an addition to the current file.
 */
void hook_log_add(rf_data_t data)
{
	if (data->flags & MENU_STATUS_ANONYMOUS)
		return;
	if (data->flags & MENU_STATUS_BARLOG)
		return;
	hook_do_syslog("addlog", 0,
		       (data->flags & MENU_STATUS_HIDETITLE) ? "" : data->
		       title);
}


/* Log an edit beginning at "*pos" being deleted.
 */
void hook_log_delete(rf_data_t data, long *pos)
{
	char *a;
	char *b;

	if (data->flags & MENU_STATUS_BARLOG)
		return;
	if (data->flags & MENU_STATUS_ANONYMOUS)
		a = "*Anon*";
	else if (!pos)
		a = "*Unknown*";
	else {				    /* work out username of deleted edit */

		if (data->line_pos[1 + (*pos)].type != MFILE_LINE_FROM) {
			a = "*Unknown*";
		} else {
			rf_read_line(data, 1 + (*pos));
			a = strrchr(data->linebuf, '(');
			if (!a) {
				a = "*Unknown*";
			} else {
				*a = 0;
				a++;
				b = strchr(a, ':');
				if (b)
					*b = 0;
				b = strchr(a, ')');
				if (b)
					*b = 0;
			}
		}
	}

	hook_do_syslog("dellog", a,
		       (data->flags & MENU_STATUS_HIDETITLE) ? "" : data->
		       title);
}


/* Log the direct editing of the current file.
 */
void hook_log_edit(rf_data_t data)
{
	if (data->flags & MENU_STATUS_BARLOG)
		return;
	hook_do_syslog("editlog", 0,
		       (data->flags & MENU_STATUS_HIDETITLE) ? "" : data->
		       title);
}


/* Log the activation of execute or spool entry "e".
 */
void hook_log_run(menuentry_t * e, menudata_t data)
{
	if (e->status & MENU_STATUS_BARLOG)
		return;
	hook_do_syslog("runlog", 0,
		       (data->flags & MENU_STATUS_HIDETITLE) ? "" : e->
		       title);
}


/* Log the mailing of all or part of the current file to the current user.
 */
void hook_log_mail(rf_data_t data)
{
	if (data->flags & MENU_STATUS_BARLOG)
		return;
	hook_do_syslog("maillog", 0,
		       (data->flags & MENU_STATUS_HIDETITLE) ? "" : data->
		       title);
}


/* Log the exit of a client.
 */
void hook_log_client(void)
{
	char fbuf[1024];
	char buf[1024];
	char *a;
	struct tm *z;
	time_t n;
	int fd;
	int i;
	int l = 0;
	long s;

	n = time(0);
	z = localtime(&n);
	if (!z)
		return;

	strcpy(fbuf, cf_str("logdir"));
	strcat(fbuf, "/");
	strcat(fbuf, cf_str("bbslog"));

	fd = open(fbuf, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	if (fd < 0)
		return;
	fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);

	t_bored(0);
	for (i = 0; i < 10; i++) {	    /* wait for file lock */
		if (!my_flock(fbuf, fd, LOCK_EX | LOCK_NB)) {
			l = 1;
			break;
		}
		t_bored(1);
		sleep(1);		    /* don't bother with lock after 10s */
	}
	t_bored(0);

	lseek(fd, 0, SEEK_END);		    /* go to end of file */

	a = "<unknown>";
	bbs_hook(HOOK_LOCATION, &a, 0);
	sprintf(buf, "%02d/%02d/%02d %2d:%02d %s %9s %s\n",
		z->tm_year % 100, z->tm_mon + 1, z->tm_mday,
		z->tm_hour, z->tm_min, mstrsince(time(0) - start_time),
		current_user, a);

	write(fd, buf, strlen(buf));
	fsync(fd);

	s = cf_int("logsize") * 1024;

	if (l)
		log_truncate(fd, -1, s, (long) (s / 10), 0);	/* trunc if locked */

	my_flock(fbuf, fd, LOCK_UN);
	close(fd);
}

/* EOF */
