/***********************************************************************
 *
 * SHOWLOG.C - Nagios Log File CGI
 *
 * Copyright (c) 1999-2008 Ethan Galstad (egalstad@nagios.org)
 * Last Modified: 01-08-2008
 *
 * This CGI program will display the contents of the Nagios
 * log file.
 *
 * License:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 ***********************************************************************/

#include "../include/config.h"
#include "../include/common.h"
#include "../include/objects.h"

#include "../include/getcgi.h"
#include "../include/cgiutils.h"
#include "../include/cgiauth.h"

extern char   main_config_file[MAX_FILENAME_LENGTH];
extern char   url_html_path[MAX_FILENAME_LENGTH];
extern char   url_images_path[MAX_FILENAME_LENGTH];
extern char   url_stylesheets_path[MAX_FILENAME_LENGTH];

extern int    log_rotation_method;

extern int    enable_splunk_integration;

void document_header(int);
void document_footer(void);
int process_cgivars(void);

authdata current_authdata;

int display_log(void);

char log_file_to_use[MAX_FILENAME_LENGTH]="";
int log_archive=0;

int use_lifo=TRUE;

int embedded=FALSE;
int display_header=TRUE;
int display_frills=TRUE;
int display_timebreaks=TRUE;


int main(void){
	int result=OK;
	char temp_buffer[MAX_INPUT_BUFFER];


	/* get the CGI variables passed in the URL */
	process_cgivars();

	/* reset internal variables */
	reset_cgi_vars();

	/* read the CGI configuration file */
	result=read_cgi_config_file(get_cgi_config_location());
	if(result==ERROR){
		document_header(FALSE);
		cgi_config_file_error(get_cgi_config_location());
		document_footer();
		return ERROR;
	        }

	/* read the main configuration file */
	result=read_main_config_file(main_config_file);
	if(result==ERROR){
		document_header(FALSE);
		main_config_file_error(main_config_file);
		document_footer();
		return ERROR;
	        }

	/* read all object configuration data */
	result=read_all_object_configuration_data(main_config_file,READ_ALL_OBJECT_DATA);
	if(result==ERROR){
		document_header(FALSE);
		object_data_error();
		document_footer();
		return ERROR;
                }


	document_header(TRUE);

	/* get authentication information */
	get_authentication_information(&current_authdata);

	/* determine what log file we should be using */
	get_log_archive_to_use(log_archive,log_file_to_use,(int)sizeof(log_file_to_use));

	if(display_header==TRUE){

		/* begin top table */
		printf("<table border=0 width=100%% cellpadding=0 cellspacing=0>\n");
		printf("<tr>\n");

		/* left column of top table - info box */
		printf("<td align=left valign=top width=33%%>\n");
		display_info_table((log_rotation_method==LOG_ROTATION_NONE || log_archive==0)?"Current Event Log":"Archived Event Log",FALSE,&current_authdata);
		printf("</td>\n");

		/* middle column of top table - log file navigation options */
		printf("<td align=center valign=top width=33%%>\n");
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s?%s",SHOWLOG_CGI,(use_lifo==FALSE)?"oldestfirst&":"");
		temp_buffer[sizeof(temp_buffer)-1]='\x0';
		display_nav_table(temp_buffer,log_archive);
		printf("</td>\n");

		/* right hand column of top row */
		printf("<td align=right valign=top width=33%%>\n");

		printf("<table border=0 cellspacing=0 cellpadding=0 CLASS='optBox'>\n");
		printf("<form method='GET' action='%s'>\n",SHOWLOG_CGI);
		printf("<input type='hidden' name='archive' value='%d'>\n",log_archive);
		printf("<tr>");
		printf("<td align=left valign=bottom CLASS='optBoxItem'><input type='checkbox' name='oldestfirst' %s> Older Entries First:</td>",(use_lifo==FALSE)?"checked":"");
		printf("</tr>\n");
		printf("<tr>");
		printf("<td align=left valign=bottom CLASS='optBoxItem'><input type='submit' value='Update'></td>\n");
		printf("</tr>\n");

		/* display context-sensitive help */
		printf("<tr>\n");
		printf("<td align=right>\n");
		display_context_help(CONTEXTHELP_LOG);
		printf("</td>\n");
		printf("</tr>\n");

		printf("</form>\n");
		printf("</table>\n");

		printf("</td>\n");

		/* end of top table */
		printf("</tr>\n");
		printf("</table>\n");
		printf("</p>\n");

	        }


	/* display the contents of the log file */
	display_log();

	document_footer();

	/* free allocated memory */
	free_memory();
	
	return OK;
        }




