/* misclog.c - log a menu action to a file
 */

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

int hook_acl_check(char *, char *, char **);


/* Log the activation of menu entry "e" to the log file specified in it,
 * checking that writing to that log file is allowed.
 *
 * Writing to the log file is only allowed if it exists and is owned by the
 * same user that the menu is. However, if the pathname of the log file
 * starts with the path specified as "nolog", no logging is done.
 */
void hook_log_action(menudata_t data, menuentry_t * e)
{
	struct stat sb;
	uid_t menu_uid;
	char buf[1024];
	struct tm *z;
	char *nolog;
	time_t n;
	int fd;
	int i;

	if (!e->logfile)
		return;			    /* no logfile specified */

	n = time(0);			    /* get current time */
	z = localtime(&n);
	if (!z)
		return;

	nolog = cf_str("nolog");
	if ((!nolog) || (nolog[0] == 0))
		nolog = 0;

	if (nolog) {			    /* check if path is allowed */
		if (!strncmp(e->logfile, nolog, strlen(nolog)))
			return;
	}

	if (stat(data->file, &sb))
		return;			    /* can't stat menu file */
	menu_uid = sb.st_uid;

	if (stat(e->logfile, &sb))
		return;			    /* can't stat log file */
	if (sb.st_uid != menu_uid) {	    /* not owned by menu owner */
		if (hook_acl_check(e->logfile, data->file, 0))
			return;		    /* ACL check */
	}

	fd = open(e->logfile, O_WRONLY | O_APPEND);	/* open log file */
	if (fd < 0)
		return;

	t_bored(0);
	for (i = 0; i < 10; i++) {	    /* wait for file lock */
		if (!my_flock(e->logfile, fd, LOCK_EX | LOCK_NB))
			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 just in case */

	sprintf(buf, "%02d/%02d/%02d %2d:%02d %9s %s\n",
		z->tm_year % 100, z->tm_mon + 1, z->tm_mday,
		z->tm_hour, z->tm_min, current_user,
		(e->log_type == MENU_LOG_TITLE)
		? e->title : getenv("MVIEW_NAMELINE")
	    );

	write(fd, buf, strlen(buf));
	my_flock(e->logfile, fd, LOCK_UN);
	close(fd);
}

/* EOF */
