#include <stdio.h>
#include <descrip.h>
#include <starlet.h>
#include "bboard.h"

/* #define some command counters */

#define SHUT 1
#define RELO 2
#define RESE 3
#define WRIT 4
#define SUSP 5
#define RESU 6
#define STAT 7
#define DISP 8
#define HELP 9

/* Structure of the commands that we can execute */

static struct command cmds[] = {
    { "SHUTDOWN", 4, TRUE,  SHUT },
    { "RELOAD",   3, TRUE,  RELO },
    { "RESET",    5, TRUE,  RESE },
    { "WRITE",    3, TRUE,  WRIT },
    { "SUSPEND",  4, TRUE,  SUSP },
    { "RESUME",   4, TRUE,  RESU },
    { "STATUS",   1, FALSE, STAT },
    { "DISPLAY",  1, FALSE, DISP },
    { "HELP",     4, FALSE, HELP },
    { "?",        1, FALSE, HELP },
    { NULL,	  0, FALSE, 0 }
};

static void do_command(char * node, char * user, int cmd, char * parm);

/* We've received a message, so let's do something with it */

void use_msg(char * node, char * user, char * msg)
{
    struct command * cur;		/* Which command is it? */
    char t_cmd[21];			/* Buffer for the command */
    int len;				/* Length of the command that we got? */

    /* Ignore commands that start with '*' - it's from a process */

    if (msg[0] == '*') {                /* Ignore commands with '*' */
	return;
    }

    /* Let's copy the first word over, unless we get ridiculous */

    for (len = 0; msg[len] != ' ' && msg[len] && len < 20; len++) {
	t_cmd[len] = msg[len];
    }

    /* Terminate the string */

    t_cmd[len] = '\0';

    /* Now let's see if we got a match anywhere */

    for (cur = cmds; cur->name; cur++) {
	if (strncmp(t_cmd, cur->name, len)) {
	    continue;
	}

	/* Do we have a minimum length match? */

	if (len < cur->min_len) {
	    continue;
	}

	/* We have a winner! */

#ifdef DEBUG
	printf("use_msg: Found command %s\n", cur->name);
#endif

	break;
    }

    /* If we ran off the end of the command list, it's invalid */

    if (!cur->name) {
	sprintf(temp, "Invalid command: '%s'.", t_cmd);
	send_msg(node, user, temp);
	send_msg(node, user, "Send 'HELP' for further information.");
	return;
    }

    /* If it's a privileged command and you're not, it's not going to happen */

    if (cur->privileged && !valid_manager(node, user)) {
	sprintf(temp, "Restricted command: '%s'.", cur->name);
	send_msg(node, user, temp);
	return;
    }

    /* So, do something useful with this */

    do_command(node, user, cur->cmd_value, msg+len);
}

/* We've received a valid command from someone who's allowed to tell us */

