btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * log.c - logging routines 
 */

#include "copyright.h"
#include "config.h"

#include <sys/types.h>
#include <sys/time.h>
#include <time.h>

#include "db.h"
#include "mudconf.h"
#include "externs.h"
#include "flags.h"
#include "powers.h"
#include "alloc.h"
#include "htab.h"
#include "ansi.h"
#ifdef ARBITRARY_LOGFILES
#include "logcache.h"
#endif

NAMETAB logdata_nametab[] = {
	{(char *) "flags", 1, 0, LOGOPT_FLAGS},
	{(char *) "location", 1, 0, LOGOPT_LOC},
	{(char *) "owner", 1, 0, LOGOPT_OWNER},
	{(char *) "timestamp", 1, 0, LOGOPT_TIMESTAMP},
	{NULL, 0, 0, 0}
};

NAMETAB logoptions_nametab[] = {
	{(char *) "accounting", 2, 0, LOG_ACCOUNTING},
	{(char *) "all_commands", 2, 0, LOG_ALLCOMMANDS},
	{(char *) "suspect_commands", 2, 0, LOG_SUSPECTCMDS},
	{(char *) "bad_commands", 2, 0, LOG_BADCOMMANDS},
	{(char *) "buffer_alloc", 3, 0, LOG_ALLOCATE},
	{(char *) "bugs", 3, 0, LOG_BUGS},
	{(char *) "checkpoints", 2, 0, LOG_DBSAVES},
	{(char *) "config_changes", 2, 0, LOG_CONFIGMODS},
	{(char *) "create", 2, 0, LOG_PCREATES},
	{(char *) "killing", 1, 0, LOG_KILLS},
	{(char *) "logins", 1, 0, LOG_LOGIN},
	{(char *) "network", 1, 0, LOG_NET},
	{(char *) "problems", 1, 0, LOG_PROBLEMS},
	{(char *) "security", 2, 0, LOG_SECURITY},
	{(char *) "shouts", 2, 0, LOG_SHOUTS},
	{(char *) "startup", 2, 0, LOG_STARTUP},
	{(char *) "wizard", 1, 0, LOG_WIZARD},
	{NULL, 0, 0, 0}
};

char *strip_ansi_r(char *dest, char *raw, size_t n)
{
	char *p = (char *) raw;
	char *q = dest;

	while (p && *p && ((q - dest) < n)) {
		if(*p == ESC_CHAR) {
			/*
			 * Start of ANSI code. Skip to end. 
			 */
			while (*p && !isalpha(*p))
				p++;
			if(*p)
				p++;
		} else
			*q++ = *p++;
	}
	*q = '\0';
	return dest;
}
char *strip_ansi(const char *raw)
{
	static char buf[LBUF_SIZE];
	char *p = (char *) raw;
	char *q = buf;

	while (p && *p) {
		if(*p == ESC_CHAR) {
			/*
			 * Start of ANSI code. Skip to end. 
			 */
			while (*p && !isalpha(*p))
				p++;
			if(*p)
				p++;
		} else
			*q++ = *p++;
	}
	*q = '\0';
	return buf;
}

char *normal_to_white(const char *raw)
{
	static char buf[LBUF_SIZE];
	char *p = (char *) raw;
	char *q = buf;

	while (p && *p) {
		if(*p == ESC_CHAR) {
			/*
			 * Start of ANSI code. 
			 */
			*q++ = *p++;		/*
								 * ESC CHAR 
								 */
			*q++ = *p++;		/*
								 * [ character. 
								 */
			if(*p == '0') {		/*
								 * ANSI_NORMAL 
								 */
				safe_str("0m", buf, &q);
				safe_chr(ESC_CHAR, buf, &q);
				safe_str("[37m", buf, &q);
				p += 2;
			}
		} else
			*q++ = *p++;
	}
	*q = '\0';
	return buf;
}

/**
 * See if it's is OK to log something, and if so, start writing the
 * log entry.
 */
int start_log(const char *primary, const char *secondary)
{
	struct tm *tp;
	time_t now;

	mudstate.logging++;
	switch (mudstate.logging) {
	case 1:
	case 2:

		/*
		 * Format the timestamp 
		 */

		if((mudconf.log_info & LOGOPT_TIMESTAMP) != 0) {
			time((time_t *) (&now));
			tp = localtime((time_t *) (&now));
			sprintf(mudstate.buffer, "%d%02d%02d.%02d%02d%02d ",
					tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday,
					tp->tm_hour, tp->tm_min, tp->tm_sec);
		} else {
			mudstate.buffer[0] = '\0';
		}

		/*
		 * Write the header to the log 
		 */

		if(secondary && *secondary)
			fprintf(stderr, "%s%s %3s/%-5s: ", mudstate.buffer,
					mudconf.mud_name, primary, secondary);
		else
			fprintf(stderr, "%s%s %-9s: ", mudstate.buffer,
					mudconf.mud_name, primary);
		/*
		 * If a recursive call, log it and return indicating no log 
		 */

		if(mudstate.logging == 1)
			return 1;
		fprintf(stderr, "Recursive logging request.\r\n");
	default:
		mudstate.logging--;
	}
	return 0;
}

/**
 * Finish up writing a log entry
 */
void end_log(void)
{
	fprintf(stderr, "\n");
	fflush(stderr);
	mudstate.logging--;
}

/**
 * Write perror message to the log
 */
void log_perror(const char *primary, const char *secondary, const char *extra,
				const char *failing_object)
{
	start_log(primary, secondary);
	if(extra && *extra) {
		log_text((char *) "(");
		log_text((char *) extra);
		log_text((char *) ") ");
	}
	perror((char *) failing_object);
	fflush(stderr);
	mudstate.logging--;
}

