/*----------------------------------------------------------------------------*/
/* Hobbit backend script for disabling/enabling tests.                        */
/*                                                                            */
/* Copyright (C) 2003-2006 Henrik Storner <henrik@storner.dk>                 */
/*                                                                            */
/* This program is released under the GNU General Public License (GPL),       */
/* version 2. See the file "COPYING" for details.                             */
/*                                                                            */
/*----------------------------------------------------------------------------*/

static char rcsid[] = "$Id: hobbit-enadis.c,v 1.24 2006/07/20 16:06:41 henrik Rel $";

#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>

#include "libbbgen.h"

enum { ACT_NONE, ACT_FILTER, ACT_ENABLE, ACT_DISABLE, ACT_SCHED_DISABLE, ACT_SCHED_CANCEL } action = ACT_NONE;
int hostcount = 0;
char **hostnames  = NULL;
int disablecount = 0;
char **disabletest = NULL;
int enablecount = 0;
char **enabletest = NULL;
int duration = 0;
int scale = 1;
char *disablemsg = "No reason given";
time_t schedtime = 0;
int cancelid = 0;
int preview = 0;

char *hostpattern = NULL;
char *pagepattern = NULL;
char *ippattern = NULL;

void errormsg(char *msg)
{
        printf("Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
        printf("<html><head><title>Invalid request</title></head>\n");
        printf("<body>%s</body></html>\n", msg);
        exit(1);
}

void parse_cgi(void)
{
	cgidata_t *postdata, *pwalk;
	struct tm schedtm;

	memset(&schedtm, 0, sizeof(schedtm));
	postdata = cgi_request();
	if (cgi_method == CGI_GET) return;

	if (!postdata) {
		errormsg(cgi_error());
	}

	pwalk = postdata;
	while (pwalk) {
		/*
		 * When handling the "go", the "Disable now" and "Schedule disable"
		 * radio buttons mess things up. So ignore the "go" if we have seen a
		 * "filter" request already.
		 */
		if ((strcmp(pwalk->name, "go") == 0) && (action != ACT_FILTER)) {
			if      (strcasecmp(pwalk->value, "enable") == 0)           action = ACT_ENABLE;
			else if (strcasecmp(pwalk->value, "disable now") == 0)      action = ACT_DISABLE;
			else if (strcasecmp(pwalk->value, "schedule disable") == 0) action = ACT_SCHED_DISABLE;
			else if (strcasecmp(pwalk->value, "cancel") == 0)           action = ACT_SCHED_CANCEL;
			else if (strcasecmp(pwalk->value, "apply filters") == 0)    action = ACT_FILTER;
		}
		else if (strcmp(pwalk->name, "duration") == 0) {
			duration = atoi(pwalk->value);
		}
		else if (strcmp(pwalk->name, "untilok") == 0) {
			if (strcasecmp(pwalk->value, "on") == 0) {
				duration = -1;
				scale = 1;
			}
		}
		else if (strcmp(pwalk->name, "scale") == 0) {
			scale = atoi(pwalk->value);
		}
		else if (strcmp(pwalk->name, "cause") == 0) {
			disablemsg = strdup(pwalk->value);
		}
		else if (strcmp(pwalk->name, "hostname") == 0) {
			if (hostnames == NULL) {
				hostnames = (char **)malloc(2 * sizeof(char *));
				hostnames[0] = strdup(pwalk->value);
				hostnames[1] = NULL;
				hostcount = 1;
			}
			else {
				hostnames = (char **)realloc(hostnames, (hostcount + 2) * sizeof(char *));
				hostnames[hostcount] = strdup(pwalk->value);
				hostnames[hostcount+1] = NULL;
				hostcount++;
			}
		}
		else if (strcmp(pwalk->name, "enabletest") == 0) {
			char *val = pwalk->value;

			if (strcmp(val, "ALL") == 0) val = "*";

			if (enabletest == NULL) {
				enabletest = (char **)malloc(2 * sizeof(char *));
				enabletest[0] = strdup(val);
				enabletest[1] = NULL;
				enablecount = 1;
			}
			else {
				enabletest = (char **)realloc(enabletest, (enablecount + 2) * sizeof(char *));
				enabletest[enablecount] = strdup(val);
				enabletest[enablecount+1] = NULL;
				enablecount++;
			}
		}
		else if (strcmp(pwalk->name, "disabletest") == 0) {
			char *val = pwalk->value;

			if (strcmp(val, "ALL") == 0) val = "*";

			if (disabletest == NULL) {
				disabletest = (char **)malloc(2 * sizeof(char *));
				disabletest[0] = strdup(val);
				disabletest[1] = NULL;
				disablecount = 1;
			}
			else {
				disabletest = (char **)realloc(disabletest, (disablecount + 2) * sizeof(char *));
				disabletest[disablecount] = strdup(val);
				disabletest[disablecount+1] = NULL;
				disablecount++;
			}
		}
		else if (strcmp(pwalk->name, "year") == 0) {
			schedtm.tm_year = atoi(pwalk->value) - 1900;
		}
		else if (strcmp(pwalk->name, "month") == 0) {
			schedtm.tm_mon = atoi(pwalk->value) - 1;
		}
		else if (strcmp(pwalk->name, "day") == 0) {
			schedtm.tm_mday = atoi(pwalk->value);
		}
		else if (strcmp(pwalk->name, "hour") == 0) {
			schedtm.tm_hour = atoi(pwalk->value);
		}
		else if (strcmp(pwalk->name, "minute") == 0) {
			schedtm.tm_min = atoi(pwalk->value);
		}
		else if (strcmp(pwalk->name, "canceljob") == 0) {
			cancelid = atoi(pwalk->value);
		}
		else if (strcmp(pwalk->name, "preview") == 0) {
			preview = (strcasecmp(pwalk->value, "on") == 0);
		}
		else if ((strcmp(pwalk->name, "hostpattern") == 0) && pwalk->value && strlen(pwalk->value)) {
			hostpattern = strdup(pwalk->value);
		}
		else if ((strcmp(pwalk->name, "pagepattern") == 0) && pwalk->value && strlen(pwalk->value)) {
			pagepattern = strdup(pwalk->value);
		}
		else if ((strcmp(pwalk->name, "ippattern") == 0)   && pwalk->value && strlen(pwalk->value)) {
			ippattern = strdup(pwalk->value);
		}

		pwalk = pwalk->next;
	}

	schedtm.tm_isdst = -1;
	schedtime = mktime(&schedtm);
}

void do_one_host(char *hostname, char *fullmsg, char *username)
{
	char hobbitcmd[4096];
	int i, result;

	switch (action) {
	  case ACT_ENABLE:
		for (i=0; (i < enablecount); i++) {
			if (preview) result = 0;
			else {
				sprintf(hobbitcmd, "enable %s.%s", commafy(hostname), enabletest[i]);
				result = sendmessage(hobbitcmd, NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
				sprintf(hobbitcmd, "notify %s.%s\nMonitoring of %s:%s has been ENABLED by %s\n", 
					commafy(hostname), enabletest[i], 
					hostname, enabletest[i], username);
				sendmessage(hobbitcmd, NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
			}

			if (preview) {
				printf("<tr><td>Enabling host <b>%s</b> test <b>%s</b> : %s</td></tr>\n", 
					hostname, enabletest[i], ((result == BB_OK) ? "OK" : "Failed"));
			}
		}
		break;

	  case ACT_DISABLE:
		for (i=0; (i < disablecount); i++) {
			if (preview) result = 0;
			else {
				sprintf(hobbitcmd, "disable %s.%s %d %s", 
					commafy(hostname), disabletest[i], duration*scale, fullmsg);
				result = sendmessage(hobbitcmd, NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
				sprintf(hobbitcmd, "notify %s.%s\nMonitoring of %s:%s has been DISABLED by %s for %d minutes\n%s", 
					commafy(hostname), disabletest[i], 
					hostname, disabletest[i], username, duration*scale, fullmsg);
				result = sendmessage(hobbitcmd, NULL, NULL, NULL, 0, BBTALK_TIMEOUT);
			}

			if (preview) {
				printf("<tr><td>Disabling host <b>%s</b> test <b>%s</b>: %s</td></tr>\n", 
					hostname, disabletest[i], ((result == BB_OK) ? "OK" : "Failed"));
			}
		}
		break;

	  case ACT_SCHED_DISABLE:
		for (i=0; (i < disablecount); i++) {
			sprintf(hobbitcmd, "schedule %d disable %s.%s %d %s", 
				(int) schedtime, commafy(hostname), disabletest[i], duration*scale, fullmsg);
			result = (preview ? 0 : sendmessage(hobbitcmd, NULL, NULL, NULL, 0, BBTALK_TIMEOUT));

			if (preview) {
				printf("<tr><td>Scheduling disable of host <b>%s</b> test <b>%s</b> at <b>%s</b>: %s</td></tr>\n", 
					hostname, disabletest[i], ctime(&schedtime), ((result == BB_OK) ? "OK" : "Failed"));
			}
		}
		break;

	  case ACT_SCHED_CANCEL:
		sprintf(hobbitcmd, "schedule cancel %d", cancelid);
		result = (preview ? 0 : sendmessage(hobbitcmd, NULL, NULL, NULL, 0, BBTALK_TIMEOUT));

		if (preview) {
			printf("<tr><td>Canceling job <b>%d</b> : %s</td></tr>\n", cancelid, ((result == BB_OK) ? "OK" : "Failed"));
		}
		break;

	  default:
		errprintf("No action\n");
		break;
	}
}

int main(int argc, char *argv[])
{
	int argi, i;
	char *username = getenv("REMOTE_USER");
	char *userhost = getenv("REMOTE_HOST");
	char *userip   = getenv("REMOTE_ADDR");
	char *fullmsg = "No cause specified";
	char *envarea = NULL;
	int  obeycookies = 1;

	if ((username == NULL) || (strlen(username) == 0)) username = "unknown";
	if ((userhost == NULL) || (strlen(userhost) == 0)) userhost = userip;
	
	for (argi=1; (argi < argc); argi++) {
		if (argnmatch(argv[argi], "--env=")) {
			char *p = strchr(argv[argi], '=');
			loadenv(p+1, envarea);
		}
		else if (argnmatch(argv[argi], "--area=")) {
			char *p = strchr(argv[argi], '=');
			envarea = strdup(p+1);
		}
		else if (strcmp(argv[argi], "--no-cookies") == 0) {
			obeycookies = 0;
		}
		else if (strcmp(argv[argi], "--debug") == 0) {
			debug = 1;
		}
	}

	redirect_cgilog("hobbit-enadis");

	parse_cgi();
	if (debug) preview = 1;

	if (cgi_method == CGI_GET) {
		/*
		 * It's a GET , so the initial request.
		 * If we have a pagepath cookie, use that as the initial
		 * host-name filter.
		 */
		char *cookie, *p;

		action = ACT_FILTER;

		cookie = getenv("HTTP_COOKIE");
		if (obeycookies && cookie && ((p = strstr(cookie, "pagepath=")) != NULL)) {
			p += strlen("pagepath=");
			pagepattern = strdup(p);
			p = strchr(pagepattern, ';'); if (p) *p = '\0';
			if (strlen(pagepattern) == 0) { xfree(pagepattern); pagepattern = 0; }
		}
	}

	if (action == ACT_FILTER) {
		/* Present the query form */

		load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn());
		sethostenv("", "", "", colorname(COL_BLUE), NULL);
		sethostenv_filter(hostpattern, pagepattern, ippattern);
		showform(stdout, "maint", "maint_form", COL_BLUE, getcurrenttime(NULL), NULL, NULL);
		return 0;
	}

	fullmsg = (char *)malloc(strlen(username) + strlen(userhost) + strlen(disablemsg) + 1024);
	sprintf(fullmsg, "\nDisabled by: %s @ %s\nReason: %s\n", username, userhost, disablemsg);

	/*
	 * Ready ... go build the webpage.
	 */
	printf("Content-Type: %s\n", xgetenv("HTMLCONTENTTYPE"));
	if (!preview) {
		printf("Location: %s\n\n", xgetenv("HTTP_REFERER"));
	}
	else {
		printf("\n");
	}

        /* It's ok with these hardcoded values, as they are not used for this page */
	sethostenv("", "", "", colorname(COL_BLUE), NULL);
	if (preview) headfoot(stdout, "maintact", "", "header", COL_BLUE);

	if (debug) {
		printf("<pre>\n");
		switch (action) {
		  case ACT_NONE   : dbgprintf("Action = none\n"); break;

		  case ACT_FILTER : dbgprintf("Action = filter\n"); break;

		  case ACT_ENABLE : dbgprintf("Action = enable\n"); 
				    dbgprintf("Tests = ");
				    for (i=0; (i < enablecount); i++) printf("%s ", enabletest[i]);
				    printf("\n");
				    break;

		  case ACT_DISABLE: dbgprintf("Action = disable\n"); 
				    dbgprintf("Tests = ");
				    for (i=0; (i < disablecount); i++) printf("%s ", disabletest[i]);
				    printf("\n");
				    dbgprintf("Duration = %d, scale = %d\n", duration, scale);
				    dbgprintf("Cause = %s\n", textornull(disablemsg));
				    break;

		  case ACT_SCHED_DISABLE:
				    dbgprintf("Action = schedule\n");
				    dbgprintf("Time = %s\n", ctime(&schedtime));
				    dbgprintf("Tests = ");
				    for (i=0; (i < disablecount); i++) printf("%s ", disabletest[i]);
				    printf("\n");
				    dbgprintf("Duration = %d, scale = %d\n", duration, scale);
				    dbgprintf("Cause = %s\n", textornull(disablemsg));
				    break;

		  case ACT_SCHED_CANCEL:
				    dbgprintf("Action = cancel\n");
				    dbgprintf("ID = %d\n", cancelid);
				    break;
		}
		printf("</pre>\n");
	}

	if (preview) printf("<table align=\"center\" summary=\"Actions performed\" width=\"60%%\">\n");
	if (action == ACT_SCHED_CANCEL) {
		do_one_host(NULL, NULL, username);
	}
	else {
		for (i = 0; (i < hostcount); i++) do_one_host(hostnames[i], fullmsg, username);
	}
	if (preview) {
		printf("<tr><td align=center><br><br><form method=\"GET\" ACTION=\"%s\"><input type=submit value=\"Continue\"></form></td></tr>\n", xgetenv("HTTP_REFERER"));
		printf("</table>\n");

		headfoot(stdout, "maintact", "", "footer", COL_BLUE);
	}

	return 0;
}

