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(¤t_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(¤t_time);
324 get_time_string(¤t_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(¤t_time);
366 get_time_string(¤t_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, ¤t_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 </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'> 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, ¤t_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) ? "¬ext" : "", (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, ¤t_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, ¤t_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, ¤t_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(¤t_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) ? "¬ext" : "", (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