/* Change History:

T1.00 31-Jul-1989	BMC
    Initial version
    Includes writing notes, unknown message handling, note_log_file parsing,
	and some other strange and wonderous stuff.

T1.10 06-Aug-1989	BMC
    Split USEFILE.C into USEFILE.C and RULES.C to further isolate Rules
	processing.
    Split BBSUPP.C into BBSUPP.C and HOOKS.C to isolate link trapping.
    Add :manager, :ignore and :links.
    Support messages (RELOAD, SHUTDOWN, and STATUS).
    Add SHUTDOWN processing, checking for down links first.
    Rewrite loading control files for future (and current) enhancement.

T1.20 12-Aug-1989	BMC
    Remove 'xx' rule and replace with logical BBOARD_ERROR_CONF.
    Remove '*' as comment character from control file for wildcarding purposes.
    Multiple line message header fields should have a " " added between lines.
    Expand tab characters when reading from files.
    Rewrite entire control rules handling for dynamic allocation.
    Investigate the new control file before reloading. Don't if it's not going
	to fly.
    Log all startup, shutdown, and initial error messages to OPCOM.
    Use BECOME when writing the notes to support "reply/author".

T1.22 21-Aug-1989	BMC
    Split Note-log-file handling from USEFILE.C into NOTELOG.C.
    Change format of Note-log-file for better calculation and to allow
	inclusion of last posting date.
    Add RESET command to zap a conference close date back to the stone age
    Add DISPLAY command to see close and last posting date of wildcarded
	conferences.
    Add #ifdef DEBUG code for future use

T1.30 16-Sep-1989	BMC
    Add digest support
    Move actual note addition into a detached run. Add note count and timer
	information to control how often notes are added.
    Add WRITE command to force immediate note addition.
    Process messages while we're running through a digest.
    Sort NOTELOG file whenever there are any additions.

T1.31 20-Sep-1989	BMC
    Use SETUNAME, not BECOME
    Support multiple length separators in digests.
    Change informative log messages to start with 'I'.
    Change interactive command log messages to start with 'C'.

V1.32 05-Oct-1989	BMC
    Minor cleanup for real release.

V1.33 20-Oct-1989	BMC
    Maintain conference posted to for the log file (SMTPUSER mixup).
    Show destination conference in log file.
    Don't delete Jnet file until _after_ we've built info to post the entry.
    Add flag_user_exit in jnet_file_header for later development.

T1.34 08-Dec-1989	BMC
    Minor change to digests. The topic and the replies should be written at
	the same time.
    Check on com_write_notes() that there aren't any other posting jobs
	running. If there are, defer execution. This will prevent umpteen-
	billion posting jobs running simultaneously if a link restarts after
	being down for a while.
    Add type "C" for digests.

V1.40 02-Feb-1990	BMC
    Consolidate doing things to From: and Subj: text (individually).
    If Subject text starts with a '$', prepend a space to keep DCL happy.
    If From text doesn't have any of "<> ", throw "<>" around the text so
	that the Notes support stuff can do (potentially) useful stuff with it.
    Remove table_name as an internal logical. It belongs in bbsupp.c and now
	resides there.
    Restructure rules (one more time). Move some of the logicals into the rules
	file as "singular" lines. Additionally, move all defaults into
	bboard.h.
    Add a "HELP" command so we don't keep having BBOARD bothered by people.
    Move logical names into bboard.h so so that, if TEST is defined, we can
	change the names for testing, separate from DEBUG output.
    Move digest definitions into new Control File section :digests. This lets
	digest definitions be added on the fly.

V1.41 24-Feb-1990	BMC
    Add SUSPend and RESUme commands to integrate well with purging Notes
	conferences.

V1.42 23-Jul-1992	TMK
    Make changes to work with Jnet X3.6 (can't log until hook is installed),
	assorted cleanups.

V1.43 19-Jun-1993	TMK
    Add additional debugging output in hooks.c, fix crash in rules.c if full
	debugging is requested and no digests are configured, add DEBUG info
	to STATUS command.

V1.44 28-Jan-1994	TMK
    DEC broke served access from the local node in DEC Notes V2.5. Add an ex-
	plicit 0:: in front of the conference name to work around this.

*/

#include <descrip.h>
#include <ssdef.h>
#include <stdio.h>
#include <stdlib.h>
#include <starlet.h>
#include <psldef.h>
#include "bboard.h"

/* Functions declared later, for prototyping purposes */

static void do_logicals(void);
static void timer_check(void);
static void process_file(void);

/* Global variables, please... */

char * version = "V1.44 28-Jan-94";
unsigned int mail_received = 0;
char host[9];
SYSTIM bboard_start;
unsigned int new_count = 0;
int postings_suspended = FALSE;
int shutdown_state = FALSE;
int log_available = FALSE;

struct dsc$descriptor hook_name;
static char * bboard_hook_name_log = LOG_HOOK_NAME;
static char * bboard_hook_name;

struct dsc$descriptor root_dir;
static char * bboard_root_dir_log = LOG_ROOT_DIR;
static char * bboard_root_dir;

struct dsc$descriptor scratch_dir;
static char * bboard_scratch_dir_log = LOG_SCRATCH_DIR;
static char * bboard_scratch_dir;

struct dsc$descriptor control_file;
static char * bboard_control_file_log = LOG_CONTROL_FILE;
static char * bboard_control_file;

struct dsc$descriptor log_file;
struct dsc$descriptor error_conf;
SYSTIM bboard_time_interval;
unsigned int bboard_count_interval;
struct dsc$descriptor local_contact;

/* These aren't really global, I just don't want to define them all over... */