void document_header(int use_stylesheet){
	char date_time[MAX_DATETIME_LENGTH];
	time_t current_time;
	time_t expire_time;

	printf("Cache-Control: no-store\r\n");
	printf("Pragma: no-cache\r\n");

	time(&current_time);
	get_time_string(&current_time,date_time,(int)sizeof(date_time),HTTP_DATE_TIME);
	printf("Last-Modified: %s\r\n",date_time);

	expire_time=(time_t)0L;
	get_time_string(&expire_time,date_time,(int)sizeof(date_time),HTTP_DATE_TIME);
	printf("Expires: %s\r\n",date_time);

	printf("Content-type: text/html\r\n\r\n");

	if(embedded==TRUE)
		return;

	printf("<HTML>\n");
	printf("<HEAD>\n");
	printf("<link rel=\"shortcut icon\" href=\"%sfavicon.ico\" type=\"image/ico\">\n",url_images_path);
	printf("<TITLE>\n");
	printf("Nagios Log File\n");
	printf("</TITLE>\n");

	if(use_stylesheet==TRUE){
		printf("<LINK REL='stylesheet' TYPE='text/css' HREF='%s%s'>\n",url_stylesheets_path,COMMON_CSS);
		printf("<LINK REL='stylesheet' TYPE='text/css' HREF='%s%s'>\n",url_stylesheets_path,SHOWLOG_CSS);
		}

	printf("</HEAD>\n");
	printf("<BODY CLASS='showlog'>\n");

	/* include user SSI header */
	include_ssi_files(SHOWLOG_CGI,SSI_HEADER);

	return;
        }


void document_footer(void){

	if(embedded==TRUE)
		return;

	/* include user SSI footer */
	include_ssi_files(SHOWLOG_CGI,SSI_FOOTER);

	printf("</BODY>\n");
	printf("</HTML>\n");

	return;
        }


int process_cgivars(void){
	char **variables;
	int error=FALSE;
	int x;

	variables=getcgivars();

	for(x=0;variables[x]!=NULL;x++){

		/* do some basic length checking on the variable identifier to prevent buffer overflows */
		if(strlen(variables[x])>=MAX_INPUT_BUFFER-1){
			continue;
		        }

		/* we found the archive argument */
		else if(!strcmp(variables[x],"archive")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			log_archive=atoi(variables[x]);
			if(log_archive<0)
				log_archive=0;
		        }

		/* we found the order argument */
		else if(!strcmp(variables[x],"oldestfirst")){
			use_lifo=FALSE;
		        }

		/* we found the embed option */
		else if(!strcmp(variables[x],"embedded"))
			embedded=TRUE;

		/* we found the noheader option */
		else if(!strcmp(variables[x],"noheader"))
			display_header=FALSE;

		/* we found the nofrills option */
		else if (!strcmp(variables[x],"nofrills"))
			display_frills=FALSE;

		/* we found the notimebreaks option */
		else if(!strcmp(variables[x],"notimebreaks"))
			display_timebreaks=FALSE;

		/* we received an invalid argument */
		else
			error=TRUE;
	
	        }

	/* free memory allocated to the CGI variables */
	free_cgivars(variables);

	return error;
        }



