/*
 * LOG.C
 *
 */

#include "defs.h"

Prototype void OpenLog(const char *ident, int option);
Prototype void CloseLog(LogInfo *LI, int killit);
Prototype void Log(LogInfo *LI, int priority, const char *ctl, ...);
Prototype void VLog(LogInfo *LI, int priority, const char *ctl, va_list va);
Prototype void logit(int priority, const char *ctl, ...);
Prototype void vlogit(int priority, const char *ctl, va_list va);
Prototype void LogIncoming(const char *format, char *label, const char *msgid, char *err);
Prototype void CloseIncomingLog(void);
Prototype void WritePath(char *path);
Prototype void ClosePathLog(int killit);
Prototype void WriteArtLog(char *path, int size, char *arttype, char *nglist);
Prototype void CloseArtLog(int killit);

static LogInfo GeneralLog = { &GeneralLogPat, NULL, NULL, 0, 0, 0, 0, 0, {0} };
static LogInfo IncomingLog = { &IncomingLogPat, NULL, NULL, 0, 0, 0, 0, 0, {0} };
static LogInfo PathLog = { &FPathLogPat, NULL, NULL, 0, 0, 0, 0, 0, {0} };
static LogInfo ArtLog = { &FArtLogPat, NULL, NULL, 0, 0, 0, 0, 0, {0} };

#if USE_INTERNAL_VSYSLOG
void
vsyslog(int priority, const char *ctl, va_list va) 
{
    char buf[1024];

    vsnprintf(buf, sizeof(buf), ctl, va);
    syslog(priority, "%s", buf);
}
#endif

void
openProg(LogInfo *LI, const char *prog)
{
    int fds[2];

    if (pipe(fds) < 0) {
	logit(LOG_ERR, "log unable to pipe(): %s", strerror(errno));
	return;
    }
    if ((LI->Pid = fork()) < 0) {
	logit(LOG_ERR, "log unable to fork(): %s", strerror(errno));
	close(fds[0]);
	close(fds[1]);
	return;
    }
    if (!LI->Pid) {
	if (dup2(fds[0], fileno(stdin)) < 0) {
	    logit(LOG_ERR, "log unable to dup2(): %s", strerror(errno));
	    close(fds[0]);
	    close(fds[1]);
	    return;
	}
	close(fds[0]);
	close(fds[1]);
	execl(prog, prog, NULL);
	logit(LOG_ERR, "log unable to execl(%s): %s", prog, strerror(errno));
	close(fileno(stdin));
	_exit(1);
    }
    /*
     * Only parent should reach here
     */
    close(fds[0]);
    if (fcntl(fds[1], F_SETFD, 1) < 0)
	logit(LOG_ERR, "log unable to fcntl(): %s", strerror(errno));
    LI->Fd = fdopen(fds[1], "a");
}

void
openLog(LogInfo *LI)
{
    struct stat st;
    const char *Fname;

    if ((!LI->Fd && !LI->UseSyslog && !LI->Disabled) ||
    		(time(NULL) > LI->NextCheck)) {
	LI->NextCheck = time(NULL) + 10;
	if (strcmp(*LI->Pat, "SYSLOG") == 0) {
	    /*
	     * I'm sure this seemed like a good idea at the time, but
	     * this is really and truly broken.  dreaderd ends up calling
	     * closelog() all the time because of the way this was hacked
	     * in to things.  Combined with some changes made to FreeBSD
	     * in the late rev. 4's, some weird stuff starts happening
	     * and so I've commented this out.  JG20031020
	     */
	    /*CloseLog(LI, 1);*/
	    LI->UseSyslog = 1;
	} else if (strcmp(*LI->Pat, "NONE") == 0) {
	    CloseLog(LI, 1);
	    LI->Disabled = 1;
	} else if (**LI->Pat == '|') {
	    Fname = PatLogExpand(*LI->Pat);
	    if (LI->Fd == NULL || strcmp(Fname, LI->Fname) != 0) {
		CloseLog(LI, 1);
		strncpy(LI->Fname, Fname, sizeof(LI->Fname) - 1);
		LI->Fname[sizeof(LI->Fname) - 1] = '\0';
		openProg(LI, Fname + 1);
	    }
	} else {
	    Fname = PatLogExpand(*LI->Pat);
	    if (stat(Fname, &st) != 0)
		LI->LastInode = 0;
	    if (!LI->Fd || !LI->LastInode || (LI->LastInode != st.st_ino)) {
		/* Need to reopen the log file */
		CloseLog(LI, 1);
		LI->Fd = fopen(Fname, "a");
		if (LI->Fd == NULL) {
		    fprintf(stderr, "Unable to open log file: %s\n", Fname);
		    logit(LOG_ERR, "Unable to open log file: %s\n", Fname);
	            LI->UseSyslog = 1;
		} else {
		    if (stat(Fname, &st) == 0)
			LI->LastInode = st.st_ino;
		    strncpy(LI->Fname, Fname, sizeof(LI->Fname) - 1);
		    LI->Fname[sizeof(LI->Fname) - 1] = '\0';
		}
	    }
	}
    }

}