static void do_command(char * node, char * user, int cmd, char * parm)
{
    static char time_str[24];		/* For when we started */
    static struct dsc$descriptor_s time_buf =
	{ 23, DSC$K_DTYPE_T, DSC$K_CLASS_S, &time_str };
    int time_len;			/* How long is returned string? */
    char * bad_link;			/* Which link isn't inactive yet */

    switch (cmd) {			/* Use the command number */

    /* Shutdown request */
	case SHUT:

	    /* Check if we're allowed to (do we have anything to post, and */
	    /*	we're not allowed to). */

	    if (postings_suspended && new_count) {
		strcpy(temp, "I Posting suspended with outstanding entries");
		send_msg(node, user, "SHUTDOWN command not accepted");
		send_msg(node, user, temp+2);
		send_log_file(temp);
	    }

	    /* Now see if everything is down that should be */

#ifdef DEBUG
	    printf("do_command: shutdown: checking links\n");
#endif

	    bad_link = check_links_down();

	    /* Did it work? */

	    if (bad_link) {
		sprintf(temp, "Link '%s' is not inactive.", bad_link);
		send_msg(node, user, "SHUTDOWN command not accepted");
		send_msg(node, user, temp);
		break;
	    }

	    /* We're ready to run away. Tell them that it worked */

	    send_msg(node, user, "SHUTDOWN command accepted.");

	    /* And set the flag */

	    shutdown_state = TRUE;
	    break;

    /* Reload rules file */
	case RELO:

	    /* We heard you... */

	    send_msg(node, user, "RELOAD command accepted.");

	    /* We'll do it and let you know if it worked */

	    if (read_control_file(TRUE, node, user)) {
		send_msg(node, user, "Rules reload complete.");
		send_log_file("I Rules reloaded.");
	    }

	    break;

    /* Reset the closing date on a conference */
	case RESE:

	    /* Just call someone else to do it all */

	    reset_log_file_entry(parm, node, user);

	    break;

    /* Write all unprocessed messages to Notes */
	case WRIT:

	    /* If we're SUSPENDed, don't even think about it. We're */
	    /*	SUSPENDed for a reason, let's keep it that way. */

	    if (postings_suspended) {
		send_msg(node, user, 
			"Postings SUSPENDed. WRITE command rejected.");
		break;
	    }

	    /* This will force it through normal channels */

	    if (new_count) {
		new_count = -1;
		send_msg(node, user, "WRITE command accepted.");
		send_log_file("I WRITE forced for unposted entries.");
	    } else {
		send_msg(node, user,
			"WRITE command ignored. No unposted entries");
	    }

	    break;

    /* Suspend BBoard's ability to post to Notes */
	case SUSP:

	    /* Send the message first */

	    sprintf(temp, "Postings are %ssuspended", (postings_suspended ?
		    "already " : ""));
	    send_msg(node, user, temp);

	    /* Now log it, if needed */

	    if (!postings_suspended) {
		send_log_file("I Posting SUSPENDed");
	    }

	    /* Just set the flag */

	    postings_suspended = TRUE;
	    break;

    /* Resume posting after a suspension */
	case RESU:

	    /* Send message first */

	    sprintf(temp, "Postings are %senabled", (postings_suspended ?
		    "" : "already "));
	    send_msg(node, user, temp);

	    /* Now log the event */

	    if (postings_suspended) {
		send_log_file("I Posting RESUMEd");
	    }

	    /* Now just set the flag */

	    postings_suspended = FALSE;

	    /* If something was waiting, make sure it goes out immediately */

	    if (new_count) {
		new_count = -1;
	    }
	    break;

    /* Status message */
	case STAT:

	    /* Format the time that we started */

	    sys$asctim(&time_len, &time_buf, bboard_start, 0);

	    /* Chop off the trailing hundredths of a second (silly) */

	    time_str[20] = '\0';

	    /* Format it for outgoing */

	    sprintf(temp, "BBOARD %s, %s, VMS %s", version,
		get_jnet_ver(), get_vms_ver());
	    sprintf(temp+128, "Started at %s, Entries since restart: %d",
		time_str, mail_received);
	    sprintf(temp+256, "Unposted entries: %d, Posting state: %s", 
		(new_count >= 0 ? new_count : 0), (postings_suspended ?
		"SUSPENDED" : "NORMAL"));

#ifdef	DEBUG
#if (DEBUG & 1)
	    sprintf(temp+384,"Debugging: FULL");
#else
	    sprintf(temp+384,"Debugging: ON");
#endif	/* (DEBUG & 1) */
#else
	    sprintf(temp+384,"Debugging: OFF");
#endif	/* DEBUG */

	    /* And bop it out there */

	    send_msg(node, user, temp);
	    send_msg(node, user, temp+128);
	    send_msg(node, user, temp+256);
	    send_msg(node, user, temp+384);

	    break;

    /* Display the status of a conference */
	case DISP:

	    /* Just call someone else to take care of it */

	    display_log_file_entry(parm, node, user);

	    break;

    /* Send something useful if someone asks */
	case HELP:

	    /* Ok. Now start spitting... */

	    send_msg(node, user,
		"You have reached the BBoard VAX Notes Posting Facility.");
	    send_msg(node, user,
		"This facility is for local VAX Notes users to read BITNET-");
	    send_msg(node, user,
		"or Internet-distributed LISTs.");

	    if (local_contact.dsc$w_length) {
		send_msg(node, user,
		"For further information, contact either TERRY@SPCVXA.BITNET");
		sprintf(temp, "or %s@%s.BITNET for local information.",
			local_contact.dsc$a_pointer, host);
		send_msg(node, user, temp);
	    } else {
		send_msg(node, user,
		"For further information, contact TERRY@SPCVXA.BITNET");
	    }
	    break;
    }
}