/* display the contents of the log file */
int display_log(void){
	char *input=NULL;
	char image[MAX_INPUT_BUFFER];
	char image_alt[MAX_INPUT_BUFFER];
	time_t t;
	char *temp_buffer=NULL;
	char date_time[MAX_DATETIME_LENGTH];
	int error=FALSE;
	mmapfile *thefile=NULL;
	char last_message_date[MAX_INPUT_BUFFER]="";
	char current_message_date[MAX_INPUT_BUFFER]="";
	struct tm *time_ptr=NULL;


	/* check to see if the user is authorized to view the log file */
	if(is_authorized_for_system_information(&current_authdata)==FALSE){
		printf("<HR>\n");
		printf("<DIV CLASS='errorMessage'>It appears as though you do not have permission to view the log file...</DIV><br><br>\n");
		printf("<DIV CLASS='errorDescription'>If you believe this is an error, check the HTTP server authentication requirements for accessing this CGI<br>and check the authorization options in your CGI configuration file.</DIV>\n");
		printf("<HR>\n");
		return ERROR;
	        }

	error=FALSE;

	if(use_lifo==TRUE){
		error=read_file_into_lifo(log_file_to_use);
		if(error!=LIFO_OK){
			if(error==LIFO_ERROR_MEMORY){
				printf("<P><DIV CLASS='warningMessage'>Not enough memory to reverse log file - displaying log in natural order...</DIV></P>");
				error=FALSE;
			        }
			else
				error=TRUE;
			use_lifo=FALSE;
		        }
		else
			error=FALSE;
	        }

	if(use_lifo==FALSE){
  
		if((thefile=mmap_fopen(log_file_to_use))==NULL){
			printf("<HR>\n");
			printf("<P><DIV CLASS='errorMessage'>Error: Could not open log file '%s' for reading!</DIV></P>",log_file_to_use);
			printf("<HR>\n");
			error=TRUE;
	                }
	        }

	if(error==FALSE){

		printf("<P><DIV CLASS='logEntries'>\n");
		
		while(1){

			free(input);

			if(use_lifo==TRUE){
				if((input=pop_lifo())==NULL)
					break;
			        }
			else if((input=mmap_fgets(thefile))==NULL)
				break;

			strip(input);

			if(strstr(input," starting...")){
				strcpy(image,START_ICON);
				strcpy(image_alt,START_ICON_ALT);
			        }
			else if(strstr(input," shutting down...")){
				strcpy(image,STOP_ICON);
				strcpy(image_alt,STOP_ICON_ALT);
			        }
			else if(strstr(input,"Bailing out")){
				strcpy(image,STOP_ICON);
				strcpy(image_alt,STOP_ICON_ALT);
			        }
			else if(strstr(input," restarting...")){
				strcpy(image,RESTART_ICON);
				strcpy(image_alt,RESTART_ICON_ALT);
			        }
			else if(strstr(input,"HOST ALERT:") && strstr(input,";DOWN;")){
				strcpy(image,HOST_DOWN_ICON);
				strcpy(image_alt,HOST_DOWN_ICON_ALT);
			        }
			else if(strstr(input,"HOST ALERT:") && strstr(input,";UNREACHABLE;")){
				strcpy(image,HOST_UNREACHABLE_ICON);
				strcpy(image_alt,HOST_UNREACHABLE_ICON_ALT);
			        }
			else if(strstr(input,"HOST ALERT:") && (strstr(input,";RECOVERY;") || strstr(input,";UP;"))){
				strcpy(image,HOST_UP_ICON);
				strcpy(image_alt,HOST_UP_ICON_ALT);
			        }
			else if(strstr(input,"HOST NOTIFICATION:")){
				strcpy(image,HOST_NOTIFICATION_ICON);
				strcpy(image_alt,HOST_NOTIFICATION_ICON_ALT);
			        }
			else if(strstr(input,"SERVICE ALERT:") && strstr(input,";CRITICAL;")){
				strcpy(image,CRITICAL_ICON);
				strcpy(image_alt,CRITICAL_ICON_ALT);
			        }
			else if(strstr(input,"SERVICE ALERT:") && strstr(input,";WARNING;")){
				strcpy(image,WARNING_ICON);
				strcpy(image_alt,WARNING_ICON_ALT);
			        }
			else if(strstr(input,"SERVICE ALERT:") && strstr(input,";UNKNOWN;")){
				strcpy(image,UNKNOWN_ICON);
				strcpy(image_alt,UNKNOWN_ICON_ALT);
			        }
			else if(strstr(input,"SERVICE ALERT:") && (strstr(input,";RECOVERY;") || strstr(input,";OK;"))){
				strcpy(image,OK_ICON);
				strcpy(image_alt,OK_ICON_ALT);
			        }
			else if(strstr(input,"SERVICE NOTIFICATION:")){
				strcpy(image,NOTIFICATION_ICON);
				strcpy(image_alt,NOTIFICATION_ICON_ALT);
			        }
			else if(strstr(input,"SERVICE EVENT HANDLER:")){
				strcpy(image,SERVICE_EVENT_ICON);
				strcpy(image_alt,SERVICE_EVENT_ICON_ALT);
			        }
			else if(strstr(input,"HOST EVENT HANDLER:")){
				strcpy(image,HOST_EVENT_ICON);
				strcpy(image_alt,HOST_EVENT_ICON_ALT);
			        }
			else if(strstr(input,"EXTERNAL COMMAND:")){
				strcpy(image,EXTERNAL_COMMAND_ICON);
				strcpy(image_alt,EXTERNAL_COMMAND_ICON_ALT);
			        }
			else if(strstr(input,"PASSIVE SERVICE CHECK:")){
				strcpy(image,PASSIVE_ICON);
				strcpy(image_alt,"Passive Service Check");
			        }
			else if(strstr(input,"PASSIVE HOST CHECK:")){
				strcpy(image,PASSIVE_ICON);
				strcpy(image_alt,"Passive Host Check");
			        }
			else if(strstr(input,"LOG ROTATION:")){
				strcpy(image,LOG_ROTATION_ICON);
				strcpy(image_alt,LOG_ROTATION_ICON_ALT);
			        }
			else if(strstr(input,"active mode...")){
				strcpy(image,ACTIVE_ICON);
				strcpy(image_alt,ACTIVE_ICON_ALT);
			        }
			else if(strstr(input,"standby mode...")){
				strcpy(image,STANDBY_ICON);
				strcpy(image_alt,STANDBY_ICON_ALT);
			        }
			else if(strstr(input,"SERVICE FLAPPING ALERT:") && strstr(input,";STARTED;")){
				strcpy(image,FLAPPING_ICON);
				strcpy(image_alt,"Service started flapping");
			        }
			else if(strstr(input,"SERVICE FLAPPING ALERT:") && strstr(input,";STOPPED;")){
				strcpy(image,FLAPPING_ICON);
				strcpy(image_alt,"Service stopped flapping");
			        }
			else if(strstr(input,"SERVICE FLAPPING ALERT:") && strstr(input,";DISABLED;")){
				strcpy(image,FLAPPING_ICON);
				strcpy(image_alt,"Service flap detection disabled");
			        }
			else if(strstr(input,"HOST FLAPPING ALERT:") && strstr(input,";STARTED;")){
				strcpy(image,FLAPPING_ICON);
				strcpy(image_alt,"Host started flapping");
			        }
			else if(strstr(input,"HOST FLAPPING ALERT:") && strstr(input,";STOPPED;")){
				strcpy(image,FLAPPING_ICON);
				strcpy(image_alt,"Host stopped flapping");
			        }
			else if(strstr(input,"HOST FLAPPING ALERT:") && strstr(input,";DISABLED;")){
				strcpy(image,FLAPPING_ICON);
				strcpy(image_alt,"Host flap detection disabled");
			        }
			else if(strstr(input,"SERVICE DOWNTIME ALERT:") && strstr(input,";STARTED;")){
				strcpy(image,SCHEDULED_DOWNTIME_ICON);
				strcpy(image_alt,"Service entered a period of scheduled downtime");
			        }
			else if(strstr(input,"SERVICE DOWNTIME ALERT:") && strstr(input,";STOPPED;")){
				strcpy(image,SCHEDULED_DOWNTIME_ICON);
				strcpy(image_alt,"Service exited a period of scheduled downtime");
			        }
			else if(strstr(input,"SERVICE DOWNTIME ALERT:") && strstr(input,";CANCELLED;")){
				strcpy(image,SCHEDULED_DOWNTIME_ICON);
				strcpy(image_alt,"Service scheduled downtime has been cancelled");
			        }
			else if(strstr(input,"HOST DOWNTIME ALERT:") && strstr(input,";STARTED;")){
				strcpy(image,SCHEDULED_DOWNTIME_ICON);
				strcpy(image_alt,"Host entered a period of scheduled downtime");
			        }
			else if(strstr(input,"HOST DOWNTIME ALERT:") && strstr(input,";STOPPED;")){
				strcpy(image,SCHEDULED_DOWNTIME_ICON);
				strcpy(image_alt,"Host exited a period of scheduled downtime");
			        }
			else if(strstr(input,"HOST DOWNTIME ALERT:") && strstr(input,";CANCELLED;")){
				strcpy(image,SCHEDULED_DOWNTIME_ICON);
				strcpy(image_alt,"Host scheduled downtime has been cancelled");
			        }
			else{
				strcpy(image,INFO_ICON);
				strcpy(image_alt,INFO_ICON_ALT);
			        }

			temp_buffer=strtok(input,"]");
			t=(temp_buffer==NULL)?0L:strtoul(temp_buffer+1,NULL,10);

			time_ptr=localtime(&t);
			strftime(current_message_date,sizeof(current_message_date),"%B %d, %Y %H:00\n",time_ptr);
			current_message_date[sizeof(current_message_date)-1]='\x0';

			if(strcmp(last_message_date,current_message_date)!=0 && display_timebreaks==TRUE){
				printf("<BR CLEAR='all'>\n");
				printf("<DIV CLASS='dateTimeBreak'>\n");
				printf("<table border=0 width=95%%><tr>");
				printf("<td width=40%%><hr width=100%%></td>");
				printf("<td align=center CLASS='dateTimeBreak'>%s</td>",current_message_date);
				printf("<td width=40%%><hr width=100%%></td>");
				printf("</tr></table>\n");
				printf("</DIV>\n");
				printf("<BR CLEAR='all'><DIV CLASS='logEntries'>\n");
				strncpy(last_message_date,current_message_date,sizeof(last_message_date));
				last_message_date[sizeof(last_message_date)-1]='\x0';
				}

			get_time_string(&t,date_time,(int)sizeof(date_time),SHORT_DATE_TIME);
			strip(date_time);

			temp_buffer=strtok(NULL,"\n");
			
			if(display_frills==TRUE)
				printf("<img align='left' src='%s%s' alt='%s' title='%s'>",url_images_path,image,image_alt,image_alt);
			printf("[%s] %s",date_time,(temp_buffer==NULL)?"":html_encode(temp_buffer,FALSE));
			if(enable_splunk_integration==TRUE){
				printf("&nbsp;&nbsp;&nbsp;");
				display_splunk_generic_url(temp_buffer,2);
				}
			printf("<br clear='all'>\n");
		        }

		printf("</DIV></P>\n");
		printf("<HR>\n");

		free(input);

		if(use_lifo==FALSE)
			mmap_fclose(thefile);
	        }

	if(use_lifo==TRUE)
		free_lifo_memory();

	return OK;
        }