void
OpenLog(const char *ident, int option)
{
    GeneralLog.Ident = ident;
    openlog(ident, option, LOG_NEWS);
}

void
Log(LogInfo *LI, int priority, const char *ctl, ...)
{
    va_list va;

    va_start(va, ctl);
    VLog(LI, priority, ctl, va);
    va_end(va);
}

void
VLog(LogInfo *LI, int priority, const char *ctl, va_list va)
{
    /* check & (re)open the log if neccessary */
    openLog(LI);

    /* print message itself */
    if (LI->UseSyslog) {
	vsyslog(priority, ctl, va);
    } else if (LI->Disabled || (priority == LOG_DEBUG && !DebugOpt)) {
	/* Do nothing. */
    } else {
	static char logLine[8192];
	char *p = logLine;

	/* Add date and time. Syslog has its own time stamps. */
	p += sprintf(logLine, "%s %s%s ", LogTime(),
				LI->Ident ? LI->Ident : "",
				LI->Ident ? ":" : "");
	vsnprintf(p, sizeof(logLine) - (p - logLine) - 1, ctl, va);
	fprintf(LI->Fd, "%s\n", logLine);
	fflush(LI->Fd);
    }
}

void
CloseLog(LogInfo *LI, int killit)
{
    if (LI == NULL)
	LI = &GeneralLog;
    if (LI->UseSyslog)
	closelog();
    if (LI->Fd != NULL) {
	if (LI->Pid > 0 && killit) {
	    kill(LI->Pid, SIGINT);
	    LI->Pid = -1;
	}
	fclose(LI->Fd);
	LI->Fd = NULL;
	LI->LastInode = 0;
    }
}

void
logit(int priority, const char *ctl, ...)
{
    va_list va;

    va_start(va, ctl);
    vlogit(priority, ctl, va);
    va_end(va);
}

void
vlogit(int priority, const char *ctl, va_list va)
{
    VLog(&GeneralLog, priority, ctl, va);
}

void
LogIncoming(const char *format, char *label, const char *msgid, char *err)
{
    Log(&IncomingLog, LOG_INFO, format, label, msgid, err);
}

void
CloseIncomingLog(void)
{
    CloseLog(&IncomingLog, 1);
}

void
WritePath(char *path)
{
    openLog(&PathLog);

    /* print message itself */
    if (PathLog.Fd != NULL) {
	if (fprintf(PathLog.Fd, "Path: %s\n", path) == 0)
	    ClosePathLog(1);
	else
	    fflush(PathLog.Fd);
    }
}

void
ClosePathLog(int killit)
{
    CloseLog(&PathLog, killit);
}

void
WriteArtLog(char *path, int size, char *arttype, char *nglist)
{
    char host[255];
    char *p;

    openLog(&ArtLog);

    if ((p = strchr(path, '!')) != NULL && p - path < sizeof(host)) {
	int n = p - path;
	if (n >= sizeof(host))
	    n = sizeof(host) - 1;
	strncpy(host, path, n);
	host[n] = '\0';
    } else {
	strncpy(host, path, sizeof(host) - 1);
	host[sizeof(host) - 1] = '\0';
    }
    /* print message itself */
    if (ArtLog.Fd != NULL) {
	if (fprintf(ArtLog.Fd, "%s %d %s %s\n", host, size, arttype, nglist) == 0)
	    CloseArtLog(1);
	else
	    fflush(ArtLog.Fd);
    }
}

void
CloseArtLog(int killit)
{
    CloseLog(&ArtLog, killit);
}



syntax highlighted by Code2HTML, v. 0.9.1