int mode;				/* Used by Jnet routines */
int status;				/* SYS$, etc. status returns */
char temp[512]; 			/* Temporary string space */

/* Where the whole kit and caboodle starts... */

int main(void)
{

    /* Set up the hardcoded defaults for all the possible logicals */

    str_desc(&hook_name, DEF_HOOK_NAME);
    str_desc(&root_dir, DEF_ROOT_DIR);
    str_desc(&scratch_dir, DEF_SCRATCH_DIR);
    str_desc(&control_file, DEF_CONTROL_FILE);

    /* Load the logicals */

    do_logicals();

#ifdef DEBUG
    printf("main: logicals loaded\n");
#endif

    /* Are we the first ones to try for this hook name? */

    if (check_for_hook(hook_name.dsc$a_pointer)) {
	sprintf(temp, "F A duplicate hook name of '%s' currently exists.",
		hook_name.dsc$a_pointer);
	critical_error(temp);
    };

    /* What's the local host name? */

    load_host_name(host);

    /* When are we actually starting the hook (for STATUS commands) */

    get_time(bboard_start);		/* Save that for use later */

    /* Set up the timer */

    timer_reset();

    /* Ok. Let's tell Jnet we're lurking about */

    mode = 2;
    if (!jan_hook_init(&mode, &hook_name)) {
	return(0);
    }

    /* Tell Jnet to update number of files queued for our hook */

    jan_adjust(&hook_name);

    /* Indicate that we can begin logging */

    log_available = TRUE;

#ifdef DEBUG
    printf("main: hook installed and adjusted\n");
#endif

    /* Put a new startup entry to the log file and OPCOM */

    init_log_file();			/* start up a new one */

    /* Read from the control file, as an initial read */

    read_control_file(FALSE, NULL, NULL);

#ifdef DEBUG
    printf("main: control file loaded\n");
#if (DEBUG & 1)
    dump_control_file();
#endif
#endif

    /* Now to the meat of everything... */

    while (TRUE) {
	sys$setast(TRUE);		/* Allow ASTs while waiting */
#ifdef DEBUG
	printf("main: going to sleep\n");
#endif
	sys$hiber();			/* Sleep until something interesting */
	sys$setast(FALSE);		/* Don't wake up while we're running */
#ifdef DEBUG
	printf("main: woke up\n");
#endif
	process_message();		/* Messages, maybe? */
	process_file(); 		/* Files, maybe? */
	if (new_count < 0 || new_count >= bboard_count_interval) {
	    com_write_notes();
	}
	if (shutdown_state) {		/* Asked to leave, maybe? */
	    if (new_count) {		/* Anything? Do it. */
		com_write_notes();
	    }
	    sprintf(temp, "I BBOARD (%s) shutting down.", version);
	    send_log_file(temp);
	    send_opcom(temp+2);
	    return(SS$_NORMAL);
	}
    };
}

/* Build all of our interesting logicals */

static void do_logicals(void)
{
    unsigned int t_cnt;

    /* Who are we, first off... */

    bboard_hook_name = log_tran(bboard_hook_name_log);
    if (bboard_hook_name) {
	str_desc(&hook_name, bboard_hook_name);
    };

    /* Where is our NOTES$NOTEBOOK.NOTE hiding? */

    bboard_root_dir = log_tran(bboard_root_dir_log);
    if (bboard_root_dir) {
	str_desc(&root_dir, bboard_root_dir);
    };

    /* Ok. Where do things go while we're playing with them? */

    bboard_scratch_dir = log_tran(bboard_scratch_dir_log);
    if (bboard_scratch_dir) {
	str_desc(&scratch_dir, bboard_scratch_dir);
    };

    /* And where's all of the interesting information hiding? */

    bboard_control_file = log_tran(bboard_control_file_log);
    if (bboard_control_file) {
	str_desc(&control_file, bboard_control_file);
    }
}

/* We've been kicked by the AST */

static void timer_check(void)
{
    if (new_count > 0) {
	com_write_notes();
    } else {
	timer_reset();
    }
}

/* Actually setup the AST timer */

void timer_reset(void)
{
    sys$cantim(1, PSL$C_USER);
    sys$setimr(0, bboard_time_interval, timer_check, 1);
}

/* Get the file and begin doing something with it */

static void process_file(void)
{
    struct jnet_file_header fin;

    while (rou_if_file() & 1) { 	/* Is the next thing a file? */

	process_message();		/* Check if got an interactive msg */

#ifdef DEBUG
	printf("process_file: About to receive a file\n");
#endif
	status = receive_file(&fin);	/* Try receiving it */
	if (!(status & 1)) {		/* That didn't work */
	    report_error("Receive file failed", status);
	}
	use_file(&fin); 		/* And now do something with it */

	sprintf(temp, "F %s %s  %s %s %s", fin.host, fin.user, fin.filename,
		fin.filetype, fin.conf_name);
#ifdef DEBUG
	printf("process_file: Received: %s\n", temp+2);
#endif
	send_log_file(temp);		/* Report that we got the file */
    }
}

/* Get a message and process the interactive command */

void process_message(void)
{
    char node[10];
    char user[10];
    char msg[260];

    while (rou_if_msg() & 1) {		/* Is the next thing a message */
#ifdef DEBUG
	printf("process_message: About to receive a message\n");
#endif
	receive_message(node, user, msg);   /* Get it and who sent it */

	if (user[0] == '\0' || user[0] == ' ') {    /* Is this for real? */
	    continue;
	}
	if (ignore_msgs(node, user)) {	/* Should we pay attention to this */
	    continue;
	}
	use_msg(node, user, msg);	/* And do somthing with the command */
    }
}
