1 /*****************************************************************************
2  *
3  * STATUSMAP.C - Nagios Network Status Map CGI
4  *
5  * Copyright (c) 1999-2008 Ethan Galstad (egalstad@nagios.org)
6  * Last Modified: 05-19-2008
7  *
8  * Description:
9  *
10  * This CGI will create a map of all hosts that are being monitored on your
11  * network.
12  *
13  * License:
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License version 2 as
17  * published by the Free Software Foundation.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  *
28  *****************************************************************************/
29 
30 #include "../include/config.h"
31 #include "../include/common.h"
32 #include "../include/objects.h"
33 #include "../include/macros.h"
34 #include "../include/statusdata.h"
35 #include "../include/cgiutils.h"
36 #include "../include/getcgi.h"
37 #include "../include/cgiauth.h"
38 
39 #include <gd.h>			/* Boutell's GD library function */
40 #include <gdfonts.h>		/* GD library small font definition */
41 
42 static nagios_macros *mac;
43 
44 extern int             refresh_rate;
45 
46 /*#define DEBUG*/
47 
48 #define UNKNOWN_GD2_ICON      "unknown.gd2"
49 #define UNKNOWN_ICON_IMAGE    "unknown.gif"
50 #define NAGIOS_GD2_ICON       "nagios.gd2"
51 
52 extern char main_config_file[MAX_FILENAME_LENGTH];
53 extern char url_html_path[MAX_FILENAME_LENGTH];
54 extern char physical_images_path[MAX_FILENAME_LENGTH];
55 extern char url_images_path[MAX_FILENAME_LENGTH];
56 extern char url_logo_images_path[MAX_FILENAME_LENGTH];
57 extern char url_stylesheets_path[MAX_FILENAME_LENGTH];
58 
59 extern host *host_list;
60 extern hostgroup *hostgroup_list;
61 extern service *service_list;
62 extern hoststatus *hoststatus_list;
63 extern servicestatus *servicestatus_list;
64 
65 extern char *statusmap_background_image;
66 
67 extern int default_statusmap_layout_method;
68 
69 #define DEFAULT_NODE_WIDTH		40
70 #define DEFAULT_NODE_HEIGHT		65
71 
72 #define DEFAULT_NODE_VSPACING           15
73 #define DEFAULT_NODE_HSPACING           45
74 
75 #define DEFAULT_PROXIMITY_WIDTH		1000
76 #define DEFAULT_PROXIMITY_HEIGHT	800
77 
78 #define MINIMUM_PROXIMITY_WIDTH         250
79 #define MINIMUM_PROXIMITY_HEIGHT        200
80 
81 #define COORDS_WARNING_WIDTH            650
82 #define COORDS_WARNING_HEIGHT           60
83 
84 #define CIRCULAR_DRAWING_RADIUS         100
85 
86 #define CREATE_HTML	0
87 #define CREATE_IMAGE	1
88 
89 #define LAYOUT_USER_SUPPLIED            0
90 #define LAYOUT_SUBLAYERS                1
91 #define LAYOUT_COLLAPSED_TREE           2
92 #define LAYOUT_BALANCED_TREE            3
93 #define LAYOUT_CIRCULAR                 4
94 #define LAYOUT_CIRCULAR_MARKUP          5
95 #define LAYOUT_CIRCULAR_BALLOON         6
96 
97 
98 typedef struct layer_struct {
99 	char *layer_name;
100 	struct layer_struct *next;
101 	} layer;
102 
103 
104 void document_header(int);
105 void document_footer(void);
106 int process_cgivars(void);
107 
108 void display_page_header(void);
109 void display_map(void);
110 void calculate_host_coords(void);
111 void calculate_total_image_bounds(void);
112 void calculate_canvas_bounds(void);
113 void calculate_canvas_bounds_from_host(char *);
114 void calculate_scaling_factor(void);
115 void find_eligible_hosts(void);
116 void load_background_image(void);
117 void draw_background_image(void);
118 void draw_background_extras(void);
119 void draw_host_links(void);
120 void draw_hosts(void);
121 void draw_host_text(char *, int, int);
122 void draw_text(char *, int, int, int);
123 void write_popup_code(void);
124 void write_host_popup_text(host *);
125 
126 int initialize_graphics(void);
127 gdImagePtr load_image_from_file(char *);
128 void write_graphics(void);
129 void cleanup_graphics(void);
130 void draw_line(int, int, int, int, int);
131 void draw_dotted_line(int, int, int, int, int);
132 void draw_dashed_line(int, int, int, int, int);
133 
134 int is_host_in_layer_list(host *);
135 int add_layer(char *);
136 void free_layer_list(void);
137 void print_layer_url(int);
138 
139 int number_of_host_layer_members(host *, int);
140 int max_child_host_layer_members(host *);
141 int host_child_depth_separation(host *, host *);
142 int max_child_host_drawing_width(host *);
143 int number_of_host_services(host *);
144 
145 void calculate_balanced_tree_coords(host *, int, int);
146 void calculate_circular_coords(void);
147 void calculate_circular_layer_coords(host *, double, double, int, int);
148 
149 void draw_circular_markup(void);
150 void draw_circular_layer_markup(host *, double, double, int, int);
151 
152 
153 char physical_logo_images_path[MAX_FILENAME_LENGTH];
154 
155 authdata current_authdata;
156 
157 int create_type = CREATE_HTML;
158 
159 gdImagePtr unknown_logo_image = NULL;
160 gdImagePtr logo_image = NULL;
161 gdImagePtr map_image = NULL;
162 gdImagePtr background_image = NULL;
163 int color_white = 0;
164 int color_black = 0;
165 int color_red = 0;
166 int color_lightred = 0;
167 int color_green = 0;
168 int color_lightgreen = 0;
169 int color_blue = 0;
170 int color_yellow = 0;
171 int color_orange = 0;
172 int color_grey = 0;
173 int color_lightgrey = 0;
174 int color_transparency_index = 0;
175 extern int color_transparency_index_r;
176 extern int color_transparency_index_g;
177 extern int color_transparency_index_b;
178 
179 int show_all_hosts = TRUE;
180 char *host_name = "all";
181 
182 int embedded = FALSE;
183 int display_header = TRUE;
184 int display_popups = TRUE;
185 int use_links = TRUE;
186 int use_text = TRUE;
187 int use_highlights = TRUE;
188 int user_supplied_canvas = FALSE;
189 int user_supplied_scaling = FALSE;
190 
191 int layout_method = LAYOUT_USER_SUPPLIED;
192 
193 int proximity_width = DEFAULT_PROXIMITY_WIDTH;
194 int proximity_height = DEFAULT_PROXIMITY_HEIGHT;
195 
196 int coordinates_were_specified = FALSE; /* were any coordinates specified in extended host information entries? */
197 
198 int scaled_image_width = 0;      /* size of the image actually displayed on the screen (after scaling) */
199 int scaled_image_height = 0;
200 int canvas_width = 0;            /* actual size of the image (or portion thereof) that we are drawing */
201 int canvas_height = 0;
202 int total_image_width = 0;       /* actual size of the image that would be created if we drew all hosts */
203 int total_image_height = 0;
204 int max_image_width = 0;         /* max image size the user wants (scaled) */
205 int max_image_height = 0;
206 double scaling_factor = 1.0;     /* scaling factor to use */
207 double user_scaling_factor = 1.0; /* user-supplied scaling factor */
208 int background_image_width = 0;
209 int background_image_height = 0;
210 
211 int canvas_x = 0;                   /* upper left coords of drawing canvas */
212 int canvas_y = 0;
213 
214 int bottom_margin = 0;
215 
216 int draw_child_links = FALSE;
217 int draw_parent_links = FALSE;
218 
219 int draw_nagios_icon = FALSE;  /* should we drawn the Nagios process icon? */
220 int nagios_icon_x = 0;         /* coords of Nagios icon */
221 int nagios_icon_y = 0;
222 
223 extern hoststatus *hoststatus_list;
224 
225 extern time_t program_start;
226 
227 layer *layer_list = NULL;
228 int exclude_layers = TRUE;
229 int all_layers = FALSE;
230 
231 
232 
233 
234 
main(int argc,char ** argv)235 int main(int argc, char **argv) {
236 	int result;
237 
238 	mac = get_global_macros();
239 
240 	/* reset internal variables */
241 	reset_cgi_vars();
242 
243 	/* read the CGI configuration file */
244 	result = read_cgi_config_file(get_cgi_config_location());
245 	if(result == ERROR) {
246 		document_header(FALSE);
247 		if(create_type == CREATE_HTML)
248 			cgi_config_file_error(get_cgi_config_location());
249 		document_footer();
250 		return ERROR;
251 		}
252 
253 	/* defaults from CGI config file */
254 	layout_method = default_statusmap_layout_method;
255 
256 	/* get the arguments passed in the URL */
257 	process_cgivars();
258 
259 	/* read the main configuration file */
260 	result = read_main_config_file(main_config_file);
261 	if(result == ERROR) {
262 		document_header(FALSE);
263 		if(create_type == CREATE_HTML)
264 			main_config_file_error(main_config_file);
265 		document_footer();
266 		return ERROR;
267 		}
268 
269 	/* read all object configuration data */
270 	result = read_all_object_configuration_data(main_config_file, READ_ALL_OBJECT_DATA);
271 	if(result == ERROR) {
272 		document_header(FALSE);
273 		if(create_type == CREATE_HTML)
274 			object_data_error();
275 		document_footer();
276 		return ERROR;
277 		}
278 
279 	/* read all status data */
280 	result = read_all_status_data(get_cgi_config_location(), READ_ALL_STATUS_DATA);
281 	if(result == ERROR) {
282 		document_header(FALSE);
283 		if(create_type == CREATE_HTML)
284 			status_data_error();
285 		document_footer();
286 		free_memory();
287 		return ERROR;
288 		}
289 
290 	/* initialize macros */
291 	init_macros();
292 
293 
294 	document_header(TRUE);
295 
296 	/* get authentication information */
297 	get_authentication_information(&current_authdata);
298 
299 	/* display the network map... */
300 	display_map();
301 
302 	document_footer();
303 
304 	/* free all allocated memory */
305 	free_memory();
306 	free_layer_list();
307 
308 	return OK;
309 	}
310 
311 
312 
document_header(int use_stylesheet)313 void document_header(int use_stylesheet) {
314 	char date_time[MAX_DATETIME_LENGTH];
315 	time_t current_time;
316 	time_t expire_time;
317 
318 	if(create_type == CREATE_HTML) {
319 		printf("Cache-Control: no-store\r\n");
320 		printf("Pragma: no-cache\r\n");
321 		printf("Refresh: %d\r\n", refresh_rate);
322 
323 		time(&current_time);
324 		get_time_string(&current_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
325 		printf("Last-Modified: %s\r\n", date_time);
326 
327 		expire_time = 0L;
328 		get_time_string(&expire_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
329 		printf("Expires: %s\r\n", date_time);
330 
331 		printf("Content-Type: text/html\r\n\r\n");
332 
333 		if(embedded == TRUE)
334 			return;
335 
336 		printf("<html>\n");
337 		printf("<head>\n");
338 		printf("<link rel=\"shortcut icon\" href=\"%sfavicon.ico\" type=\"image/ico\">\n", url_images_path);
339 		printf("<title>\n");
340 		printf("Network Map\n");
341 		printf("</title>\n");
342 
343 		if(use_stylesheet == TRUE) {
344 			printf("<LINK REL='stylesheet' TYPE='text/css' HREF='%s%s'>\n", url_stylesheets_path, COMMON_CSS);
345 			printf("<LINK REL='stylesheet' TYPE='text/css' HREF='%s%s'>\n", url_stylesheets_path, STATUSMAP_CSS);
346 			}
347 
348 		/* write JavaScript code for popup window */
349 		write_popup_code();
350 
351 		printf("</head>\n");
352 
353 		printf("<body CLASS='statusmap' name='mappage' id='mappage'>\n");
354 
355 		/* include user SSI header */
356 		include_ssi_files(STATUSMAP_CGI, SSI_HEADER);
357 
358 		printf("<div id=\"popup\" style=\"position:absolute; z-index:1; visibility: hidden\"></div>\n");
359 		}
360 
361 	else {
362 		printf("Cache-Control: no-store\n");
363 		printf("Pragma: no-cache\n");
364 
365 		time(&current_time);
366 		get_time_string(&current_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
367 		printf("Last-Modified: %s\n", date_time);
368 
369 		expire_time = (time_t)0L;
370 		get_time_string(&expire_time, date_time, sizeof(date_time), HTTP_DATE_TIME);
371 		printf("Expires: %s\n", date_time);
372 
373 		printf("Content-Type: image/png\n\n");
374 		}
375 
376 	return;
377 	}
378 
379 
document_footer(void)380 void document_footer(void) {
381 
382 	if(embedded == TRUE)
383 		return;
384 
385 	if(create_type == CREATE_HTML) {
386 
387 		/* include user SSI footer */
388 		include_ssi_files(STATUSMAP_CGI, SSI_FOOTER);
389 
390 		printf("</body>\n");
391 		printf("</html>\n");
392 		}
393 
394 	return;
395 	}
396 
397 
398 
process_cgivars(void)399 int process_cgivars(void) {
400 	char **variables;
401 	int error = FALSE;
402 	int x;
403 
404 	variables = getcgivars();
405 
406 	for(x = 0; variables[x] != NULL; x++) {
407 
408 		/* do some basic length checking on the variable identifier to prevent buffer overflows */
409 		if(strlen(variables[x]) >= MAX_INPUT_BUFFER - 1) {
410 			continue;
411 			}
412 
413 		/* we found the host argument */
414 		else if(!strcmp(variables[x], "host")) {
415 			x++;
416 			if(variables[x] == NULL) {
417 				error = TRUE;
418 				break;
419 				}
420 
421 			if((host_name = (char *)strdup(variables[x])) == NULL)
422 				host_name = "all";
423 			else
424 				strip_html_brackets(host_name);
425 
426 			if(!strcmp(host_name, "all"))
427 				show_all_hosts = TRUE;
428 			else
429 				show_all_hosts = FALSE;
430 			}
431 
432 		/* we found the image creation option */
433 		else if(!strcmp(variables[x], "createimage")) {
434 			create_type = CREATE_IMAGE;
435 			}
436 
437 		/* we found the embed option */
438 		else if(!strcmp(variables[x], "embedded"))
439 			embedded = TRUE;
440 
441 		/* we found the noheader option */
442 		else if(!strcmp(variables[x], "noheader"))
443 			display_header = FALSE;
444 
445 		/* we found the canvas origin */
446 		else if(!strcmp(variables[x], "canvas_x")) {
447 			x++;
448 			if(variables[x] == NULL) {
449 				error = TRUE;
450 				break;
451 				}
452 			canvas_x = atoi(variables[x]);
453 			user_supplied_canvas = TRUE;
454 			}
455 		else if(!strcmp(variables[x], "canvas_y")) {
456 			x++;
457 			if(variables[x] == NULL) {
458 				error = TRUE;
459 				break;
460 				}
461 			canvas_y = atoi(variables[x]);
462 			user_supplied_canvas = TRUE;
463 			}
464 
465 		/* we found the canvas size */
466 		else if(!strcmp(variables[x], "canvas_width")) {
467 			x++;
468 			if(variables[x] == NULL) {
469 				error = TRUE;
470 				break;
471 				}
472 			canvas_width = atoi(variables[x]);
473 			user_supplied_canvas = TRUE;
474 			}
475 		else if(!strcmp(variables[x], "canvas_height")) {
476 			x++;
477 			if(variables[x] == NULL) {
478 				error = TRUE;
479 				break;
480 				}
481 			canvas_height = atoi(variables[x]);
482 			user_supplied_canvas = TRUE;
483 			}
484 		else if(!strcmp(variables[x], "proximity_width")) {
485 			x++;
486 			if(variables[x] == NULL) {
487 				error = TRUE;
488 				break;
489 				}
490 			proximity_width = atoi(variables[x]);
491 			if(proximity_width < 0)
492 				proximity_width = DEFAULT_PROXIMITY_WIDTH;
493 			}
494 		else if(!strcmp(variables[x], "proximity_height")) {
495 			x++;
496 			if(variables[x] == NULL) {
497 				error = TRUE;
498 				break;
499 				}
500 			proximity_height = atoi(variables[x]);
501 			if(proximity_height < 0)
502 				proximity_height = DEFAULT_PROXIMITY_HEIGHT;
503 			}
504 
505 		/* we found the scaling factor */
506 		else if(!strcmp(variables[x], "scaling_factor")) {
507 			x++;
508 			if(variables[x] == NULL) {
509 				error = TRUE;
510 				break;
511 				}
512 			user_scaling_factor = strtod(variables[x], NULL);
513 			if(user_scaling_factor > 0.0)
514 				user_supplied_scaling = TRUE;
515 			}
516 
517 		/* we found the max image size */
518 		else if(!strcmp(variables[x], "max_width")) {
519 			x++;
520 			if(variables[x] == NULL) {
521 				error = TRUE;
522 				break;
523 				}
524 			max_image_width = atoi(variables[x]);
525 			}
526 		else if(!strcmp(variables[x], "max_height")) {
527 			x++;
528 			if(variables[x] == NULL) {
529 				error = TRUE;
530 				break;
531 				}
532 			max_image_height = atoi(variables[x]);
533 			}
534 
535 		/* we found the layout method option */
536 		else if(!strcmp(variables[x], "layout")) {
537 			x++;
538 			if(variables[x] == NULL) {
539 				error = TRUE;
540 				break;
541 				}
542 			layout_method = atoi(variables[x]);
543 			}
544 
545 		/* we found the no links argument*/
546 		else if(!strcmp(variables[x], "nolinks"))
547 			use_links = FALSE;
548 
549 		/* we found the no text argument*/
550 		else if(!strcmp(variables[x], "notext"))
551 			use_text = FALSE;
552 
553 		/* we found the no highlights argument*/
554 		else if(!strcmp(variables[x], "nohighlights"))
555 			use_highlights = FALSE;
556 
557 		/* we found the no popups argument*/
558 		else if(!strcmp(variables[x], "nopopups"))
559 			display_popups = FALSE;
560 
561 		/* we found the layer inclusion/exclusion argument */
562 		else if(!strcmp(variables[x], "layermode")) {
563 			x++;
564 			if(variables[x] == NULL) {
565 				error = TRUE;
566 				break;
567 				}
568 
569 			if(!strcmp(variables[x], "include"))
570 				exclude_layers = FALSE;
571 			else
572 				exclude_layers = TRUE;
573 			}
574 
575 		/* we found the layer argument */
576 		else if(!strcmp(variables[x], "layer")) {
577 			x++;
578 			if(variables[x] == NULL) {
579 				error = TRUE;
580 				break;
581 				}
582 
583 			strip_html_brackets(variables[x]);
584 			add_layer(variables[x]);
585 			}
586 		}
587 
588 	/* free memory allocated to the CGI variables */
589 	free_cgivars(variables);
590 
591 	return error;
592 	}
593 
594 
595 
596 /* top of page */
display_page_header(void)597 void display_page_header(void) {
598 	char temp_buffer[MAX_INPUT_BUFFER];
599 	int zoom;
600 	int zoom_width, zoom_height;
601 	int zoom_width_granularity = 0;
602 	int zoom_height_granularity = 0;
603 	int current_zoom_granularity = 0;
604 	hostgroup *temp_hostgroup;
605 	layer *temp_layer;
606 	int found = 0;
607 
608 
609 	if(create_type != CREATE_HTML)
610 		return;
611 
612 	if(display_header == TRUE) {
613 
614 		/* begin top table */
615 		printf("<table border=0 width=100%% cellspacing=0 cellpadding=0>\n");
616 		printf("<tr>\n");
617 
618 		/* left column of the first row */
619 		printf("<td align=left valign=top>\n");
620 
621 		if(show_all_hosts == TRUE)
622 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Network Map For All Hosts");
623 		else
624 			snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Network Map For Host <I>%s</I>", host_name);
625 		temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
626 		display_info_table(temp_buffer, TRUE, &current_authdata);
627 
628 		printf("<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 CLASS='linkBox'>\n");
629 		printf("<TR><TD CLASS='linkBox'>\n");
630 
631 		if(show_all_hosts == FALSE) {
632 			printf("<a href='%s?host=all&max_width=%d&max_height=%d'>View Status Map For All Hosts</a><BR>", STATUSMAP_CGI, max_image_width, max_image_height);
633 			printf("<a href='%s?host=%s'>View Status Detail For This Host</a><BR>\n", STATUS_CGI, url_encode(host_name));
634 			}
635 		printf("<a href='%s?host=all'>View Status Detail For All Hosts</a><BR>\n", STATUS_CGI);
636 		printf("<a href='%s?hostgroup=all'>View Status Overview For All Hosts</a>\n", STATUS_CGI);
637 
638 		printf("</TD></TR>\n");
639 		printf("</TABLE>\n");
640 
641 		printf("</td>\n");
642 
643 
644 
645 		/* center column of top row */
646 		printf("<td align=center valign=center>\n");
647 
648 		/* print image size and scaling info */
649 #ifdef DEBUG
650 		printf("<p><div align=center><font size=-1>\n");
651 		printf("[ Raw Image Size: %d x %d pixels | Scaling Factor: %1.2lf | Scaled Image Size: %d x %d pixels ]", canvas_width, canvas_height, scaling_factor, (int)(canvas_width * scaling_factor), (int)(canvas_height * scaling_factor));
652 		printf("</font></div></p>\n");
653 
654 		printf("<p><div align=center><font size=-1>\n");
655 		printf("[ Canvas_x: %d | Canvas_y: %d | Canvas_width: %d | Canvas_height: %d ]", canvas_x, canvas_y, canvas_width, canvas_height);
656 		printf("</font></div></p>\n");
657 #endif
658 
659 		/* zoom links */
660 		if(user_supplied_canvas == FALSE && strcmp(host_name, "all") && display_header == TRUE) {
661 
662 			printf("<p><div align=center>\n");
663 
664 			zoom_width_granularity = ((total_image_width - MINIMUM_PROXIMITY_WIDTH) / 11);
665 			if(zoom_width_granularity == 0)
666 				zoom_width_granularity = 1;
667 			zoom_height_granularity = ((total_image_height - MINIMUM_PROXIMITY_HEIGHT) / 11);
668 
669 			if(proximity_width <= 0)
670 				current_zoom_granularity = 0;
671 			else
672 				current_zoom_granularity = (total_image_width - proximity_width) / zoom_width_granularity;
673 			if(current_zoom_granularity > 10)
674 				current_zoom_granularity = 10;
675 
676 			printf("<table border=0 cellpadding=0 cellspacing=2>\n");
677 			printf("<tr>\n");
678 			printf("<td valign=center class='zoomTitle'>Zoom Out&nbsp;&nbsp;</td>\n");
679 
680 			for(zoom = 0; zoom <= 10; zoom++) {
681 
682 				zoom_width = total_image_width - (zoom * zoom_width_granularity);
683 				zoom_height = total_image_height - (zoom * zoom_height_granularity);
684 
685 				printf("<td valign=center><a href='%s?host=%s&layout=%d&max_width=%d&max_height=%d&proximity_width=%d&proximity_height=%d%s%s", STATUSMAP_CGI, url_encode(host_name), layout_method, max_image_width, max_image_height, zoom_width, zoom_height, (display_header == TRUE) ? "" : "&noheader", (display_popups == FALSE) ? "&nopopups" : "");
686 				if(user_supplied_scaling == TRUE)
687 					printf("&scaling_factor=%2.1f", user_scaling_factor);
688 				print_layer_url(TRUE);
689 				printf("'>");
690 				printf("<img src='%s%s' border=0 alt='%d' title='%d'></a></td>\n", url_images_path, (current_zoom_granularity == zoom) ? ZOOM2_ICON : ZOOM1_ICON, zoom, zoom);
691 				}
692 
693 			printf("<td valign=center class='zoomTitle'>&nbsp;&nbsp;Zoom In</td>\n");
694 			printf("</tr>\n");
695 			printf("</table>\n");
696 
697 			printf("</div></p>\n");
698 			}
699 
700 		printf("</td>\n");
701 
702 
703 
704 		/* right hand column of top row */
705 		printf("<td align=right valign=top>\n");
706 
707 		printf("<form method=\"POST\" action=\"%s\">\n", STATUSMAP_CGI);
708 		printf("<table border=0 CLASS='optBox'>\n");
709 		printf("<tr><td valign=top>\n");
710 		printf("<input type='hidden' name='host' value='%s'>\n", escape_string(host_name));
711 		printf("<input type='hidden' name='layout' value='%d'>\n", layout_method);
712 
713 		printf("</td><td valign=top>\n");
714 
715 		printf("<table border=0>\n");
716 
717 		printf("<tr><td CLASS='optBoxItem'>\n");
718 		printf("Layout Method:<br>\n");
719 		printf("<select name='layout'>\n");
720 #ifndef DUMMY_INSTALL
721 		printf("<option value=%d %s>User-supplied coords\n", LAYOUT_USER_SUPPLIED, (layout_method == LAYOUT_USER_SUPPLIED) ? "selected" : "");
722 #endif
723 		printf("<option value=%d %s>Depth layers\n", LAYOUT_SUBLAYERS, (layout_method == LAYOUT_SUBLAYERS) ? "selected" : "");
724 		printf("<option value=%d %s>Collapsed tree\n", LAYOUT_COLLAPSED_TREE, (layout_method == LAYOUT_COLLAPSED_TREE) ? "selected" : "");
725 		printf("<option value=%d %s>Balanced tree\n", LAYOUT_BALANCED_TREE, (layout_method == LAYOUT_BALANCED_TREE) ? "selected" : "");
726 		printf("<option value=%d %s>Circular\n", LAYOUT_CIRCULAR, (layout_method == LAYOUT_CIRCULAR) ? "selected" : "");
727 		printf("<option value=%d %s>Circular (Marked Up)\n", LAYOUT_CIRCULAR_MARKUP, (layout_method == LAYOUT_CIRCULAR_MARKUP) ? "selected" : "");
728 		printf("<option value=%d %s>Circular (Balloon)\n", LAYOUT_CIRCULAR_BALLOON, (layout_method == LAYOUT_CIRCULAR_BALLOON) ? "selected" : "");
729 		printf("</select>\n");
730 		printf("</td>\n");
731 		printf("<td CLASS='optBoxItem'>\n");
732 		printf("Scaling factor:<br>\n");
733 		printf("<input type='text' name='scaling_factor' maxlength='5' size='4' value='%2.1f'>\n", (user_supplied_scaling == TRUE) ? user_scaling_factor : 0.0);
734 		printf("</td></tr>\n");
735 
736 		/*
737 		printf("<tr><td CLASS='optBoxItem'>\n");
738 		printf("Max image width:<br>\n");
739 		printf("<input type='text' name='max_width' maxlength='5' size='4' value='%d'>\n",max_image_width);
740 		printf("</td>\n");
741 		printf("<td CLASS='optBoxItem'>\n");
742 		printf("Max image height:<br>\n");
743 		printf("<input type='text' name='max_height' maxlength='5' size='4' value='%d'>\n",max_image_height);
744 		printf("</td></tr>\n");
745 
746 		printf("<tr><td CLASS='optBoxItem'>\n");
747 		printf("Proximity width:<br>\n");
748 		printf("<input type='text' name='proximity_width' maxlength='5' size='4' value='%d'>\n",proximity_width);
749 		printf("</td>\n");
750 		printf("<td CLASS='optBoxItem'>\n");
751 		printf("Proximity height:<br>\n");
752 		printf("<input type='text' name='proximity_height' maxlength='5' size='4' value='%d'>\n",proximity_height);
753 		printf("</td></tr>\n");
754 		*/
755 
756 		printf("<input type='hidden' name='max_width' value='%d'>\n", max_image_width);
757 		printf("<input type='hidden' name='max_height' value='%d'>\n", max_image_height);
758 		printf("<input type='hidden' name='proximity_width' value='%d'>\n", proximity_width);
759 		printf("<input type='hidden' name='proximity_height' value='%d'>\n", proximity_height);
760 
761 		printf("<tr><td CLASS='optBoxItem'>Drawing Layers:<br>\n");
762 		printf("<select multiple name='layer' size='4'>\n");
763 		for(temp_hostgroup = hostgroup_list; temp_hostgroup != NULL; temp_hostgroup = temp_hostgroup->next) {
764 			if(is_authorized_for_hostgroup(temp_hostgroup, &current_authdata) == FALSE)
765 				continue;
766 			found = 0;
767 			for(temp_layer = layer_list; temp_layer != NULL; temp_layer = temp_layer->next) {
768 				if(!strcmp(temp_layer->layer_name, temp_hostgroup->group_name)) {
769 					found = 1;
770 					break;
771 					}
772 				}
773 			printf("<option value='%s' %s>%s\n", escape_string(temp_hostgroup->group_name), (found == 1) ? "SELECTED" : "", temp_hostgroup->alias);
774 			}
775 		printf("</select>\n");
776 		printf("</td><td CLASS='optBoxItem' valign=top>Layer mode:<br>");
777 		printf("<input type='radio' name='layermode' value='include' %s>Include<br>\n", (exclude_layers == FALSE) ? "CHECKED" : "");
778 		printf("<input type='radio' name='layermode' value='exclude' %s>Exclude\n", (exclude_layers == TRUE) ? "CHECKED" : "");
779 		printf("</td></tr>\n");
780 
781 		printf("<tr><td CLASS='optBoxItem'>\n");
782 		printf("Suppress popups:<br>\n");
783 		printf("<input type='checkbox' name='nopopups' %s>\n", (display_popups == FALSE) ? "CHECKED" : "");
784 		printf("</td><td CLASS='optBoxItem'>\n");
785 		printf("<input type='submit' value='Update'>\n");
786 		printf("</td></tr>\n");
787 
788 		/* display context-sensitive help */
789 		printf("<tr><td></td><td align=right valign=bottom>\n");
790 		display_context_help(CONTEXTHELP_MAP);
791 		printf("</td></tr>\n");
792 
793 		printf("</table>\n");
794 
795 		printf("</td></tr>\n");
796 		printf("</table>\n");
797 		printf("</form>\n");
798 
799 		printf("</td>\n");
800 
801 		/* end of top table */
802 		printf("</tr>\n");
803 		printf("</table>\n");
804 		}
805 
806 
807 	return;
808 	}
809 
810 
811 
812 /* top-level map generation... */
display_map(void)813 void display_map(void) {
814 
815 	load_background_image();
816 	calculate_host_coords();
817 	calculate_total_image_bounds();
818 	calculate_canvas_bounds();
819 	calculate_scaling_factor();
820 	find_eligible_hosts();
821 
822 	/* display page header */
823 	display_page_header();
824 
825 	initialize_graphics();
826 	draw_background_image();
827 	draw_background_extras();
828 	draw_host_links();
829 
830 	if(create_type == CREATE_HTML)
831 		printf("<map name='statusmap'>\n");
832 
833 	draw_hosts();
834 
835 	if(create_type == CREATE_HTML)
836 		printf("</map>\n");
837 
838 	write_graphics();
839 	cleanup_graphics();
840 
841 
842 	/* write the URL location for the image we just generated - the web browser will come and get it... */
843 	if(create_type == CREATE_HTML) {
844 		printf("<P><DIV ALIGN=center>\n");
845 		printf("<img src='%s?host=%s&createimage&time=%lu", STATUSMAP_CGI, url_encode(host_name), (unsigned long)time(NULL));
846 		printf("&canvas_x=%d&canvas_y=%d&canvas_width=%d&canvas_height=%d&max_width=%d&max_height=%d&layout=%d%s%s%s", canvas_x, canvas_y, canvas_width, canvas_height, max_image_width, max_image_height, layout_method, (use_links == FALSE) ? "&nolinks" : "", (use_text == FALSE) ? "&notext" : "", (use_highlights == FALSE) ? "&nohighlights" : "");
847 		print_layer_url(TRUE);
848 		printf("' width=%d height=%d border=0 name='statusimage' useMap='#statusmap'>\n", (int)(canvas_width * scaling_factor), (int)(canvas_height * scaling_factor));
849 		printf("</DIV></P>\n");
850 		}
851 
852 	return;
853 	}
854 
855 
856 
857 /******************************************************************/
858 /********************* CALCULATION FUNCTIONS **********************/
859 /******************************************************************/
860 
861 /* calculates host drawing coordinates */
calculate_host_coords(void)862 void calculate_host_coords(void) {
863 	host *this_host;
864 	host *temp_host;
865 	int child_hosts = 0;
866 	int parent_hosts = 0;
867 	int max_layer_width = 1;
868 	int current_child_host = 0;
869 	int current_parent_host = 0;
870 	int center_x = 0;
871 	int offset_x = DEFAULT_NODE_WIDTH / 2;
872 	int offset_y = DEFAULT_NODE_WIDTH / 2;
873 	int current_layer = 0;
874 	int layer_members = 0;
875 	int current_layer_member = 0;
876 	int max_drawing_width = 0;
877 
878 
879 	/******************************/
880 	/***** MANUAL LAYOUT MODE *****/
881 	/******************************/
882 
883 	/* user-supplied coords */
884 	if(layout_method == LAYOUT_USER_SUPPLIED) {
885 
886 		/* see which hosts we should draw and calculate drawing coords */
887 		for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
888 
889 			if(temp_host->have_2d_coords == TRUE)
890 				temp_host->should_be_drawn = TRUE;
891 			else
892 				temp_host->should_be_drawn = FALSE;
893 			}
894 
895 		return;
896 		}
897 
898 
899 	/*****************************/
900 	/***** AUTO-LAYOUT MODES *****/
901 	/*****************************/
902 
903 	/***** DEPTH LAYER MODE *****/
904 	if(layout_method == LAYOUT_SUBLAYERS) {
905 
906 		/* find the "main" host we're displaying */
907 		if(show_all_hosts == TRUE)
908 			this_host = NULL;
909 		else
910 			this_host = find_host(host_name);
911 
912 		/* find total number of immediate parents/children for this host */
913 		child_hosts = number_of_immediate_child_hosts(this_host);
914 		parent_hosts = number_of_immediate_parent_hosts(this_host);
915 
916 		if(child_hosts == 0 && parent_hosts == 0)
917 			max_layer_width = 1;
918 		else
919 			max_layer_width = (child_hosts > parent_hosts) ? child_hosts : parent_hosts;
920 
921 		/* calculate center x coord */
922 		center_x = (((DEFAULT_NODE_WIDTH * max_layer_width) + (DEFAULT_NODE_HSPACING * (max_layer_width - 1))) / 2) + offset_x;
923 
924 		/* coords for Nagios icon if necessary */
925 		if(this_host == NULL || this_host->parent_hosts == NULL) {
926 			nagios_icon_x = center_x;
927 			nagios_icon_y = offset_y;
928 			draw_nagios_icon = TRUE;
929 			}
930 
931 		/* do we need to draw a link to parent(s)? */
932 		if(this_host != NULL && is_host_immediate_child_of_host(NULL, this_host) == FALSE) {
933 			draw_parent_links = TRUE;
934 			offset_y += DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
935 			}
936 
937 		/* see which hosts we should draw and calculate drawing coords */
938 		for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
939 
940 			/* this is an immediate parent of the "main" host we're drawing */
941 			if(is_host_immediate_parent_of_host(this_host, temp_host) == TRUE) {
942 				temp_host->should_be_drawn = TRUE;
943 				temp_host->have_2d_coords = TRUE;
944 				temp_host->x_2d = center_x - (((parent_hosts * DEFAULT_NODE_WIDTH) + ((parent_hosts - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_parent_host * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
945 				temp_host->y_2d = offset_y;
946 				current_parent_host++;
947 				}
948 
949 			/* this is the "main" host we're drawing */
950 			else if(this_host == temp_host) {
951 				temp_host->should_be_drawn = TRUE;
952 				temp_host->have_2d_coords = TRUE;
953 				temp_host->x_2d = center_x;
954 				temp_host->y_2d = DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING + offset_y;
955 				}
956 
957 			/* this is an immediate child of the "main" host we're drawing */
958 			else if(is_host_immediate_child_of_host(this_host, temp_host) == TRUE) {
959 				temp_host->should_be_drawn = TRUE;
960 				temp_host->have_2d_coords = TRUE;
961 				temp_host->x_2d = center_x - (((child_hosts * DEFAULT_NODE_WIDTH) + ((child_hosts - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_child_host * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
962 				if(this_host == NULL)
963 					temp_host->y_2d = (DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING) + offset_y;
964 				else
965 					temp_host->y_2d = ((DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING) * 2) + offset_y;
966 				current_child_host++;
967 				if(number_of_immediate_child_hosts(temp_host) > 0) {
968 					bottom_margin = DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
969 					draw_child_links = TRUE;
970 					}
971 				}
972 
973 			/* else do not draw this host */
974 			else {
975 				temp_host->should_be_drawn = FALSE;
976 				temp_host->have_2d_coords = FALSE;
977 				}
978 			}
979 		}
980 
981 
982 
983 	/***** COLLAPSED TREE MODE *****/
984 	else if(layout_method == LAYOUT_COLLAPSED_TREE) {
985 
986 		/* find the "main" host we're displaying  - DO NOT USE THIS (THIS IS THE OLD METHOD) */
987 		/*
988 		if(show_all_hosts==TRUE)
989 			this_host=NULL;
990 		else
991 			this_host=find_host(host_name);
992 		*/
993 
994 		/* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
995 		this_host = NULL;
996 
997 		/* find total number of immediate parents for this host */
998 		parent_hosts = number_of_immediate_parent_hosts(this_host);
999 
1000 		/* find the max layer width we have... */
1001 		max_layer_width = max_child_host_layer_members(this_host);
1002 		if(parent_hosts > max_layer_width)
1003 			max_layer_width = parent_hosts;
1004 
1005 		/* calculate center x coord */
1006 		center_x = (((DEFAULT_NODE_WIDTH * max_layer_width) + (DEFAULT_NODE_HSPACING * (max_layer_width - 1))) / 2) + offset_x;
1007 
1008 		/* coords for Nagios icon if necessary */
1009 		if(this_host == NULL || this_host->parent_hosts == NULL) {
1010 			nagios_icon_x = center_x;
1011 			nagios_icon_y = offset_y;
1012 			draw_nagios_icon = TRUE;
1013 			}
1014 
1015 		/* do we need to draw a link to parent(s)? */
1016 		if(this_host != NULL && is_host_immediate_child_of_host(NULL, this_host) == FALSE) {
1017 			draw_parent_links = TRUE;
1018 			offset_y += DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
1019 			}
1020 
1021 		/* see which hosts we should draw and calculate drawing coords */
1022 		for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
1023 
1024 			/* this is an immediate parent of the "main" host we're drawing */
1025 			if(is_host_immediate_parent_of_host(this_host, temp_host) == TRUE) {
1026 				temp_host->should_be_drawn = TRUE;
1027 				temp_host->have_2d_coords = TRUE;
1028 				temp_host->x_2d = center_x - (((parent_hosts * DEFAULT_NODE_WIDTH) + ((parent_hosts - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_parent_host * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
1029 				temp_host->y_2d = offset_y;
1030 				current_parent_host++;
1031 				}
1032 
1033 			/* this is the "main" host we're drawing */
1034 			else if(this_host == temp_host) {
1035 				temp_host->should_be_drawn = TRUE;
1036 				temp_host->have_2d_coords = TRUE;
1037 				temp_host->x_2d = center_x;
1038 				temp_host->y_2d = DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING + offset_y;
1039 				}
1040 
1041 			/* else do not draw this host (we might if its a child - see below, but assume no for now) */
1042 			else {
1043 				temp_host->should_be_drawn = FALSE;
1044 				temp_host->have_2d_coords = FALSE;
1045 				}
1046 			}
1047 
1048 
1049 		/* TODO: REORDER CHILD LAYER MEMBERS SO THAT WE MINIMIZE LINK CROSSOVERS FROM PARENT HOSTS */
1050 
1051 		/* draw hosts in child "layers" */
1052 		for(current_layer = 1;; current_layer++) {
1053 
1054 			/* how many members in this layer? */
1055 			layer_members = number_of_host_layer_members(this_host, current_layer);
1056 
1057 			if(layer_members == 0)
1058 				break;
1059 
1060 			current_layer_member = 0;
1061 
1062 			/* see which hosts are members of this layer and calculate drawing coords */
1063 			for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
1064 
1065 				/* is this host a member of the current child layer? */
1066 				if(host_child_depth_separation(this_host, temp_host) == current_layer) {
1067 					temp_host->should_be_drawn = TRUE;
1068 					temp_host->have_2d_coords = TRUE;
1069 					temp_host->x_2d = center_x - (((layer_members * DEFAULT_NODE_WIDTH) + ((layer_members - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_layer_member * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
1070 					if(this_host == NULL)
1071 						temp_host->y_2d = ((DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING) * current_layer) + offset_y;
1072 					else
1073 						temp_host->y_2d = ((DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING) * (current_layer + 1)) + offset_y;
1074 					current_layer_member++;
1075 					}
1076 				}
1077 			}
1078 
1079 		}
1080 
1081 
1082 	/***** "BALANCED" TREE MODE *****/
1083 	else if(layout_method == LAYOUT_BALANCED_TREE) {
1084 
1085 		/* find the "main" host we're displaying  - DO NOT USE THIS (THIS IS THE OLD METHOD) */
1086 		/*
1087 		if(show_all_hosts==TRUE)
1088 			this_host=NULL;
1089 		else
1090 			this_host=find_host(host_name);
1091 		*/
1092 
1093 		/* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
1094 		this_host = NULL;
1095 
1096 		/* find total number of immediate parents for this host */
1097 		parent_hosts = number_of_immediate_parent_hosts(this_host);
1098 
1099 		/* find the max drawing width we have... */
1100 		max_drawing_width = max_child_host_drawing_width(this_host);
1101 		if(parent_hosts > max_drawing_width)
1102 			max_drawing_width = parent_hosts;
1103 
1104 		/* calculate center x coord */
1105 		center_x = (((DEFAULT_NODE_WIDTH * max_drawing_width) + (DEFAULT_NODE_HSPACING * (max_drawing_width - 1))) / 2) + offset_x;
1106 
1107 		/* coords for Nagios icon if necessary */
1108 		if(this_host == NULL || this_host->parent_hosts == NULL) {
1109 			nagios_icon_x = center_x;
1110 			nagios_icon_y = offset_y;
1111 			draw_nagios_icon = TRUE;
1112 			}
1113 
1114 		/* do we need to draw a link to parent(s)? */
1115 		if(this_host != NULL && is_host_immediate_child_of_host(NULL, this_host) == FALSE) {
1116 			draw_parent_links = TRUE;
1117 			offset_y += DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
1118 			}
1119 
1120 		/* see which hosts we should draw and calculate drawing coords */
1121 		for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
1122 
1123 			/* this is an immediate parent of the "main" host we're drawing */
1124 			if(is_host_immediate_parent_of_host(this_host, temp_host) == TRUE) {
1125 				temp_host->should_be_drawn = TRUE;
1126 				temp_host->have_2d_coords = TRUE;
1127 				temp_host->x_2d = center_x - (((parent_hosts * DEFAULT_NODE_WIDTH) + ((parent_hosts - 1) * DEFAULT_NODE_HSPACING)) / 2) + (current_parent_host * (DEFAULT_NODE_WIDTH + DEFAULT_NODE_HSPACING)) + (DEFAULT_NODE_WIDTH / 2);
1128 				temp_host->y_2d = offset_y;
1129 				current_parent_host++;
1130 				}
1131 
1132 			/* this is the "main" host we're drawing */
1133 			else if(this_host == temp_host) {
1134 				temp_host->should_be_drawn = TRUE;
1135 				temp_host->have_2d_coords = TRUE;
1136 				temp_host->x_2d = center_x;
1137 				temp_host->y_2d = DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING + offset_y;
1138 				}
1139 
1140 			/* else do not draw this host (we might if its a child - see below, but assume no for now) */
1141 			else {
1142 				temp_host->should_be_drawn = FALSE;
1143 				temp_host->have_2d_coords = FALSE;
1144 				}
1145 			}
1146 
1147 		/* draw all children hosts */
1148 		calculate_balanced_tree_coords(this_host, center_x, DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING + offset_y);
1149 
1150 		}
1151 
1152 
1153 	/***** CIRCULAR LAYOUT MODE *****/
1154 	else if(layout_method == LAYOUT_CIRCULAR || layout_method == LAYOUT_CIRCULAR_MARKUP || layout_method == LAYOUT_CIRCULAR_BALLOON) {
1155 
1156 		/* draw process icon */
1157 		nagios_icon_x = 0;
1158 		nagios_icon_y = 0;
1159 		draw_nagios_icon = TRUE;
1160 
1161 		/* calculate coordinates for all hosts */
1162 		calculate_circular_coords();
1163 		}
1164 
1165 	return;
1166 	}
1167 
1168 
1169 
1170 /* calculates max possible image dimensions */
calculate_total_image_bounds(void)1171 void calculate_total_image_bounds(void) {
1172 	host *temp_host;
1173 
1174 	total_image_width = 0;
1175 	total_image_height = 0;
1176 
1177 	/* check all extended host information entries... */
1178 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
1179 
1180 		/* only check entries that have 2-D coords specified */
1181 		if(temp_host->have_2d_coords == FALSE)
1182 			continue;
1183 
1184 		/* skip hosts we shouldn't be drawing */
1185 		if(temp_host->should_be_drawn == FALSE)
1186 			continue;
1187 
1188 		if(temp_host->x_2d > total_image_width)
1189 			total_image_width = temp_host->x_2d;
1190 		if(temp_host->y_2d > total_image_height)
1191 			total_image_height = temp_host->y_2d;
1192 
1193 		coordinates_were_specified = TRUE;
1194 		}
1195 
1196 	/* add some space for icon size and overlapping text... */
1197 	if(coordinates_were_specified == TRUE) {
1198 
1199 		total_image_width += (DEFAULT_NODE_WIDTH * 2);
1200 		total_image_height += DEFAULT_NODE_HEIGHT;
1201 
1202 		/* add space for bottom margin if necessary */
1203 		total_image_height += bottom_margin;
1204 		}
1205 
1206 	/* image size should be at least as large as dimensions of background image */
1207 	if(total_image_width < background_image_width)
1208 		total_image_width = background_image_width;
1209 	if(total_image_height < background_image_height)
1210 		total_image_height = background_image_height;
1211 
1212 	/* we didn't find any hosts that had user-supplied coordinates, so we're going to display a warning */
1213 	if(coordinates_were_specified == FALSE) {
1214 		coordinates_were_specified = FALSE;
1215 		total_image_width = COORDS_WARNING_WIDTH;
1216 		total_image_height = COORDS_WARNING_HEIGHT;
1217 		}
1218 
1219 	return;
1220 	}
1221 
1222 
1223 /* calculates canvas coordinates/dimensions */
calculate_canvas_bounds(void)1224 void calculate_canvas_bounds(void) {
1225 
1226 	if(user_supplied_canvas == FALSE && strcmp(host_name, "all"))
1227 		calculate_canvas_bounds_from_host(host_name);
1228 
1229 	/* calculate canvas origin (based on total image bounds) */
1230 	if(canvas_x <= 0 || canvas_width > total_image_width)
1231 		canvas_x = 0;
1232 	if(canvas_y <= 0 || canvas_height > total_image_height)
1233 		canvas_y = 0;
1234 
1235 	/* calculate canvas dimensions */
1236 	if(canvas_height <= 0)
1237 		canvas_height = (total_image_height - canvas_y);
1238 	if(canvas_width <= 0)
1239 		canvas_width = (total_image_width - canvas_x);
1240 
1241 	if(canvas_x + canvas_width > total_image_width)
1242 		canvas_width = total_image_width - canvas_x;
1243 	if(canvas_y + canvas_height > total_image_height)
1244 		canvas_height = total_image_height - canvas_y;
1245 
1246 	return;
1247 	}
1248 
1249 
1250 /* calculates canvas coordinates/dimensions around a particular host */
calculate_canvas_bounds_from_host(char * host_name)1251 void calculate_canvas_bounds_from_host(char *host_name) {
1252 	host *temp_host;
1253 	int zoom_width;
1254 	int zoom_height;
1255 
1256 	/* find the extended host info */
1257 	temp_host = find_host(host_name);
1258 	if(temp_host == NULL)
1259 		return;
1260 
1261 	/* make sure we have 2-D coords */
1262 	if(temp_host->have_2d_coords == FALSE)
1263 		return;
1264 
1265 	if(max_image_width > 0 && proximity_width > max_image_width)
1266 		zoom_width = max_image_width;
1267 	else
1268 		zoom_width = proximity_width;
1269 	if(max_image_height > 0 && proximity_height > max_image_height)
1270 		zoom_height = max_image_height;
1271 	else
1272 		zoom_height = proximity_height;
1273 
1274 	canvas_width = zoom_width;
1275 	if(canvas_width >= total_image_width)
1276 		canvas_x = 0;
1277 	else
1278 		canvas_x = (temp_host->x_2d - (zoom_width / 2));
1279 
1280 	canvas_height = zoom_height;
1281 	if(canvas_height >= total_image_height)
1282 		canvas_y = 0;
1283 	else
1284 		canvas_y = (temp_host->y_2d - (zoom_height / 2));
1285 
1286 
1287 	return;
1288 	}
1289 
1290 
1291 /* calculates scaling factor used in image generation */
calculate_scaling_factor(void)1292 void calculate_scaling_factor(void) {
1293 	double x_scaling = 1.0;
1294 	double y_scaling = 1.0;
1295 
1296 	/* calculate horizontal scaling factor */
1297 	if(max_image_width <= 0 || canvas_width <= max_image_width)
1298 		x_scaling = 1.0;
1299 	else
1300 		x_scaling = (double)((double)max_image_width / (double)canvas_width);
1301 
1302 	/* calculate vertical scaling factor */
1303 	if(max_image_height <= 0 || canvas_height <= max_image_height)
1304 		y_scaling = 1.0;
1305 	else
1306 		y_scaling = (double)((double)max_image_height / (double)canvas_height);
1307 
1308 	/* calculate general scaling factor to use */
1309 	if(x_scaling < y_scaling)
1310 		scaling_factor = x_scaling;
1311 	else
1312 		scaling_factor = y_scaling;
1313 
1314 	/*** USER-SUPPLIED SCALING FACTOR ***/
1315 	if(user_supplied_scaling == TRUE)
1316 		scaling_factor = user_scaling_factor;
1317 
1318 	return;
1319 	}
1320 
1321 
1322 /* finds hosts that can be drawn in the canvas area */
find_eligible_hosts(void)1323 void find_eligible_hosts(void) {
1324 	int total_eligible_hosts = 0;
1325 	host *temp_host;
1326 
1327 	/* check all extended host information entries... */
1328 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
1329 
1330 		/* only include hosts that have 2-D coords supplied */
1331 		if(temp_host->have_2d_coords == FALSE)
1332 			temp_host->should_be_drawn = FALSE;
1333 
1334 		/* make sure coords are all positive */
1335 		else if(temp_host->x_2d < 0 || temp_host->y_2d < 0)
1336 			temp_host->should_be_drawn = FALSE;
1337 
1338 		/* make sure x coordinates fall within canvas bounds */
1339 		else if(temp_host->x_2d < (canvas_x - DEFAULT_NODE_WIDTH) || temp_host->x_2d > (canvas_x + canvas_width))
1340 			temp_host->should_be_drawn = FALSE;
1341 
1342 		/* make sure y coordinates fall within canvas bounds */
1343 		else if(temp_host->y_2d < (canvas_y - DEFAULT_NODE_HEIGHT) || temp_host->y_2d > (canvas_y + canvas_height))
1344 			temp_host->should_be_drawn = FALSE;
1345 
1346 		/* see if the user is authorized to view the host */
1347 		else if(is_authorized_for_host(temp_host, &current_authdata) == FALSE)
1348 			temp_host->should_be_drawn = FALSE;
1349 
1350 		/* all checks passed, so we can draw the host! */
1351 		else {
1352 			temp_host->should_be_drawn = TRUE;
1353 			total_eligible_hosts++;
1354 			}
1355 		}
1356 
1357 	return;
1358 	}
1359 
1360 
1361 
1362 /******************************************************************/
1363 /*********************** DRAWING FUNCTIONS ************************/
1364 /******************************************************************/
1365 
1366 
1367 /* loads background image from file */
load_background_image(void)1368 void load_background_image(void) {
1369 	char temp_buffer[MAX_INPUT_BUFFER];
1370 
1371 	/* bail out if we shouldn't be drawing a background image */
1372 	if(layout_method != LAYOUT_USER_SUPPLIED || statusmap_background_image == NULL)
1373 		return;
1374 
1375 	snprintf(temp_buffer, sizeof(temp_buffer) - 1, "%s%s", physical_images_path, statusmap_background_image);
1376 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1377 
1378 	/* read the background image into memory */
1379 	background_image = load_image_from_file(temp_buffer);
1380 
1381 	/* grab background image dimensions for calculating total image width later */
1382 	if(background_image != NULL) {
1383 		background_image_width = background_image->sx;
1384 		background_image_height = background_image->sy;
1385 		}
1386 
1387 	/* if we are just creating the html, we don't need the image anymore */
1388 	if(create_type == CREATE_HTML && background_image != NULL)
1389 		gdImageDestroy(background_image);
1390 
1391 	return;
1392 	}
1393 
1394 
1395 /* draws background image on drawing canvas */
draw_background_image(void)1396 void draw_background_image(void) {
1397 
1398 	/* bail out if we shouldn't be drawing a background image */
1399 	if(create_type == CREATE_HTML || layout_method != LAYOUT_USER_SUPPLIED || statusmap_background_image == NULL)
1400 		return;
1401 
1402 	/* bail out if we don't have an image */
1403 	if(background_image == NULL)
1404 		return;
1405 
1406 	/* copy the background image to the canvas */
1407 	gdImageCopy(map_image, background_image, 0, 0, canvas_x, canvas_y, canvas_width, canvas_height);
1408 
1409 	/* free memory for background image, as we don't need it anymore */
1410 	gdImageDestroy(background_image);
1411 
1412 	return;
1413 	}
1414 
1415 
1416 
1417 /* draws background "extras" */
draw_background_extras(void)1418 void draw_background_extras(void) {
1419 
1420 	/* bail out if we shouldn't be here */
1421 	if(create_type == CREATE_HTML)
1422 		return;
1423 
1424 	/* circular layout stuff... */
1425 	if(layout_method == LAYOUT_CIRCULAR_MARKUP) {
1426 
1427 		/* draw colored sections... */
1428 		draw_circular_markup();
1429 		}
1430 
1431 	return;
1432 	}
1433 
1434 
1435 /* draws host links */
draw_host_links(void)1436 void draw_host_links(void) {
1437 	host *this_host;
1438 	host *main_host;
1439 	host *parent_host;
1440 	hostsmember *temp_hostsmember;
1441 	int status_color = color_black;
1442 	hoststatus *this_hoststatus;
1443 	hoststatus *parent_hoststatus;
1444 	int child_in_layer_list = FALSE;
1445 	int parent_in_layer_list = FALSE;
1446 	int dotted_line = FALSE;
1447 	int x = 0;
1448 	int y = 0;
1449 
1450 	if(create_type == CREATE_HTML)
1451 		return;
1452 
1453 	if(use_links == FALSE)
1454 		return;
1455 
1456 	/* find the "main" host we're drawing */
1457 	main_host = find_host(host_name);
1458 	if(show_all_hosts == TRUE)
1459 		main_host = NULL;
1460 
1461 	/* check all extended host information entries... */
1462 	for(this_host = host_list; this_host != NULL; this_host = this_host->next) {
1463 
1464 		/* only draw link if user is authorized to view this host */
1465 		if(is_authorized_for_host(this_host, &current_authdata) == FALSE)
1466 			continue;
1467 
1468 		/* this is a "root" host, so draw link to Nagios process icon if using auto-layout mode */
1469 		if(this_host->parent_hosts == NULL && layout_method != LAYOUT_USER_SUPPLIED && draw_nagios_icon == TRUE) {
1470 
1471 			x = this_host->x_2d + (DEFAULT_NODE_WIDTH / 2) - canvas_x;
1472 			y = this_host->y_2d + (DEFAULT_NODE_WIDTH / 2) - canvas_y;
1473 
1474 			draw_line(x, y, nagios_icon_x + (DEFAULT_NODE_WIDTH / 2) - canvas_x, nagios_icon_y + (DEFAULT_NODE_WIDTH / 2) - canvas_y, color_black);
1475 			}
1476 
1477 		/* this is a child of the main host we're drawing in auto-layout mode... */
1478 		if(layout_method != LAYOUT_USER_SUPPLIED && draw_child_links == TRUE && number_of_immediate_child_hosts(this_host) > 0 && is_host_immediate_child_of_host(main_host, this_host) == TRUE) {
1479 			/* determine color to use when drawing links to children  */
1480 			this_hoststatus = find_hoststatus(this_host->name);
1481 			if(this_hoststatus != NULL) {
1482 				if(this_hoststatus->status == HOST_DOWN || this_hoststatus->status == HOST_UNREACHABLE)
1483 					status_color = color_red;
1484 				else
1485 					status_color = color_black;
1486 				}
1487 			else
1488 				status_color = color_black;
1489 
1490 			x = this_host->x_2d + (DEFAULT_NODE_WIDTH / 2) - canvas_x;
1491 			y = (this_host->y_2d + (DEFAULT_NODE_WIDTH) / 2) - canvas_y;
1492 
1493 			draw_dashed_line(x, y, x, y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING, status_color);
1494 
1495 			/* draw arrow tips */
1496 			draw_line(x, y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING, x - 5, y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING - 5, color_black);
1497 			draw_line(x, y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING, x + 5, y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING - 5, color_black);
1498 			}
1499 
1500 		/* this is a parent of the main host we're drawing in auto-layout mode... */
1501 		if(layout_method != LAYOUT_USER_SUPPLIED && draw_parent_links == TRUE && is_host_immediate_child_of_host(this_host, main_host) == TRUE) {
1502 
1503 			x = this_host->x_2d + (DEFAULT_NODE_WIDTH / 2) - canvas_x;
1504 			y = this_host->y_2d + (DEFAULT_NODE_WIDTH / 2) - canvas_y;
1505 
1506 			draw_dashed_line(x, y, x, y - DEFAULT_NODE_HEIGHT - DEFAULT_NODE_VSPACING, color_black);
1507 
1508 			/* draw arrow tips */
1509 			draw_line(x, y - DEFAULT_NODE_HEIGHT - DEFAULT_NODE_VSPACING, x - 5, y - DEFAULT_NODE_HEIGHT - DEFAULT_NODE_VSPACING + 5, color_black);
1510 			draw_line(x, y - DEFAULT_NODE_HEIGHT - DEFAULT_NODE_VSPACING, x + 5, y - DEFAULT_NODE_HEIGHT - DEFAULT_NODE_VSPACING + 5, color_black);
1511 			}
1512 
1513 		/* draw links to all parent hosts */
1514 		for(temp_hostsmember = this_host->parent_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) {
1515 
1516 			/* find the parent host config entry */
1517 			parent_host = find_host(temp_hostsmember->host_name);
1518 			if(parent_host == NULL)
1519 				continue;
1520 
1521 			/* don't draw the link if we don't have the coords */
1522 			if(parent_host->have_2d_coords == FALSE || this_host->have_2d_coords == FALSE)
1523 				continue;
1524 
1525 			/* only draw link if user is authorized for this parent host */
1526 			if(is_authorized_for_host(parent_host, &current_authdata) == FALSE)
1527 				continue;
1528 
1529 			/* are the hosts in the layer list? */
1530 			child_in_layer_list = is_host_in_layer_list(this_host);
1531 			parent_in_layer_list = is_host_in_layer_list(parent_host);
1532 
1533 			/* use dotted or solid line? */
1534 			/* either the child or parent should not be drawn, so use a dotted line */
1535 			if((child_in_layer_list == TRUE && parent_in_layer_list == FALSE) || (child_in_layer_list == FALSE && parent_in_layer_list == TRUE))
1536 				dotted_line = TRUE;
1537 			/* both hosts should not be drawn, so use a dotted line */
1538 			else if((child_in_layer_list == FALSE && parent_in_layer_list == FALSE && exclude_layers == FALSE) || (child_in_layer_list == TRUE && parent_in_layer_list == TRUE && exclude_layers == TRUE))
1539 				dotted_line = TRUE;
1540 			/* both hosts should be drawn, so use a solid line */
1541 			else
1542 				dotted_line = FALSE;
1543 
1544 			/* determine color to use when drawing links to parent host */
1545 			parent_hoststatus = find_hoststatus(parent_host->name);
1546 			if(parent_hoststatus != NULL) {
1547 				if(parent_hoststatus->status == HOST_DOWN || parent_hoststatus->status == HOST_UNREACHABLE)
1548 					status_color = color_red;
1549 				else
1550 					status_color = color_black;
1551 				}
1552 			else
1553 				status_color = color_black;
1554 
1555 			/* draw the link */
1556 			if(dotted_line == TRUE)
1557 				draw_dotted_line((this_host->x_2d + (DEFAULT_NODE_WIDTH / 2)) - canvas_x, (this_host->y_2d + (DEFAULT_NODE_WIDTH) / 2) - canvas_y, (parent_host->x_2d + (DEFAULT_NODE_WIDTH / 2)) - canvas_x, (parent_host->y_2d + (DEFAULT_NODE_WIDTH / 2)) - canvas_y, status_color);
1558 			else
1559 				draw_line((this_host->x_2d + (DEFAULT_NODE_WIDTH / 2)) - canvas_x, (this_host->y_2d + (DEFAULT_NODE_WIDTH) / 2) - canvas_y, (parent_host->x_2d + (DEFAULT_NODE_WIDTH / 2)) - canvas_x, (parent_host->y_2d + (DEFAULT_NODE_WIDTH / 2)) - canvas_y, status_color);
1560 			}
1561 
1562 		}
1563 
1564 	return;
1565 	}
1566 
1567 
1568 
1569 /* draws hosts */
draw_hosts(void)1570 void draw_hosts(void) {
1571 	host *temp_host;
1572 	int x1, x2;
1573 	int y1, y2;
1574 	int has_image = FALSE;
1575 	char image_input_file[MAX_INPUT_BUFFER];
1576 	int current_radius = 0;
1577 	int status_color = color_black;
1578 	hoststatus *temp_hoststatus;
1579 	int in_layer_list = FALSE;
1580 	int average_host_services;
1581 	int host_services;
1582 	double host_services_ratio;
1583 	int outer_radius;
1584 	int inner_radius;
1585 	int time_color = 0;
1586 	time_t current_time;
1587 	int translated_x;
1588 	int translated_y;
1589 
1590 
1591 	/* user didn't supply any coordinates for hosts, so display a warning */
1592 	if(coordinates_were_specified == FALSE) {
1593 
1594 		if(create_type == CREATE_IMAGE) {
1595 			draw_text("You have not supplied any host drawing coordinates, so you cannot use this layout method.", (COORDS_WARNING_WIDTH / 2), 30, color_black);
1596 			draw_text("Read the FAQs for more information on specifying drawing coordinates or select a different layout method.", (COORDS_WARNING_WIDTH / 2), 45, color_black);
1597 			}
1598 
1599 		return;
1600 		}
1601 
1602 	/* draw Nagios process icon if using auto-layout mode */
1603 	if(layout_method != LAYOUT_USER_SUPPLIED && draw_nagios_icon == TRUE) {
1604 
1605 		/* get coords of bounding box */
1606 		x1 = nagios_icon_x - canvas_x;
1607 		x2 = x1 + DEFAULT_NODE_WIDTH;
1608 		y1 = nagios_icon_y - canvas_y;
1609 		y2 = y1 + DEFAULT_NODE_HEIGHT;
1610 
1611 		/* get the name of the image file to open for the logo */
1612 		snprintf(image_input_file, sizeof(image_input_file) - 1, "%s%s", physical_logo_images_path, NAGIOS_GD2_ICON);
1613 		image_input_file[sizeof(image_input_file) - 1] = '\x0';
1614 
1615 		/* read in the image from file... */
1616 		logo_image = load_image_from_file(image_input_file);
1617 
1618 		/* copy the logo image to the canvas image... */
1619 		if(logo_image != NULL) {
1620 			gdImageCopy(map_image, logo_image, x1, y1, 0, 0, logo_image->sx, logo_image->sy);
1621 			gdImageDestroy(logo_image);
1622 			}
1623 
1624 		/* if we don't have an image, draw a bounding box */
1625 		else {
1626 			draw_line(x1, y1, x1, y1 + DEFAULT_NODE_WIDTH, color_black);
1627 			draw_line(x1, y1 + DEFAULT_NODE_WIDTH, x2, y1 + DEFAULT_NODE_WIDTH, color_black);
1628 			draw_line(x2, y1 + DEFAULT_NODE_WIDTH, x2, y1, color_black);
1629 			draw_line(x2, y1, x1, y1, color_black);
1630 			}
1631 
1632 		if(create_type == CREATE_IMAGE)
1633 			draw_text("Nagios Process", x1 + (DEFAULT_NODE_WIDTH / 2), y1 + DEFAULT_NODE_HEIGHT, color_black);
1634 		}
1635 
1636 	/* calculate average services per host */
1637 	average_host_services = 4;
1638 
1639 	/* draw all hosts... */
1640 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
1641 
1642 		/* skip hosts that should not be drawn */
1643 		if(temp_host->should_be_drawn == FALSE)
1644 			continue;
1645 
1646 		/* is this host in the layer inclusion/exclusion list? */
1647 		in_layer_list = is_host_in_layer_list(temp_host);
1648 		if((in_layer_list == TRUE && exclude_layers == TRUE) || (in_layer_list == FALSE && exclude_layers == FALSE))
1649 			continue;
1650 
1651 		/* get coords of host bounding box */
1652 		x1 = temp_host->x_2d - canvas_x;
1653 		x2 = x1 + DEFAULT_NODE_WIDTH;
1654 		y1 = temp_host->y_2d - canvas_y;
1655 		y2 = y1 + DEFAULT_NODE_HEIGHT;
1656 
1657 		if(create_type == CREATE_IMAGE) {
1658 
1659 
1660 			temp_hoststatus = find_hoststatus(temp_host->name);
1661 			if(temp_hoststatus != NULL) {
1662 				if(temp_hoststatus->status == HOST_DOWN)
1663 					status_color = color_red;
1664 				else if(temp_hoststatus->status == HOST_UNREACHABLE)
1665 					status_color = color_red;
1666 				else if(temp_hoststatus->status == HOST_UP)
1667 					status_color = color_green;
1668 				else if(temp_hoststatus->status == HOST_PENDING)
1669 					status_color = color_grey;
1670 				}
1671 			else
1672 				status_color = color_black;
1673 
1674 
1675 			/* use balloons instead of icons... */
1676 			if(layout_method == LAYOUT_CIRCULAR_BALLOON) {
1677 
1678 				/* get the number of services associated with the host */
1679 				host_services = number_of_host_services(temp_host);
1680 
1681 				if(average_host_services == 0)
1682 					host_services_ratio = 0.0;
1683 				else
1684 					host_services_ratio = (double)((double)host_services / (double)average_host_services);
1685 
1686 				/* calculate size of node */
1687 				if(host_services_ratio >= 2.0)
1688 					outer_radius = DEFAULT_NODE_WIDTH;
1689 				else if(host_services_ratio >= 1.5)
1690 					outer_radius = DEFAULT_NODE_WIDTH * 0.8;
1691 				else if(host_services_ratio >= 1.0)
1692 					outer_radius = DEFAULT_NODE_WIDTH * 0.6;
1693 				else if(host_services_ratio >= 0.5)
1694 					outer_radius = DEFAULT_NODE_WIDTH * 0.4;
1695 				else
1696 					outer_radius = DEFAULT_NODE_WIDTH * 0.2;
1697 
1698 				/* calculate width of border */
1699 				if(temp_hoststatus == NULL)
1700 					inner_radius = outer_radius;
1701 				else if((temp_hoststatus->status == HOST_DOWN || temp_hoststatus->status == HOST_UNREACHABLE) && temp_hoststatus->problem_has_been_acknowledged == FALSE)
1702 					inner_radius = outer_radius - 3;
1703 				else
1704 					inner_radius = outer_radius;
1705 
1706 				/* fill node with color based on how long its been in this state... */
1707 				gdImageArc(map_image, x1 + (DEFAULT_NODE_WIDTH / 2), y1 + (DEFAULT_NODE_WIDTH / 2), outer_radius, outer_radius, 0, 360, color_blue);
1708 
1709 				/* determine fill color */
1710 				time(&current_time);
1711 				if(temp_hoststatus == NULL)
1712 					time_color = color_white;
1713 				else if(current_time - temp_hoststatus->last_state_change <= 900)
1714 					time_color = color_orange;
1715 				else if(current_time - temp_hoststatus->last_state_change <= 3600)
1716 					time_color = color_yellow;
1717 				else
1718 					time_color = color_white;
1719 
1720 				/* fill node with appropriate time color */
1721 				/* the fill function only works with coordinates that are in bounds of the actual image */
1722 				translated_x = x1 + (DEFAULT_NODE_WIDTH / 2);
1723 				translated_y = y1 + (DEFAULT_NODE_WIDTH / 2);
1724 				if(translated_x > 0 && translated_y > 0 && translated_x < canvas_width && translated_y < canvas_height)
1725 					gdImageFillToBorder(map_image, translated_x, translated_y, color_blue, time_color);
1726 
1727 				/* border of node should reflect current state */
1728 				for(current_radius = outer_radius; current_radius >= inner_radius; current_radius--)
1729 					gdImageArc(map_image, x1 + (DEFAULT_NODE_WIDTH / 2), y1 + (DEFAULT_NODE_WIDTH / 2), current_radius, current_radius, 0, 360, status_color);
1730 
1731 				/* draw circles around the selected host (if there is one) */
1732 				if(!strcmp(host_name, temp_host->name) && use_highlights == TRUE) {
1733 					for(current_radius = DEFAULT_NODE_WIDTH * 2; current_radius > 0; current_radius -= 10)
1734 						gdImageArc(map_image, x1 + (DEFAULT_NODE_WIDTH / 2), y1 + (DEFAULT_NODE_WIDTH / 2), current_radius, current_radius, 0, 360, status_color);
1735 					}
1736 				}
1737 
1738 
1739 			/* normal method is to use icons for hosts... */
1740 			else {
1741 
1742 				/* draw a target around root hosts (hosts with no parents) */
1743 				if(temp_host != NULL && use_highlights == TRUE) {
1744 					if(temp_host->parent_hosts == NULL) {
1745 						gdImageArc(map_image, x1 + (DEFAULT_NODE_WIDTH / 2), y1 + (DEFAULT_NODE_WIDTH / 2), (DEFAULT_NODE_WIDTH * 2), (DEFAULT_NODE_WIDTH * 2), 0, 360, status_color);
1746 						draw_line(x1 - (DEFAULT_NODE_WIDTH / 2), y1 + (DEFAULT_NODE_WIDTH / 2), x1 + (DEFAULT_NODE_WIDTH * 3 / 2), y1 + (DEFAULT_NODE_WIDTH / 2), status_color);
1747 						draw_line(x1 + (DEFAULT_NODE_WIDTH / 2), y1 - (DEFAULT_NODE_WIDTH / 2), x1 + (DEFAULT_NODE_WIDTH / 2), y1 + (DEFAULT_NODE_WIDTH * 3 / 2), status_color);
1748 						}
1749 					}
1750 
1751 				/* draw circles around the selected host (if there is one) */
1752 				if(!strcmp(host_name, temp_host->name) && use_highlights == TRUE) {
1753 					for(current_radius = DEFAULT_NODE_WIDTH * 2; current_radius > 0; current_radius -= 10)
1754 						gdImageArc(map_image, x1 + (DEFAULT_NODE_WIDTH / 2), y1 + (DEFAULT_NODE_WIDTH / 2), current_radius, current_radius, 0, 360, status_color);
1755 					}
1756 
1757 
1758 				if(temp_host->statusmap_image != NULL)
1759 					has_image = TRUE;
1760 				else
1761 					has_image = FALSE;
1762 
1763 				/* load the logo associated with this host */
1764 				if(has_image == TRUE) {
1765 
1766 					/* get the name of the image file to open for the logo */
1767 					snprintf(image_input_file, sizeof(image_input_file) - 1, "%s%s", physical_logo_images_path, temp_host->statusmap_image);
1768 					image_input_file[sizeof(image_input_file) - 1] = '\x0';
1769 
1770 					/* read in the logo image from file... */
1771 					logo_image = load_image_from_file(image_input_file);
1772 
1773 					/* copy the logo image to the canvas image... */
1774 					if(logo_image != NULL) {
1775 						gdImageCopy(map_image, logo_image, x1, y1, 0, 0, logo_image->sx, logo_image->sy);
1776 						gdImageDestroy(logo_image);
1777 						}
1778 					else
1779 						has_image = FALSE;
1780 					}
1781 
1782 				/* if the host doesn't have an image associated with it (or the user doesn't have rights to see this host), use the unknown image */
1783 				if(has_image == FALSE) {
1784 
1785 					if(unknown_logo_image != NULL)
1786 						gdImageCopy(map_image, unknown_logo_image, x1, y1, 0, 0, unknown_logo_image->sx, unknown_logo_image->sy);
1787 
1788 					else {
1789 
1790 						/* last ditch effort - draw a host bounding box */
1791 						draw_line(x1, y1, x1, y1 + DEFAULT_NODE_WIDTH, color_black);
1792 						draw_line(x1, y1 + DEFAULT_NODE_WIDTH, x2, y1 + DEFAULT_NODE_WIDTH, color_black);
1793 						draw_line(x2, y1 + DEFAULT_NODE_WIDTH, x2, y1, color_black);
1794 						draw_line(x2, y1, x1, y1, color_black);
1795 						}
1796 					}
1797 				}
1798 
1799 
1800 			/* draw host name, status, etc. */
1801 			draw_host_text(temp_host->name, x1 + (DEFAULT_NODE_WIDTH / 2), y1 + DEFAULT_NODE_HEIGHT);
1802 			}
1803 
1804 		/* we're creating HTML image map... */
1805 		else {
1806 			printf("<AREA shape='rect' ");
1807 
1808 			/* coordinates */
1809 			printf("coords='%d,%d,%d,%d' ", (int)(x1 * scaling_factor), (int)(y1 * scaling_factor), (int)((x1 + DEFAULT_NODE_WIDTH)*scaling_factor), (int)((y1 + DEFAULT_NODE_HEIGHT)*scaling_factor));
1810 
1811 			/* URL */
1812 			if(!strcmp(host_name, temp_host->name))
1813 				printf("href='%s?host=%s' ", STATUS_CGI, url_encode(temp_host->name));
1814 			else {
1815 				printf("href='%s?host=%s&layout=%d&max_width=%d&max_height=%d&proximity_width=%d&proximity_height=%d%s%s%s%s%s", STATUSMAP_CGI, url_encode(temp_host->name), layout_method, max_image_width, max_image_height, proximity_width, proximity_height, (display_header == TRUE) ? "" : "&noheader", (use_links == FALSE) ? "&nolinks" : "", (use_text == FALSE) ? "&notext" : "", (use_highlights == FALSE) ? "&nohighlights" : "", (display_popups == FALSE) ? "&nopopups" : "");
1816 				if(user_supplied_scaling == TRUE)
1817 					printf("&scaling_factor=%2.1f", user_scaling_factor);
1818 				print_layer_url(TRUE);
1819 				printf("' ");
1820 				}
1821 
1822 			/* popup text */
1823 			if(display_popups == TRUE) {
1824 
1825 				printf("onMouseOver='showPopup(\"");
1826 				write_host_popup_text(find_host(temp_host->name));
1827 				printf("\",event)' onMouseOut='hidePopup()'");
1828 				}
1829 
1830 			printf(">\n");
1831 			}
1832 
1833 		}
1834 
1835 	return;
1836 	}
1837 
1838 
1839 /* draws text */
draw_text(char * buffer,int x,int y,int text_color)1840 void draw_text(char *buffer, int x, int y, int text_color) {
1841 	int string_width = 0;
1842 	int string_height = 0;
1843 
1844 	/* write the string to the generated image... */
1845 	string_height = gdFontSmall->h;
1846 	string_width = gdFontSmall->w * strlen(buffer);
1847 	if(layout_method != LAYOUT_CIRCULAR_MARKUP)
1848 		gdImageFilledRectangle(map_image, x - (string_width / 2) - 2, y - (2 * string_height), x + (string_width / 2) + 2, y - string_height, color_white);
1849 	gdImageString(map_image, gdFontSmall, x - (string_width / 2), y - (2 * string_height), (unsigned char *)buffer, text_color);
1850 
1851 	return;
1852 	}
1853 
1854 
1855 /* draws host text */
draw_host_text(char * name,int x,int y)1856 void draw_host_text(char *name, int x, int y) {
1857 	hoststatus *temp_hoststatus;
1858 	int status_color = color_black;
1859 	char temp_buffer[MAX_INPUT_BUFFER];
1860 
1861 	if(use_text == FALSE)
1862 		return;
1863 
1864 	strncpy(temp_buffer, name, sizeof(temp_buffer) - 1);
1865 	temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1866 
1867 	/* write the host status string to the generated image... */
1868 	draw_text(temp_buffer, x, y, color_black);
1869 
1870 	/* find the status entry for this host */
1871 	temp_hoststatus = find_hoststatus(name);
1872 
1873 	/* get the status of the host (pending, up, down, or unreachable) */
1874 	if(temp_hoststatus != NULL) {
1875 
1876 		/* draw the status string */
1877 		if(temp_hoststatus->status == HOST_DOWN) {
1878 			strncpy(temp_buffer, "Down", sizeof(temp_buffer));
1879 			status_color = color_red;
1880 			}
1881 		else if(temp_hoststatus->status == HOST_UNREACHABLE) {
1882 			strncpy(temp_buffer, "Unreachable", sizeof(temp_buffer));
1883 			status_color = color_red;
1884 			}
1885 		else if(temp_hoststatus->status == HOST_UP) {
1886 			strncpy(temp_buffer, "Up", sizeof(temp_buffer));
1887 			status_color = color_green;
1888 			}
1889 		else if(temp_hoststatus->status == HOST_PENDING) {
1890 			strncpy(temp_buffer, "Pending", sizeof(temp_buffer));
1891 			status_color = color_grey;
1892 			}
1893 		else {
1894 			strncpy(temp_buffer, "Unknown", sizeof(temp_buffer));
1895 			status_color = color_orange;
1896 			}
1897 
1898 		temp_buffer[sizeof(temp_buffer) - 1] = '\x0';
1899 
1900 		/* write the host status string to the generated image... */
1901 		draw_text(temp_buffer, x, y + gdFontSmall->h, status_color);
1902 		}
1903 
1904 	return;
1905 	}
1906 
1907 
1908 /* writes popup text for a specific host */
write_host_popup_text(host * hst)1909 void write_host_popup_text(host *hst) {
1910 	hoststatus *temp_status = NULL;
1911 	hostsmember *temp_hostsmember = NULL;
1912 	char *processed_string = NULL;
1913 	int service_totals;
1914 	char date_time[48];
1915 	time_t current_time;
1916 	time_t t;
1917 	char state_duration[48];
1918 	int days;
1919 	int hours;
1920 	int minutes;
1921 	int seconds;
1922 
1923 	if(hst == NULL) {
1924 		printf("Host data not found");
1925 		return;
1926 		}
1927 
1928 	/* find the status entry for this host */
1929 	temp_status = find_hoststatus(hst->name);
1930 	if(temp_status == NULL) {
1931 		printf("Host status information not found");
1932 		return;
1933 		}
1934 
1935 	/* grab macros */
1936 	grab_host_macros_r(mac, hst);
1937 
1938 	/* strip nasty stuff from plugin output */
1939 	sanitize_plugin_output(temp_status->plugin_output);
1940 
1941 	printf("<table border=0 cellpadding=0 cellspacing=5>");
1942 
1943 	printf("<tr><td><img src=\\\"%s", url_logo_images_path);
1944 	if(hst->icon_image == NULL)
1945 		printf("%s", UNKNOWN_ICON_IMAGE);
1946 	else {
1947 		process_macros_r(mac, hst->icon_image, &processed_string, 0);
1948 		printf("%s", processed_string);
1949 		free(processed_string);
1950 		}
1951 	printf("\\\" border=0 width=40 height=40></td>");
1952 	printf("<td class=\\\"popupText\\\"><i>%s</i></td></tr>", (hst->icon_image_alt == NULL) ? "" : html_encode(hst->icon_image_alt, TRUE));
1953 
1954 	printf("<tr><td class=\\\"popupText\\\">Name:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>", escape_string(hst->name));
1955 	printf("<tr><td class=\\\"popupText\\\">Alias:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>", escape_string(hst->alias));
1956 	printf("<tr><td class=\\\"popupText\\\">Address:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>", html_encode(hst->address, TRUE));
1957 	printf("<tr><td class=\\\"popupText\\\">State:</td><td class=\\\"popupText\\\"><b>");
1958 
1959 	/* get the status of the host (pending, up, down, or unreachable) */
1960 	if(temp_status->status == HOST_DOWN) {
1961 		printf("<font color=red>Down");
1962 		if(temp_status->problem_has_been_acknowledged == TRUE)
1963 			printf(" (Acknowledged)");
1964 		printf("</font>");
1965 		}
1966 
1967 	else if(temp_status->status == HOST_UNREACHABLE) {
1968 		printf("<font color=red>Unreachable");
1969 		if(temp_status->problem_has_been_acknowledged == TRUE)
1970 			printf(" (Acknowledged)");
1971 		printf("</font>");
1972 		}
1973 
1974 	else if(temp_status->status == HOST_UP)
1975 		printf("<font color=green>Up</font>");
1976 
1977 	else if(temp_status->status == HOST_PENDING)
1978 		printf("Pending");
1979 
1980 	printf("</b></td></tr>");
1981 	printf("<tr><td class=\\\"popupText\\\">Status Information:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>", (temp_status->plugin_output == NULL) ? "" : temp_status->plugin_output);
1982 
1983 	current_time = time(NULL);
1984 	if(temp_status->last_state_change == (time_t)0)
1985 		t = current_time - program_start;
1986 	else
1987 		t = current_time - temp_status->last_state_change;
1988 	get_time_breakdown((unsigned long)t, &days, &hours, &minutes, &seconds);
1989 	snprintf(state_duration, sizeof(state_duration) - 1, "%2dd %2dh %2dm %2ds%s", days, hours, minutes, seconds, (temp_status->last_state_change == (time_t)0) ? "+" : "");
1990 	state_duration[sizeof(state_duration) - 1] = '\x0';
1991 	printf("<tr><td class=\\\"popupText\\\">State Duration:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>", state_duration);
1992 
1993 	get_time_string(&temp_status->last_check, date_time, (int)sizeof(date_time), SHORT_DATE_TIME);
1994 	printf("<tr><td class=\\\"popupText\\\">Last Status Check:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>", (temp_status->last_check == (time_t)0) ? "N/A" : date_time);
1995 	get_time_string(&temp_status->last_state_change, date_time, (int)sizeof(date_time), SHORT_DATE_TIME);
1996 	printf("<tr><td class=\\\"popupText\\\">Last State Change:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>", (temp_status->last_state_change == (time_t)0) ? "N/A" : date_time);
1997 
1998 	printf("<tr><td class=\\\"popupText\\\">Parent Host(s):</td><td class=\\\"popupText\\\"><b>");
1999 	if(hst->parent_hosts == NULL)
2000 		printf("None (This is a root host)");
2001 	else {
2002 		for(temp_hostsmember = hst->parent_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next)
2003 			printf("%s%s", (temp_hostsmember == hst->parent_hosts) ? "" : ", ", html_encode(temp_hostsmember->host_name, TRUE));
2004 		}
2005 	printf("</b></td></tr>");
2006 
2007 	printf("<tr><td class=\\\"popupText\\\">Immediate Child Hosts:</td><td class=\\\"popupText\\\"><b>");
2008 	printf("%d", number_of_immediate_child_hosts(hst));
2009 	printf("</b></td></tr>");
2010 
2011 	printf("</table>");
2012 
2013 	printf("<br><b><u>Services:</u></b><br>");
2014 
2015 	service_totals = get_servicestatus_count(hst->name, SERVICE_OK);
2016 	if(service_totals > 0)
2017 		printf("- <font color=green>%d ok</font><br>", service_totals);
2018 	service_totals = get_servicestatus_count(hst->name, SERVICE_CRITICAL);
2019 	if(service_totals > 0)
2020 		printf("- <font color=red>%d critical</font><br>", service_totals);
2021 	service_totals = get_servicestatus_count(hst->name, SERVICE_WARNING);
2022 	if(service_totals > 0)
2023 		printf("- <font color=orange>%d warning</font><br>", service_totals);
2024 	service_totals = get_servicestatus_count(hst->name, SERVICE_UNKNOWN);
2025 	if(service_totals > 0)
2026 		printf("- <font color=orange>%d unknown</font><br>", service_totals);
2027 	service_totals = get_servicestatus_count(hst->name, SERVICE_PENDING);
2028 	if(service_totals > 0)
2029 		printf("- %d pending<br>", service_totals);
2030 
2031 	return;
2032 	}
2033 
2034 
2035 
2036 /* draws a solid line */
draw_line(int x1,int y1,int x2,int y2,int color)2037 void draw_line(int x1, int y1, int x2, int y2, int color) {
2038 
2039 	if(create_type == CREATE_HTML)
2040 		return;
2041 
2042 	gdImageLine(map_image, x1, y1, x2, y2, color);
2043 
2044 	return;
2045 	}
2046 
2047 
2048 /* draws a dotted line */
draw_dotted_line(int x1,int y1,int x2,int y2,int color)2049 void draw_dotted_line(int x1, int y1, int x2, int y2, int color) {
2050 	int styleDotted[12];
2051 
2052 	styleDotted[0] = color;
2053 	styleDotted[1] = gdTransparent;
2054 	styleDotted[2] = gdTransparent;
2055 	styleDotted[3] = gdTransparent;
2056 	styleDotted[4] = gdTransparent;
2057 	styleDotted[5] = gdTransparent;
2058 	styleDotted[6] = color;
2059 	styleDotted[7] = gdTransparent;
2060 	styleDotted[8] = gdTransparent;
2061 	styleDotted[9] = gdTransparent;
2062 	styleDotted[10] = gdTransparent;
2063 	styleDotted[11] = gdTransparent;
2064 
2065 	/* sets current style to a dashed line */
2066 	gdImageSetStyle(map_image, styleDotted, 12);
2067 
2068 	/* draws a line (dotted) */
2069 	gdImageLine(map_image, x1, y1, x2, y2, gdStyled);
2070 
2071 	return;
2072 	}
2073 
2074 /* draws a dashed line */
draw_dashed_line(int x1,int y1,int x2,int y2,int color)2075 void draw_dashed_line(int x1, int y1, int x2, int y2, int color) {
2076 	int styleDashed[12];
2077 
2078 	styleDashed[0] = color;
2079 	styleDashed[1] = color;
2080 	styleDashed[2] = color;
2081 	styleDashed[3] = color;
2082 	styleDashed[4] = gdTransparent;
2083 	styleDashed[5] = gdTransparent;
2084 	styleDashed[6] = color;
2085 	styleDashed[7] = color;
2086 	styleDashed[8] = color;
2087 	styleDashed[9] = color;
2088 	styleDashed[10] = gdTransparent;
2089 	styleDashed[11] = gdTransparent;
2090 
2091 	/* sets current style to a dashed line */
2092 	gdImageSetStyle(map_image, styleDashed, 12);
2093 
2094 	/* draws a line (dashed) */
2095 	gdImageLine(map_image, x1, y1, x2, y2, gdStyled);
2096 
2097 	return;
2098 	}
2099 
2100 
2101 
2102 /******************************************************************/
2103 /*********************** GRAPHICS FUNCTIONS ***********************/
2104 /******************************************************************/
2105 
2106 /* initialize graphics */
initialize_graphics(void)2107 int initialize_graphics(void) {
2108 	char image_input_file[MAX_INPUT_BUFFER];
2109 
2110 	if(create_type == CREATE_HTML)
2111 		return ERROR;
2112 
2113 	/* allocate buffer for storing image */
2114 #ifndef HAVE_GDIMAGECREATETRUECOLOR
2115 	map_image = gdImageCreate(canvas_width, canvas_height);
2116 #else
2117 	map_image = gdImageCreateTrueColor(canvas_width, canvas_height);
2118 #endif
2119 	if(map_image == NULL)
2120 		return ERROR;
2121 
2122 	/* allocate colors used for drawing */
2123 	color_white = gdImageColorAllocate(map_image, 255, 255, 255);
2124 	color_black = gdImageColorAllocate(map_image, 0, 0, 0);
2125 	color_grey = gdImageColorAllocate(map_image, 128, 128, 128);
2126 	color_lightgrey = gdImageColorAllocate(map_image, 210, 210, 210);
2127 	color_red = gdImageColorAllocate(map_image, 255, 0, 0);
2128 	color_lightred = gdImageColorAllocate(map_image, 215, 175, 175);
2129 	color_green = gdImageColorAllocate(map_image, 0, 175, 0);
2130 	color_lightgreen = gdImageColorAllocate(map_image, 210, 255, 215);
2131 	color_blue = gdImageColorAllocate(map_image, 0, 0, 255);
2132 	color_yellow = gdImageColorAllocate(map_image, 255, 255, 0);
2133 	color_orange = gdImageColorAllocate(map_image, 255, 100, 25);
2134 	color_transparency_index = gdImageColorAllocate(map_image, color_transparency_index_r, color_transparency_index_g, color_transparency_index_b);
2135 
2136 	/* set transparency index */
2137 #ifndef HAVE_GDIMAGECREATETRUECOLOR
2138 	gdImageColorTransparent(map_image, color_white);
2139 #else
2140 	gdImageColorTransparent(map_image, color_transparency_index);
2141 
2142 	/* set background */
2143 	gdImageFill(map_image, 0, 0, color_transparency_index);
2144 #endif
2145 
2146 	/* make sure the graphic is interlaced */
2147 	gdImageInterlace(map_image, 1);
2148 
2149 	/* get the path where we will be reading logo images from (GD2 format)... */
2150 	snprintf(physical_logo_images_path, sizeof(physical_logo_images_path) - 1, "%slogos/", physical_images_path);
2151 	physical_logo_images_path[sizeof(physical_logo_images_path) - 1] = '\x0';
2152 
2153 	/* load the unknown icon to use for hosts that don't have pretty images associated with them... */
2154 	snprintf(image_input_file, sizeof(image_input_file) - 1, "%s%s", physical_logo_images_path, UNKNOWN_GD2_ICON);
2155 	image_input_file[sizeof(image_input_file) - 1] = '\x0';
2156 	unknown_logo_image = load_image_from_file(image_input_file);
2157 
2158 	return OK;
2159 	}
2160 
2161 
2162 
2163 /* loads a graphic image (GD2, JPG or PNG) from file into memory */
load_image_from_file(char * filename)2164 gdImagePtr load_image_from_file(char *filename) {
2165 	FILE *fp;
2166 	gdImagePtr im = NULL;
2167 	char *ext;
2168 
2169 	/* make sure we were passed a file name */
2170 	if(filename == NULL)
2171 		return NULL;
2172 
2173 	/* find the file extension */
2174 	if((ext = rindex(filename, '.')) == NULL)
2175 		return NULL;
2176 
2177 	/* open the file for reading (binary mode) */
2178 	fp = fopen(filename, "rb");
2179 	if(fp == NULL)
2180 		return NULL;
2181 
2182 	/* attempt to read files in various formats */
2183 	if(!strcasecmp(ext, ".png"))
2184 		im = gdImageCreateFromPng(fp);
2185 	else if(!strcasecmp(ext, ".jpg") || !strcasecmp(ext, ".jpeg"))
2186 		im = gdImageCreateFromJpeg(fp);
2187 	else if(!strcasecmp(ext, ".xbm"))
2188 		im = gdImageCreateFromXbm(fp);
2189 	else if(!strcasecmp(ext, ".gd2"))
2190 		im = gdImageCreateFromGd2(fp);
2191 	else if(!strcasecmp(ext, ".gd"))
2192 		im = gdImageCreateFromGd(fp);
2193 
2194 	/* fall back to GD2 image format */
2195 	else
2196 		im = gdImageCreateFromGd2(fp);
2197 
2198 	/* close the file */
2199 	fclose(fp);
2200 
2201 	return im;
2202 	}
2203 
2204 
2205 
2206 /* draw graphics */
write_graphics(void)2207 void write_graphics(void) {
2208 	FILE *image_output_file = NULL;
2209 
2210 	if(create_type == CREATE_HTML)
2211 		return;
2212 
2213 	/* use STDOUT for writing the image data... */
2214 	image_output_file = stdout;
2215 
2216 	/* write the image out in PNG format */
2217 	gdImagePng(map_image, image_output_file);
2218 
2219 	/* or we could write the image out in JPG format... */
2220 	/*gdImageJpeg(map_image,image_output_file,99);*/
2221 
2222 	return;
2223 	}
2224 
2225 
2226 /* cleanup graphics resources */
cleanup_graphics(void)2227 void cleanup_graphics(void) {
2228 
2229 	if(create_type == CREATE_HTML)
2230 		return;
2231 
2232 	/* free memory allocated to image */
2233 	gdImageDestroy(map_image);
2234 
2235 	return;
2236 	}
2237 
2238 
2239 
2240 
2241 /******************************************************************/
2242 /************************* MISC FUNCTIONS *************************/
2243 /******************************************************************/
2244 
2245 
2246 /* write JavaScript code an layer for popup window */
write_popup_code(void)2247 void write_popup_code(void) {
2248 	char *border_color = "#000000";
2249 	char *background_color = "#ffffcc";
2250 	int border = 1;
2251 	int padding = 3;
2252 	int x_offset = 3;
2253 	int y_offset = 3;
2254 
2255 	printf("<SCRIPT LANGUAGE='JavaScript'>\n");
2256 	printf("<!--\n");
2257 	printf("// JavaScript popup based on code originally found at http://www.helpmaster.com/htmlhelp/javascript/popjbpopup.htm\n");
2258 	printf("function showPopup(text, eventObj){\n");
2259 	printf("if(!document.all && document.getElementById)\n");
2260 	printf("{ document.all=document.getElementsByTagName(\"*\")}\n");
2261 	printf("ieLayer = 'document.all[\\'popup\\']';\n");
2262 	printf("nnLayer = 'document.layers[\\'popup\\']';\n");
2263 	printf("moLayer = 'document.getElementById(\\'popup\\')';\n");
2264 
2265 	printf("if(!(document.all||document.layers||document.documentElement)) return;\n");
2266 
2267 	printf("if(document.all) { document.popup=eval(ieLayer); }\n");
2268 	printf("else {\n");
2269 	printf("  if (document.documentElement) document.popup=eval(moLayer);\n");
2270 	printf("  else document.popup=eval(nnLayer);\n");
2271 	printf("}\n");
2272 
2273 	printf("var table = \"\";\n");
2274 
2275 	printf("if (document.all||document.documentElement){\n");
2276 	printf("table += \"<table bgcolor='%s' border=%d cellpadding=%d cellspacing=0>\";\n", background_color, border, padding);
2277 	printf("table += \"<tr><td>\";\n");
2278 	printf("table += \"<table cellspacing=0 cellpadding=%d>\";\n", padding);
2279 	printf("table += \"<tr><td bgcolor='%s' class='popupText'>\" + text + \"</td></tr>\";\n", background_color);
2280 	printf("table += \"</table></td></tr></table>\"\n");
2281 	printf("document.popup.innerHTML = table;\n");
2282 	printf("document.popup.style.left = document.body.scrollLeft + %d;\n", x_offset);
2283 	printf("document.popup.style.top = document.body.scrollTop + %d;\n", y_offset);
2284 	/*
2285 	printf("document.popup.style.left = (document.all ? eventObj.x : eventObj.layerX) + %d;\n",x_offset);
2286 	printf("document.popup.style.top  = (document.all ? eventObj.y : eventObj.layerY) + %d;\n",y_offset);
2287 	*/
2288 
2289 	printf("document.popup.style.visibility = \"visible\";\n");
2290 	printf("} \n");
2291 
2292 
2293 	printf("else{\n");
2294 	printf("table += \"<table cellpadding=%d border=%d cellspacing=0 bordercolor='%s'>\";\n", padding, border, border_color);
2295 	printf("table += \"<tr><td bgcolor='%s' class='popupText'>\" + text + \"</td></tr></table>\";\n", background_color);
2296 	printf("document.popup.document.open();\n");
2297 	printf("document.popup.document.write(table);\n");
2298 	printf("document.popup.document.close();\n");
2299 
2300 	/* set x coordinate */
2301 	printf("document.popup.left = eventObj.layerX + %d;\n", x_offset);
2302 
2303 	/* make sure we don't overlap the right side of the screen */
2304 	printf("if(document.popup.left + document.popup.document.width + %d > window.innerWidth) document.popup.left = window.innerWidth - document.popup.document.width - %d - 16;\n", x_offset, x_offset);
2305 
2306 	/* set y coordinate */
2307 	printf("document.popup.top  = eventObj.layerY + %d;\n", y_offset);
2308 
2309 	/* make sure we don't overlap the bottom edge of the screen */
2310 	printf("if(document.popup.top + document.popup.document.height + %d > window.innerHeight) document.popup.top = window.innerHeight - document.popup.document.height - %d - 16;\n", y_offset, y_offset);
2311 
2312 	/* make the popup visible */
2313 	printf("document.popup.visibility = \"visible\";\n");
2314 	printf("}\n");
2315 	printf("}\n");
2316 
2317 	printf("function hidePopup(){ \n");
2318 	printf("if (!(document.all || document.layers || document.documentElement)) return;\n");
2319 	printf("if (document.popup == null){ }\n");
2320 	printf("else if (document.all||document.documentElement) document.popup.style.visibility = \"hidden\";\n");
2321 	printf("else document.popup.visibility = \"hidden\";\n");
2322 	printf("document.popup = null;\n");
2323 	printf("}\n");
2324 	printf("//-->\n");
2325 
2326 	printf("</SCRIPT>\n");
2327 
2328 	return;
2329 	}
2330 
2331 
2332 
2333 /* adds a layer to the list in memory */
add_layer(char * group_name)2334 int add_layer(char *group_name) {
2335 	layer *new_layer;
2336 
2337 	if(group_name == NULL)
2338 		return ERROR;
2339 
2340 	/* allocate memory for a new layer */
2341 	new_layer = (layer *)malloc(sizeof(layer));
2342 	if(new_layer == NULL)
2343 		return ERROR;
2344 
2345 	new_layer->layer_name = (char *)malloc(strlen(group_name) + 1);
2346 	if(new_layer->layer_name == NULL) {
2347 		free(new_layer);
2348 		return ERROR;
2349 		}
2350 
2351 	strcpy(new_layer->layer_name, group_name);
2352 
2353 	/* add new layer to head of layer list */
2354 	new_layer->next = layer_list;
2355 	layer_list = new_layer;
2356 
2357 	return OK;
2358 	}
2359 
2360 
2361 
2362 /* frees memory allocated to the layer list */
free_layer_list(void)2363 void free_layer_list(void) {
2364 	layer *this_layer;
2365 	layer *next_layer;
2366 
2367 	return;
2368 
2369 	for(this_layer = layer_list; layer_list != NULL; this_layer = next_layer) {
2370 		next_layer = this_layer->next;
2371 		free(this_layer->layer_name);
2372 		free(this_layer);
2373 		}
2374 
2375 	return;
2376 	}
2377 
2378 
2379 /* checks to see if a host is in the layer list */
is_host_in_layer_list(host * hst)2380 int is_host_in_layer_list(host *hst) {
2381 	hostgroup *temp_hostgroup;
2382 	layer *temp_layer;
2383 
2384 	if(hst == NULL)
2385 		return FALSE;
2386 
2387 	/* check each layer... */
2388 	for(temp_layer = layer_list; temp_layer != NULL; temp_layer = temp_layer->next) {
2389 
2390 		/* find the hostgroup */
2391 		temp_hostgroup = find_hostgroup(temp_layer->layer_name);
2392 		if(temp_hostgroup == NULL)
2393 			continue;
2394 
2395 		/* is the requested host a member of the hostgroup/layer? */
2396 		if(is_host_member_of_hostgroup(temp_hostgroup, hst) == TRUE)
2397 			return TRUE;
2398 		}
2399 
2400 	return FALSE;
2401 	}
2402 
2403 
2404 /* print layer url info */
print_layer_url(int get_method)2405 void print_layer_url(int get_method) {
2406 	layer *temp_layer;
2407 
2408 	for(temp_layer = layer_list; temp_layer != NULL; temp_layer = temp_layer->next) {
2409 		if(get_method == TRUE)
2410 			printf("&layer=%s", escape_string(temp_layer->layer_name));
2411 		else
2412 			printf("<input type='hidden' name='layer' value='%s'>\n", escape_string(temp_layer->layer_name));
2413 		}
2414 
2415 	if(get_method == TRUE)
2416 		printf("&layermode=%s", (exclude_layers == TRUE) ? "exclude" : "include");
2417 	else
2418 		printf("<input type='hidden' name='layermode' value='%s'>\n", (exclude_layers == TRUE) ? "exclude" : "include");
2419 
2420 	return;
2421 	}
2422 
2423 
2424 
2425 
2426 /******************************************************************/
2427 /************************ UTILITY FUNCTIONS ***********************/
2428 /******************************************************************/
2429 
2430 /* calculates how many "layers" separate parent and child - used by collapsed tree layout method */
host_child_depth_separation(host * parent,host * child)2431 int host_child_depth_separation(host *parent, host *child) {
2432 	int this_depth = 0;
2433 	int min_depth = 0;
2434 	int have_min_depth = FALSE;
2435 	host *temp_host;
2436 
2437 	if(child == NULL)
2438 		return -1;
2439 
2440 	if(parent == child)
2441 		return 0;
2442 
2443 	if(is_host_immediate_child_of_host(parent, child) == TRUE)
2444 		return 1;
2445 
2446 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2447 
2448 		if(is_host_immediate_child_of_host(parent, temp_host) == TRUE) {
2449 
2450 			this_depth = host_child_depth_separation(temp_host, child);
2451 
2452 			if(this_depth >= 0 && (have_min_depth == FALSE || (have_min_depth == TRUE && (this_depth < min_depth)))) {
2453 				have_min_depth = TRUE;
2454 				min_depth = this_depth;
2455 				}
2456 			}
2457 		}
2458 
2459 	if(have_min_depth == FALSE)
2460 		return -1;
2461 	else
2462 		return min_depth + 1;
2463 	}
2464 
2465 
2466 
2467 /* calculates how many hosts reside on a specific "layer" - used by collapsed tree layout method */
number_of_host_layer_members(host * parent,int layer)2468 int number_of_host_layer_members(host *parent, int layer) {
2469 	int current_layer;
2470 	int layer_members = 0;
2471 	host *temp_host;
2472 
2473 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2474 
2475 		current_layer = host_child_depth_separation(parent, temp_host);
2476 
2477 		if(current_layer == layer)
2478 			layer_members++;
2479 		}
2480 
2481 	return layer_members;
2482 	}
2483 
2484 
2485 
2486 /* calculate max number of members on all "layers" beneath and including parent host - used by collapsed tree layout method */
max_child_host_layer_members(host * parent)2487 int max_child_host_layer_members(host *parent) {
2488 	int current_layer;
2489 	int max_members = 1;
2490 	int current_members = 0;
2491 
2492 	for(current_layer = 1;; current_layer++) {
2493 
2494 		current_members = number_of_host_layer_members(parent, current_layer);
2495 
2496 		if(current_members <= 0)
2497 			break;
2498 
2499 		if(current_members > max_members)
2500 			max_members = current_members;
2501 		}
2502 
2503 	return max_members;
2504 	}
2505 
2506 
2507 
2508 /* calculate max drawing width for host and children - used by balanced tree layout method */
max_child_host_drawing_width(host * parent)2509 int max_child_host_drawing_width(host *parent) {
2510 	host *temp_host;
2511 	int child_width = 0;
2512 
2513 
2514 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2515 
2516 		if(is_host_immediate_child_of_host(parent, temp_host) == TRUE)
2517 			child_width += max_child_host_drawing_width(temp_host);
2518 		}
2519 
2520 	/* no children, so set width to 1 for this host */
2521 	if(child_width == 0)
2522 		return 1;
2523 
2524 	else
2525 		return child_width;
2526 	}
2527 
2528 
2529 
2530 /* calculates number of services associated with a particular service */
number_of_host_services(host * hst)2531 int number_of_host_services(host *hst) {
2532 	service *temp_service;
2533 	int total_services = 0;
2534 
2535 	if(hst == NULL)
2536 		return 0;
2537 
2538 	/* check all the services */
2539 	for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) {
2540 		if(!strcmp(temp_service->host_name, hst->name))
2541 			total_services++;
2542 		}
2543 
2544 	return total_services;
2545 	}
2546 
2547 
2548 
2549 /******************************************************************/
2550 /***************** COORDINATE CALCULATION FUNCTIONS ***************/
2551 /******************************************************************/
2552 
2553 /* calculates coords of a host's children - used by balanced tree layout method */
calculate_balanced_tree_coords(host * parent,int x,int y)2554 void calculate_balanced_tree_coords(host *parent, int x, int y) {
2555 	int parent_drawing_width;
2556 	int start_drawing_x;
2557 	int current_drawing_x;
2558 	int this_drawing_width;
2559 	host *temp_host;
2560 
2561 	/* calculate total drawing width of parent host */
2562 	parent_drawing_width = max_child_host_drawing_width(parent);
2563 
2564 	/* calculate starting x coord */
2565 	start_drawing_x = x - (((DEFAULT_NODE_WIDTH * parent_drawing_width) + (DEFAULT_NODE_HSPACING * (parent_drawing_width - 1))) / 2);
2566 	current_drawing_x = start_drawing_x;
2567 
2568 
2569 	/* calculate coords for children */
2570 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2571 
2572 		if(is_host_immediate_child_of_host(parent, temp_host) == TRUE) {
2573 
2574 			/* get drawing width of child host */
2575 			this_drawing_width = max_child_host_drawing_width(temp_host);
2576 
2577 			temp_host->x_2d = current_drawing_x + (((DEFAULT_NODE_WIDTH * this_drawing_width) + (DEFAULT_NODE_HSPACING * (this_drawing_width - 1))) / 2);
2578 			temp_host->y_2d = y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_VSPACING;
2579 			temp_host->have_2d_coords = TRUE;
2580 			temp_host->should_be_drawn = TRUE;
2581 
2582 			current_drawing_x += (this_drawing_width * DEFAULT_NODE_WIDTH) + ((this_drawing_width - 1) * DEFAULT_NODE_HSPACING) + DEFAULT_NODE_HSPACING;
2583 
2584 			/* recurse into child host ... */
2585 			calculate_balanced_tree_coords(temp_host, temp_host->x_2d, temp_host->y_2d);
2586 			}
2587 
2588 		}
2589 
2590 	return;
2591 	}
2592 
2593 
2594 /* calculate coords of all hosts in circular layout method */
calculate_circular_coords(void)2595 void calculate_circular_coords(void) {
2596 	int min_x = 0;
2597 	int min_y = 0;
2598 	int have_min_x = FALSE;
2599 	int have_min_y = FALSE;
2600 	host *temp_host;
2601 
2602 	/* calculate all host coords, starting with first layer */
2603 	calculate_circular_layer_coords(NULL, 0.0, 360.0, 1, CIRCULAR_DRAWING_RADIUS);
2604 
2605 	/* adjust all calculated coords so none are negative in x or y axis... */
2606 
2607 	/* calculate min x, y coords */
2608 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2609 		if(have_min_x == FALSE || temp_host->x_2d < min_x) {
2610 			have_min_x = TRUE;
2611 			min_x = temp_host->x_2d;
2612 			}
2613 		if(have_min_y == FALSE || temp_host->y_2d < min_y) {
2614 			have_min_y = TRUE;
2615 			min_y = temp_host->y_2d;
2616 			}
2617 		}
2618 
2619 	/* offset all drawing coords by the min x,y coords we found */
2620 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2621 		if(min_x < 0)
2622 			temp_host->x_2d -= min_x;
2623 		if(min_y < 0)
2624 			temp_host->y_2d -= min_y;
2625 		}
2626 
2627 	if(min_x < 0)
2628 		nagios_icon_x -= min_x;
2629 	if(min_y < 0)
2630 		nagios_icon_y -= min_y;
2631 
2632 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2633 		temp_host->x_2d += (DEFAULT_NODE_WIDTH / 2);
2634 		temp_host->y_2d += (DEFAULT_NODE_HEIGHT / 2);
2635 		}
2636 	nagios_icon_x += (DEFAULT_NODE_WIDTH / 2);
2637 	nagios_icon_y += (DEFAULT_NODE_HEIGHT / 2);
2638 
2639 	return;
2640 	}
2641 
2642 
2643 /* calculates coords of all hosts in a particular "layer" in circular layout method */
calculate_circular_layer_coords(host * parent,double start_angle,double useable_angle,int layer,int radius)2644 void calculate_circular_layer_coords(host *parent, double start_angle, double useable_angle, int layer, int radius) {
2645 	int parent_drawing_width = 0;
2646 	int this_drawing_width = 0;
2647 	int immediate_children = 0;
2648 	double current_drawing_angle = 0.0;
2649 	double this_drawing_angle = 0.0;
2650 	double available_angle = 0.0;
2651 	double clipped_available_angle = 0.0;
2652 	double average_child_angle = 0.0;
2653 	double x_coord = 0.0;
2654 	double y_coord = 0.0;
2655 	host *temp_host;
2656 
2657 
2658 	/* get the total number of immediate children to this host */
2659 	immediate_children = number_of_immediate_child_hosts(parent);
2660 
2661 	/* bail out if we're done */
2662 	if(immediate_children == 0)
2663 		return;
2664 
2665 	/* calculate total drawing "width" of parent host */
2666 	parent_drawing_width = max_child_host_drawing_width(parent);
2667 
2668 	/* calculate average angle given to each child host */
2669 	average_child_angle = (double)(useable_angle / (double)immediate_children);
2670 
2671 	/* calculate initial drawing angle */
2672 	current_drawing_angle = start_angle;
2673 
2674 
2675 	/* calculate coords for children */
2676 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2677 
2678 		if(is_host_immediate_child_of_host(parent, temp_host) == TRUE) {
2679 
2680 			/* get drawing width of child host */
2681 			this_drawing_width = max_child_host_drawing_width(temp_host);
2682 
2683 			/* calculate angle this host gets for drawing */
2684 			available_angle = useable_angle * ((double)this_drawing_width / (double)parent_drawing_width);
2685 
2686 			/* clip available angle if necessary */
2687 			/* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */
2688 			clipped_available_angle = 360.0 / layer;
2689 			if(available_angle < clipped_available_angle)
2690 				clipped_available_angle = available_angle;
2691 
2692 			/* calculate the exact angle at which we should draw this child */
2693 			this_drawing_angle = current_drawing_angle + (available_angle / 2.0);
2694 
2695 			/* compensate for angle overflow */
2696 			while(this_drawing_angle >= 360.0)
2697 				this_drawing_angle -= 360.0;
2698 			while(this_drawing_angle < 0.0)
2699 				this_drawing_angle += 360.0;
2700 
2701 			/* calculate drawing coords of this host using good ol' geometry... */
2702 			x_coord = -(sin(-this_drawing_angle * (M_PI / 180.0)) * radius);
2703 			y_coord = -(sin((90 + this_drawing_angle) * (M_PI / 180.0)) * radius);
2704 
2705 			temp_host->x_2d = (int)x_coord;
2706 			temp_host->y_2d = (int)y_coord;
2707 			temp_host->have_2d_coords = TRUE;
2708 			temp_host->should_be_drawn = TRUE;
2709 
2710 			/* recurse into child host ... */
2711 			calculate_circular_layer_coords(temp_host, current_drawing_angle + ((available_angle - clipped_available_angle) / 2), clipped_available_angle, layer + 1, radius + CIRCULAR_DRAWING_RADIUS);
2712 
2713 			/* increment current drawing angle */
2714 			current_drawing_angle += available_angle;
2715 			}
2716 		}
2717 
2718 	return;
2719 	}
2720 
2721 
2722 
2723 /* draws background "extras" for all hosts in circular markup layout */
draw_circular_markup(void)2724 void draw_circular_markup(void) {
2725 
2726 	/* calculate all host sections, starting with first layer */
2727 	draw_circular_layer_markup(NULL, 0.0, 360.0, 1, CIRCULAR_DRAWING_RADIUS);
2728 
2729 	return;
2730 	}
2731 
2732 
2733 /* draws background "extras" for all hosts in a particular "layer" in circular markup layout */
draw_circular_layer_markup(host * parent,double start_angle,double useable_angle,int layer,int radius)2734 void draw_circular_layer_markup(host *parent, double start_angle, double useable_angle, int layer, int radius) {
2735 	int parent_drawing_width = 0;
2736 	int this_drawing_width = 0;
2737 	int immediate_children = 0;
2738 	double current_drawing_angle = 0.0;
2739 	double available_angle = 0.0;
2740 	double clipped_available_angle = 0.0;
2741 	double average_child_angle = 0.0;
2742 	double x_coord[4] = {0.0, 0.0, 0.0, 0.0};
2743 	double y_coord[4] = {0.0, 0.0, 0.0, 0.0};
2744 	hoststatus *temp_hoststatus;
2745 	host *temp_host;
2746 	int x_offset = 0;
2747 	int y_offset = 0;
2748 	int center_x = 0;
2749 	int center_y = 0;
2750 	int bgcolor = 0;
2751 	double arc_start_angle = 0.0;
2752 	double arc_end_angle = 0.0;
2753 	int translated_x = 0;
2754 	int translated_y = 0;
2755 
2756 	/* get the total number of immediate children to this host */
2757 	immediate_children = number_of_immediate_child_hosts(parent);
2758 
2759 	/* bail out if we're done */
2760 	if(immediate_children == 0)
2761 		return;
2762 
2763 	/* calculate total drawing "width" of parent host */
2764 	parent_drawing_width = max_child_host_drawing_width(parent);
2765 
2766 	/* calculate average angle given to each child host */
2767 	average_child_angle = (double)(useable_angle / (double)immediate_children);
2768 
2769 	/* calculate initial drawing angle */
2770 	current_drawing_angle = start_angle;
2771 
2772 	/* calculate coords for children */
2773 	for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
2774 
2775 		if(is_host_immediate_child_of_host(parent, temp_host) == TRUE) {
2776 
2777 			/* get drawing width of child host */
2778 			this_drawing_width = max_child_host_drawing_width(temp_host);
2779 
2780 			/* calculate angle this host gets for drawing */
2781 			available_angle = useable_angle * ((double)this_drawing_width / (double)parent_drawing_width);
2782 
2783 			/* clip available angle if necessary */
2784 			/* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */
2785 			clipped_available_angle = 360.0 / layer;
2786 			if(available_angle < clipped_available_angle)
2787 				clipped_available_angle = available_angle;
2788 
2789 			/* calculate drawing coords of "leftmost" divider using good ol' geometry... */
2790 			x_coord[0] = -(sin(-current_drawing_angle * (M_PI / 180.0)) * (radius - (CIRCULAR_DRAWING_RADIUS / 2)));
2791 			y_coord[0] = -(sin((90 + current_drawing_angle) * (M_PI / 180.0)) * (radius - (CIRCULAR_DRAWING_RADIUS / 2)));
2792 			x_coord[1] = -(sin(-current_drawing_angle * (M_PI / 180.0)) * (radius + (CIRCULAR_DRAWING_RADIUS / 2)));
2793 			y_coord[1] = -(sin((90 + current_drawing_angle) * (M_PI / 180.0)) * (radius + (CIRCULAR_DRAWING_RADIUS / 2)));
2794 
2795 			/* calculate drawing coords of "rightmost" divider using good ol' geometry... */
2796 			x_coord[2] = -(sin((-(current_drawing_angle + available_angle)) * (M_PI / 180.0)) * (radius - (CIRCULAR_DRAWING_RADIUS / 2)));
2797 			y_coord[2] = -(sin((90 + current_drawing_angle + available_angle) * (M_PI / 180.0)) * (radius - (CIRCULAR_DRAWING_RADIUS / 2)));
2798 			x_coord[3] = -(sin((-(current_drawing_angle + available_angle)) * (M_PI / 180.0)) * (radius + (CIRCULAR_DRAWING_RADIUS / 2)));
2799 			y_coord[3] = -(sin((90 + current_drawing_angle + available_angle) * (M_PI / 180.0)) * (radius + (CIRCULAR_DRAWING_RADIUS / 2)));
2800 
2801 
2802 			x_offset = nagios_icon_x + (DEFAULT_NODE_WIDTH / 2) - canvas_x;
2803 			y_offset = nagios_icon_y + (DEFAULT_NODE_HEIGHT / 2) - canvas_y;
2804 
2805 			/* draw "slice" dividers */
2806 			if(immediate_children > 1 || layer > 1) {
2807 
2808 				/* draw "leftmost" divider */
2809 				gdImageLine(map_image, (int)x_coord[0] + x_offset, (int)y_coord[0] + y_offset, (int)x_coord[1] + x_offset, (int)y_coord[1] + y_offset, color_lightgrey);
2810 
2811 				/* draw "rightmost" divider */
2812 				gdImageLine(map_image, (int)x_coord[2] + x_offset, (int)y_coord[2] + y_offset, (int)x_coord[3] + x_offset, (int)y_coord[3] + y_offset, color_lightgrey);
2813 				}
2814 
2815 			/* determine arc drawing angles */
2816 			arc_start_angle = current_drawing_angle - 90.0;
2817 			while(arc_start_angle < 0.0)
2818 				arc_start_angle += 360.0;
2819 			arc_end_angle = arc_start_angle + available_angle;
2820 
2821 			/* draw inner arc */
2822 			gdImageArc(map_image, x_offset, y_offset, (radius - (CIRCULAR_DRAWING_RADIUS / 2)) * 2, (radius - (CIRCULAR_DRAWING_RADIUS / 2)) * 2, floor(arc_start_angle), ceil(arc_end_angle), color_lightgrey);
2823 
2824 			/* draw outer arc */
2825 			gdImageArc(map_image, x_offset, y_offset, (radius + (CIRCULAR_DRAWING_RADIUS / 2)) * 2, (radius + (CIRCULAR_DRAWING_RADIUS / 2)) * 2, floor(arc_start_angle), ceil(arc_end_angle), color_lightgrey);
2826 
2827 
2828 			/* determine center of "slice" and fill with appropriate color */
2829 			center_x = -(sin(-(current_drawing_angle + (available_angle / 2.0)) * (M_PI / 180.0)) * (radius));
2830 			center_y = -(sin((90 + current_drawing_angle + (available_angle / 2.0)) * (M_PI / 180.0)) * (radius));
2831 			translated_x = center_x + x_offset;
2832 			translated_y = center_y + y_offset;
2833 
2834 			/* determine background color */
2835 			temp_hoststatus = find_hoststatus(temp_host->name);
2836 			if(temp_hoststatus == NULL)
2837 				bgcolor = color_lightgrey;
2838 			else if(temp_hoststatus->status == HOST_DOWN || temp_hoststatus->status == HOST_UNREACHABLE)
2839 				bgcolor = color_lightred;
2840 			else
2841 				bgcolor = color_lightgreen;
2842 
2843 			/* fill slice with background color */
2844 			/* the fill function only works with coordinates that are in bounds of the actual image */
2845 			if(translated_x > 0 && translated_y > 0 && translated_x < canvas_width && translated_y < canvas_height)
2846 				gdImageFillToBorder(map_image, translated_x, translated_y, color_lightgrey, bgcolor);
2847 
2848 			/* recurse into child host ... */
2849 			draw_circular_layer_markup(temp_host, current_drawing_angle + ((available_angle - clipped_available_angle) / 2), clipped_available_angle, layer + 1, radius + CIRCULAR_DRAWING_RADIUS);
2850 
2851 			/* increment current drawing angle */
2852 			current_drawing_angle += available_angle;
2853 			}
2854 		}
2855 
2856 	return;
2857 	}
2858 
2859