/**
 * Write text to log file.
 */
void log_text(char *text)
{
	fprintf(stderr, "%s", strip_ansi(text));
}

void log_error(int key, char *primary, char *secondary, char *format, ...)
{
	char buffer[LBUF_SIZE];
	char stripped_buffer[LBUF_SIZE];
	va_list ap;

    if(!(key & mudconf.log_options))
		return;

	if(mudconf.log_info & LOGOPT_TIMESTAMP) {
		time_t now;
		struct tm tm;
		time(&now);
		localtime_r(&now, &tm);
		fprintf(stderr, "%d%02d%02d.%02d%02d%02d ",
				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
				tm.tm_hour, tm.tm_min, tm.tm_sec);
	}

	if(secondary && &secondary) {
		fprintf(stderr, "%s%s %3s/%-5s: ", mudstate.buffer,
				mudconf.mud_name, primary, secondary);
	} else {
		fprintf(stderr, "%s%s %-9s: ", mudstate.buffer,
				mudconf.mud_name, primary);
	}

	va_start(ap, format);
	vsnprintf(buffer, LBUF_SIZE, format, ap);
	va_end(ap);

	strip_ansi_r(stripped_buffer, buffer, LBUF_SIZE);
	fprintf(stderr, "%s\n", stripped_buffer);
}

void log_printf(char *format, ...)
{
	char buffer[LBUF_SIZE];
	char stripped_buffer[LBUF_SIZE];
	va_list ap;

	va_start(ap, format);
	vsnprintf(buffer, LBUF_SIZE, format, ap);
	va_end(ap);

	strip_ansi_r(stripped_buffer, buffer, LBUF_SIZE);
	fprintf(stderr, "%s\n", stripped_buffer);
}

/*
 * Write a number to log file.
 */
void log_number(int num)
{
	fprintf(stderr, "%d", num);
}

/**
 * Writes the name, db number, and flags of an object to the log.
 * If the object does not own itself, append the name, db number, and flags
 * of the owner.
 */
void log_name(dbref target)
{
	char *tp;

	if((mudconf.log_info & LOGOPT_FLAGS) != 0)
		tp = unparse_object((dbref) GOD, target, 0);
	else
		tp = unparse_object_numonly(target);
	fprintf(stderr, "%s", strip_ansi(tp));
	free_lbuf(tp);
	if(((mudconf.log_info & LOGOPT_OWNER) != 0) && (target != Owner(target))) {
		if((mudconf.log_info & LOGOPT_FLAGS) != 0)
			tp = unparse_object((dbref) GOD, Owner(target), 0);
		else
			tp = unparse_object_numonly(Owner(target));
		fprintf(stderr, "[%s]", strip_ansi(tp));
		free_lbuf(tp);
	}
	return;
}

/**
 * Log both the name and location of an object
 */
void log_name_and_loc(dbref player)
{
	log_name(player);
	if((mudconf.log_info & LOGOPT_LOC) && Has_location(player)) {
		log_text((char *) " in ");
		log_name(Location(player));
	}
	return;
}

/*
 * Returns the object type of specified object.
 */
char *OBJTYP(dbref thing)
{
	if(!Good_obj(thing)) {
		return (char *) "??OUT-OF-RANGE??";
	}
	switch (Typeof(thing)) {
	case TYPE_PLAYER:
		return (char *) "PLAYER";
	case TYPE_THING:
		return (char *) "THING";
	case TYPE_ROOM:
		return (char *) "ROOM";
	case TYPE_EXIT:
		return (char *) "EXIT";
	case TYPE_GARBAGE:
		return (char *) "GARBAGE";
	default:
		return (char *) "??ILLEGAL??";
	}
}

void log_type_and_name(dbref thing)
{
	char nbuf[16];

	log_text(OBJTYP(thing));
	sprintf(nbuf, " #%d(", thing);
	log_text(nbuf);
	if(Good_obj(thing))
		log_text(Name(thing));
	log_text((char *) ")");
	return;
}

void log_type_and_num(dbref thing)
{
	char nbuf[16];

	log_text(OBJTYP(thing));
	sprintf(nbuf, " #%d", thing);
	log_text(nbuf);
	return;
}

#ifdef ARBITRARY_LOGFILES
int log_to_file(dbref thing, const char *logfile, const char *message)
{
	char pathname[210];			/* Arbitrary limit in logfile length */
	char message_buffer[4096];

	if(!message || !*message)
		return 1;				/* Nothing to do */

	if(!logfile || !*logfile || strlen(logfile) > 200)
		return 0;				/* invalid logfile name */

	if(strstr(pathname, "..") != NULL)
		return 0;
	if(strstr(pathname, "/") != NULL)
		return 0;
	snprintf(pathname, 210, "logs/%s", logfile);

	/* Hacking checks. */

	if(access(pathname, R_OK | W_OK) != 0)
		return 0;

	snprintf(message_buffer, 4096, "%s\n", message);

	if(!logcache_writelog(pathname, message_buffer)) {
		notify(thing, "Serious failure while trying to write to log.");
		return 0;
	}
	return 1;
}

void do_log(dbref player, dbref cause, int key, char *logfile, char *message)
{
	if(!message || !*message) {
		notify(player, "Nothing to log!");
		return;
	}

	if(!logfile || !*logfile) {
		notify(player, "Invalid logfile.");
		return;
	}

	if(!log_to_file(player, logfile, message)) {
		notify(player, "Request failed.");
		return;
	}

	notify(player, "Message logged.");
}
#endif