/*
 * tnmSyslog.c --
 *
 *	A command to access the system logging facility. This
 *	implementation is supposed to be thread-safe.
 *
 * Copyright (c) 1993-1996 Technical University of Braunschweig.
 * Copyright (c) 1996-1997 University of Twente.
 * Copyright (c) 1997-1999 Technical University of Braunschweig.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tnmInt.h"
#include "tnmPort.h"

TnmTable tnmLogTable[] = {
    { TNM_LOG_EMERG,	"emergency" },
    { TNM_LOG_ALERT,	"alert" },
    { TNM_LOG_CRIT,	"critical" },
    { TNM_LOG_ERR,	"error" },
    { TNM_LOG_WARNING,	"warning" },
    { TNM_LOG_NOTICE,	"notice" },
    { TNM_LOG_INFO,	"info" },
    { TNM_LOG_DEBUG,	"debug" },
    { 0, NULL }
};

/*
 * Every Tcl interpreter has an associated DnsControl record. It
 * keeps track of the default settings for this interpreter.
 */

static char tnmSyslogControl[] = "tnmSyslogControl";

typedef struct SyslogControl {
    char *ident;		/* Identification of the event source. */
} SyslogControl;

/*
 * The options for the syslog command.
 */

enum options { optIdent };

static TnmTable syslogOptionTable[] = {
    { optIdent,		"-ident" },
    { 0, NULL }
};

/*
 * Forward declarations for procedures defined later in this file:
 */

static void
AssocDeleteProc	_ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp));


/*
 *----------------------------------------------------------------------
 *
 * AssocDeleteProc --
 *
 *	This procedure is called when a Tcl interpreter gets destroyed
 *	so that we can clean up the data associated with this interpreter.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static void
AssocDeleteProc(clientData, interp)
    ClientData clientData;
    Tcl_Interp *interp;
{
    SyslogControl *control = (SyslogControl *) clientData;

    if (control) {
	if (control->ident) {
	    ckfree(control->ident);
	}
	ckfree((char *) control);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tnm_SyslogObjCmd --
 *
 *	This procedure is invoked to process the "syslog" command.
 *	See the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

int
Tnm_SyslogObjCmd(clientData, interp, objc, objv)
    ClientData clientData;
    Tcl_Interp *interp;
    int objc;
    Tcl_Obj *CONST objv[];
{
    int x, level, code;
    char *ident = NULL;

    SyslogControl *control = (SyslogControl *)
	Tcl_GetAssocData(interp, tnmSyslogControl, NULL);

    if (! control) {
	control = (SyslogControl *) ckalloc(sizeof(SyslogControl));
	control->ident = ckstrdup("scotty");
	Tcl_SetAssocData(interp, tnmSyslogControl, AssocDeleteProc, 
			 (ClientData) control);
    }

    if (objc < 2) {
    wrongArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "?-ident string? level message");
	return TCL_ERROR;
    }

    for (x = 1; x < objc; x++) {
	code = TnmGetTableKeyFromObj(interp, syslogOptionTable,
				     objv[x], "option");
	if (code == -1) {
	    char *option = Tcl_GetStringFromObj(objv[x], NULL);
	    if (*option == '-') {
		return TCL_ERROR;
	    } else {
		Tcl_ResetResult(interp);
		break;
	    }
	}
	switch ((enum options) code) {
	case optIdent:
	    if (x == objc-1) {
		Tcl_SetResult(interp, control->ident, TCL_STATIC);
		return TCL_OK;
	    }
	    ident = Tcl_GetStringFromObj(objv[++x], NULL);
	}
    }

    if (x == objc) {
	if (ident) {
	    if (control->ident) {
		ckfree(control->ident);
	    }
	    control->ident = ckstrdup(ident);
	}
	return TCL_OK;
    }

    if (x != objc-2) {
	goto wrongArgs;
    }

    if (! ident) {
	ident = control->ident;
    }

    level = TnmGetTableKeyFromObj(interp, tnmLogTable, objv[x], "level");
    if (level < 0) {
	return TCL_ERROR;
    }

    code = TnmWriteLogMessage(ident, level,
			      Tcl_GetStringFromObj(objv[++x], NULL));
    if (code != 0) {
	Tcl_SetResult(interp, "error while accessing system logging facility",
		      TCL_STATIC);
	return TCL_ERROR;
    }

    return TCL_OK;
}
