1 /**************************************************************************
2  *
3  * HISTOGRAM.C -  Nagios Alert Histogram CGI
4  *
5  * Copyright (c) 2001-2008 Ethan Galstad (egalstad@nagios.org)
6  * Last Modified: 10-15-2008
7  *
8  * License:
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *************************************************************************/
23 
24 #include "../include/config.h"
25 #include "../include/common.h"
26 #include "../include/objects.h"
27 #include "../include/statusdata.h"
28 
29 #include "../include/cgiutils.h"
30 #include "../include/getcgi.h"
31 #include "../include/cgiauth.h"
32 
33 #include <gd.h>			/* Boutell's GD library function */
34 #include <gdfonts.h>		/* GD library small font definition */
35 
36 
37 /*#define DEBUG			1*/
38 
39 
40 #define HISTOGRAM_IMAGE         "histogram.png"
41 
42 /* archived state types */
43 #define AS_NO_DATA              0
44 #define AS_PROGRAM_START        1
45 #define AS_PROGRAM_END          2
46 #define AS_HOST_UP		3
47 #define AS_HOST_DOWN		4
48 #define AS_HOST_UNREACHABLE	5
49 #define AS_SVC_OK		6
50 #define AS_SVC_UNKNOWN		7
51 #define AS_SVC_WARNING		8
52 #define AS_SVC_CRITICAL		9
53 
54 
55 /* display types */
56 #define DISPLAY_HOST_HISTOGRAM	        0
57 #define DISPLAY_SERVICE_HISTOGRAM	1
58 #define DISPLAY_NO_HISTOGRAM    	2
59 
60 /* input types */
61 #define GET_INPUT_NONE                  0
62 #define GET_INPUT_TARGET_TYPE           1
63 #define GET_INPUT_HOST_TARGET           2
64 #define GET_INPUT_SERVICE_TARGET        3
65 #define GET_INPUT_OPTIONS               4
66 
67 /* breakdown types */
68 #define BREAKDOWN_MONTHLY       0
69 #define BREAKDOWN_DAY_OF_MONTH  1
70 #define BREAKDOWN_DAY_OF_WEEK   2
71 #define BREAKDOWN_HOURLY        3
72 
73 /* modes */
74 #define CREATE_HTML		0
75 #define CREATE_IMAGE		1
76 
77 /* standard report times */
78 #define TIMEPERIOD_CUSTOM	0
79 #define TIMEPERIOD_TODAY	1
80 #define TIMEPERIOD_YESTERDAY	2
81 #define TIMEPERIOD_THISWEEK	3
82 #define TIMEPERIOD_LASTWEEK	4
83 #define TIMEPERIOD_THISMONTH	5
84 #define TIMEPERIOD_LASTMONTH	6
85 #define TIMEPERIOD_THISQUARTER	7
86 #define TIMEPERIOD_LASTQUARTER	8
87 #define TIMEPERIOD_THISYEAR	9
88 #define TIMEPERIOD_LASTYEAR	10
89 #define TIMEPERIOD_LAST24HOURS	11
90 #define TIMEPERIOD_LAST7DAYS	12
91 #define TIMEPERIOD_LAST31DAYS   13
92 
93 
94 #define MAX_ARCHIVE_SPREAD	65
95 #define MAX_ARCHIVE		65
96 #define MAX_ARCHIVE_BACKTRACKS	60
97 
98 #define DRAWING_WIDTH	        550
99 #define DRAWING_HEIGHT	        195
100 #define DRAWING_X_OFFSET	60
101 #define DRAWING_Y_OFFSET        235
102 
103 #define GRAPH_HOST_UP                   1
104 #define GRAPH_HOST_DOWN                 2
105 #define GRAPH_HOST_UNREACHABLE          4
106 #define GRAPH_SERVICE_OK                8
107 #define GRAPH_SERVICE_WARNING           16
108 #define GRAPH_SERVICE_UNKNOWN           32
109 #define GRAPH_SERVICE_CRITICAL          64
110 
111 #define GRAPH_HOST_PROBLEMS             6
112 #define GRAPH_HOST_ALL                  7
113 
114 #define GRAPH_SERVICE_PROBLEMS          112
115 #define GRAPH_SERVICE_ALL               120
116 
117 #define GRAPH_EVERYTHING                255
118 
119 
120 #define GRAPH_SOFT_STATETYPES           1
121 #define GRAPH_HARD_STATETYPES           2
122 #define GRAPH_ALL_STATETYPES            3
123 
124 
125 
126 
127 extern char main_config_file[MAX_FILENAME_LENGTH];
128 extern char url_html_path[MAX_FILENAME_LENGTH];
129 extern char url_images_path[MAX_FILENAME_LENGTH];
130 extern char url_stylesheets_path[MAX_FILENAME_LENGTH];
131 extern char physical_images_path[MAX_FILENAME_LENGTH];
132 
133 extern int     log_rotation_method;
134 
135 extern host *host_list;
136 extern service *service_list;
137 
138 
139 
140 authdata current_authdata;
141 
142 
143 typedef struct timeslice_data_struct {
144 	unsigned long    service_ok;
145 	unsigned long    host_up;
146 	unsigned long    service_critical;
147 	unsigned long    host_down;
148 	unsigned long    service_unknown;
149 	unsigned long    host_unreachable;
150 	unsigned long    service_warning;
151 	} timeslice_data;
152 
153 
154 timeslice_data *tsdata;
155 
156 
157 void convert_timeperiod_to_times(int);
158 void compute_report_times(void);
159 void graph_all_histogram_data(void);
160 void add_archived_state(int, time_t);
161 void read_archived_state_data(void);
162 void scan_log_file_for_archived_state_data(char *);
163 void draw_line(int, int, int, int, int);
164 void draw_dashed_line(int, int, int, int, int);
165 
166 void document_header(int);
167 void document_footer(void);
168 int process_cgivars(void);
169 
170 
171 time_t t1;
172 time_t t2;
173 
174 int start_second = 0;
175 int start_minute = 0;
176 int start_hour = 0;
177 int start_day = 1;
178 int start_month = 1;
179 int start_year = 2000;
180 int end_second = 0;
181 int end_minute = 0;
182 int end_hour = 24;
183 int end_day = 1;
184 int end_month = 1;
185 int end_year = 2000;
186 
187 int display_type = DISPLAY_NO_HISTOGRAM;
188 int mode = CREATE_HTML;
189 int input_type = GET_INPUT_NONE;
190 int timeperiod_type = TIMEPERIOD_LAST24HOURS;
191 int breakdown_type = BREAKDOWN_HOURLY;
192 int compute_time_from_parts = FALSE;
193 
194 int initial_states_logged = FALSE;
195 int assume_state_retention = TRUE;
196 int new_states_only = FALSE;
197 
198 int last_state = AS_NO_DATA;
199 int program_restart_has_occurred = FALSE;
200 
201 int graph_events = GRAPH_EVERYTHING;
202 int graph_statetypes = GRAPH_HARD_STATETYPES;
203 
204 int embedded = FALSE;
205 int display_header = TRUE;
206 
207 char *host_name = "";
208 char *svc_description = "";
209 
210 gdImagePtr histogram_image = 0;
211 int color_white = 0;
212 int color_black = 0;
213 int color_red = 0;
214 int color_darkred = 0;
215 int color_green = 0;
216 int color_yellow = 0;
217 int color_orange = 0;
218 int color_lightgray = 0;
219 FILE *image_file = NULL;
220 
221 int backtrack_archives = 0;
222 int earliest_archive = 0;
223 time_t earliest_time;
224 time_t latest_time;
225 
226 int image_width = 900;
227 int image_height = 320;
228 
229 int total_buckets = 96;
230 
231 
232 
main(int argc,char ** argv)233 int main(int argc, char **argv) {
234 	int result = OK;
235 	char temp_buffer[MAX_INPUT_BUFFER];
236 	char image_template[MAX_INPUT_BUFFER];
237 	char start_timestring[MAX_INPUT_BUFFER];
238 	char end_timestring[MAX_INPUT_BUFFER];
239 	host *temp_host;
240 	service *temp_service;
241 	int is_authorized = TRUE;
242 	int found = FALSE;
243 	int days, hours, minutes, seconds;
244 	char *first_service = NULL;
245 	int x;
246 	time_t t3;
247 	time_t current_time;
248 	struct tm *t;
249 
250 	/* initialize time period to last 24 hours */
251 	time(&t2);
252 	t1 = (time_t)(t2 - (60 * 60 * 24));
253 
254 	/* get the arguments passed in the URL */
255 	process_cgivars();
256 
257 	/* reset internal CGI variables */
258 	reset_cgi_vars();
259 
260 	/* read the CGI configuration file */
261 	result = read_cgi_config_file(get_cgi_config_location());
262 	if(result == ERROR) {
263 		if(mode == CREATE_HTML) {
264 			document_header(FALSE);
265 			cgi_config_file_error(get_cgi_config_location());
266 			document_footer();
267 			}
268 		return ERROR;
269 		}
270 
271 	/* read the main configuration file */
272 	result = read_main_config_file(main_config_file);
273 	if(result == ERROR) {
274 		if(mode == CREATE_HTML) {
275 			document_header(FALSE);
276 			main_config_file_error(main_config_file);
277 			document_footer();
278 			}
279 		return ERROR;
280 		}
281 
282 	/* read all object configuration data */
283 	result = read_all_object_configuration_data(main_config_file, READ_ALL_OBJECT_DATA);
284 	if(result == ERROR) {
285 		if(mode == CREATE_HTML) {
286 			document_header(FALSE);
287 			object_data_error();
288 			document_footer();
289 			}
290 		return ERROR;
291 		}
292 
293 	/* read all status data */
294 	result = read_all_status_data(get_cgi_config_location(), READ_ALL_STATUS_DATA);
295 	if(result == ERROR) {
296 		if(mode == CREATE_HTML) {
297 			document_header(FALSE);
298 			status_data_error();
299 			document_footer();
300 			}
301 		free_memory();
302 		return ERROR;
303 		}
304 
305 	document_header(TRUE);
306 
307 	/* get authentication information */
308 	get_authentication_information(&current_authdata);
309 
310 	if(compute_time_from_parts == TRUE)
311 		compute_report_times();
312 
313 	/* make sure times are sane, otherwise swap them */
314 	if(t2 < t1) {
315 		t3 = t2;
316 		t2 = t1;
317 		t1 = t3;
318 		}
319 
320 
321 	if(mode == CREATE_HTML && display_header == TRUE) {
322 
323 		/* begin top table */
324 		printf("<table border=0 width=100%% cellspacing=0 cellpadding=0>\n");
325 		printf("<tr>\n");
326 
327 		/* left column of the first row */
328 		printf("<td align=left valign=top width=33%%>\n");
329 
330 		if(display_type == DISPLAY_HOST_HISTOGRAM)
331 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Host Alert Histogram");
332 		else if(display_type == DISPLAY_SERVICE_HISTOGRAM)
333 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Service Alert Histogram");
334 		else
335 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Host and Service Alert Histogram");
336 		temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
337 		display_info_table(temp_buffer, FALSE, &current_authdata);
338 
339 		if(display_type != DISPLAY_NO_HISTOGRAM && input_type == GET_INPUT_NONE) {
340 
341 			printf("<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 CLASS='linkBox'>\n");
342 			printf("<TR><TD CLASS='linkBox'>\n");
343 
344 			if(display_type == DISPLAY_HOST_HISTOGRAM) {
345 #ifdef USE_TRENDS
346 				printf("<a href='%s?host=%s&t1=%lu&t2=%lu&assumestateretention=%s'>View Trends For This Host</a><BR>\n", TRENDS_CGI, url_encode(host_name), t1, t2, (assume_state_retention == TRUE) ? "yes" : "no");
347 #endif
348 				printf("<a href='%s?host=%s&t1=%lu&t2=%lu&assumestateretention=%s&show_log_entries'>View Availability Report For This Host</a><BR>\n", AVAIL_CGI, url_encode(host_name), t1, t2, (assume_state_retention == TRUE) ? "yes" : "no");
349 				printf("<a href='%s?host=%s'>View Status Detail For This Host</a><BR>\n", STATUS_CGI, url_encode(host_name));
350 				printf("<a href='%s?host=%s'>View History For This Host</a><BR>\n", HISTORY_CGI, url_encode(host_name));
351 				printf("<a href='%s?host=%s'>View Notifications For This Host</a><BR>\n", NOTIFICATIONS_CGI, url_encode(host_name));
352 				}
353 			else {
354 #ifdef USE_TRENDS
355 				printf("<a href='%s?host=%s", TRENDS_CGI, url_encode(host_name));
356 #endif
357 				printf("&service=%s&t1=%lu&t2=%lu&assumestateretention=%s'>View Trends For This Service</a><BR>\n", url_encode(svc_description), t1, t2, (assume_state_retention == TRUE) ? "yes" : "no");
358 				printf("<a href='%s?host=%s", AVAIL_CGI, url_encode(host_name));
359 				printf("&service=%s&t1=%lu&t2=%lu&assumestateretention=%s&show_log_entries'>View Availability Report For This Service</a><BR>\n", url_encode(svc_description), t1, t2, (assume_state_retention == TRUE) ? "yes" : "no");
360 				printf("<A HREF='%s?host=%s&", HISTORY_CGI, url_encode(host_name));
361 				printf("service=%s'>View History For This Service</A><BR>\n", url_encode(svc_description));
362 				printf("<A HREF='%s?host=%s&", NOTIFICATIONS_CGI, url_encode(host_name));
363 				printf("service=%s'>View Notifications For This Service</A><BR>\n", url_encode(svc_description));
364 				}
365 
366 			printf("</TD></TR>\n");
367 			printf("</TABLE>\n");
368 			}
369 
370 		printf("</td>\n");
371 
372 		/* center column of top row */
373 		printf("<td align=center valign=top width=33%%>\n");
374 
375 		if(display_type != DISPLAY_NO_HISTOGRAM && input_type == GET_INPUT_NONE) {
376 
377 			printf("<DIV ALIGN=CENTER CLASS='dataTitle'>\n");
378 			if(display_type == DISPLAY_HOST_HISTOGRAM)
379 				printf("Host '%s'", host_name);
380 			else if(display_type == DISPLAY_SERVICE_HISTOGRAM)
381 				printf("Service '%s' On Host '%s'", svc_description, host_name);
382 			printf("</DIV>\n");
383 
384 			printf("<BR>\n");
385 
386 			printf("<IMG SRC='%s%s' BORDER=0 ALT='%s Event Histogram' TITLE='%s Event Histogram'>\n", url_images_path, TRENDS_ICON, (display_type == DISPLAY_HOST_HISTOGRAM) ? "Host" : "Service", (display_type == DISPLAY_HOST_HISTOGRAM) ? "Host" : "Service");
387 
388 			printf("<BR CLEAR=ALL>\n");
389 
390 			get_time_string(&t1, start_timestring, sizeof(start_timestring) - 1, SHORT_DATE_TIME);
391 			get_time_string(&t2, end_timestring, sizeof(end_timestring) - 1, SHORT_DATE_TIME);
392 			printf("<div align=center class='reportRange'>%s to %s</div>\n", start_timestring, end_timestring);
393 
394 			get_time_breakdown((time_t)(t2 - t1), &days, &hours, &minutes, &seconds);
395 			printf("<div align=center class='reportDuration'>Duration: %dd %dh %dm %ds</div>\n", days, hours, minutes, seconds);
396 			}
397 
398 		printf("</td>\n");
399 
400 		/* right hand column of top row */
401 		printf("<td align=right valign=bottom width=33%%>\n");
402 
403 		printf("<form method=\"GET\" action=\"%s\">\n", HISTOGRAM_CGI);
404 		printf("<table border=0 CLASS='optBox'>\n");
405 
406 		if(display_type != DISPLAY_NO_HISTOGRAM && input_type == GET_INPUT_NONE) {
407 
408 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>Report period:</td><td CLASS='optBoxItem' valign=top align=left>Assume state retention:</td></tr>\n");
409 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
410 
411 			printf("<input type='hidden' name='t1' value='%lu'>\n", (unsigned long)t1);
412 			printf("<input type='hidden' name='t2' value='%lu'>\n", (unsigned long)t2);
413 			printf("<input type='hidden' name='host' value='%s'>\n", escape_string(host_name));
414 			if(display_type == DISPLAY_SERVICE_HISTOGRAM)
415 				printf("<input type='hidden' name='service' value='%s'>\n", escape_string(svc_description));
416 
417 			printf("<select name='timeperiod'>\n");
418 			printf("<option value=custom>[ Current time range ]\n");
419 			printf("<option value=today %s>Today\n", (timeperiod_type == TIMEPERIOD_TODAY) ? "SELECTED" : "");
420 			printf("<option value=last24hours %s>Last 24 Hours\n", (timeperiod_type == TIMEPERIOD_LAST24HOURS) ? "SELECTED" : "");
421 			printf("<option value=yesterday %s>Yesterday\n", (timeperiod_type == TIMEPERIOD_YESTERDAY) ? "SELECTED" : "");
422 			printf("<option value=thisweek %s>This Week\n", (timeperiod_type == TIMEPERIOD_THISWEEK) ? "SELECTED" : "");
423 			printf("<option value=last7days %s>Last 7 Days\n", (timeperiod_type == TIMEPERIOD_LAST7DAYS) ? "SELECTED" : "");
424 			printf("<option value=lastweek %s>Last Week\n", (timeperiod_type == TIMEPERIOD_LASTWEEK) ? "SELECTED" : "");
425 			printf("<option value=thismonth %s>This Month\n", (timeperiod_type == TIMEPERIOD_THISMONTH) ? "SELECTED" : "");
426 			printf("<option value=last31days %s>Last 31 Days\n", (timeperiod_type == TIMEPERIOD_LAST31DAYS) ? "SELECTED" : "");
427 			printf("<option value=lastmonth %s>Last Month\n", (timeperiod_type == TIMEPERIOD_LASTMONTH) ? "SELECTED" : "");
428 			printf("<option value=thisyear %s>This Year\n", (timeperiod_type == TIMEPERIOD_THISYEAR) ? "SELECTED" : "");
429 			printf("<option value=lastyear %s>Last Year\n", (timeperiod_type == TIMEPERIOD_LASTYEAR) ? "SELECTED" : "");
430 			printf("</select>\n");
431 			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
432 			printf("<select name='assumestateretention'>\n");
433 			printf("<option value=yes %s>yes\n", (assume_state_retention == TRUE) ? "SELECTED" : "");
434 			printf("<option value=no %s>no\n", (assume_state_retention == TRUE) ? "" : "SELECTED");
435 			printf("</select>\n");
436 			printf("</td></tr>\n");
437 
438 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>Breakdown type:</td><td CLASS='optBoxItem' valign=top align=left>Initial states logged:</td></tr>\n");
439 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
440 			printf("<select name='breakdown'>\n");
441 			printf("<option value=monthly %s>Month\n", (breakdown_type == BREAKDOWN_MONTHLY) ? "SELECTED" : "");
442 			printf("<option value=dayofmonth %s>Day of the Month\n", (breakdown_type == BREAKDOWN_DAY_OF_MONTH) ? "SELECTED" : "");
443 			printf("<option value=dayofweek %s>Day of the Week\n", (breakdown_type == BREAKDOWN_DAY_OF_WEEK) ? "SELECTED" : "");
444 			printf("<option value=hourly %s>Hour of the Day\n", (breakdown_type == BREAKDOWN_HOURLY) ? "SELECTED" : "");
445 			printf("</select>\n");
446 			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
447 			printf("<select name='initialstateslogged'>\n");
448 			printf("<option value=yes %s>yes\n", (initial_states_logged == TRUE) ? "SELECTED" : "");
449 			printf("<option value=no %s>no\n", (initial_states_logged == TRUE) ? "" : "SELECTED");
450 			printf("</select>\n");
451 			printf("</td></tr>\n");
452 
453 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>Events to graph:</td><td CLASS='optBoxItem' valign=top align=left>Ignore repeated states:</td></tr>\n");
454 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
455 			printf("<select name='graphevents'>\n");
456 			if(display_type == DISPLAY_HOST_HISTOGRAM) {
457 				printf("<option value=%d %s>All host events\n", GRAPH_HOST_ALL, (graph_events == GRAPH_HOST_ALL) ? "SELECTED" : "");
458 				printf("<option value=%d %s>Host problem events\n", GRAPH_HOST_PROBLEMS, (graph_events == GRAPH_HOST_PROBLEMS) ? "SELECTED" : "");
459 				printf("<option value=%d %s>Host up events\n", GRAPH_HOST_UP, (graph_events == GRAPH_HOST_UP) ? "SELECTED" : "");
460 				printf("<option value=%d %s>Host down events\n", GRAPH_HOST_DOWN, (graph_events == GRAPH_HOST_DOWN) ? "SELECTED" : "");
461 				printf("<option value=%d %s>Host unreachable events\n", GRAPH_HOST_UNREACHABLE, (graph_events == GRAPH_HOST_UNREACHABLE) ? "SELECTED" : "");
462 				}
463 			else {
464 				printf("<option value=%d %s>All service events\n", GRAPH_SERVICE_ALL, (graph_events == GRAPH_SERVICE_ALL) ? "SELECTED" : "");
465 				printf("<option value=%d %s>Service problem events\n", GRAPH_SERVICE_PROBLEMS, (graph_events == GRAPH_SERVICE_PROBLEMS) ? "SELECTED" : "");
466 				printf("<option value=%d %s>Service ok events\n", GRAPH_SERVICE_OK, (graph_events == GRAPH_SERVICE_OK) ? "SELECTED" : "");
467 				printf("<option value=%d %s>Service warning events\n", GRAPH_SERVICE_WARNING, (graph_events == GRAPH_SERVICE_WARNING) ? "SELECTED" : "");
468 				printf("<option value=%d %s>Service unknown events\n", GRAPH_SERVICE_UNKNOWN, (graph_events == GRAPH_SERVICE_UNKNOWN) ? "SELECTED" : "");
469 				printf("<option value=%d %s>Service critical events\n", GRAPH_SERVICE_CRITICAL, (graph_events == GRAPH_SERVICE_CRITICAL) ? "SELECTED" : "");
470 				}
471 			printf("</select>\n");
472 			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
473 			printf("<select name='newstatesonly'>\n");
474 			printf("<option value=yes %s>yes\n", (new_states_only == TRUE) ? "SELECTED" : "");
475 			printf("<option value=no %s>no\n", (new_states_only == TRUE) ? "" : "SELECTED");
476 			printf("</select>\n");
477 			printf("</td></tr>\n");
478 
479 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>State types to graph:</td><td CLASS='optBoxItem' valign=top align=left></td></tr>\n");
480 			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
481 			printf("<select name='graphstatetypes'>\n");
482 			printf("<option value=%d %s>Hard states\n", GRAPH_HARD_STATETYPES, (graph_statetypes == GRAPH_HARD_STATETYPES) ? "SELECTED" : "");
483 			printf("<option value=%d %s>Soft states\n", GRAPH_SOFT_STATETYPES, (graph_statetypes == GRAPH_SOFT_STATETYPES) ? "SELECTED" : "");
484 			printf("<option value=%d %s>Hard and soft states\n", GRAPH_ALL_STATETYPES, (graph_statetypes == GRAPH_ALL_STATETYPES) ? "SELECTED" : "");
485 			printf("</select>\n");
486 			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
487 			printf("<input type='submit' value='Update'>\n");
488 			printf("</td></tr>\n");
489 			}
490 
491 		/* display context-sensitive help */
492 		printf("<tr><td></td><td align=right valign=bottom>\n");
493 		if(display_type != DISPLAY_NO_HISTOGRAM && input_type == GET_INPUT_NONE) {
494 			if(display_type == DISPLAY_HOST_HISTOGRAM)
495 				display_context_help(CONTEXTHELP_HISTOGRAM_HOST);
496 			else
497 				display_context_help(CONTEXTHELP_HISTOGRAM_SERVICE);
498 			}
499 		else if(display_type == DISPLAY_NO_HISTOGRAM || input_type != GET_INPUT_NONE) {
500 			if(input_type == GET_INPUT_NONE)
501 				display_context_help(CONTEXTHELP_HISTOGRAM_MENU1);
502 			else if(input_type == GET_INPUT_TARGET_TYPE)
503 				display_context_help(CONTEXTHELP_HISTOGRAM_MENU1);
504 			else if(input_type == GET_INPUT_HOST_TARGET)
505 				display_context_help(CONTEXTHELP_HISTOGRAM_MENU2);
506 			else if(input_type == GET_INPUT_SERVICE_TARGET)
507 				display_context_help(CONTEXTHELP_HISTOGRAM_MENU3);
508 			else if(input_type == GET_INPUT_OPTIONS)
509 				display_context_help(CONTEXTHELP_HISTOGRAM_MENU4);
510 			}
511 		printf("</td></tr>\n");
512 
513 		printf("</table>\n");
514 		printf("</form>\n");
515 
516 		printf("</td>\n");
517 
518 		/* end of top table */
519 		printf("</tr>\n");
520 		printf("</table>\n");
521 		}
522 
523 	/* check authorization... */
524 	if(display_type == DISPLAY_HOST_HISTOGRAM) {
525 		temp_host = find_host(host_name);
526 		if(temp_host == NULL || is_authorized_for_host(temp_host, &current_authdata) == FALSE)
527 			is_authorized = FALSE;
528 		}
529 	else if(display_type == DISPLAY_SERVICE_HISTOGRAM) {
530 		temp_service = find_service(host_name, svc_description);
531 		if(temp_service == NULL || is_authorized_for_service(temp_service, &current_authdata) == FALSE)
532 			is_authorized = FALSE;
533 		}
534 	if(is_authorized == FALSE) {
535 
536 		if(mode == CREATE_HTML)
537 			printf("<P><DIV ALIGN=CENTER CLASS='errorMessage'>It appears as though you are not authorized to view information for the specified %s...</DIV></P>\n", (display_type == DISPLAY_HOST_HISTOGRAM) ? "host" : "service");
538 
539 		document_footer();
540 		free_memory();
541 		return ERROR;
542 		}
543 
544 	if(display_type != DISPLAY_NO_HISTOGRAM && input_type == GET_INPUT_NONE) {
545 
546 		/* print URL to image */
547 		if(mode == CREATE_HTML) {
548 
549 			printf("<BR><BR>\n");
550 			printf("<DIV ALIGN=CENTER>\n");
551 			printf("<IMG SRC='%s?createimage&t1=%lu&t2=%lu", HISTOGRAM_CGI, (unsigned long)t1, (unsigned long)t2);
552 			printf("&host=%s", url_encode(host_name));
553 			if(display_type == DISPLAY_SERVICE_HISTOGRAM)
554 				printf("&service=%s", url_encode(svc_description));
555 			printf("&breakdown=");
556 			if(breakdown_type == BREAKDOWN_MONTHLY)
557 				printf("monthly");
558 			else if(breakdown_type == BREAKDOWN_DAY_OF_MONTH)
559 				printf("dayofmonth");
560 			else if(breakdown_type == BREAKDOWN_DAY_OF_WEEK)
561 				printf("dayofweek");
562 			else
563 				printf("hourly");
564 			printf("&assumestateretention=%s", (assume_state_retention == TRUE) ? "yes" : "no");
565 			printf("&initialstateslogged=%s", (initial_states_logged == TRUE) ? "yes" : "no");
566 			printf("&newstatesonly=%s", (new_states_only == TRUE) ? "yes" : "no");
567 			printf("&graphevents=%d", graph_events);
568 			printf("&graphstatetypes=%d", graph_statetypes);
569 			printf("' BORDER=0 name='histogramimage'>\n");
570 			printf("</DIV>\n");
571 			}
572 
573 		/* read and process state data */
574 		else {
575 
576 			/* allocate memory */
577 			tsdata = NULL;
578 			if(breakdown_type == BREAKDOWN_MONTHLY)
579 				total_buckets = 12;
580 			else if(breakdown_type == BREAKDOWN_DAY_OF_MONTH)
581 				total_buckets = 31;
582 			else if(breakdown_type == BREAKDOWN_DAY_OF_WEEK)
583 				total_buckets = 7;
584 			else
585 				total_buckets = 96;
586 
587 			tsdata = (timeslice_data *)malloc(sizeof(timeslice_data) * total_buckets);
588 			if(tsdata == NULL)
589 				return ERROR;
590 
591 			for(x = 0; x < total_buckets; x++) {
592 				tsdata[x].service_ok = 0L;
593 				tsdata[x].service_unknown = 0L;
594 				tsdata[x].service_warning = 0L;
595 				tsdata[x].service_critical = 0L;
596 				tsdata[x].host_up = 0L;
597 				tsdata[x].host_down = 0L;
598 				tsdata[x].host_unreachable = 0L;
599 				}
600 
601 			/* read in all necessary archived state data */
602 			read_archived_state_data();
603 
604 #ifdef DEBUG
605 			printf("Done reading archived state data.\n");
606 #endif
607 
608 			/* location of image template */
609 			snprintf(image_template, sizeof(image_template) - 1, "%s/%s", physical_images_path, HISTOGRAM_IMAGE);
610 			image_template[sizeof(image_template) - 1] = '\x0';
611 
612 			/* allocate buffer for storing image */
613 			image_file = fopen(image_template, "r");
614 			if(image_file != NULL) {
615 				histogram_image = gdImageCreateFromPng(image_file);
616 				fclose(image_file);
617 				}
618 			if(histogram_image == NULL)
619 				histogram_image = gdImageCreate(image_width, image_height);
620 			if(histogram_image == NULL) {
621 #ifdef DEBUG
622 				printf("Error: Could not allocate memory for image\n");
623 #endif
624 				return ERROR;
625 				}
626 
627 			/* allocate colors used for drawing */
628 			color_white = gdImageColorAllocate(histogram_image, 255, 255, 255);
629 			color_black = gdImageColorAllocate(histogram_image, 0, 0, 0);
630 			color_red = gdImageColorAllocate(histogram_image, 255, 0, 0);
631 			color_darkred = gdImageColorAllocate(histogram_image, 128, 0, 0);
632 			color_green = gdImageColorAllocate(histogram_image, 0, 128, 0);
633 			color_yellow = gdImageColorAllocate(histogram_image, 176, 178, 20);
634 			color_orange = gdImageColorAllocate(histogram_image, 255, 100, 25);
635 			color_lightgray = gdImageColorAllocate(histogram_image, 192, 192, 192);
636 
637 			/* set transparency index */
638 			gdImageColorTransparent(histogram_image, color_white);
639 
640 			/* make sure the graphic is interlaced */
641 			gdImageInterlace(histogram_image, 1);
642 
643 #ifdef DEBUG
644 			printf("Starting to graph data...\n");
645 #endif
646 
647 			/* graph archived state histogram data */
648 			graph_all_histogram_data();
649 
650 #ifdef DEBUG
651 			printf("Done graphing data.\n");
652 #endif
653 
654 			/* use STDOUT for writing the image data... */
655 			image_file = stdout;
656 
657 #ifdef DEBUG
658 			image_file = fopen("/tmp/histogram.png", "w");
659 #endif
660 
661 			/* write the image to to STDOUT */
662 			gdImagePng(histogram_image, image_file);
663 
664 #ifdef DEBUG
665 			fclose(image_file);
666 #endif
667 
668 			/* free memory allocated to image */
669 			gdImageDestroy(histogram_image);
670 
671 			/* free memory allocated for data */
672 			free(tsdata);
673 			}
674 		}
675 
676 
677 	/* show user a selection of hosts and services to choose from... */
678 	if(display_type == DISPLAY_NO_HISTOGRAM || input_type != GET_INPUT_NONE) {
679 
680 		/* ask the user for what host they want a report for */
681 		if(input_type == GET_INPUT_HOST_TARGET) {
682 
683 			printf("<P><DIV ALIGN=CENTER>\n");
684 			printf("<DIV CLASS='reportSelectTitle'>Step 2: Select Host</DIV>\n");
685 			printf("</DIV></P>\n");
686 
687 			printf("<P><DIV ALIGN=CENTER>\n");
688 
689 			printf("<form method=\"GET\" action=\"%s\">\n", HISTOGRAM_CGI);
690 			printf("<input type='hidden' name='input' value='getoptions'>\n");
691 
692 			printf("<TABLE BORDER=0 cellspacing=0 cellpadding=10>\n");
693 			printf("<tr><td class='reportSelectSubTitle' valign=center>Host:</td>\n");
694 			printf("<td class='reportSelectItem' valign=center>\n");
695 			printf("<select name='host'>\n");
696 
697 			for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
698 				if(is_authorized_for_host(temp_host, &current_authdata) == TRUE)
699 					printf("<option value='%s'>%s\n", escape_string(temp_host->name), temp_host->name);
700 				}
701 
702 			printf("</select>\n");
703 			printf("</td></tr>\n");
704 
705 			printf("<tr><td></td><td class='reportSelectItem'>\n");
706 			printf("<input type='submit' value='Continue to Step 3'>\n");
707 			printf("</td></tr>\n");
708 
709 			printf("</TABLE>\n");
710 			printf("</form>\n");
711 
712 			printf("</DIV></P>\n");
713 			}
714 
715 		/* ask the user for what service they want a report for */
716 		else if(input_type == GET_INPUT_SERVICE_TARGET) {
717 
718 			printf("<SCRIPT LANGUAGE='JavaScript'>\n");
719 			printf("function gethostname(hostindex){\n");
720 			printf("hostnames=[");
721 
722 			for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) {
723 				if(is_authorized_for_service(temp_service, &current_authdata) == TRUE) {
724 					if(found == TRUE)
725 						printf(",");
726 					else
727 						first_service = temp_service->host_name;
728 					printf(" \"%s\"", temp_service->host_name);
729 					found = TRUE;
730 					}
731 				}
732 
733 			printf(" ]\n");
734 			printf("return hostnames[hostindex];\n");
735 			printf("}\n");
736 			printf("</SCRIPT>\n");
737 
738 
739 			printf("<P><DIV ALIGN=CENTER>\n");
740 			printf("<DIV CLASS='reportSelectTitle'>Step 2: Select Service</DIV>\n");
741 			printf("</DIV></P>\n");
742 
743 			printf("<P><DIV ALIGN=CENTER>\n");
744 
745 			printf("<form method=\"GET\" action=\"%s\" name=\"serviceform\">\n", HISTOGRAM_CGI);
746 			printf("<input type='hidden' name='input' value='getoptions'>\n");
747 			printf("<input type='hidden' name='host' value='%s'>\n", (first_service == NULL) ? "unknown" : (char *)escape_string(first_service));
748 
749 			printf("<TABLE BORDER=0 cellpadding=5>\n");
750 			printf("<tr><td class='reportSelectSubTitle'>Service:</td>\n");
751 			printf("<td class='reportSelectItem'>\n");
752 			printf("<select name='service' onFocus='document.serviceform.host.value=gethostname(this.selectedIndex);' onChange='document.serviceform.host.value=gethostname(this.selectedIndex);'>\n");
753 
754 			for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) {
755 				if(is_authorized_for_service(temp_service, &current_authdata) == TRUE)
756 					printf("<option value='%s'>%s;%s\n", escape_string(temp_service->description), temp_service->host_name, temp_service->description);
757 				}
758 
759 			printf("</select>\n");
760 			printf("</td></tr>\n");
761 
762 			printf("<tr><td></td><td class='reportSelectItem'>\n");
763 			printf("<input type='submit' value='Continue to Step 3'>\n");
764 			printf("</td></tr>\n");
765 
766 			printf("</TABLE>\n");
767 			printf("</form>\n");
768 
769 			printf("</DIV></P>\n");
770 			}
771 
772 		/* ask the user for report range and options */
773 		else if(input_type == GET_INPUT_OPTIONS) {
774 
775 			time(&current_time);
776 			t = localtime(&current_time);
777 
778 			start_day = 1;
779 			start_year = t->tm_year + 1900;
780 			end_day = t->tm_mday;
781 			end_year = t->tm_year + 1900;
782 
783 			printf("<P><DIV ALIGN=CENTER>\n");
784 			printf("<DIV CLASS='reportSelectTitle'>Step 3: Select Report Options</DIV>\n");
785 			printf("</DIV></P>\n");
786 
787 			printf("<P><DIV ALIGN=CENTER>\n");
788 
789 			printf("<form method=\"GET\" action=\"%s\">\n", HISTOGRAM_CGI);
790 			printf("<input type='hidden' name='host' value='%s'>\n", escape_string(host_name));
791 			if(display_type == DISPLAY_SERVICE_HISTOGRAM)
792 				printf("<input type='hidden' name='service' value='%s'>\n", escape_string(svc_description));
793 
794 			printf("<TABLE BORDER=0 cellpadding=5>\n");
795 			printf("<tr><td class='reportSelectSubTitle' align=right>Report Period:</td>\n");
796 			printf("<td class='reportSelectItem'>\n");
797 			printf("<select name='timeperiod'>\n");
798 			printf("<option value=today>Today\n");
799 			printf("<option value=last24hours>Last 24 Hours\n");
800 			printf("<option value=yesterday>Yesterday\n");
801 			printf("<option value=thisweek>This Week\n");
802 			printf("<option value=last7days SELECTED>Last 7 Days\n");
803 			printf("<option value=lastweek>Last Week\n");
804 			printf("<option value=thismonth>This Month\n");
805 			printf("<option value=last31days>Last 31 Days\n");
806 			printf("<option value=lastmonth>Last Month\n");
807 			printf("<option value=thisyear>This Year\n");
808 			printf("<option value=lastyear>Last Year\n");
809 			printf("<option value=custom>* CUSTOM REPORT PERIOD *\n");
810 			printf("</select>\n");
811 			printf("</td></tr>\n");
812 
813 			printf("<tr><td valign=top class='reportSelectSubTitle'>If Custom Report Period...</td></tr>\n");
814 
815 			printf("<tr>");
816 			printf("<td valign=top class='reportSelectSubTitle'>Start Date (Inclusive):</td>\n");
817 			printf("<td align=left valign=top class='reportSelectItem'>");
818 			printf("<select name='smon'>\n");
819 			printf("<option value='1' %s>January\n", (t->tm_mon == 0) ? "SELECTED" : "");
820 			printf("<option value='2' %s>February\n", (t->tm_mon == 1) ? "SELECTED" : "");
821 			printf("<option value='3' %s>March\n", (t->tm_mon == 2) ? "SELECTED" : "");
822 			printf("<option value='4' %s>April\n", (t->tm_mon == 3) ? "SELECTED" : "");
823 			printf("<option value='5' %s>May\n", (t->tm_mon == 4) ? "SELECTED" : "");
824 			printf("<option value='6' %s>June\n", (t->tm_mon == 5) ? "SELECTED" : "");
825 			printf("<option value='7' %s>July\n", (t->tm_mon == 6) ? "SELECTED" : "");
826 			printf("<option value='8' %s>August\n", (t->tm_mon == 7) ? "SELECTED" : "");
827 			printf("<option value='9' %s>September\n", (t->tm_mon == 8) ? "SELECTED" : "");
828 			printf("<option value='10' %s>October\n", (t->tm_mon == 9) ? "SELECTED" : "");
829 			printf("<option value='11' %s>November\n", (t->tm_mon == 10) ? "SELECTED" : "");
830 			printf("<option value='12' %s>December\n", (t->tm_mon == 11) ? "SELECTED" : "");
831 			printf("</select>\n ");
832 			printf("<input type='text' size='2' maxlength='2' name='sday' value='%d'> ", start_day);
833 			printf("<input type='text' size='4' maxlength='4' name='syear' value='%d'>", start_year);
834 			printf("<input type='hidden' name='shour' value='0'>\n");
835 			printf("<input type='hidden' name='smin' value='0'>\n");
836 			printf("<input type='hidden' name='ssec' value='0'>\n");
837 			printf("</td>\n");
838 			printf("</tr>\n");
839 
840 			printf("<tr>");
841 			printf("<td valign=top class='reportSelectSubTitle'>End Date (Inclusive):</td>\n");
842 			printf("<td align=left valign=top class='reportSelectItem'>");
843 			printf("<select name='emon'>\n");
844 			printf("<option value='1' %s>January\n", (t->tm_mon == 0) ? "SELECTED" : "");
845 			printf("<option value='2' %s>February\n", (t->tm_mon == 1) ? "SELECTED" : "");
846 			printf("<option value='3' %s>March\n", (t->tm_mon == 2) ? "SELECTED" : "");
847 			printf("<option value='4' %s>April\n", (t->tm_mon == 3) ? "SELECTED" : "");
848 			printf("<option value='5' %s>May\n", (t->tm_mon == 4) ? "SELECTED" : "");
849 			printf("<option value='6' %s>June\n", (t->tm_mon == 5) ? "SELECTED" : "");
850 			printf("<option value='7' %s>July\n", (t->tm_mon == 6) ? "SELECTED" : "");
851 			printf("<option value='8' %s>August\n", (t->tm_mon == 7) ? "SELECTED" : "");
852 			printf("<option value='9' %s>September\n", (t->tm_mon == 8) ? "SELECTED" : "");
853 			printf("<option value='10' %s>October\n", (t->tm_mon == 9) ? "SELECTED" : "");
854 			printf("<option value='11' %s>November\n", (t->tm_mon == 10) ? "SELECTED" : "");
855 			printf("<option value='12' %s>December\n", (t->tm_mon == 11) ? "SELECTED" : "");
856 			printf("</select>\n ");
857 			printf("<input type='text' size='2' maxlength='2' name='eday' value='%d'> ", end_day);
858 			printf("<input type='text' size='4' maxlength='4' name='eyear' value='%d'>", end_year);
859 			printf("<input type='hidden' name='ehour' value='24'>\n");
860 			printf("<input type='hidden' name='emin' value='0'>\n");
861 			printf("<input type='hidden' name='esec' value='0'>\n");
862 			printf("</td>\n");
863 			printf("</tr>\n");
864 
865 			printf("<tr><td colspan=2><br></td></tr>\n");
866 
867 			printf("<tr><td class='reportSelectSubTitle' align=right>Statistics Breakdown:</td>\n");
868 			printf("<td class='reportSelectItem'>\n");
869 			printf("<select name='breakdown'>\n");
870 			printf("<option value=monthly>Month\n");
871 			printf("<option value=dayofmonth SELECTED>Day of the Month\n");
872 			printf("<option value=dayofweek>Day of the Week\n");
873 			printf("<option value=hourly>Hour of the Day\n");
874 			printf("</select>\n");
875 			printf("</td></tr>\n");
876 
877 			printf("<tr><td class='reportSelectSubTitle' align=right>Events To Graph:</td>\n");
878 			printf("<td class='reportSelectItem'>\n");
879 			printf("<select name='graphevents'>\n");
880 			if(display_type == DISPLAY_HOST_HISTOGRAM) {
881 				printf("<option value=%d %s>All host events\n", GRAPH_HOST_ALL, (graph_events == GRAPH_HOST_ALL) ? "SELECTED" : "");
882 				printf("<option value=%d %s>Host problem events\n", GRAPH_HOST_PROBLEMS, (graph_events == GRAPH_HOST_PROBLEMS) ? "SELECTED" : "");
883 				printf("<option value=%d %s>Host up events\n", GRAPH_HOST_UP, (graph_events == GRAPH_HOST_UP) ? "SELECTED" : "");
884 				printf("<option value=%d %s>Host down events\n", GRAPH_HOST_DOWN, (graph_events == GRAPH_HOST_DOWN) ? "SELECTED" : "");
885 				printf("<option value=%d %s>Host unreachable events\n", GRAPH_HOST_UNREACHABLE, (graph_events == GRAPH_HOST_UNREACHABLE) ? "SELECTED" : "");
886 				}
887 			else {
888 				printf("<option value=%d %s>All service events\n", GRAPH_SERVICE_ALL, (graph_events == GRAPH_SERVICE_ALL) ? "SELECTED" : "");
889 				printf("<option value=%d %s>Service problem events\n", GRAPH_SERVICE_PROBLEMS, (graph_events == GRAPH_SERVICE_PROBLEMS) ? "SELECTED" : "");
890 				printf("<option value=%d %s>Service ok events\n", GRAPH_SERVICE_OK, (graph_events == GRAPH_SERVICE_OK) ? "SELECTED" : "");
891 				printf("<option value=%d %s>Service warning events\n", GRAPH_SERVICE_WARNING, (graph_events == GRAPH_SERVICE_WARNING) ? "SELECTED" : "");
892 				printf("<option value=%d %s>Service unknown events\n", GRAPH_SERVICE_UNKNOWN, (graph_events == GRAPH_SERVICE_UNKNOWN) ? "SELECTED" : "");
893 				printf("<option value=%d %s>Service critical events\n", GRAPH_SERVICE_CRITICAL, (graph_events == GRAPH_SERVICE_CRITICAL) ? "SELECTED" : "");
894 				}
895 			printf("</select>\n");
896 			printf("</td></tr>\n");
897 
898 			printf("<tr><td class='reportSelectSubTitle' align=right>State Types To Graph:</td>\n");
899 			printf("<td class='reportSelectItem'>\n");
900 			printf("<select name='graphstatetypes'>\n");
901 			printf("<option value=%d>Hard states\n", GRAPH_HARD_STATETYPES);
902 			printf("<option value=%d>Soft states\n", GRAPH_SOFT_STATETYPES);
903 			printf("<option value=%d SELECTED>Hard and soft states\n", GRAPH_ALL_STATETYPES);
904 			printf("</select>\n");
905 			printf("</td></tr>\n");
906 
907 			printf("<tr><td class='reportSelectSubTitle' align=right>Assume State Retention:</td>\n");
908 			printf("<td class='reportSelectItem'>\n");
909 			printf("<select name='assumestateretention'>\n");
910 			printf("<option value='yes'>Yes\n");
911 			printf("<option value='no'>No\n");
912 			printf("</select>\n");
913 			printf("</td></tr>\n");
914 
915 			printf("<tr><td class='reportSelectSubTitle' align=right>Initial States Logged:</td>\n");
916 			printf("<td class='reportSelectItem'>\n");
917 			printf("<select name='initialstateslogged'>\n");
918 			printf("<option value='yes'>Yes\n");
919 			printf("<option value='no' SELECTED>No\n");
920 			printf("</select>\n");
921 			printf("</td></tr>\n");
922 
923 			printf("<tr><td class='reportSelectSubTitle' align=right>Ignore Repeated States:</td>\n");
924 			printf("<td class='reportSelectItem'>\n");
925 			printf("<select name='newstatesonly'>\n");
926 			printf("<option value='yes'>Yes\n");
927 			printf("<option value='no' SELECTED>No\n");
928 			printf("</select>\n");
929 			printf("</td></tr>\n");
930 
931 			printf("<tr><td></td><td class='reportSelectItem'><input type='submit' value='Create Report'></td></tr>\n");
932 
933 			printf("</TABLE>\n");
934 			printf("</form>\n");
935 
936 			printf("</DIV></P>\n");
937 			}
938 
939 		/* as the user whether they want a graph for a host or service */
940 		else {
941 			printf("<P><DIV ALIGN=CENTER>\n");
942 			printf("<DIV CLASS='reportSelectTitle'>Step 1: Select Report Type</DIV>\n");
943 			printf("</DIV></P>\n");
944 
945 			printf("<P><DIV ALIGN=CENTER>\n");
946 
947 			printf("<form method=\"GET\" action=\"%s\">\n", HISTOGRAM_CGI);
948 			printf("<TABLE BORDER=0 cellpadding=5>\n");
949 			printf("<tr><td class='reportSelectSubTitle' align=right>Type:</td>\n");
950 			printf("<td class='reportSelectItem'>\n");
951 			printf("<select name='input'>\n");
952 			printf("<option value=gethost>Host\n");
953 			printf("<option value=getservice>Service\n");
954 			printf("</select>\n");
955 			printf("</td></tr>\n");
956 
957 			printf("<tr><td></td><td class='reportSelectItem'>\n");
958 			printf("<input type='submit' value='Continue to Step 2'>\n");
959 			printf("</td></tr>\n");
960 
961 			printf("</TABLE>\n");
962 			printf("</form>\n");
963 
964 			printf("</DIV></P>\n");
965 			}
966 
967 		}
968 
969 	document_footer();
970 
971 	/* free all other allocated memory */
972 	free_memory();
973 
974 	return OK;
975 	}
976 
977 
document_header(int use_stylesheet)978 void document_header(int use_stylesheet) {
979 	char date_time[MAX_DATETIME_LENGTH];
980 	time_t current_time;
981 	time_t expire_time;
982 
983 	if(mode == CREATE_HTML) {
984 		printf("Cache-Control: no-store\r\n");
985 		printf("Pragma: no-cache\r\n");
986 
987 		time(&current_time);
988 		get_time_string(&current_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
989 		printf("Last-Modified: %s\r\n", date_time);
990 
991 		expire_time = (time_t)0;
992 		get_time_string(&expire_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
993 		printf("Expires: %s\r\n", date_time);
994 
995 		printf("Content-type: text/html\r\n\r\n");
996 
997 		if(embedded == TRUE)
998 			return;
999 
1000 		printf("<html>\n");
1001 		printf("<head>\n");
1002 		printf("<link rel=\"shortcut icon\" href=\"%sfavicon.ico\" type=\"image/ico\">\n", url_images_path);
1003 		printf("<title>\n");
1004 		printf("Nagios Histogram\n");
1005 		printf("</title>\n");
1006 
1007 		if(use_stylesheet == TRUE) {
1008 			printf("<LINK REL='stylesheet' TYPE='text/css' HREF='%s%s'>\n", url_stylesheets_path, COMMON_CSS);
1009 			printf("<LINK REL='stylesheet' TYPE='text/css' HREF='%s%s'>\n", url_stylesheets_path, HISTOGRAM_CSS);
1010 			}
1011 
1012 		printf("</head>\n");
1013 
1014 		printf("<BODY CLASS='histogram'>\n");
1015 
1016 		/* include user SSI header */
1017 		include_ssi_files(HISTOGRAM_CGI, SSI_HEADER);
1018 
1019 		printf("<div id=\"popup\" style=\"position:absolute; z-index:1; visibility: hidden\"></div>\n");
1020 		}
1021 
1022 	else {
1023 		printf("Cache-Control: no-store\r\n");
1024 		printf("Pragma: no-cache\r\n");
1025 
1026 		time(&current_time);
1027 		get_time_string(&current_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
1028 		printf("Last-Modified: %s\r\n", date_time);
1029 
1030 		expire_time = (time_t)0L;
1031 		get_time_string(&expire_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
1032 		printf("Expires: %s\r\n", date_time);
1033 
1034 		printf("Content-Type: image/png\r\n\r\n");
1035 		}
1036 
1037 	return;
1038 	}
1039 
1040 
1041 
document_footer(void)1042 void document_footer(void) {
1043 
1044 	if(embedded == TRUE)
1045 		return;
1046 
1047 	if(mode == CREATE_HTML) {
1048 
1049 		/* include user SSI footer */
1050 		include_ssi_files(HISTOGRAM_CGI, SSI_FOOTER);
1051 
1052 		printf("</body>\n");
1053 		printf("</html>\n");
1054 		}
1055 
1056 	return;
1057 	}
1058 
1059 
1060 
process_cgivars(void)1061 int process_cgivars(void) {
1062 	char **variables;
1063 	int error = FALSE;
1064 	int x;
1065 
1066 	variables = getcgivars();
1067 
1068 	for(x = 0; variables[x] != NULL; x++) {
1069 
1070 		/* do some basic length checking on the variable identifier to prevent buffer overflows */
1071 		if(strlen(variables[x]) >= MAX_INPUT_BUFFER - 1) {
1072 			continue;
1073 			}
1074 
1075 		/* we found the host argument */
1076 		else if(!strcmp(variables[x], "host")) {
1077 			x++;
1078 			if(variables[x] == NULL) {
1079 				error = TRUE;
1080 				break;
1081 				}
1082 
1083 			if((host_name = (char *)strdup(variables[x])) == NULL)
1084 				host_name = "";
1085 			strip_html_brackets(host_name);
1086 
1087 			display_type = DISPLAY_HOST_HISTOGRAM;
1088 			}
1089 
1090 		/* we found the node width argument */
1091 		else if(!strcmp(variables[x], "service")) {
1092 			x++;
1093 			if(variables[x] == NULL) {
1094 				error = TRUE;
1095 				break;
1096 				}
1097 
1098 			if((svc_description = (char *)strdup(variables[x])) == NULL)
1099 				svc_description = "";
1100 			strip_html_brackets(svc_description);
1101 
1102 			display_type = DISPLAY_SERVICE_HISTOGRAM;
1103 			}
1104 
1105 		/* we found first time argument */
1106 		else if(!strcmp(variables[x], "t1")) {
1107 			x++;
1108 			if(variables[x] == NULL) {
1109 				error = TRUE;
1110 				break;
1111 				}
1112 
1113 			t1 = (time_t)strtoul(variables[x], NULL, 10);
1114 			timeperiod_type = TIMEPERIOD_CUSTOM;
1115 			}
1116 
1117 		/* we found first time argument */
1118 		else if(!strcmp(variables[x], "t2")) {
1119 			x++;
1120 			if(variables[x] == NULL) {
1121 				error = TRUE;
1122 				break;
1123 				}
1124 
1125 			t2 = (time_t)strtoul(variables[x], NULL, 10);
1126 			timeperiod_type = TIMEPERIOD_CUSTOM;
1127 			}
1128 
1129 		/* we found the image creation option */
1130 		else if(!strcmp(variables[x], "createimage")) {
1131 			mode = CREATE_IMAGE;
1132 			}
1133 
1134 		/* we found the backtrack archives argument */
1135 		else if(!strcmp(variables[x], "backtrack")) {
1136 			x++;
1137 			if(variables[x] == NULL) {
1138 				error = TRUE;
1139 				break;
1140 				}
1141 
1142 			backtrack_archives = atoi(variables[x]);
1143 			if(backtrack_archives < 0)
1144 				backtrack_archives = 0;
1145 			if(backtrack_archives > MAX_ARCHIVE_BACKTRACKS)
1146 				backtrack_archives = MAX_ARCHIVE_BACKTRACKS;
1147 			}
1148 
1149 		/* we found the standard timeperiod argument */
1150 		else if(!strcmp(variables[x], "timeperiod")) {
1151 			x++;
1152 			if(variables[x] == NULL) {
1153 				error = TRUE;
1154 				break;
1155 				}
1156 
1157 			if(!strcmp(variables[x], "today"))
1158 				timeperiod_type = TIMEPERIOD_TODAY;
1159 			else if(!strcmp(variables[x], "yesterday"))
1160 				timeperiod_type = TIMEPERIOD_YESTERDAY;
1161 			else if(!strcmp(variables[x], "thisweek"))
1162 				timeperiod_type = TIMEPERIOD_THISWEEK;
1163 			else if(!strcmp(variables[x], "lastweek"))
1164 				timeperiod_type = TIMEPERIOD_LASTWEEK;
1165 			else if(!strcmp(variables[x], "thismonth"))
1166 				timeperiod_type = TIMEPERIOD_THISMONTH;
1167 			else if(!strcmp(variables[x], "lastmonth"))
1168 				timeperiod_type = TIMEPERIOD_LASTMONTH;
1169 			else if(!strcmp(variables[x], "thisquarter"))
1170 				timeperiod_type = TIMEPERIOD_THISQUARTER;
1171 			else if(!strcmp(variables[x], "lastquarter"))
1172 				timeperiod_type = TIMEPERIOD_LASTQUARTER;
1173 			else if(!strcmp(variables[x], "thisyear"))
1174 				timeperiod_type = TIMEPERIOD_THISYEAR;
1175 			else if(!strcmp(variables[x], "lastyear"))
1176 				timeperiod_type = TIMEPERIOD_LASTYEAR;
1177 			else if(!strcmp(variables[x], "last24hours"))
1178 				timeperiod_type = TIMEPERIOD_LAST24HOURS;
1179 			else if(!strcmp(variables[x], "last7days"))
1180 				timeperiod_type = TIMEPERIOD_LAST7DAYS;
1181 			else if(!strcmp(variables[x], "last31days"))
1182 				timeperiod_type = TIMEPERIOD_LAST31DAYS;
1183 			else if(!strcmp(variables[x], "custom"))
1184 				timeperiod_type = TIMEPERIOD_CUSTOM;
1185 			else
1186 				timeperiod_type = TIMEPERIOD_TODAY;
1187 
1188 
1189 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1190 				convert_timeperiod_to_times(timeperiod_type);
1191 			}
1192 
1193 		/* we found time argument */
1194 		else if(!strcmp(variables[x], "smon")) {
1195 			x++;
1196 			if(variables[x] == NULL) {
1197 				error = TRUE;
1198 				break;
1199 				}
1200 
1201 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1202 				continue;
1203 
1204 			start_month = atoi(variables[x]);
1205 			timeperiod_type = TIMEPERIOD_CUSTOM;
1206 			compute_time_from_parts = TRUE;
1207 			}
1208 
1209 		/* we found time argument */
1210 		else if(!strcmp(variables[x], "sday")) {
1211 			x++;
1212 			if(variables[x] == NULL) {
1213 				error = TRUE;
1214 				break;
1215 				}
1216 
1217 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1218 				continue;
1219 
1220 			start_day = atoi(variables[x]);
1221 			timeperiod_type = TIMEPERIOD_CUSTOM;
1222 			compute_time_from_parts = TRUE;
1223 			}
1224 
1225 		/* we found time argument */
1226 		else if(!strcmp(variables[x], "syear")) {
1227 			x++;
1228 			if(variables[x] == NULL) {
1229 				error = TRUE;
1230 				break;
1231 				}
1232 
1233 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1234 				continue;
1235 
1236 			start_year = atoi(variables[x]);
1237 			timeperiod_type = TIMEPERIOD_CUSTOM;
1238 			compute_time_from_parts = TRUE;
1239 			}
1240 
1241 		/* we found time argument */
1242 		else if(!strcmp(variables[x], "smin")) {
1243 			x++;
1244 			if(variables[x] == NULL) {
1245 				error = TRUE;
1246 				break;
1247 				}
1248 
1249 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1250 				continue;
1251 
1252 			start_minute = atoi(variables[x]);
1253 			timeperiod_type = TIMEPERIOD_CUSTOM;
1254 			compute_time_from_parts = TRUE;
1255 			}
1256 
1257 		/* we found time argument */
1258 		else if(!strcmp(variables[x], "ssec")) {
1259 			x++;
1260 			if(variables[x] == NULL) {
1261 				error = TRUE;
1262 				break;
1263 				}
1264 
1265 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1266 				continue;
1267 
1268 			start_second = atoi(variables[x]);
1269 			timeperiod_type = TIMEPERIOD_CUSTOM;
1270 			compute_time_from_parts = TRUE;
1271 			}
1272 
1273 		/* we found time argument */
1274 		else if(!strcmp(variables[x], "shour")) {
1275 			x++;
1276 			if(variables[x] == NULL) {
1277 				error = TRUE;
1278 				break;
1279 				}
1280 
1281 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1282 				continue;
1283 
1284 			start_hour = atoi(variables[x]);
1285 			timeperiod_type = TIMEPERIOD_CUSTOM;
1286 			compute_time_from_parts = TRUE;
1287 			}
1288 
1289 
1290 		/* we found time argument */
1291 		else if(!strcmp(variables[x], "emon")) {
1292 			x++;
1293 			if(variables[x] == NULL) {
1294 				error = TRUE;
1295 				break;
1296 				}
1297 
1298 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1299 				continue;
1300 
1301 			end_month = atoi(variables[x]);
1302 			timeperiod_type = TIMEPERIOD_CUSTOM;
1303 			compute_time_from_parts = TRUE;
1304 			}
1305 
1306 		/* we found time argument */
1307 		else if(!strcmp(variables[x], "eday")) {
1308 			x++;
1309 			if(variables[x] == NULL) {
1310 				error = TRUE;
1311 				break;
1312 				}
1313 
1314 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1315 				continue;
1316 
1317 			end_day = atoi(variables[x]);
1318 			timeperiod_type = TIMEPERIOD_CUSTOM;
1319 			compute_time_from_parts = TRUE;
1320 			}
1321 
1322 		/* we found time argument */
1323 		else if(!strcmp(variables[x], "eyear")) {
1324 			x++;
1325 			if(variables[x] == NULL) {
1326 				error = TRUE;
1327 				break;
1328 				}
1329 
1330 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1331 				continue;
1332 
1333 			end_year = atoi(variables[x]);
1334 			timeperiod_type = TIMEPERIOD_CUSTOM;
1335 			compute_time_from_parts = TRUE;
1336 			}
1337 
1338 		/* we found time argument */
1339 		else if(!strcmp(variables[x], "emin")) {
1340 			x++;
1341 			if(variables[x] == NULL) {
1342 				error = TRUE;
1343 				break;
1344 				}
1345 
1346 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1347 				continue;
1348 
1349 			end_minute = atoi(variables[x]);
1350 			timeperiod_type = TIMEPERIOD_CUSTOM;
1351 			compute_time_from_parts = TRUE;
1352 			}
1353 
1354 		/* we found time argument */
1355 		else if(!strcmp(variables[x], "esec")) {
1356 			x++;
1357 			if(variables[x] == NULL) {
1358 				error = TRUE;
1359 				break;
1360 				}
1361 
1362 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1363 				continue;
1364 
1365 			end_second = atoi(variables[x]);
1366 			timeperiod_type = TIMEPERIOD_CUSTOM;
1367 			compute_time_from_parts = TRUE;
1368 			}
1369 
1370 		/* we found time argument */
1371 		else if(!strcmp(variables[x], "ehour")) {
1372 			x++;
1373 			if(variables[x] == NULL) {
1374 				error = TRUE;
1375 				break;
1376 				}
1377 
1378 			if(timeperiod_type != TIMEPERIOD_CUSTOM)
1379 				continue;
1380 
1381 			end_hour = atoi(variables[x]);
1382 			timeperiod_type = TIMEPERIOD_CUSTOM;
1383 			compute_time_from_parts = TRUE;
1384 			}
1385 
1386 		/* we found the embed option */
1387 		else if(!strcmp(variables[x], "embedded"))
1388 			embedded = TRUE;
1389 
1390 		/* we found the noheader option */
1391 		else if(!strcmp(variables[x], "noheader"))
1392 			display_header = FALSE;
1393 
1394 		/* we found the input option */
1395 		else if(!strcmp(variables[x], "input")) {
1396 			x++;
1397 			if(variables[x] == NULL) {
1398 				error = TRUE;
1399 				break;
1400 				}
1401 
1402 			if(!strcmp(variables[x], "gethost"))
1403 				input_type = GET_INPUT_HOST_TARGET;
1404 			else if(!strcmp(variables[x], "getservice"))
1405 				input_type = GET_INPUT_SERVICE_TARGET;
1406 			else if(!strcmp(variables[x], "getoptions"))
1407 				input_type = GET_INPUT_OPTIONS;
1408 			else
1409 				input_type = GET_INPUT_TARGET_TYPE;
1410 			}
1411 
1412 		/* we found the graph states option */
1413 		else if(!strcmp(variables[x], "graphevents")) {
1414 			x++;
1415 			if(variables[x] == NULL) {
1416 				error = TRUE;
1417 				break;
1418 				}
1419 
1420 			graph_events = atoi(variables[x]);
1421 			}
1422 
1423 		/* we found the graph state types option */
1424 		else if(!strcmp(variables[x], "graphstatetypes")) {
1425 			x++;
1426 			if(variables[x] == NULL) {
1427 				error = TRUE;
1428 				break;
1429 				}
1430 
1431 			graph_statetypes = atoi(variables[x]);
1432 			}
1433 
1434 		/* we found the breakdown option */
1435 		else if(!strcmp(variables[x], "breakdown")) {
1436 			x++;
1437 			if(variables[x] == NULL) {
1438 				error = TRUE;
1439 				break;
1440 				}
1441 
1442 			if(!strcmp(variables[x], "monthly"))
1443 				breakdown_type = BREAKDOWN_MONTHLY;
1444 			else if(!strcmp(variables[x], "dayofmonth"))
1445 				breakdown_type = BREAKDOWN_DAY_OF_MONTH;
1446 			else if(!strcmp(variables[x], "dayofweek"))
1447 				breakdown_type = BREAKDOWN_DAY_OF_WEEK;
1448 			else
1449 				breakdown_type = BREAKDOWN_HOURLY;
1450 			}
1451 
1452 		/* we found the assume state retention option */
1453 		else if(!strcmp(variables[x], "assumestateretention")) {
1454 			x++;
1455 			if(variables[x] == NULL) {
1456 				error = TRUE;
1457 				break;
1458 				}
1459 
1460 			if(!strcmp(variables[x], "yes"))
1461 				assume_state_retention = TRUE;
1462 			else
1463 				assume_state_retention = FALSE;
1464 			}
1465 
1466 		/* we found the initial states logged option */
1467 		else if(!strcmp(variables[x], "initialstateslogged")) {
1468 			x++;
1469 			if(variables[x] == NULL) {
1470 				error = TRUE;
1471 				break;
1472 				}
1473 
1474 			if(!strcmp(variables[x], "yes"))
1475 				initial_states_logged = TRUE;
1476 			else
1477 				initial_states_logged = FALSE;
1478 
1479 			}
1480 
1481 		/* we found the new states only option */
1482 		else if(!strcmp(variables[x], "newstatesonly")) {
1483 			x++;
1484 			if(variables[x] == NULL) {
1485 				error = TRUE;
1486 				break;
1487 				}
1488 
1489 			if(!strcmp(variables[x], "yes"))
1490 				new_states_only = TRUE;
1491 			else
1492 				new_states_only = FALSE;
1493 
1494 			}
1495 		}
1496 
1497 	/* free memory allocated to the CGI variables */
1498 	free_cgivars(variables);
1499 
1500 	return error;
1501 	}
1502 
1503 
1504 
1505 /* graphs histogram data */
graph_all_histogram_data(void)1506 void graph_all_histogram_data(void) {
1507 	int pixel_x;
1508 	int pixel_y;
1509 	int last_pixel_y;
1510 	int current_bucket;
1511 	int actual_bucket;
1512 	unsigned long max_value;
1513 	double x_scaling_factor;
1514 	double y_scaling_factor;
1515 	double x_units;
1516 	double y_units;
1517 	int current_unit;
1518 	int actual_unit;
1519 	char temp_buffer[MAX_INPUT_BUFFER];
1520 	int string_width;
1521 	int string_height;
1522 	char *days[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
1523 	char *months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
1524 	char start_time[MAX_INPUT_BUFFER];
1525 	char end_time[MAX_INPUT_BUFFER];
1526 
1527 	unsigned long state1_max = 0L;
1528 	unsigned long state1_min = 0L;
1529 	int have_state1_min = FALSE;
1530 	unsigned long state1_sum = 0L;
1531 	double state1_avg = 0.0;
1532 	unsigned long state2_max = 0L;
1533 	unsigned long state2_min = 0L;
1534 	int have_state2_min = FALSE;
1535 	unsigned long state2_sum = 0L;
1536 	double state2_avg = 0.0;
1537 	unsigned long state3_max = 0L;
1538 	unsigned long state3_min = 0L;
1539 	int have_state3_min = FALSE;
1540 	unsigned long state3_sum = 0L;
1541 	double state3_avg = 0.0;
1542 	unsigned long state4_max = 0L;
1543 	unsigned long state4_min = 0L;
1544 	int have_state4_min = FALSE;
1545 	unsigned long state4_sum = 0L;
1546 	double state4_avg = 0.0;
1547 
1548 
1549 #ifdef DEBUG
1550 	printf("Total Buckets: %d\n", total_buckets);
1551 #endif
1552 
1553 	/* determine max value in the buckets (for scaling) */
1554 	max_value = 0L;
1555 	for(current_bucket = 0; current_bucket < total_buckets; current_bucket++) {
1556 		if(tsdata[current_bucket].service_ok > max_value)
1557 			max_value = tsdata[current_bucket].service_ok;
1558 		if(tsdata[current_bucket].service_warning > max_value)
1559 			max_value = tsdata[current_bucket].service_warning;
1560 		if(tsdata[current_bucket].service_unknown > max_value)
1561 			max_value = tsdata[current_bucket].service_unknown;
1562 		if(tsdata[current_bucket].service_critical > max_value)
1563 			max_value = tsdata[current_bucket].service_critical;
1564 		if(tsdata[current_bucket].host_up > max_value)
1565 			max_value = tsdata[current_bucket].host_up;
1566 		if(tsdata[current_bucket].host_down > max_value)
1567 			max_value = tsdata[current_bucket].host_down;
1568 		if(tsdata[current_bucket].host_unreachable > max_value)
1569 			max_value = tsdata[current_bucket].host_unreachable;
1570 		}
1571 
1572 #ifdef DEBUG
1573 	printf("Done determining max bucket values\n");
1574 	printf("MAX_VALUE=%lu\n", max_value);
1575 	printf("DRAWING_HEIGHT=%lu\n", DRAWING_HEIGHT);
1576 #endif
1577 
1578 	/* min number of values to graph */
1579 	if(max_value < 10)
1580 		max_value = 10;
1581 #ifdef DEBUG
1582 	printf("ADJUSTED MAX_VALUE=%lu\n", max_value);
1583 #endif
1584 
1585 	/* determine y scaling factor */
1586 	/*y_scaling_factor=floor((double)DRAWING_HEIGHT/(double)max_value);*/
1587 	y_scaling_factor = (double)((double)DRAWING_HEIGHT / (double)max_value);
1588 
1589 	/* determine x scaling factor */
1590 	x_scaling_factor = (double)((double)DRAWING_WIDTH / (double)total_buckets);
1591 
1592 	/* determine y units resolution - we want a max of about 10 y grid lines */
1593 	/*
1594 	y_units=(double)((double)DRAWING_HEIGHT/19.0);
1595 	y_units=ceil(y_units/y_scaling_factor)*y_scaling_factor;
1596 	*/
1597 	y_units = ceil(19.0 / y_scaling_factor);
1598 
1599 	/* determine x units resolution */
1600 	if(breakdown_type == BREAKDOWN_HOURLY)
1601 		x_units = (double)((double)DRAWING_WIDTH / (double)(total_buckets / 4.0));
1602 	else
1603 		x_units = x_scaling_factor;
1604 
1605 #ifdef DEBUG
1606 	printf("DRAWING_WIDTH: %d\n", DRAWING_WIDTH);
1607 	printf("DRAWING_HEIGHT: %d\n", DRAWING_HEIGHT);
1608 	printf("max_value: %lu\n", max_value);
1609 	printf("x_scaling_factor: %.3f\n", x_scaling_factor);
1610 	printf("y_scaling_factor: %.3f\n", y_scaling_factor);
1611 	printf("x_units: %.3f\n", x_units);
1612 	printf("y_units: %.3f\n", y_units);
1613 	printf("y units to draw: %.3f\n", ((double)max_value / y_units));
1614 #endif
1615 
1616 	string_height = gdFontSmall->h;
1617 
1618 #ifdef DEBUG
1619 	printf("Starting to draw Y grid lines...\n");
1620 #endif
1621 
1622 	/* draw y grid lines */
1623 	if(max_value > 0) {
1624 		for(current_unit = 1; (current_unit * y_units * y_scaling_factor) <= DRAWING_HEIGHT; current_unit++) {
1625 			draw_dashed_line(DRAWING_X_OFFSET, DRAWING_Y_OFFSET - (current_unit * y_units * y_scaling_factor), DRAWING_X_OFFSET + DRAWING_WIDTH, DRAWING_Y_OFFSET - (current_unit * y_units * y_scaling_factor), color_lightgray);
1626 #ifdef DEBUG
1627 			printf("  Drawing Y unit #%d @ %d\n", current_unit, (int)(current_unit * y_units * y_scaling_factor));
1628 #endif
1629 			}
1630 		}
1631 
1632 #ifdef DEBUG
1633 	printf("Starting to draw X grid lines...\n");
1634 #endif
1635 
1636 	/* draw x grid lines */
1637 	for(current_unit = 1; (int)(current_unit * x_units) <= DRAWING_WIDTH; current_unit++)
1638 		draw_dashed_line(DRAWING_X_OFFSET + (int)(current_unit * x_units), DRAWING_Y_OFFSET, DRAWING_X_OFFSET + (int)(current_unit * x_units), DRAWING_Y_OFFSET - DRAWING_HEIGHT, color_lightgray);
1639 
1640 #ifdef DEBUG
1641 	printf("Starting to draw grid units...\n");
1642 #endif
1643 
1644 	/* draw y units */
1645 	if(max_value > 0) {
1646 		for(current_unit = 0; (current_unit * y_units * y_scaling_factor) <= DRAWING_HEIGHT; current_unit++) {
1647 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%d", (int)(current_unit * y_units));
1648 			temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1649 			string_width = gdFontSmall->w * strlen(temp_buffer);
1650 			gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET - string_width - 5, DRAWING_Y_OFFSET - (current_unit * y_units * y_scaling_factor) - (string_height / 2), (unsigned char *)temp_buffer, color_black);
1651 			}
1652 		}
1653 
1654 	/* draw x units */
1655 	for(current_unit = 0, actual_unit = 0; (int)(current_unit * x_units) <= DRAWING_WIDTH; current_unit++, actual_unit++) {
1656 
1657 		if(actual_unit >= total_buckets)
1658 			actual_unit = 0;
1659 
1660 		if(breakdown_type == BREAKDOWN_MONTHLY)
1661 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%s", months[actual_unit]);
1662 		else if(breakdown_type == BREAKDOWN_DAY_OF_MONTH)
1663 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%d", actual_unit + 1);
1664 		else if(breakdown_type == BREAKDOWN_DAY_OF_WEEK)
1665 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%s", days[actual_unit]);
1666 		else
1667 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%02d:00", (actual_unit == 24) ? 0 : actual_unit);
1668 
1669 		temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1670 		string_width = gdFontSmall->w * strlen(temp_buffer);
1671 
1672 		gdImageStringUp(histogram_image, gdFontSmall, DRAWING_X_OFFSET + (current_unit * x_units) - (string_height / 2), DRAWING_Y_OFFSET + 5 + string_width, (unsigned char *)temp_buffer, color_black);
1673 		}
1674 
1675 	/* draw y unit measure */
1676 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Number of Events");
1677 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1678 	string_width = gdFontSmall->w * strlen(temp_buffer);
1679 	gdImageStringUp(histogram_image, gdFontSmall, 0, DRAWING_Y_OFFSET - (DRAWING_HEIGHT / 2) + (string_width / 2), (unsigned char *)temp_buffer, color_black);
1680 
1681 	/* draw x unit measure */
1682 	if(breakdown_type == BREAKDOWN_MONTHLY)
1683 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Month");
1684 	else if(breakdown_type == BREAKDOWN_DAY_OF_MONTH)
1685 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Day of the Month");
1686 	else if(breakdown_type == BREAKDOWN_DAY_OF_WEEK)
1687 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Day of the Week");
1688 	else
1689 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Hour of the Day (15 minute increments)");
1690 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1691 	string_width = gdFontSmall->w * strlen(temp_buffer);
1692 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + (DRAWING_WIDTH / 2) - (string_width / 2), DRAWING_Y_OFFSET + 70, (unsigned char *)temp_buffer, color_black);
1693 
1694 	/* draw title */
1695 	snprintf(start_time, sizeof(start_time) - 1, "%s", ctime(&t1));
1696 	start_time[sizeof(start_time) - 1] = '\x0';
1697 	start_time[strlen(start_time) - 1] = '\x0';
1698 	snprintf(end_time, sizeof(end_time) - 1, "%s", ctime(&t2));
1699 	end_time[sizeof(end_time) - 1] = '\x0';
1700 	end_time[strlen(end_time) - 1] = '\x0';
1701 
1702 	if(display_type == DISPLAY_HOST_HISTOGRAM)
1703 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Event History For Host '%s'", host_name);
1704 	else
1705 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Event History For Service '%s' On Host '%s'", svc_description, host_name);
1706 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1707 	string_width = gdFontSmall->w * strlen(temp_buffer);
1708 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + (DRAWING_WIDTH / 2) - (string_width / 2), 0, (unsigned char *)temp_buffer, color_black);
1709 
1710 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%s to %s", start_time, end_time);
1711 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1712 	string_width = gdFontSmall->w * strlen(temp_buffer);
1713 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + (DRAWING_WIDTH / 2) - (string_width / 2), string_height + 5, (unsigned char *)temp_buffer, color_black);
1714 
1715 
1716 #ifdef DEBUG
1717 	printf("About to starting graphing (total_buckets=%d)...\n", total_buckets);
1718 #endif
1719 
1720 
1721 	/* graph service states */
1722 	if(display_type == DISPLAY_HOST_HISTOGRAM) {
1723 
1724 		/* graph host recoveries */
1725 		if(graph_events & GRAPH_HOST_UP) {
1726 
1727 			last_pixel_y = 0;
1728 			for(current_bucket = 0, actual_bucket = 0; current_bucket <= total_buckets; current_bucket++, actual_bucket++) {
1729 
1730 				if(actual_bucket >= total_buckets)
1731 					actual_bucket = 0;
1732 
1733 				pixel_x = (int)(current_bucket * x_scaling_factor);
1734 
1735 				pixel_y = (int)(tsdata[actual_bucket].host_up * y_scaling_factor);
1736 
1737 				if(current_bucket > 0 && !(last_pixel_y == 0 && pixel_y == 0))
1738 					draw_line(DRAWING_X_OFFSET + pixel_x - (int)x_scaling_factor, DRAWING_Y_OFFSET - last_pixel_y, DRAWING_X_OFFSET + pixel_x, DRAWING_Y_OFFSET - pixel_y, color_green);
1739 
1740 				last_pixel_y = pixel_y;
1741 
1742 				if(current_bucket < total_buckets) {
1743 					if(have_state1_min == FALSE || tsdata[actual_bucket].host_up < state1_min) {
1744 						state1_min = tsdata[actual_bucket].host_up;
1745 						have_state1_min = TRUE;
1746 						}
1747 					if(state1_max == 0 || tsdata[actual_bucket].host_up > state1_max)
1748 						state1_max = tsdata[actual_bucket].host_up;
1749 					state1_sum += tsdata[actual_bucket].host_up;
1750 					}
1751 				}
1752 			}
1753 
1754 #ifdef DEBUG
1755 		printf("Done graphing HOST UP states...\n");
1756 #endif
1757 
1758 		/* graph host down states */
1759 		if(graph_events & GRAPH_HOST_DOWN) {
1760 
1761 			last_pixel_y = 0;
1762 			for(current_bucket = 0, actual_bucket = 0; current_bucket <= total_buckets; current_bucket++, actual_bucket++) {
1763 
1764 				if(actual_bucket >= total_buckets)
1765 					actual_bucket = 0;
1766 
1767 				pixel_x = (int)(current_bucket * x_scaling_factor);
1768 
1769 				pixel_y = (int)(tsdata[actual_bucket].host_down * y_scaling_factor);
1770 
1771 				if(current_bucket > 0 && !(last_pixel_y == 0 && pixel_y == 0))
1772 					draw_line(DRAWING_X_OFFSET + pixel_x - (int)x_scaling_factor, DRAWING_Y_OFFSET - last_pixel_y, DRAWING_X_OFFSET + pixel_x, DRAWING_Y_OFFSET - pixel_y, color_red);
1773 
1774 				last_pixel_y = pixel_y;
1775 
1776 				if(current_bucket < total_buckets) {
1777 					if(have_state2_min == FALSE || tsdata[actual_bucket].host_down < state2_min) {
1778 						state2_min = tsdata[actual_bucket].host_down;
1779 						have_state2_min = TRUE;
1780 						}
1781 					if(state2_max == 0 || tsdata[actual_bucket].host_down > state2_max)
1782 						state2_max = tsdata[actual_bucket].host_down;
1783 					state2_sum += tsdata[actual_bucket].host_down;
1784 					}
1785 				}
1786 			}
1787 
1788 #ifdef DEBUG
1789 		printf("Done graphing HOST DOWN states...\n");
1790 #endif
1791 
1792 		/* graph host unreachable states */
1793 		if(graph_events & GRAPH_HOST_UNREACHABLE) {
1794 
1795 			last_pixel_y = 0;
1796 			for(current_bucket = 0, actual_bucket = 0; current_bucket <= total_buckets; current_bucket++, actual_bucket++) {
1797 
1798 				if(actual_bucket >= total_buckets)
1799 					actual_bucket = 0;
1800 
1801 				pixel_x = (int)(current_bucket * x_scaling_factor);
1802 
1803 				pixel_y = (int)(tsdata[actual_bucket].host_unreachable * y_scaling_factor);
1804 
1805 				if(current_bucket > 0 && !(last_pixel_y == 0 && pixel_y == 0))
1806 					draw_line(DRAWING_X_OFFSET + pixel_x - (int)x_scaling_factor, DRAWING_Y_OFFSET - last_pixel_y, DRAWING_X_OFFSET + pixel_x, DRAWING_Y_OFFSET - pixel_y, color_darkred);
1807 
1808 				last_pixel_y = pixel_y;
1809 
1810 				if(current_bucket < total_buckets) {
1811 					if(have_state3_min == FALSE || tsdata[actual_bucket].host_unreachable < state3_min) {
1812 						state3_min = tsdata[actual_bucket].host_unreachable;
1813 						have_state3_min = TRUE;
1814 						}
1815 					if(state3_max == 0 || tsdata[actual_bucket].host_unreachable > state3_max)
1816 						state3_max = tsdata[actual_bucket].host_unreachable;
1817 					state3_sum += tsdata[actual_bucket].host_unreachable;
1818 					}
1819 				}
1820 			}
1821 
1822 #ifdef DEBUG
1823 		printf("Done graphing HOST UNREACHABLE states...\n");
1824 #endif
1825 
1826 		}
1827 
1828 	/* graph service states */
1829 	else {
1830 
1831 		/* graph service recoveries */
1832 		if(graph_events & GRAPH_SERVICE_OK) {
1833 
1834 			last_pixel_y = 0;
1835 			for(current_bucket = 0, actual_bucket = 0; current_bucket <= total_buckets; current_bucket++, actual_bucket++) {
1836 
1837 				if(actual_bucket >= total_buckets)
1838 					actual_bucket = 0;
1839 
1840 				pixel_x = (int)(current_bucket * x_scaling_factor);
1841 
1842 				pixel_y = (int)(tsdata[actual_bucket].service_ok * y_scaling_factor);
1843 
1844 				if(current_bucket > 0 && !(last_pixel_y == 0 && pixel_y == 0))
1845 					draw_line(DRAWING_X_OFFSET + pixel_x - (int)x_scaling_factor, DRAWING_Y_OFFSET - last_pixel_y, DRAWING_X_OFFSET + pixel_x, DRAWING_Y_OFFSET - pixel_y, color_green);
1846 
1847 				last_pixel_y = pixel_y;
1848 
1849 				if(current_bucket < total_buckets) {
1850 					if(have_state1_min == FALSE || tsdata[actual_bucket].service_ok < state1_min) {
1851 						state1_min = tsdata[actual_bucket].service_ok;
1852 						have_state1_min = TRUE;
1853 						}
1854 					if(state1_max == 0 || tsdata[actual_bucket].service_ok > state1_max)
1855 						state1_max = tsdata[actual_bucket].service_ok;
1856 					state1_sum += tsdata[actual_bucket].service_ok;
1857 					}
1858 				}
1859 			}
1860 
1861 		/* graph service warning states */
1862 		if(graph_events & GRAPH_SERVICE_WARNING) {
1863 
1864 			last_pixel_y = 0;
1865 			for(current_bucket = 0, actual_bucket = 0; current_bucket <= total_buckets; current_bucket++, actual_bucket++) {
1866 
1867 				if(actual_bucket >= total_buckets)
1868 					actual_bucket = 0;
1869 
1870 				pixel_x = (int)(current_bucket * x_scaling_factor);
1871 
1872 				pixel_y = (int)(tsdata[actual_bucket].service_warning * y_scaling_factor);
1873 
1874 				if(current_bucket > 0 && !(last_pixel_y == 0 && pixel_y == 0))
1875 					draw_line(DRAWING_X_OFFSET + pixel_x - (int)x_scaling_factor, DRAWING_Y_OFFSET - last_pixel_y, DRAWING_X_OFFSET + pixel_x, DRAWING_Y_OFFSET - pixel_y, color_yellow);
1876 
1877 				last_pixel_y = pixel_y;
1878 
1879 				if(current_bucket < total_buckets) {
1880 					if(have_state2_min == FALSE || tsdata[actual_bucket].service_warning < state2_min) {
1881 						state2_min = tsdata[actual_bucket].service_warning;
1882 						have_state2_min = TRUE;
1883 						}
1884 					if(state2_max == 0 || tsdata[actual_bucket].service_warning > state2_max)
1885 						state2_max = tsdata[actual_bucket].service_warning;
1886 					state2_sum += tsdata[actual_bucket].service_warning;
1887 					}
1888 				}
1889 			}
1890 
1891 		/* graph service unknown states */
1892 		if(graph_events & GRAPH_SERVICE_UNKNOWN) {
1893 
1894 			last_pixel_y = 0;
1895 			for(current_bucket = 0, actual_bucket = 0; current_bucket <= total_buckets; current_bucket++, actual_bucket++) {
1896 
1897 				if(actual_bucket >= total_buckets)
1898 					actual_bucket = 0;
1899 
1900 				pixel_x = (int)(current_bucket * x_scaling_factor);
1901 
1902 				pixel_y = (int)(tsdata[actual_bucket].service_unknown * y_scaling_factor);
1903 
1904 				if(current_bucket > 0 && !(last_pixel_y == 0 && pixel_y == 0))
1905 					draw_line(DRAWING_X_OFFSET + pixel_x - (int)x_scaling_factor, DRAWING_Y_OFFSET - last_pixel_y, DRAWING_X_OFFSET + pixel_x, DRAWING_Y_OFFSET - pixel_y, color_orange);
1906 
1907 				last_pixel_y = pixel_y;
1908 
1909 				if(current_bucket < total_buckets) {
1910 					if(have_state3_min == FALSE || tsdata[actual_bucket].service_unknown < state3_min) {
1911 						state3_min = tsdata[actual_bucket].service_unknown;
1912 						have_state3_min = TRUE;
1913 						}
1914 					if(state3_max == 0 || tsdata[actual_bucket].service_unknown > state3_max)
1915 						state3_max = tsdata[actual_bucket].service_unknown;
1916 					state3_sum += tsdata[actual_bucket].service_unknown;
1917 					}
1918 				}
1919 			}
1920 
1921 		/* graph service critical states */
1922 		if(graph_events & GRAPH_SERVICE_CRITICAL) {
1923 
1924 			last_pixel_y = 0;
1925 			for(current_bucket = 0, actual_bucket = 0; current_bucket <= total_buckets; current_bucket++, actual_bucket++) {
1926 
1927 				if(actual_bucket >= total_buckets)
1928 					actual_bucket = 0;
1929 
1930 				pixel_x = (int)(current_bucket * x_scaling_factor);
1931 
1932 				pixel_y = (int)(tsdata[actual_bucket].service_critical * y_scaling_factor);
1933 
1934 				if(current_bucket > 0 && !(last_pixel_y == 0 && pixel_y == 0))
1935 					draw_line(DRAWING_X_OFFSET + pixel_x - (int)x_scaling_factor, DRAWING_Y_OFFSET - last_pixel_y, DRAWING_X_OFFSET + pixel_x, DRAWING_Y_OFFSET - pixel_y, color_red);
1936 
1937 				last_pixel_y = pixel_y;
1938 
1939 				if(current_bucket < total_buckets) {
1940 					if(have_state4_min == FALSE || tsdata[actual_bucket].service_critical < state4_min) {
1941 						state4_min = tsdata[actual_bucket].service_critical;
1942 						have_state4_min = TRUE;
1943 						}
1944 					if(state4_max == 0 || tsdata[actual_bucket].service_critical > state4_max)
1945 						state4_max = tsdata[actual_bucket].service_critical;
1946 					state4_sum += tsdata[actual_bucket].service_critical;
1947 					}
1948 				}
1949 			}
1950 		}
1951 
1952 #ifdef DEBUG
1953 	printf("Done graphing states...\n");
1954 #endif
1955 
1956 	/* draw graph boundaries */
1957 	draw_line(DRAWING_X_OFFSET, DRAWING_Y_OFFSET, DRAWING_X_OFFSET, DRAWING_Y_OFFSET - DRAWING_HEIGHT, color_black);
1958 	draw_line(DRAWING_X_OFFSET + DRAWING_WIDTH, DRAWING_Y_OFFSET, DRAWING_X_OFFSET + DRAWING_WIDTH, DRAWING_Y_OFFSET - DRAWING_HEIGHT, color_black);
1959 	draw_line(DRAWING_X_OFFSET, DRAWING_Y_OFFSET, DRAWING_X_OFFSET + DRAWING_WIDTH, DRAWING_Y_OFFSET, color_black);
1960 
1961 
1962 	/* graph stats */
1963 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "EVENT TYPE");
1964 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1965 	string_width = gdFontSmall->w * strlen(temp_buffer);
1966 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 15, DRAWING_Y_OFFSET - DRAWING_HEIGHT, (unsigned char *)temp_buffer, color_black);
1967 
1968 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "  MIN   MAX   SUM   AVG");
1969 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1970 	string_width = gdFontSmall->w * strlen(temp_buffer);
1971 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 115, DRAWING_Y_OFFSET - DRAWING_HEIGHT, (unsigned char *)temp_buffer, color_black);
1972 
1973 	draw_line(DRAWING_X_OFFSET + DRAWING_WIDTH + 15, DRAWING_Y_OFFSET - DRAWING_HEIGHT + string_height + 2, DRAWING_X_OFFSET + DRAWING_WIDTH + 275, DRAWING_Y_OFFSET - DRAWING_HEIGHT + string_height + 2, color_black);
1974 
1975 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Recovery (%s):", (display_type == DISPLAY_SERVICE_HISTOGRAM) ? "Ok" : "Up");
1976 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1977 	string_width = gdFontSmall->w * strlen(temp_buffer);
1978 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 15, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 1), (unsigned char *)temp_buffer, color_green);
1979 
1980 	state1_avg = (double)((double)state1_sum / (double)total_buckets);
1981 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%5lu %5lu %5lu   %.2f", state1_min, state1_max, state1_sum, state1_avg);
1982 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1983 	string_width = gdFontSmall->w * strlen(temp_buffer);
1984 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 115, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 1), (unsigned char *)temp_buffer, color_black);
1985 
1986 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%s:", (display_type == DISPLAY_SERVICE_HISTOGRAM) ? "Warning" : "Down");
1987 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1988 	string_width = gdFontSmall->w * strlen(temp_buffer);
1989 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 15, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 2), (unsigned char *)temp_buffer, (display_type == DISPLAY_SERVICE_HISTOGRAM) ? color_yellow : color_red);
1990 
1991 	state2_avg = (double)((double)state2_sum / (double)total_buckets);
1992 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%5lu %5lu %5lu   %.2f", state2_min, state2_max, state2_sum, state2_avg);
1993 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1994 	string_width = gdFontSmall->w * strlen(temp_buffer);
1995 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 115, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 2), (unsigned char *)temp_buffer, color_black);
1996 
1997 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%s:", (display_type == DISPLAY_SERVICE_HISTOGRAM) ? "Unknown" : "Unreachable");
1998 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1999 	string_width = gdFontSmall->w * strlen(temp_buffer);
2000 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 15, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 3), (unsigned char *)temp_buffer, (display_type == DISPLAY_SERVICE_HISTOGRAM) ? color_orange : color_darkred);
2001 
2002 	state3_avg = (double)((double)state3_sum / (double)total_buckets);
2003 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%5lu %5lu %5lu   %.2f", state3_min, state3_max, state3_sum, state3_avg);
2004 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
2005 	string_width = gdFontSmall->w * strlen(temp_buffer);
2006 	gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 115, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 3), (unsigned char *)temp_buffer, color_black);
2007 
2008 	if(display_type == DISPLAY_SERVICE_HISTOGRAM) {
2009 
2010 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Critical:");
2011 		temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
2012 		string_width = gdFontSmall->w * strlen(temp_buffer);
2013 		gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 15, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 4), (unsigned char *)temp_buffer, color_red);
2014 
2015 		state4_avg = (double)((double)state4_sum / (double)total_buckets);
2016 		snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%5lu %5lu %5lu   %.2f", state4_min, state4_max, state4_sum, state4_avg);
2017 		temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
2018 		string_width = gdFontSmall->w * strlen(temp_buffer);
2019 		gdImageString(histogram_image, gdFontSmall, DRAWING_X_OFFSET + DRAWING_WIDTH + 115, DRAWING_Y_OFFSET - DRAWING_HEIGHT + ((string_height + 5) * 4), (unsigned char *)temp_buffer, color_black);
2020 		}
2021 
2022 	return;
2023 	}
2024 
2025 
2026 /* adds an archived state entry */
add_archived_state(int state_type,time_t time_stamp)2027 void add_archived_state(int state_type, time_t time_stamp) {
2028 	struct tm *our_time;
2029 	int bucket;
2030 	int skip_state = FALSE;
2031 
2032 #ifdef DEBUG2
2033 	printf("NEW ENTRY: last=%d this=%d\n", last_state, state_type);
2034 #endif
2035 
2036 	/* don't record program starts/stops, just make a note that one occurred */
2037 	if(state_type == AS_PROGRAM_START || state_type == AS_PROGRAM_END) {
2038 #ifdef DEBUG2
2039 		printf("Recording a program start: %d\n", state_type);
2040 #endif
2041 		program_restart_has_occurred = TRUE;
2042 		return;
2043 		}
2044 
2045 	/* see if we should even take into account this event */
2046 	if(program_restart_has_occurred == TRUE) {
2047 
2048 #ifdef DEBUG2
2049 		printf("program_restart_has_occurred: last=%d this=%d\n", last_state, state_type);
2050 #endif
2051 
2052 		if(initial_states_logged == TRUE) {
2053 			if(state_type == AS_SVC_OK && last_state == AS_SVC_OK)
2054 				skip_state = TRUE;
2055 			if(state_type == AS_HOST_UP && last_state == AS_HOST_UP)
2056 				skip_state = TRUE;
2057 			}
2058 
2059 		if(assume_state_retention == TRUE && initial_states_logged == TRUE) {
2060 			if(state_type == AS_SVC_WARNING && last_state == AS_SVC_WARNING)
2061 				skip_state = TRUE;
2062 			if(state_type == AS_SVC_UNKNOWN && last_state == AS_SVC_UNKNOWN)
2063 				skip_state = TRUE;
2064 			if(state_type == AS_SVC_CRITICAL && last_state == AS_SVC_CRITICAL)
2065 				skip_state = TRUE;
2066 			if(state_type == AS_HOST_DOWN && last_state == AS_HOST_DOWN)
2067 				skip_state = TRUE;
2068 			if(state_type == AS_HOST_UNREACHABLE && last_state == AS_HOST_UNREACHABLE)
2069 				skip_state = TRUE;
2070 			}
2071 
2072 		if(skip_state == TRUE) {
2073 			program_restart_has_occurred = FALSE;
2074 #ifdef DEBUG2
2075 			printf("Skipping state...\n");
2076 #endif
2077 			return;
2078 			}
2079 		}
2080 
2081 	/* reset program restart variable */
2082 	program_restart_has_occurred = FALSE;
2083 
2084 	/* are we only processing new states */
2085 	if(new_states_only == TRUE && state_type == last_state) {
2086 #ifdef DEBUG2
2087 		printf("Skipping state (not a new state)...\n");
2088 #endif
2089 		return;
2090 		}
2091 
2092 #ifdef DEBUG2
2093 	printf("GOODSTATE: %d @ %lu\n", state_type, (unsigned long)time_stamp);
2094 #endif
2095 
2096 
2097 
2098 	our_time = localtime(&time_stamp);
2099 
2100 	/* calculate the correct bucket to dump the data into */
2101 	if(breakdown_type == BREAKDOWN_MONTHLY)
2102 		bucket = our_time->tm_mon;
2103 
2104 	else if(breakdown_type == BREAKDOWN_DAY_OF_MONTH)
2105 		bucket = our_time->tm_mday - 1;
2106 
2107 	else if(breakdown_type == BREAKDOWN_DAY_OF_WEEK)
2108 		bucket = our_time->tm_wday;
2109 
2110 	else
2111 		bucket = (our_time->tm_hour * 4) + (our_time->tm_min / 15);
2112 
2113 #ifdef DEBUG2
2114 	printf("\tBucket=%d\n", bucket);
2115 #endif
2116 
2117 	/* save the data in the correct bucket */
2118 	if(state_type == AS_SVC_OK)
2119 		tsdata[bucket].service_ok++;
2120 	else if(state_type == AS_SVC_UNKNOWN)
2121 		tsdata[bucket].service_unknown++;
2122 	else if(state_type == AS_SVC_WARNING)
2123 		tsdata[bucket].service_warning++;
2124 	else if(state_type == AS_SVC_CRITICAL)
2125 		tsdata[bucket].service_critical++;
2126 	else if(state_type == AS_HOST_UP)
2127 		tsdata[bucket].host_up++;
2128 	else if(state_type == AS_HOST_DOWN)
2129 		tsdata[bucket].host_down++;
2130 	else if(state_type == AS_HOST_UNREACHABLE)
2131 		tsdata[bucket].host_unreachable++;
2132 
2133 	/* record last state type */
2134 	last_state = state_type;
2135 
2136 	return;
2137 	}
2138 
2139 
2140 
2141 /* reads log files for archived state data */
read_archived_state_data(void)2142 void read_archived_state_data(void) {
2143 	char filename[MAX_FILENAME_LENGTH];
2144 	int newest_archive = 0;
2145 	int oldest_archive = 0;
2146 	int current_archive;
2147 
2148 #ifdef DEBUG2
2149 	printf("Determining archives to use...\n");
2150 #endif
2151 
2152 	/* determine earliest archive to use */
2153 	oldest_archive = determine_archive_to_use_from_time(t1);
2154 	if(log_rotation_method != LOG_ROTATION_NONE)
2155 		oldest_archive += backtrack_archives;
2156 
2157 	/* determine most recent archive to use */
2158 	newest_archive = determine_archive_to_use_from_time(t2);
2159 
2160 	if(oldest_archive < newest_archive)
2161 		oldest_archive = newest_archive;
2162 
2163 #ifdef DEBUG2
2164 	printf("Oldest archive: %d\n", oldest_archive);
2165 	printf("Newest archive: %d\n", newest_archive);
2166 #endif
2167 
2168 	/* read in all the necessary archived logs */
2169 	for(current_archive = newest_archive; current_archive <= oldest_archive; current_archive++) {
2170 
2171 		/* get the name of the log file that contains this archive */
2172 		get_log_archive_to_use(current_archive, filename, sizeof(filename) - 1);
2173 
2174 #ifdef DEBUG2
2175 		printf("\tCurrent archive: %d (%s)\n", current_archive, filename);
2176 #endif
2177 
2178 		/* scan the log file for archived state data */
2179 		scan_log_file_for_archived_state_data(filename);
2180 		}
2181 
2182 	return;
2183 	}
2184 
2185 
2186 
2187 /* grabs archives state data from a log file */
scan_log_file_for_archived_state_data(char * filename)2188 void scan_log_file_for_archived_state_data(char *filename) {
2189 	char *input = NULL;
2190 	char *input2 = NULL;
2191 	char entry_host_name[MAX_INPUT_BUFFER];
2192 	char entry_svc_description[MAX_INPUT_BUFFER];
2193 	char *temp_buffer;
2194 	time_t time_stamp;
2195 	mmapfile *thefile;
2196 
2197 	/* print something so browser doesn't time out */
2198 	if(mode == CREATE_HTML) {
2199 		printf(" ");
2200 		fflush(NULL);
2201 		}
2202 
2203 	if((thefile = mmap_fopen(filename)) == NULL) {
2204 #ifdef DEBUG2
2205 		printf("Could not open file '%s' for reading.\n", filename);
2206 #endif
2207 		return;
2208 		}
2209 
2210 #ifdef DEBUG2
2211 	printf("Scanning log file '%s' for archived state data...\n", filename);
2212 #endif
2213 
2214 	while(1) {
2215 
2216 		/* free memory */
2217 		free(input);
2218 		free(input2);
2219 		input = NULL;
2220 		input2 = NULL;
2221 
2222 		/* read the next line */
2223 		if((input = mmap_fgets(thefile)) == NULL)
2224 			break;
2225 
2226 		strip(input);
2227 
2228 		if((input2 = strdup(input)) == NULL)
2229 			continue;
2230 
2231 		temp_buffer = my_strtok(input2, "]");
2232 		time_stamp = (temp_buffer == NULL) ? (time_t)0 : (time_t)strtoul(temp_buffer + 1, NULL, 10);
2233 
2234 		/* program starts/restarts */
2235 		if(strstr(input, " starting..."))
2236 			add_archived_state(AS_PROGRAM_START, time_stamp);
2237 		if(strstr(input, " restarting..."))
2238 			add_archived_state(AS_PROGRAM_START, time_stamp);
2239 
2240 		/* program stops */
2241 		if(strstr(input, " shutting down..."))
2242 			add_archived_state(AS_PROGRAM_END, time_stamp);
2243 		if(strstr(input, "Bailing out"))
2244 			add_archived_state(AS_PROGRAM_END, time_stamp);
2245 
2246 		if(display_type == DISPLAY_HOST_HISTOGRAM) {
2247 			if(strstr(input, "HOST ALERT:")) {
2248 
2249 				/* get host name */
2250 				temp_buffer = my_strtok(NULL, ":");
2251 				temp_buffer = my_strtok(NULL, ";");
2252 				strncpy(entry_host_name, (temp_buffer == NULL) ? "" : temp_buffer + 1, sizeof(entry_host_name));
2253 				entry_host_name[sizeof(entry_host_name) - 1] = '\x0';
2254 
2255 				if(strcmp(host_name, entry_host_name))
2256 					continue;
2257 
2258 				/* skip soft states if necessary */
2259 				if(!(graph_statetypes & GRAPH_SOFT_STATETYPES) && strstr(input, ";SOFT;"))
2260 					continue;
2261 
2262 				/* skip hard states if necessary */
2263 				if(!(graph_statetypes & GRAPH_HARD_STATETYPES) && strstr(input, ";HARD;"))
2264 					continue;
2265 
2266 				if(strstr(input, ";DOWN;"))
2267 					add_archived_state(AS_HOST_DOWN, time_stamp);
2268 				else if(strstr(input, ";UNREACHABLE;"))
2269 					add_archived_state(AS_HOST_UNREACHABLE, time_stamp);
2270 				else if(strstr(input, ";RECOVERY") || strstr(input, ";UP;"))
2271 					add_archived_state(AS_HOST_UP, time_stamp);
2272 				}
2273 			}
2274 		if(display_type == DISPLAY_SERVICE_HISTOGRAM) {
2275 			if(strstr(input, "SERVICE ALERT:")) {
2276 
2277 				/* get host name */
2278 				temp_buffer = my_strtok(NULL, ":");
2279 				temp_buffer = my_strtok(NULL, ";");
2280 				strncpy(entry_host_name, (temp_buffer == NULL) ? "" : temp_buffer + 1, sizeof(entry_host_name));
2281 				entry_host_name[sizeof(entry_host_name) - 1] = '\x0';
2282 
2283 				if(strcmp(host_name, entry_host_name))
2284 					continue;
2285 
2286 				/* get service description */
2287 				temp_buffer = my_strtok(NULL, ";");
2288 				strncpy(entry_svc_description, (temp_buffer == NULL) ? "" : temp_buffer, sizeof(entry_svc_description));
2289 				entry_svc_description[sizeof(entry_svc_description) - 1] = '\x0';
2290 
2291 				if(strcmp(svc_description, entry_svc_description))
2292 					continue;
2293 
2294 				/* skip soft states if necessary */
2295 				if(!(graph_statetypes & GRAPH_SOFT_STATETYPES) && strstr(input, ";SOFT;"))
2296 					continue;
2297 
2298 				/* skip hard states if necessary */
2299 				if(!(graph_statetypes & GRAPH_HARD_STATETYPES) && strstr(input, ";HARD;"))
2300 					continue;
2301 
2302 				if(strstr(input, ";CRITICAL;"))
2303 					add_archived_state(AS_SVC_CRITICAL, time_stamp);
2304 				else if(strstr(input, ";WARNING;"))
2305 					add_archived_state(AS_SVC_WARNING, time_stamp);
2306 				else if(strstr(input, ";UNKNOWN;"))
2307 					add_archived_state(AS_SVC_UNKNOWN, time_stamp);
2308 				else if(strstr(input, ";RECOVERY;") || strstr(input, ";OK;"))
2309 					add_archived_state(AS_SVC_OK, time_stamp);
2310 				}
2311 			}
2312 
2313 		}
2314 
2315 	/* free memory and close the file */
2316 	free(input);
2317 	free(input2);
2318 	mmap_fclose(thefile);
2319 
2320 	return;
2321 	}
2322 
2323 
2324 
2325 
convert_timeperiod_to_times(int type)2326 void convert_timeperiod_to_times(int type) {
2327 	time_t current_time;
2328 	struct tm *t;
2329 
2330 	/* get the current time */
2331 	time(&current_time);
2332 
2333 	t = localtime(&current_time);
2334 
2335 	t->tm_sec = 0;
2336 	t->tm_min = 0;
2337 	t->tm_hour = 0;
2338 	t->tm_isdst = -1;
2339 
2340 	switch(type) {
2341 		case TIMEPERIOD_LAST24HOURS:
2342 			t1 = current_time - (60 * 60 * 24);
2343 			t2 = current_time;
2344 			break;
2345 		case TIMEPERIOD_TODAY:
2346 			t1 = mktime(t);
2347 			t2 = current_time;
2348 			break;
2349 		case TIMEPERIOD_YESTERDAY:
2350 			t1 = (time_t)(mktime(t) - (60 * 60 * 24));
2351 			t2 = (time_t)mktime(t);
2352 			break;
2353 		case TIMEPERIOD_THISWEEK:
2354 			t1 = (time_t)(mktime(t) - (60 * 60 * 24 * t->tm_wday));
2355 			t2 = current_time;
2356 			break;
2357 		case TIMEPERIOD_LASTWEEK:
2358 			t1 = (time_t)(mktime(t) - (60 * 60 * 24 * t->tm_wday) - (60 * 60 * 24 * 7));
2359 			t2 = (time_t)(mktime(t) - (60 * 60 * 24 * t->tm_wday));
2360 			break;
2361 		case TIMEPERIOD_THISMONTH:
2362 			t->tm_mday = 1;
2363 			t1 = mktime(t);
2364 			t2 = current_time;
2365 			break;
2366 		case TIMEPERIOD_LASTMONTH:
2367 			t->tm_mday = 1;
2368 			t2 = mktime(t);
2369 			if(t->tm_mon == 0) {
2370 				t->tm_mon = 11;
2371 				t->tm_year--;
2372 				}
2373 			else
2374 				t->tm_mon--;
2375 			t1 = mktime(t);
2376 			break;
2377 		case TIMEPERIOD_THISQUARTER:
2378 			break;
2379 		case TIMEPERIOD_LASTQUARTER:
2380 			break;
2381 		case TIMEPERIOD_THISYEAR:
2382 			t->tm_mon = 0;
2383 			t->tm_mday = 1;
2384 			t1 = mktime(t);
2385 			t2 = current_time;
2386 			break;
2387 		case TIMEPERIOD_LASTYEAR:
2388 			t->tm_mon = 0;
2389 			t->tm_mday = 1;
2390 			t2 = mktime(t);
2391 			t->tm_year--;
2392 			t1 = mktime(t);
2393 			break;
2394 		case TIMEPERIOD_LAST7DAYS:
2395 			t2 = current_time;
2396 			t1 = current_time - (7 * 24 * 60 * 60);
2397 			break;
2398 		case TIMEPERIOD_LAST31DAYS:
2399 			t2 = current_time;
2400 			t1 = current_time - (31 * 24 * 60 * 60);
2401 			break;
2402 		default:
2403 			break;
2404 		}
2405 
2406 	return;
2407 	}
2408 
2409 
2410 
compute_report_times(void)2411 void compute_report_times(void) {
2412 	time_t current_time;
2413 	struct tm *st;
2414 	struct tm *et;
2415 
2416 	/* get the current time */
2417 	time(&current_time);
2418 
2419 	st = localtime(&current_time);
2420 
2421 	st->tm_sec = start_second;
2422 	st->tm_min = start_minute;
2423 	st->tm_hour = start_hour;
2424 	st->tm_mday = start_day;
2425 	st->tm_mon = start_month - 1;
2426 	st->tm_year = start_year - 1900;
2427 	st->tm_isdst = -1;
2428 
2429 	t1 = mktime(st);
2430 
2431 	et = localtime(&current_time);
2432 
2433 	et->tm_sec = end_second;
2434 	et->tm_min = end_minute;
2435 	et->tm_hour = end_hour;
2436 	et->tm_mday = end_day;
2437 	et->tm_mon = end_month - 1;
2438 	et->tm_year = end_year - 1900;
2439 	et->tm_isdst = -1;
2440 
2441 	t2 = mktime(et);
2442 	}
2443 
2444 
2445 
2446 /* draws a solid line */
draw_line(int x1,int y1,int x2,int y2,int color)2447 void draw_line(int x1, int y1, int x2, int y2, int color) {
2448 	int styleSolid[1];
2449 
2450 	styleSolid[0] = color;
2451 
2452 	/* sets current style to a solid line */
2453 	gdImageSetStyle(histogram_image, styleSolid, 1);
2454 
2455 	/* draws a line (dashed) */
2456 	gdImageLine(histogram_image, x1, y1, x2, y2, gdStyled);
2457 
2458 	return;
2459 	}
2460 
2461 
2462 /* draws a dashed line */
draw_dashed_line(int x1,int y1,int x2,int y2,int color)2463 void draw_dashed_line(int x1, int y1, int x2, int y2, int color) {
2464 	int styleDashed[6];
2465 
2466 	styleDashed[0] = color;
2467 	styleDashed[1] = color;
2468 	styleDashed[2] = gdTransparent;
2469 	styleDashed[3] = gdTransparent;
2470 	styleDashed[4] = gdTransparent;
2471 	styleDashed[5] = gdTransparent;
2472 
2473 	/* sets current style to a solid line */
2474 	gdImageSetStyle(histogram_image, styleDashed, 6);
2475 
2476 	/* draws a line (dashed) */
2477 	gdImageLine(histogram_image, x1, y1, x2, y2, gdStyled);
2478 
2479 	return;
2480 	}
2481