Icinga-core 1.4.0
next gen monitoring
cgi/statusmap.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * STATUSMAP.C - Icinga Network Status Map CGI
00004  *
00005  * Copyright (c) 1999-2008 Ethan Galstad (egalstad@nagios.org)
00006  * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org)
00007  *
00008  * Description:
00009  *
00010  * This CGI will create a map of all hosts that are being monitored on your
00011  * network.
00012  *
00013  * License:
00014  *
00015  * This program is free software; you can redistribute it and/or modify
00016  * it under the terms of the GNU General Public License version 2 as
00017  * published by the Free Software Foundation.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027  *
00028  *****************************************************************************/
00029 
00030 #include "../include/config.h"
00031 #include "../include/common.h"
00032 #include "../include/objects.h"
00033 #include "../include/macros.h"
00034 #include "../include/statusdata.h"
00035 #include "../include/cgiutils.h"
00036 #include "../include/getcgi.h"
00037 #include "../include/cgiauth.h"
00038 
00039 #include <gd.h>                 /* Boutell's GD library function */
00040 #include <gdfonts.h>            /* GD library small font definition */
00041 
00042 static icinga_macros *mac;
00043 
00044 /*#define DEBUG*/
00045 
00046 #define UNKNOWN_GD2_ICON      "unknown.gd2"
00047 #define UNKNOWN_ICON_IMAGE    "unknown.gif"
00048 #define ICINGA_GD2_ICON       "icinga.gd2"
00049 
00050 extern char main_config_file[MAX_FILENAME_LENGTH];
00051 extern char url_html_path[MAX_FILENAME_LENGTH];
00052 extern char physical_images_path[MAX_FILENAME_LENGTH];
00053 extern char url_images_path[MAX_FILENAME_LENGTH];
00054 extern char url_logo_images_path[MAX_FILENAME_LENGTH];
00055 extern char url_stylesheets_path[MAX_FILENAME_LENGTH];
00056 extern char url_js_path[MAX_FILENAME_LENGTH];
00057 
00058 extern host *host_list;
00059 extern hostgroup *hostgroup_list;
00060 extern service *service_list;
00061 extern hoststatus *hoststatus_list;
00062 extern servicestatus *servicestatus_list;
00063 
00064 extern char *statusmap_background_image;
00065 
00066 extern int default_statusmap_layout_method;
00067 
00068 #define DEFAULT_NODE_WIDTH              40
00069 #define DEFAULT_NODE_HEIGHT             65
00070 
00071 #define DEFAULT_NODE_VSPACING           15
00072 #define DEFAULT_NODE_HSPACING           45
00073 
00074 #define DEFAULT_PROXIMITY_WIDTH         1000
00075 #define DEFAULT_PROXIMITY_HEIGHT        800
00076 
00077 #define MINIMUM_PROXIMITY_WIDTH         250
00078 #define MINIMUM_PROXIMITY_HEIGHT        200
00079 
00080 #define COORDS_WARNING_WIDTH            650
00081 #define COORDS_WARNING_HEIGHT           60
00082 
00083 #define CIRCULAR_DRAWING_RADIUS         100
00084 
00085 #define LAYOUT_USER_SUPPLIED            0
00086 #define LAYOUT_SUBLAYERS                1
00087 #define LAYOUT_COLLAPSED_TREE           2
00088 #define LAYOUT_BALANCED_TREE            3
00089 #define LAYOUT_CIRCULAR                 4
00090 #define LAYOUT_CIRCULAR_MARKUP          5
00091 #define LAYOUT_CIRCULAR_BALLOON         6
00092 
00093 
00094 typedef struct layer_struct{
00095         char *layer_name;
00096         struct layer_struct *next;
00097         }layer;
00098 
00099 int process_cgivars(void);
00100 
00101 void display_page_header(void);
00102 void display_map(void);
00103 void calculate_host_coords(void);
00104 void calculate_total_image_bounds(void);
00105 void calculate_canvas_bounds(void);
00106 void calculate_canvas_bounds_from_host(char *);
00107 void calculate_scaling_factor(void);
00108 void find_eligible_hosts(void);
00109 void load_background_image(void);
00110 void draw_background_image(void);
00111 void draw_background_extras(void);
00112 void draw_host_links(void);
00113 void draw_hosts(void);
00114 void draw_host_text(char *,int,int);
00115 void draw_text(char *,int,int,int);
00116 void write_host_popup_text(host *);
00117 
00118 int initialize_graphics(void);
00119 gdImagePtr load_image_from_file(char *);
00120 void write_graphics(void);
00121 void cleanup_graphics(void);
00122 void draw_line(int,int,int,int,int);
00123 void draw_dotted_line(int,int,int,int,int);
00124 void draw_dashed_line(int,int,int,int,int);
00125 
00126 int is_host_in_layer_list(host *);
00127 int add_layer(char *);
00128 void free_layer_list(void);
00129 void print_layer_url(int);
00130 
00131 int number_of_host_layer_members(host *,int);
00132 int max_child_host_layer_members(host *);
00133 int host_child_depth_separation(host *, host *);
00134 int max_child_host_drawing_width(host *);
00135 int number_of_host_services(host *);
00136 
00137 void calculate_balanced_tree_coords(host *,int,int);
00138 void calculate_circular_coords(void);
00139 void calculate_circular_layer_coords(host *,double,double,int,int);
00140 
00141 void draw_circular_markup(void);
00142 void draw_circular_layer_markup(host *,double,double,int,int);
00143 
00144 
00145 char physical_logo_images_path[MAX_FILENAME_LENGTH];
00146 
00147 authdata current_authdata;
00148 
00149 extern int content_type;
00150 
00151 gdImagePtr unknown_logo_image=NULL;
00152 gdImagePtr logo_image=NULL;
00153 gdImagePtr map_image=NULL;
00154 gdImagePtr background_image=NULL;
00155 int color_white=0;
00156 int color_black=0;
00157 int color_red=0;
00158 int color_lightred=0;
00159 int color_green=0;
00160 int color_lightgreen=0;
00161 int color_blue=0;
00162 int color_yellow=0;
00163 int color_orange=0;
00164 int color_grey=0;
00165 int color_lightgrey=0;
00166 int color_transparency_index=0;
00167 extern int color_transparency_index_r;
00168 extern int color_transparency_index_g;
00169 extern int color_transparency_index_b;
00170 
00171 extern int embedded;
00172 extern int refresh;
00173 extern int display_header;
00174 extern int daemon_check;
00175 
00176 int display_popups=TRUE;
00177 int use_links=TRUE;
00178 int use_text=TRUE;
00179 int use_highlights=TRUE;
00180 int user_supplied_canvas=FALSE;
00181 int user_supplied_scaling=FALSE;
00182 
00183 int layout_method=LAYOUT_USER_SUPPLIED;
00184 
00185 int proximity_width=DEFAULT_PROXIMITY_WIDTH;
00186 int proximity_height=DEFAULT_PROXIMITY_HEIGHT;
00187 
00188 int coordinates_were_specified=FALSE;   /* were any coordinates specified in extended host information entries? */
00189 
00190 int scaled_image_width=0;        /* size of the image actually displayed on the screen (after scaling) */
00191 int scaled_image_height=0;
00192 int canvas_width=0;              /* actual size of the image (or portion thereof) that we are drawing */
00193 int canvas_height=0;
00194 int total_image_width=0;         /* actual size of the image that would be created if we drew all hosts */
00195 int total_image_height=0;
00196 int max_image_width=0;           /* max image size the user wants (scaled) */
00197 int max_image_height=0;
00198 double scaling_factor=1.0;       /* scaling factor to use */
00199 double user_scaling_factor=1.0;  /* user-supplied scaling factor */
00200 int background_image_width=0;
00201 int background_image_height=0;
00202 
00203 int canvas_x=0;                     /* upper left coords of drawing canvas */
00204 int canvas_y=0;
00205 
00206 int bottom_margin=0;
00207 
00208 int draw_child_links=FALSE;
00209 int draw_parent_links=FALSE;
00210 
00211 int draw_nagios_icon=FALSE;    /* should we drawn the Icinga process icon? */
00212 int nagios_icon_x=0;           /* coords of Icinga icon */
00213 int nagios_icon_y=0;
00214 
00215 extern hoststatus *hoststatus_list;
00216 
00217 extern time_t program_start;
00218 
00219 layer *layer_list=NULL;
00220 int exclude_layers=TRUE;
00221 int all_layers=FALSE;
00222 
00223 int display_type=DISPLAY_HOSTS;
00224 int show_all_hosts=TRUE;
00225 int show_all_hostgroups=TRUE;
00226 int show_all_servicegroups=TRUE;
00227 
00228 char *host_name="all";
00229 char *host_filter=NULL;
00230 char *hostgroup_name=NULL;
00231 char *servicegroup_name=NULL;
00232 char *service_desc=NULL;
00233 char *service_filter=NULL;
00234 
00235 int CGI_ID=STATUSMAP_CGI_ID;
00236 
00237 int main(int argc, char **argv){
00238         int result;
00239 
00240         mac = get_global_macros();
00241 
00242         /* reset internal variables */
00243         reset_cgi_vars();
00244 
00245         /* read the CGI configuration file */
00246         result=read_cgi_config_file(get_cgi_config_location());
00247         if(result==ERROR){
00248                 document_header(CGI_ID,FALSE);
00249                 if(content_type==HTML_CONTENT)
00250                         print_error(get_cgi_config_location(), ERROR_CGI_CFG_FILE);
00251                 document_footer(CGI_ID);
00252                 return ERROR;
00253                 }
00254 
00255         /* defaults from CGI config file */
00256         layout_method=default_statusmap_layout_method;
00257 
00258         /* get the arguments passed in the URL */
00259         process_cgivars();
00260 
00261         /* read the main configuration file */
00262         result=read_main_config_file(main_config_file);
00263         if(result==ERROR){
00264                 document_header(CGI_ID,FALSE);
00265                 if(content_type==HTML_CONTENT)
00266                         print_error(main_config_file, ERROR_CGI_MAIN_CFG);
00267                 document_footer(CGI_ID);
00268                 return ERROR;
00269                 }
00270 
00271         /* read all object configuration data */
00272         result=read_all_object_configuration_data(main_config_file,READ_ALL_OBJECT_DATA);
00273         if(result==ERROR){
00274                 document_header(CGI_ID,FALSE);
00275                 if(content_type==HTML_CONTENT)
00276                         print_error(NULL, ERROR_CGI_OBJECT_DATA);
00277                 document_footer(CGI_ID);
00278                 return ERROR;
00279                 }
00280 
00281         /* read all status data */
00282         result=read_all_status_data(get_cgi_config_location(),READ_ALL_STATUS_DATA);
00283         if(result==ERROR && daemon_check==TRUE){
00284                 document_header(CGI_ID,FALSE);
00285                 if(content_type==HTML_CONTENT)
00286                         print_error(NULL, ERROR_CGI_STATUS_DATA);
00287                 document_footer(CGI_ID);
00288                 free_memory();
00289                 return ERROR;
00290                 }
00291 
00292         /* initialize macros */
00293         init_macros();
00294 
00295 
00296         document_header(CGI_ID,TRUE);
00297 
00298         /* get authentication information */
00299         get_authentication_information(&current_authdata);
00300 
00301         /* display the network map... */
00302         display_map();
00303 
00304         document_footer(CGI_ID);
00305 
00306         /* free all allocated memory */
00307         free_memory();
00308         free_layer_list();
00309 
00310         return OK;
00311         }
00312 
00313 int process_cgivars(void){
00314         char **variables;
00315         int error=FALSE;
00316         int x;
00317 
00318         variables=getcgivars();
00319 
00320         for(x=0;variables[x]!=NULL;x++){
00321 
00322                 /* do some basic length checking on the variable identifier to prevent buffer overflows */
00323                 if(strlen(variables[x])>=MAX_INPUT_BUFFER-1){
00324                         x++;
00325                         continue;
00326                         }
00327 
00328                 /* we found the host argument */
00329                 else if(!strcmp(variables[x],"host")){
00330                         x++;
00331                         if(variables[x]==NULL){
00332                                 error=TRUE;
00333                                 break;
00334                                 }
00335 
00336                         if((host_name=(char *)strdup(variables[x]))==NULL)
00337                                 host_name="all";
00338                         else
00339                                 strip_html_brackets(host_name);
00340 
00341                         if(!strcmp(host_name,"all"))
00342                                 show_all_hosts=TRUE;
00343                         else
00344                                 show_all_hosts=FALSE;
00345                         }
00346 
00347                 /* we found the image creation option */
00348                 else if(!strcmp(variables[x],"createimage")){
00349                         content_type=IMAGE_CONTENT;
00350                         }
00351 
00352                 /* we found the embed option */
00353                 else if(!strcmp(variables[x],"embedded"))
00354                         embedded=TRUE;
00355 
00356                 /* we found the noheader option */
00357                 else if(!strcmp(variables[x],"noheader"))
00358                         display_header=FALSE;
00359 
00360                 /* we found the canvas origin */
00361                 else if(!strcmp(variables[x],"canvas_x")){
00362                         x++;
00363                         if(variables[x]==NULL){
00364                                 error=TRUE;
00365                                 break;
00366                                 }
00367                         canvas_x=atoi(variables[x]);
00368                         user_supplied_canvas=TRUE;
00369                         }
00370                 else if(!strcmp(variables[x],"canvas_y")){
00371                         x++;
00372                         if(variables[x]==NULL){
00373                                 error=TRUE;
00374                                 break;
00375                                 }
00376                         canvas_y=atoi(variables[x]);
00377                         user_supplied_canvas=TRUE;
00378                         }
00379 
00380                 /* we found the canvas size */
00381                 else if(!strcmp(variables[x],"canvas_width")){
00382                         x++;
00383                         if(variables[x]==NULL){
00384                                 error=TRUE;
00385                                 break;
00386                                 }
00387                         canvas_width=atoi(variables[x]);
00388                         user_supplied_canvas=TRUE;
00389                         }
00390                 else if(!strcmp(variables[x],"canvas_height")){
00391                         x++;
00392                         if(variables[x]==NULL){
00393                                 error=TRUE;
00394                                 break;
00395                                 }
00396                         canvas_height=atoi(variables[x]);
00397                         user_supplied_canvas=TRUE;
00398                         }
00399                 else if(!strcmp(variables[x],"proximity_width")){
00400                         x++;
00401                         if(variables[x]==NULL){
00402                                 error=TRUE;
00403                                 break;
00404                                 }
00405                         proximity_width=atoi(variables[x]);
00406                         if(proximity_width<0)
00407                                 proximity_width=DEFAULT_PROXIMITY_WIDTH;
00408                         }
00409                 else if(!strcmp(variables[x],"proximity_height")){
00410                         x++;
00411                         if(variables[x]==NULL){
00412                                 error=TRUE;
00413                                 break;
00414                                 }
00415                         proximity_height=atoi(variables[x]);
00416                         if(proximity_height<0)
00417                                 proximity_height=DEFAULT_PROXIMITY_HEIGHT;
00418                         }
00419 
00420                 /* we found the scaling factor */
00421                 else if(!strcmp(variables[x],"scaling_factor")){
00422                         x++;
00423                         if(variables[x]==NULL){
00424                                 error=TRUE;
00425                                 break;
00426                                 }
00427                         user_scaling_factor=strtod(variables[x],NULL);
00428                         if(user_scaling_factor>0.0)
00429                                 user_supplied_scaling=TRUE;
00430                         }
00431 
00432                 /* we found the max image size */
00433                 else if(!strcmp(variables[x],"max_width")){
00434                         x++;
00435                         if(variables[x]==NULL){
00436                                 error=TRUE;
00437                                 break;
00438                                 }
00439                         max_image_width=atoi(variables[x]);
00440                         }
00441                 else if(!strcmp(variables[x],"max_height")){
00442                         x++;
00443                         if(variables[x]==NULL){
00444                                 error=TRUE;
00445                                 break;
00446                                 }
00447                         max_image_height=atoi(variables[x]);
00448                         }
00449 
00450                 /* we found the layout method option */
00451                 else if(!strcmp(variables[x],"layout")){
00452                         x++;
00453                         if(variables[x]==NULL){
00454                                 error=TRUE;
00455                                 break;
00456                                 }
00457                         layout_method=atoi(variables[x]);
00458                         }
00459 
00460                 /* we found the no links argument*/
00461                 else if(!strcmp(variables[x],"nolinks"))
00462                         use_links=FALSE;
00463 
00464                 /* we found the no text argument*/
00465                 else if(!strcmp(variables[x],"notext"))
00466                         use_text=FALSE;
00467 
00468                 /* we found the no highlights argument*/
00469                 else if(!strcmp(variables[x],"nohighlights"))
00470                         use_highlights=FALSE;
00471 
00472                 /* we found the no popups argument*/
00473                 else if(!strcmp(variables[x],"nopopups"))
00474                         display_popups=FALSE;
00475 
00476                 /* we found the layer inclusion/exclusion argument */
00477                 else if(!strcmp(variables[x],"layermode")){
00478                         x++;
00479                         if(variables[x]==NULL){
00480                                 error=TRUE;
00481                                 break;
00482                                 }
00483 
00484                         if(!strcmp(variables[x],"include"))
00485                                 exclude_layers=FALSE;
00486                         else
00487                                 exclude_layers=TRUE;
00488                         }
00489 
00490                 /* we found the layer argument */
00491                 else if(!strcmp(variables[x],"layer")){
00492                         x++;
00493                         if(variables[x]==NULL){
00494                                 error=TRUE;
00495                                 break;
00496                                 }
00497 
00498                         strip_html_brackets(variables[x]);
00499                         add_layer(variables[x]);
00500                         }
00501 
00502                 /* we found the pause option */
00503                 else if(!strcmp(variables[x],"paused"))
00504                         refresh=FALSE;
00505 
00506                 /* we found the nodaemoncheck option */
00507                 else if(!strcmp(variables[x],"nodaemoncheck"))
00508                         daemon_check=FALSE;
00509 
00510                 }
00511 
00512         /* free memory allocated to the CGI variables */
00513         free_cgivars(variables);
00514 
00515         return error;
00516         }
00517 
00518 
00519 
00520 /* top of page */
00521 void display_page_header(void){
00522         char temp_buffer[MAX_INPUT_BUFFER];
00523         int zoom;
00524         int zoom_width, zoom_height;
00525         int zoom_width_granularity=0;
00526         int zoom_height_granularity=0;
00527         int current_zoom_granularity=0;
00528         hostgroup *temp_hostgroup;
00529         layer *temp_layer;
00530         int found=0;
00531 
00532 
00533         if(content_type!=HTML_CONTENT)
00534                 return;
00535 
00536         if(display_header==TRUE){
00537 
00538                 /* begin top table */
00539                 printf("<table border=0 width=100%% cellspacing=0 cellpadding=0>\n");
00540                 printf("<tr>\n");
00541 
00542                 /* left column of the first row */
00543                 printf("<td align=left valign=top>\n");
00544 
00545                 if(show_all_hosts==TRUE)
00546                         snprintf(temp_buffer,sizeof(temp_buffer)-1,"Network Map For All Hosts");
00547                 else
00548                         snprintf(temp_buffer,sizeof(temp_buffer)-1,"Network Map For Host <I>%s</I>",host_name);
00549                 temp_buffer[sizeof(temp_buffer)-1]='\x0';
00550                 display_info_table(temp_buffer,refresh,&current_authdata, daemon_check);
00551 
00552                 printf("<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 CLASS='linkBox'>\n");
00553                 printf("<TR><TD CLASS='linkBox'>\n");
00554 
00555                 if(show_all_hosts==FALSE){
00556                         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);
00557                         printf("<a href='%s?host=%s'>View Status Detail For This Host</a><BR>\n",STATUS_CGI,url_encode(host_name));
00558                         }
00559                 printf("<a href='%s?host=all'>View Status Detail For All Hosts</a><BR>\n",STATUS_CGI);
00560                 printf("<a href='%s?hostgroup=all'>View Status Overview For All Hosts</a>\n",STATUS_CGI);
00561 
00562                 printf("</TD></TR>\n");
00563                 printf("</TABLE>\n");
00564 
00565                 printf("</td>\n");
00566 
00567 
00568 
00569                 /* center column of top row */
00570                 printf("<td align=center valign=center>\n");
00571 
00572                 /* print image size and scaling info */
00573 #ifdef DEBUG
00574                 printf("<p><div align=center><font size=-1>\n");
00575                 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));
00576                 printf("</font></div></p>\n");
00577 
00578                 printf("<p><div align=center><font size=-1>\n");
00579                 printf("[ Canvas_x: %d | Canvas_y: %d | Canvas_width: %d | Canvas_height: %d ]",canvas_x,canvas_y,canvas_width,canvas_height);
00580                 printf("</font></div></p>\n");
00581 #endif
00582 
00583                 /* zoom links */
00584                 if(user_supplied_canvas==FALSE && strcmp(host_name,"all") && display_header==TRUE){
00585                         
00586                         printf("<p><div align=center>\n");
00587 
00588                         zoom_width_granularity=((total_image_width-MINIMUM_PROXIMITY_WIDTH)/11);
00589                         if(zoom_width_granularity==0)
00590                                 zoom_width_granularity=1;
00591                         zoom_height_granularity=((total_image_height-MINIMUM_PROXIMITY_HEIGHT)/11);
00592 
00593                         if(proximity_width<=0)
00594                                 current_zoom_granularity=0;
00595                         else
00596                                 current_zoom_granularity=(total_image_width-proximity_width)/zoom_width_granularity;
00597                         if(current_zoom_granularity>10)
00598                                 current_zoom_granularity=10;
00599 
00600                         printf("<table border=0 cellpadding=0 cellspacing=2>\n");
00601                         printf("<tr>\n");
00602                         printf("<td valign=center class='zoomTitle'>Zoom Out&nbsp;&nbsp;</td>\n");
00603 
00604                         for(zoom=0;zoom<=10;zoom++){
00605 
00606                                 zoom_width=total_image_width-(zoom*zoom_width_granularity);
00607                                 zoom_height=total_image_height-(zoom*zoom_height_granularity);
00608 
00609                                 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":"");
00610                                 if(user_supplied_scaling==TRUE)
00611                                         printf("&scaling_factor=%2.1f",user_scaling_factor);
00612                                 print_layer_url(TRUE);
00613                                 printf("'>");
00614                                 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);
00615                                 }
00616 
00617                         printf("<td valign=center class='zoomTitle'>&nbsp;&nbsp;Zoom In</td>\n");
00618                         printf("</tr>\n");
00619                         printf("</table>\n");
00620 
00621                         printf("</div></p>\n");
00622                         }
00623 
00624                 printf("</td>\n");
00625 
00626 
00627 
00628                 /* right hand column of top row */
00629                 printf("<td align=right valign=top>\n");
00630 
00631                 printf("<form method=\"POST\" action=\"%s\">\n",STATUSMAP_CGI);
00632                 printf("<table border=0 CLASS='optBox'>\n");
00633                 printf("<tr><td valign=top>\n");
00634                 printf("<input type='hidden' name='host' value='%s'>\n",escape_string(host_name));
00635                 printf("<input type='hidden' name='layout' value='%d'>\n",layout_method);
00636 
00637                 printf("</td><td valign=top>\n");
00638 
00639                 printf("<table border=0>\n");
00640 
00641                 printf("<tr><td CLASS='optBoxItem'>\n");
00642                 printf("Layout Method:<br>\n");
00643                 printf("<select name='layout'>\n");
00644 #ifndef DUMMY_INSTALL
00645                 printf("<option value=%d %s>User-supplied coords\n",LAYOUT_USER_SUPPLIED,(layout_method==LAYOUT_USER_SUPPLIED)?"selected":"");
00646 #endif
00647                 printf("<option value=%d %s>Depth layers\n",LAYOUT_SUBLAYERS,(layout_method==LAYOUT_SUBLAYERS)?"selected":"");
00648                 printf("<option value=%d %s>Collapsed tree\n",LAYOUT_COLLAPSED_TREE,(layout_method==LAYOUT_COLLAPSED_TREE)?"selected":"");
00649                 printf("<option value=%d %s>Balanced tree\n",LAYOUT_BALANCED_TREE,(layout_method==LAYOUT_BALANCED_TREE)?"selected":"");
00650                 printf("<option value=%d %s>Circular\n",LAYOUT_CIRCULAR,(layout_method==LAYOUT_CIRCULAR)?"selected":"");
00651                 printf("<option value=%d %s>Circular (Marked Up)\n",LAYOUT_CIRCULAR_MARKUP,(layout_method==LAYOUT_CIRCULAR_MARKUP)?"selected":"");
00652                 printf("<option value=%d %s>Circular (Balloon)\n",LAYOUT_CIRCULAR_BALLOON,(layout_method==LAYOUT_CIRCULAR_BALLOON)?"selected":"");
00653                 printf("</select>\n");
00654                 printf("</td>\n");
00655                 printf("<td CLASS='optBoxItem'>\n");
00656                 printf("Scaling factor:<br>\n");
00657                 printf("<input type='text' name='scaling_factor' maxlength='5' size='4' value='%2.1f'>\n",(user_supplied_scaling==TRUE)?user_scaling_factor:0.0);
00658                 printf("</td></tr>\n");
00659 
00660                 /*
00661                 printf("<tr><td CLASS='optBoxItem'>\n");
00662                 printf("Max image width:<br>\n");
00663                 printf("<input type='text' name='max_width' maxlength='5' size='4' value='%d'>\n",max_image_width);
00664                 printf("</td>\n");
00665                 printf("<td CLASS='optBoxItem'>\n");
00666                 printf("Max image height:<br>\n");
00667                 printf("<input type='text' name='max_height' maxlength='5' size='4' value='%d'>\n",max_image_height);
00668                 printf("</td></tr>\n");
00669 
00670                 printf("<tr><td CLASS='optBoxItem'>\n");
00671                 printf("Proximity width:<br>\n");
00672                 printf("<input type='text' name='proximity_width' maxlength='5' size='4' value='%d'>\n",proximity_width);
00673                 printf("</td>\n");
00674                 printf("<td CLASS='optBoxItem'>\n");
00675                 printf("Proximity height:<br>\n");
00676                 printf("<input type='text' name='proximity_height' maxlength='5' size='4' value='%d'>\n",proximity_height);
00677                 printf("</td></tr>\n");
00678                 */
00679 
00680                 printf("<input type='hidden' name='max_width' value='%d'>\n",max_image_width);
00681                 printf("<input type='hidden' name='max_height' value='%d'>\n",max_image_height);
00682                 printf("<input type='hidden' name='proximity_width' value='%d'>\n",proximity_width);
00683                 printf("<input type='hidden' name='proximity_height' value='%d'>\n",proximity_height);
00684 
00685                 printf("<tr><td CLASS='optBoxItem'>Drawing Layers:<br>\n");
00686                 printf("<select multiple name='layer' size='4'>\n");
00687                 for(temp_hostgroup=hostgroup_list;temp_hostgroup!=NULL;temp_hostgroup=temp_hostgroup->next){
00688                         if(is_authorized_for_hostgroup(temp_hostgroup,&current_authdata)==FALSE)
00689                                 continue;
00690                         found=0;
00691                         for(temp_layer=layer_list;temp_layer!=NULL;temp_layer=temp_layer->next){
00692                                 if(!strcmp(temp_layer->layer_name,temp_hostgroup->group_name)){
00693                                         found=1;
00694                                         break;
00695                                         }
00696                                 }
00697                         printf("<option value='%s' %s>%s\n",escape_string(temp_hostgroup->group_name),(found==1)?"SELECTED":"",temp_hostgroup->alias);
00698                         }
00699                 printf("</select>\n");
00700                 printf("</td><td CLASS='optBoxItem' valign=top>Layer mode:<br>");
00701                 printf("<input type='radio' name='layermode' value='include' %s>Include<br>\n",(exclude_layers==FALSE)?"CHECKED":"");
00702                 printf("<input type='radio' name='layermode' value='exclude' %s>Exclude\n",(exclude_layers==TRUE)?"CHECKED":"");
00703                 printf("</td></tr>\n");
00704 
00705                 printf("<tr><td CLASS='optBoxItem'>\n");
00706                 printf("Suppress popups:<br>\n");
00707                 printf("<input type='checkbox' name='nopopups' %s>\n",(display_popups==FALSE)?"CHECKED":"");
00708                 printf("</td><td CLASS='optBoxItem'>\n");
00709                 printf("<input type='submit' value='Update'>\n");
00710                 printf("</td></tr>\n");
00711 
00712                 /* display context-sensitive help */
00713                 printf("<tr><td></td><td align=right valign=bottom>\n");
00714                 display_context_help(CONTEXTHELP_MAP);
00715                 printf("</td></tr>\n");
00716 
00717                 printf("</table>\n");
00718 
00719                 printf("</td></tr>\n");
00720                 printf("</table>\n");
00721                 printf("</form>\n");
00722 
00723                 printf("</td>\n");
00724         
00725                 /* end of top table */
00726                 printf("</tr>\n");
00727                 printf("</table>\n");
00728                 }
00729 
00730 
00731         return;
00732         }
00733 
00734 
00735 
00736 /* top-level map generation... */
00737 void display_map(void){
00738 
00739         load_background_image();
00740         calculate_host_coords();
00741         calculate_total_image_bounds();
00742         calculate_canvas_bounds();
00743         calculate_scaling_factor();
00744         find_eligible_hosts();
00745 
00746         /* display page header */
00747         display_page_header();
00748 
00749         initialize_graphics();
00750         draw_background_image();
00751         draw_background_extras();
00752         draw_host_links();
00753 
00754         if(content_type==HTML_CONTENT)
00755                 printf("<map name='statusmap'>\n");
00756 
00757         draw_hosts();
00758 
00759         if(content_type==HTML_CONTENT)
00760                 printf("</map>\n");
00761 
00762         write_graphics();
00763         cleanup_graphics();
00764 
00765 
00766         /* write the URL location for the image we just generated - the web browser will come and get it... */
00767         if(content_type==HTML_CONTENT){
00768                 printf("<P><DIV ALIGN=center>\n");
00769                 printf("<img src='%s?host=%s&createimage&time=%lu",STATUSMAP_CGI,url_encode(host_name),(unsigned long)time(NULL));
00770                 printf("&canvas_x=%d&canvas_y=%d&canvas_width=%d&canvas_height=%d&max_width=%d&max_height=%d&layout=%d%s%s%s",canvas_x,canvas_y,canvas_width,canvas_height,max_image_width,max_image_height,layout_method,(use_links==FALSE)?"&nolinks":"",(use_text==FALSE)?"&notext":"",(use_highlights==FALSE)?"&nohighlights":"");
00771                 print_layer_url(TRUE);
00772                 printf("' width=%d height=%d border=0 name='statusimage' useMap='#statusmap'>\n",(int)(canvas_width*scaling_factor),(int)(canvas_height*scaling_factor));
00773                 printf("</DIV></P>\n");
00774                 }
00775         
00776         return;
00777         }
00778 
00779 
00780 
00781 /******************************************************************/
00782 /********************* CALCULATION FUNCTIONS **********************/
00783 /******************************************************************/
00784 
00785 /* calculates host drawing coordinates */
00786 void calculate_host_coords(void){
00787         host *this_host;
00788         host *temp_host;
00789         int child_hosts=0;
00790         int parent_hosts=0;
00791         int max_layer_width=1;
00792         int current_child_host=0;
00793         int current_parent_host=0;
00794         int center_x=0;
00795         int offset_x=DEFAULT_NODE_WIDTH/2;
00796         int offset_y=DEFAULT_NODE_WIDTH/2;
00797         int current_layer=0;
00798         int layer_members=0;
00799         int current_layer_member=0;
00800         int max_drawing_width=0;
00801 
00802 
00803         /******************************/
00804         /***** MANUAL LAYOUT MODE *****/
00805         /******************************/
00806 
00807         /* user-supplied coords */
00808         if(layout_method==LAYOUT_USER_SUPPLIED){
00809 
00810                 /* see which hosts we should draw and calculate drawing coords */
00811                 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
00812                         
00813                         if(temp_host->have_2d_coords==TRUE)
00814                                 temp_host->should_be_drawn=TRUE;
00815                         else
00816                                 temp_host->should_be_drawn=FALSE;
00817                         }
00818 
00819                 return;
00820                 }
00821 
00822 
00823         /*****************************/
00824         /***** AUTO-LAYOUT MODES *****/
00825         /*****************************/
00826 
00827         /***** DEPTH LAYER MODE *****/
00828         if(layout_method==LAYOUT_SUBLAYERS){
00829 
00830                 /* find the "main" host we're displaying */
00831                 if(show_all_hosts==TRUE)
00832                         this_host=NULL;
00833                 else
00834                         this_host=find_host(host_name);
00835 
00836                 /* find total number of immediate parents/children for this host */
00837                 child_hosts=number_of_immediate_child_hosts(this_host);
00838                 parent_hosts=number_of_immediate_parent_hosts(this_host);
00839 
00840                 if(child_hosts==0 && parent_hosts==0)
00841                         max_layer_width=1;
00842                 else
00843                         max_layer_width=(child_hosts>parent_hosts)?child_hosts:parent_hosts;
00844 
00845                 /* calculate center x coord */
00846                 center_x=(((DEFAULT_NODE_WIDTH*max_layer_width)+(DEFAULT_NODE_HSPACING*(max_layer_width-1)))/2)+offset_x;
00847 
00848                 /* coords for Icinga icon if necessary */
00849                 if(this_host==NULL || this_host->parent_hosts==NULL){
00850                         nagios_icon_x=center_x;
00851                         nagios_icon_y=offset_y;
00852                         draw_nagios_icon=TRUE;
00853                         }
00854 
00855                 /* do we need to draw a link to parent(s)? */
00856                 if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE){
00857                         draw_parent_links=TRUE;
00858                         offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
00859                         }
00860 
00861                 /* see which hosts we should draw and calculate drawing coords */
00862                 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
00863 
00864                         /* this is an immediate parent of the "main" host we're drawing */
00865                         if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){
00866                                 temp_host->should_be_drawn=TRUE;
00867                                 temp_host->have_2d_coords=TRUE;
00868                                 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);
00869                                 temp_host->y_2d=offset_y;
00870                                 current_parent_host++;
00871                                 }
00872                         
00873                         /* this is the "main" host we're drawing */
00874                         else if(this_host==temp_host){
00875                                 temp_host->should_be_drawn=TRUE;
00876                                 temp_host->have_2d_coords=TRUE;
00877                                 temp_host->x_2d=center_x;
00878                                 temp_host->y_2d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y;
00879                                 }
00880 
00881                         /* this is an immediate child of the "main" host we're drawing */
00882                         else if(is_host_immediate_child_of_host(this_host,temp_host)==TRUE){
00883                                 temp_host->should_be_drawn=TRUE;
00884                                 temp_host->have_2d_coords=TRUE;
00885                                 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);
00886                                 if(this_host==NULL)
00887                                         temp_host->y_2d=(DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)+offset_y;
00888                                 else
00889                                         temp_host->y_2d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*2)+offset_y;
00890                                 current_child_host++;
00891                                 if(number_of_immediate_child_hosts(temp_host)>0){
00892                                         bottom_margin=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
00893                                         draw_child_links=TRUE;
00894                                         }
00895                                 }
00896 
00897                         /* else do not draw this host */
00898                         else{
00899                                 temp_host->should_be_drawn=FALSE;
00900                                 temp_host->have_2d_coords=FALSE;
00901                                 }
00902                         }
00903                 }
00904 
00905 
00906 
00907         /***** COLLAPSED TREE MODE *****/
00908         else if(layout_method==LAYOUT_COLLAPSED_TREE){
00909 
00910                 /* find the "main" host we're displaying  - DO NOT USE THIS (THIS IS THE OLD METHOD) */
00911                 /*
00912                 if(show_all_hosts==TRUE)
00913                         this_host=NULL;
00914                 else
00915                         this_host=find_host(host_name);
00916                 */
00917 
00918                 /* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
00919                 this_host=NULL;
00920 
00921                 /* find total number of immediate parents for this host */
00922                 parent_hosts=number_of_immediate_parent_hosts(this_host);
00923 
00924                 /* find the max layer width we have... */
00925                 max_layer_width=max_child_host_layer_members(this_host);
00926                 if(parent_hosts>max_layer_width)
00927                         max_layer_width=parent_hosts;
00928 
00929                 /* calculate center x coord */
00930                 center_x=(((DEFAULT_NODE_WIDTH*max_layer_width)+(DEFAULT_NODE_HSPACING*(max_layer_width-1)))/2)+offset_x;
00931 
00932                 /* coords for Icinga icon if necessary */
00933                 if(this_host==NULL || this_host->parent_hosts==NULL){
00934                         nagios_icon_x=center_x;
00935                         nagios_icon_y=offset_y;
00936                         draw_nagios_icon=TRUE;
00937                         }
00938 
00939                 /* do we need to draw a link to parent(s)? */
00940                 if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE){
00941                         draw_parent_links=TRUE;
00942                         offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
00943                         }
00944 
00945                 /* see which hosts we should draw and calculate drawing coords */
00946                 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
00947 
00948                         /* this is an immediate parent of the "main" host we're drawing */
00949                         if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){
00950                                 temp_host->should_be_drawn=TRUE;
00951                                 temp_host->have_2d_coords=TRUE;
00952                                 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);
00953                                 temp_host->y_2d=offset_y;
00954                                 current_parent_host++;
00955                                 }
00956                         
00957                         /* this is the "main" host we're drawing */
00958                         else if(this_host==temp_host){
00959                                 temp_host->should_be_drawn=TRUE;
00960                                 temp_host->have_2d_coords=TRUE;
00961                                 temp_host->x_2d=center_x;
00962                                 temp_host->y_2d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y;
00963                                 }
00964 
00965                         /* else do not draw this host (we might if its a child - see below, but assume no for now) */
00966                         else{
00967                                 temp_host->should_be_drawn=FALSE;
00968                                 temp_host->have_2d_coords=FALSE;
00969                                 }
00970                         }
00971 
00972 
00973                 /* TODO: REORDER CHILD LAYER MEMBERS SO THAT WE MINIMIZE LINK CROSSOVERS FROM PARENT HOSTS */
00974 
00975                 /* draw hosts in child "layers" */
00976                 for(current_layer=1;;current_layer++){
00977                         
00978                         /* how many members in this layer? */
00979                         layer_members=number_of_host_layer_members(this_host,current_layer);
00980 
00981                         if(layer_members==0)
00982                                 break;
00983 
00984                         current_layer_member=0;
00985 
00986                         /* see which hosts are members of this layer and calculate drawing coords */
00987                         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
00988 
00989                                 /* is this host a member of the current child layer? */
00990                                 if(host_child_depth_separation(this_host,temp_host)==current_layer){
00991                                         temp_host->should_be_drawn=TRUE;
00992                                         temp_host->have_2d_coords=TRUE;
00993                                         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);
00994                                         if(this_host==NULL)
00995                                                 temp_host->y_2d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*current_layer)+offset_y;
00996                                         else
00997                                                 temp_host->y_2d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*(current_layer+1))+offset_y;
00998                                         current_layer_member++;
00999                                         }
01000                                 }
01001                         }
01002 
01003                 }
01004 
01005 
01006         /***** "BALANCED" TREE MODE *****/
01007         else if(layout_method==LAYOUT_BALANCED_TREE){
01008 
01009                 /* find the "main" host we're displaying  - DO NOT USE THIS (THIS IS THE OLD METHOD) */
01010                 /*
01011                 if(show_all_hosts==TRUE)
01012                         this_host=NULL;
01013                 else
01014                         this_host=find_host(host_name);
01015                 */
01016                 
01017                 /* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
01018                 this_host=NULL;
01019 
01020                 /* find total number of immediate parents for this host */
01021                 parent_hosts=number_of_immediate_parent_hosts(this_host);
01022 
01023                 /* find the max drawing width we have... */
01024                 max_drawing_width=max_child_host_drawing_width(this_host);
01025                 if(parent_hosts>max_drawing_width)
01026                         max_drawing_width=parent_hosts;
01027 
01028                 /* calculate center x coord */
01029                 center_x=(((DEFAULT_NODE_WIDTH*max_drawing_width)+(DEFAULT_NODE_HSPACING*(max_drawing_width-1)))/2)+offset_x;
01030 
01031                 /* coords for Icinga icon if necessary */
01032                 if(this_host==NULL || this_host->parent_hosts==NULL){
01033                         nagios_icon_x=center_x;
01034                         nagios_icon_y=offset_y;
01035                         draw_nagios_icon=TRUE;
01036                         }
01037 
01038                 /* do we need to draw a link to parent(s)? */
01039                 if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE){
01040                         draw_parent_links=TRUE;
01041                         offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
01042                         }
01043 
01044                 /* see which hosts we should draw and calculate drawing coords */
01045                 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
01046 
01047                         /* this is an immediate parent of the "main" host we're drawing */
01048                         if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){
01049                                 temp_host->should_be_drawn=TRUE;
01050                                 temp_host->have_2d_coords=TRUE;
01051                                 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);
01052                                 temp_host->y_2d=offset_y;
01053                                 current_parent_host++;
01054                                 }
01055                         
01056                         /* this is the "main" host we're drawing */
01057                         else if(this_host==temp_host){
01058                                 temp_host->should_be_drawn=TRUE;
01059                                 temp_host->have_2d_coords=TRUE;
01060                                 temp_host->x_2d=center_x;
01061                                 temp_host->y_2d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y;
01062                                 }
01063 
01064                         /* else do not draw this host (we might if its a child - see below, but assume no for now) */
01065                         else{
01066                                 temp_host->should_be_drawn=FALSE;
01067                                 temp_host->have_2d_coords=FALSE;
01068                                 }
01069                         }
01070 
01071                 /* draw all children hosts */
01072                 calculate_balanced_tree_coords(this_host,center_x,DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y);
01073 
01074                 }
01075 
01076 
01077         /***** CIRCULAR LAYOUT MODE *****/
01078         else if(layout_method==LAYOUT_CIRCULAR || layout_method==LAYOUT_CIRCULAR_MARKUP || layout_method==LAYOUT_CIRCULAR_BALLOON){
01079 
01080                 /* draw process icon */
01081                 nagios_icon_x=0;
01082                 nagios_icon_y=0;
01083                 draw_nagios_icon=TRUE;
01084 
01085                 /* calculate coordinates for all hosts */
01086                 calculate_circular_coords();
01087                 }
01088 
01089         return;
01090         }
01091 
01092 
01093 
01094 /* calculates max possible image dimensions */
01095 void calculate_total_image_bounds(void){
01096         host *temp_host;
01097 
01098         total_image_width=0;
01099         total_image_height=0;
01100 
01101         /* check all extended host information entries... */
01102         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
01103 
01104                 /* only check entries that have 2-D coords specified */
01105                 if(temp_host->have_2d_coords==FALSE)
01106                         continue;
01107 
01108                 /* skip hosts we shouldn't be drawing */
01109                 if(temp_host->should_be_drawn==FALSE)
01110                         continue;
01111                 
01112                 if(temp_host->x_2d>total_image_width)
01113                         total_image_width=temp_host->x_2d;
01114                 if(temp_host->y_2d>total_image_height)
01115                         total_image_height=temp_host->y_2d;
01116 
01117                 coordinates_were_specified=TRUE;
01118                 }
01119 
01120         /* add some space for icon size and overlapping text... */
01121         if(coordinates_were_specified==TRUE){
01122 
01123                 total_image_width+=(DEFAULT_NODE_WIDTH*2);
01124                 total_image_height+=DEFAULT_NODE_HEIGHT;
01125 
01126                 /* add space for bottom margin if necessary */
01127                 total_image_height+=bottom_margin;
01128                 }
01129 
01130         /* image size should be at least as large as dimensions of background image */
01131         if(total_image_width<background_image_width)
01132                 total_image_width=background_image_width;
01133         if(total_image_height<background_image_height)
01134                 total_image_height=background_image_height;
01135 
01136         /* we didn't find any hosts that had user-supplied coordinates, so we're going to display a warning */
01137         if(coordinates_were_specified==FALSE){
01138                 coordinates_were_specified=FALSE;
01139                 total_image_width=COORDS_WARNING_WIDTH;
01140                 total_image_height=COORDS_WARNING_HEIGHT;
01141                 }
01142 
01143         return;
01144         }
01145 
01146 
01147 /* calculates canvas coordinates/dimensions */
01148 void calculate_canvas_bounds(void){
01149 
01150         if(user_supplied_canvas==FALSE && strcmp(host_name,"all"))
01151                 calculate_canvas_bounds_from_host(host_name);
01152 
01153         /* calculate canvas origin (based on total image bounds) */
01154         if(canvas_x<=0 || canvas_width>total_image_width)
01155                 canvas_x=0;
01156         if(canvas_y<=0 || canvas_height>total_image_height)
01157                 canvas_y=0;
01158 
01159         /* calculate canvas dimensions */
01160         if(canvas_height<=0)
01161                 canvas_height=(total_image_height-canvas_y);
01162         if(canvas_width<=0)
01163                 canvas_width=(total_image_width-canvas_x);
01164 
01165         if(canvas_x+canvas_width>total_image_width)
01166                 canvas_width=total_image_width-canvas_x;
01167         if(canvas_y+canvas_height>total_image_height)
01168                 canvas_height=total_image_height-canvas_y;
01169 
01170         return;
01171         }
01172 
01173 
01174 /* calculates canvas coordinates/dimensions around a particular host */
01175 void calculate_canvas_bounds_from_host(char *host_name){
01176         host *temp_host;
01177         int zoom_width;
01178         int zoom_height;
01179 
01180         /* find the extended host info */
01181         temp_host=find_host(host_name);
01182         if(temp_host==NULL)
01183                 return;
01184 
01185         /* make sure we have 2-D coords */
01186         if(temp_host->have_2d_coords==FALSE)
01187                 return;
01188         
01189         if(max_image_width>0 && proximity_width>max_image_width)
01190                 zoom_width=max_image_width;
01191         else
01192                 zoom_width=proximity_width;
01193         if(max_image_height>0 && proximity_height>max_image_height)
01194                 zoom_height=max_image_height;
01195         else
01196                 zoom_height=proximity_height;
01197 
01198         canvas_width=zoom_width;
01199         if(canvas_width>=total_image_width)
01200                 canvas_x=0;
01201         else
01202                 canvas_x=(temp_host->x_2d-(zoom_width/2));
01203 
01204         canvas_height=zoom_height;
01205         if(canvas_height>=total_image_height)
01206                 canvas_y=0;
01207         else
01208                 canvas_y=(temp_host->y_2d-(zoom_height/2));
01209 
01210 
01211         return;
01212         }
01213 
01214 
01215 /* calculates scaling factor used in image generation */
01216 void calculate_scaling_factor(void){
01217         double x_scaling=1.0;
01218         double y_scaling=1.0;
01219 
01220         /* calculate horizontal scaling factor */
01221         if(max_image_width<=0 || canvas_width<=max_image_width)
01222                 x_scaling=1.0;
01223         else
01224                 x_scaling=(double)((double)max_image_width/(double)canvas_width);
01225 
01226         /* calculate vertical scaling factor */
01227         if(max_image_height<=0 || canvas_height<=max_image_height)
01228                 y_scaling=1.0;
01229         else
01230                 y_scaling=(double)((double)max_image_height/(double)canvas_height);
01231 
01232         /* calculate general scaling factor to use */
01233         if(x_scaling<y_scaling)
01234                 scaling_factor=x_scaling;
01235         else
01236                 scaling_factor=y_scaling;
01237 
01238         /*** USER-SUPPLIED SCALING FACTOR ***/
01239         if(user_supplied_scaling==TRUE)
01240                 scaling_factor=user_scaling_factor;
01241 
01242         return;
01243         }
01244 
01245 
01246 /* finds hosts that can be drawn in the canvas area */
01247 void find_eligible_hosts(void){
01248         int total_eligible_hosts=0;
01249         host *temp_host;
01250 
01251         /* check all extended host information entries... */
01252         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
01253 
01254                 /* only include hosts that have 2-D coords supplied */
01255                 if(temp_host->have_2d_coords==FALSE)
01256                         temp_host->should_be_drawn=FALSE;
01257 
01258                 /* make sure coords are all positive */
01259                 else if(temp_host->x_2d<0 || temp_host->y_2d<0)
01260                         temp_host->should_be_drawn=FALSE;
01261 
01262                 /* make sure x coordinates fall within canvas bounds */
01263                 else if(temp_host->x_2d<(canvas_x-DEFAULT_NODE_WIDTH) || temp_host->x_2d>(canvas_x+canvas_width))
01264                         temp_host->should_be_drawn=FALSE;
01265 
01266                 /* make sure y coordinates fall within canvas bounds */
01267                 else if(temp_host->y_2d<(canvas_y-DEFAULT_NODE_HEIGHT) || temp_host->y_2d>(canvas_y+canvas_height))
01268                         temp_host->should_be_drawn=FALSE;
01269 
01270                 /* see if the user is authorized to view the host */
01271                 else if(is_authorized_for_host(temp_host,&current_authdata)==FALSE)
01272                         temp_host->should_be_drawn=FALSE;
01273 
01274                 /* all checks passed, so we can draw the host! */
01275                 else{
01276                         temp_host->should_be_drawn=TRUE;
01277                         total_eligible_hosts++;
01278                         }
01279                 }
01280 
01281         return;
01282         }
01283 
01284 
01285 
01286 /******************************************************************/
01287 /*********************** DRAWING FUNCTIONS ************************/
01288 /******************************************************************/
01289 
01290 
01291 /* loads background image from file */
01292 void load_background_image(void){
01293         char temp_buffer[MAX_INPUT_BUFFER];
01294 
01295         /* bail out if we shouldn't be drawing a background image */
01296         if(layout_method!=LAYOUT_USER_SUPPLIED || statusmap_background_image==NULL)
01297                 return;
01298 
01299         snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s%s",physical_images_path,statusmap_background_image);
01300         temp_buffer[sizeof(temp_buffer)-1]='\x0';
01301 
01302         /* read the background image into memory */
01303         background_image=load_image_from_file(temp_buffer);
01304 
01305         /* grab background image dimensions for calculating total image width later */
01306         if(background_image!=NULL){
01307                 background_image_width=background_image->sx;
01308                 background_image_height=background_image->sy;
01309                 }
01310 
01311         /* if we are just creating the html, we don't need the image anymore */
01312         if(content_type==HTML_CONTENT && background_image!=NULL)
01313                 gdImageDestroy(background_image);
01314 
01315         return;
01316         }
01317 
01318 
01319 /* draws background image on drawing canvas */
01320 void draw_background_image(void){
01321 
01322         /* bail out if we shouldn't be drawing a background image */
01323         if(content_type==HTML_CONTENT || layout_method!=LAYOUT_USER_SUPPLIED || statusmap_background_image==NULL)
01324                 return;
01325 
01326         /* bail out if we don't have an image */
01327         if(background_image==NULL)
01328                 return;
01329 
01330         /* copy the background image to the canvas */
01331         gdImageCopy(map_image,background_image,0,0,canvas_x,canvas_y,canvas_width,canvas_height);
01332 
01333         /* free memory for background image, as we don't need it anymore */
01334         gdImageDestroy(background_image);
01335 
01336         return;
01337         }
01338 
01339 
01340 
01341 /* draws background "extras" */
01342 void draw_background_extras(void){
01343 
01344         /* bail out if we shouldn't be here */
01345         if(content_type==HTML_CONTENT)
01346                 return;
01347 
01348         /* circular layout stuff... */
01349         if(layout_method==LAYOUT_CIRCULAR_MARKUP){
01350 
01351                 /* draw colored sections... */
01352                 draw_circular_markup();
01353                 }
01354 
01355         return;
01356         }
01357 
01358 
01359 /* draws host links */
01360 void draw_host_links(void){
01361         host *this_host;
01362         host *main_host;
01363         host *parent_host;
01364         hostsmember *temp_hostsmember;
01365         int status_color=color_black;
01366         hoststatus *this_hoststatus;
01367         hoststatus *parent_hoststatus;
01368         int child_in_layer_list=FALSE;
01369         int parent_in_layer_list=FALSE;
01370         int dotted_line=FALSE;
01371         int x=0;
01372         int y=0;
01373 
01374         if(content_type==HTML_CONTENT)
01375                 return;
01376 
01377         if(use_links==FALSE)
01378                 return;
01379 
01380         /* find the "main" host we're drawing */
01381         main_host=find_host(host_name);
01382         if(show_all_hosts==TRUE)
01383                 main_host=NULL;
01384 
01385         /* check all extended host information entries... */
01386         for(this_host=host_list;this_host!=NULL;this_host=this_host->next){
01387 
01388                 /* only draw link if user is authorized to view this host */
01389                 if(is_authorized_for_host(this_host,&current_authdata)==FALSE)
01390                         continue;
01391 
01392                 /* this is a "root" host, so draw link to Icinga process icon if using auto-layout mode */
01393                 if(this_host->parent_hosts==NULL && layout_method!=LAYOUT_USER_SUPPLIED && draw_nagios_icon==TRUE){
01394 
01395                         x=this_host->x_2d+(DEFAULT_NODE_WIDTH/2)-canvas_x;
01396                         y=this_host->y_2d+(DEFAULT_NODE_WIDTH/2)-canvas_y;
01397 
01398                         draw_line(x,y,nagios_icon_x+(DEFAULT_NODE_WIDTH/2)-canvas_x,nagios_icon_y+(DEFAULT_NODE_WIDTH/2)-canvas_y,color_black);
01399                         }
01400 
01401                 /* this is a child of the main host we're drawing in auto-layout mode... */
01402                 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){
01403                         /* determine color to use when drawing links to children  */
01404                         this_hoststatus=find_hoststatus(this_host->name);
01405                         if(this_hoststatus!=NULL){
01406                                 if(this_hoststatus->status==HOST_DOWN || this_hoststatus->status==HOST_UNREACHABLE)
01407                                         status_color=color_red;
01408                                 else
01409                                         status_color=color_black;
01410                                 }
01411                         else
01412                                 status_color=color_black;
01413 
01414                         x=this_host->x_2d+(DEFAULT_NODE_WIDTH/2)-canvas_x;
01415                         y=(this_host->y_2d+(DEFAULT_NODE_WIDTH)/2)-canvas_y;
01416 
01417                         draw_dashed_line(x,y,x,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING,status_color);
01418 
01419                         /* draw arrow tips */
01420                         draw_line(x,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING,x-5,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING-5,color_black);
01421                         draw_line(x,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING,x+5,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING-5,color_black);
01422                         }
01423 
01424                 /* this is a parent of the main host we're drawing in auto-layout mode... */
01425                 if(layout_method!=LAYOUT_USER_SUPPLIED && draw_parent_links==TRUE && is_host_immediate_child_of_host(this_host,main_host)==TRUE){
01426 
01427                         x=this_host->x_2d+(DEFAULT_NODE_WIDTH/2)-canvas_x;
01428                         y=this_host->y_2d+(DEFAULT_NODE_WIDTH/2)-canvas_y;
01429 
01430                         draw_dashed_line(x,y,x,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING,color_black);
01431 
01432                         /* draw arrow tips */
01433                         draw_line(x,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING,x-5,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING+5,color_black);
01434                         draw_line(x,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING,x+5,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING+5,color_black);
01435                         }
01436 
01437                 /* draw links to all parent hosts */
01438                 for(temp_hostsmember=this_host->parent_hosts;temp_hostsmember!=NULL;temp_hostsmember=temp_hostsmember->next){
01439 
01440                         /* find the parent host config entry */
01441                         parent_host=find_host(temp_hostsmember->host_name);
01442                         if(parent_host==NULL)
01443                                 continue;
01444 
01445                         /* don't draw the link if we don't have the coords */
01446                         if(parent_host->have_2d_coords==FALSE || this_host->have_2d_coords==FALSE)
01447                                 continue;
01448 
01449                         /* only draw link if user is authorized for this parent host */
01450                         if(is_authorized_for_host(parent_host,&current_authdata)==FALSE)
01451                                 continue;
01452 
01453                         /* are the hosts in the layer list? */
01454                         child_in_layer_list=is_host_in_layer_list(this_host);
01455                         parent_in_layer_list=is_host_in_layer_list(parent_host);
01456 
01457                         /* use dotted or solid line? */
01458                         /* either the child or parent should not be drawn, so use a dotted line */
01459                         if((child_in_layer_list==TRUE && parent_in_layer_list==FALSE) || (child_in_layer_list==FALSE && parent_in_layer_list==TRUE))
01460                                 dotted_line=TRUE;
01461                         /* both hosts should not be drawn, so use a dotted line */
01462                         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))
01463                                 dotted_line=TRUE;
01464                         /* both hosts should be drawn, so use a solid line */
01465                         else
01466                                 dotted_line=FALSE;
01467 
01468                         /* determine color to use when drawing links to parent host */
01469                         parent_hoststatus=find_hoststatus(parent_host->name);
01470                         if(parent_hoststatus!=NULL){
01471                                 if(parent_hoststatus->status==HOST_DOWN || parent_hoststatus->status==HOST_UNREACHABLE)
01472                                         status_color=color_red;
01473                                 else
01474                                         status_color=color_black;
01475                                 }
01476                         else
01477                                 status_color=color_black;
01478 
01479                         /* draw the link */
01480                         if(dotted_line==TRUE)
01481                                 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);
01482                         else
01483                                 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);
01484                         }
01485 
01486                 }
01487 
01488         return;
01489         }
01490 
01491 
01492 
01493 /* draws hosts */
01494 void draw_hosts(void){
01495         host *temp_host;
01496         int x1, x2;
01497         int y1, y2;
01498         int has_image=FALSE;
01499         char image_input_file[MAX_INPUT_BUFFER];
01500         int current_radius=0;
01501         int status_color=color_black;
01502         hoststatus *temp_hoststatus;
01503         int in_layer_list=FALSE;
01504         int average_host_services;
01505         int host_services;
01506         double host_services_ratio;
01507         int outer_radius;
01508         int inner_radius;
01509         int time_color=0;
01510         time_t current_time;
01511         int translated_x;
01512         int translated_y;
01513 
01514         
01515         /* user didn't supply any coordinates for hosts, so display a warning */
01516         if(coordinates_were_specified==FALSE){
01517 
01518                 if(content_type==IMAGE_CONTENT){
01519                         draw_text("You have not supplied any host drawing coordinates, so you cannot use this layout method.",(COORDS_WARNING_WIDTH/2),30,color_black);
01520                         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);
01521                         }
01522 
01523                 return;
01524                 }
01525 
01526         /* draw Icinga process icon if using auto-layout mode */
01527         if(layout_method!=LAYOUT_USER_SUPPLIED && draw_nagios_icon==TRUE){
01528 
01529                 /* get coords of bounding box */
01530                 x1=nagios_icon_x-canvas_x;
01531                 x2=x1+DEFAULT_NODE_WIDTH;
01532                 y1=nagios_icon_y-canvas_y;
01533                 y2=y1+DEFAULT_NODE_HEIGHT;
01534 
01535                 /* get the name of the image file to open for the logo */
01536                 snprintf(image_input_file,sizeof(image_input_file)-1,"%s%s",physical_logo_images_path,ICINGA_GD2_ICON);
01537                 image_input_file[sizeof(image_input_file)-1]='\x0';
01538 
01539                 /* read in the image from file... */
01540                 logo_image=load_image_from_file(image_input_file);
01541 
01542                 /* copy the logo image to the canvas image... */
01543                 if(logo_image!=NULL){
01544                         gdImageCopy(map_image,logo_image,x1,y1,0,0,logo_image->sx,logo_image->sy);
01545                         gdImageDestroy(logo_image);
01546                         }
01547 
01548                 /* if we don't have an image, draw a bounding box */
01549                 else{
01550                         draw_line(x1,y1,x1,y1+DEFAULT_NODE_WIDTH,color_black);
01551                         draw_line(x1,y1+DEFAULT_NODE_WIDTH,x2,y1+DEFAULT_NODE_WIDTH,color_black);
01552                         draw_line(x2,y1+DEFAULT_NODE_WIDTH,x2,y1,color_black);
01553                         draw_line(x2,y1,x1,y1,color_black);
01554                         }
01555 
01556                 if(content_type==IMAGE_CONTENT)
01557                         draw_text("Icinga Process",x1+(DEFAULT_NODE_WIDTH/2),y1+DEFAULT_NODE_HEIGHT,color_black);
01558                 }
01559 
01560         /* calculate average services per host */
01561         average_host_services=4;
01562 
01563         /* draw all hosts... */
01564         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
01565                 
01566                 /* skip hosts that should not be drawn */
01567                 if(temp_host->should_be_drawn==FALSE)
01568                         continue;
01569 
01570                 /* is this host in the layer inclusion/exclusion list? */
01571                 in_layer_list=is_host_in_layer_list(temp_host);
01572                 if((in_layer_list==TRUE && exclude_layers==TRUE) || (in_layer_list==FALSE && exclude_layers==FALSE))
01573                         continue;
01574 
01575                 /* get coords of host bounding box */
01576                 x1=temp_host->x_2d-canvas_x;
01577                 x2=x1+DEFAULT_NODE_WIDTH;
01578                 y1=temp_host->y_2d-canvas_y;
01579                 y2=y1+DEFAULT_NODE_HEIGHT;
01580 
01581                 if(content_type==IMAGE_CONTENT){
01582 
01583 
01584                         temp_hoststatus=find_hoststatus(temp_host->name);
01585                         if(temp_hoststatus!=NULL){
01586                                 if(temp_hoststatus->status==HOST_DOWN)
01587                                         status_color=color_red;
01588                                 else if(temp_hoststatus->status==HOST_UNREACHABLE)
01589                                         status_color=color_red;
01590                                 else if(temp_hoststatus->status==HOST_UP)
01591                                         status_color=color_green;
01592                                 else if(temp_hoststatus->status==HOST_PENDING)
01593                                         status_color=color_grey;
01594                                 }
01595                         else
01596                                 status_color=color_black;
01597 
01598 
01599                         /* use balloons instead of icons... */
01600                         if(layout_method==LAYOUT_CIRCULAR_BALLOON){
01601 
01602                                 /* get the number of services associated with the host */
01603                                 host_services=number_of_host_services(temp_host);
01604 
01605                                 if(average_host_services==0)
01606                                         host_services_ratio=0.0;
01607                                 else
01608                                         host_services_ratio=(double)((double)host_services/(double)average_host_services);
01609 
01610                                 /* calculate size of node */
01611                                 if(host_services_ratio>=2.0)
01612                                         outer_radius=DEFAULT_NODE_WIDTH;
01613                                 else if(host_services_ratio>=1.5)
01614                                         outer_radius=DEFAULT_NODE_WIDTH*0.8;
01615                                 else if(host_services_ratio>=1.0)
01616                                         outer_radius=DEFAULT_NODE_WIDTH*0.6;
01617                                 else if(host_services_ratio>=0.5)
01618                                         outer_radius=DEFAULT_NODE_WIDTH*0.4;
01619                                 else
01620                                         outer_radius=DEFAULT_NODE_WIDTH*0.2;
01621 
01622                                 /* calculate width of border */
01623                                 if(temp_hoststatus==NULL)
01624                                         inner_radius=outer_radius;
01625                                 else if((temp_hoststatus->status==HOST_DOWN || temp_hoststatus->status==HOST_UNREACHABLE) && temp_hoststatus->problem_has_been_acknowledged==FALSE)
01626                                         inner_radius=outer_radius-3;
01627                                 else
01628                                         inner_radius=outer_radius;
01629 
01630                                 /* fill node with color based on how long its been in this state... */
01631                                 gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),outer_radius,outer_radius,0,360,color_blue);
01632 
01633                                 /* determine fill color */
01634                                 time(&current_time);
01635                                 if(temp_hoststatus==NULL)
01636                                         time_color=color_white;
01637                                 else if(current_time-temp_hoststatus->last_state_change<=900)
01638                                         time_color=color_orange;
01639                                 else if(current_time-temp_hoststatus->last_state_change<=3600)
01640                                         time_color=color_yellow;
01641                                 else
01642                                         time_color=color_white;
01643 
01644                                 /* fill node with appropriate time color */
01645                                 /* the fill function only works with coordinates that are in bounds of the actual image */
01646                                 translated_x=x1+(DEFAULT_NODE_WIDTH/2);
01647                                 translated_y=y1+(DEFAULT_NODE_WIDTH/2);
01648                                 if(translated_x>0 && translated_y>0 && translated_x<canvas_width && translated_y<canvas_height)
01649                                         gdImageFillToBorder(map_image,translated_x,translated_y,color_blue,time_color);
01650 
01651                                 /* border of node should reflect current state */
01652                                 for(current_radius=outer_radius;current_radius>=inner_radius;current_radius--)
01653                                         gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),current_radius,current_radius,0,360,status_color);
01654 
01655                                 /* draw circles around the selected host (if there is one) */
01656                                 if(!strcmp(host_name,temp_host->name) && use_highlights==TRUE){
01657                                         for(current_radius=DEFAULT_NODE_WIDTH*2;current_radius>0;current_radius-=10)
01658                                                 gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),current_radius,current_radius,0,360,status_color);
01659                                         }
01660                                 }
01661 
01662 
01663                         /* normal method is to use icons for hosts... */
01664                         else{
01665 
01666                                 /* draw a target around root hosts (hosts with no parents) */
01667                                 if(temp_host!=NULL && use_highlights==TRUE){
01668                                         if(temp_host->parent_hosts==NULL){
01669                                                 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);
01670                                                 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);
01671                                                 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);
01672                                                 }
01673                                         }
01674 
01675                                 /* draw circles around the selected host (if there is one) */
01676                                 if(!strcmp(host_name,temp_host->name) && use_highlights==TRUE){
01677                                         for(current_radius=DEFAULT_NODE_WIDTH*2;current_radius>0;current_radius-=10)
01678                                                 gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),current_radius,current_radius,0,360,status_color);
01679                                         }
01680 
01681 
01682                                 if(temp_host->statusmap_image!=NULL)
01683                                         has_image=TRUE;
01684                                 else
01685                                         has_image=FALSE;
01686                                 
01687                                 /* load the logo associated with this host */
01688                                 if(has_image==TRUE){
01689 
01690                                         /* get the name of the image file to open for the logo */
01691                                         snprintf(image_input_file,sizeof(image_input_file)-1,"%s%s",physical_logo_images_path,temp_host->statusmap_image);
01692                                         image_input_file[sizeof(image_input_file)-1]='\x0';
01693 
01694                                         /* read in the logo image from file... */
01695                                         logo_image=load_image_from_file(image_input_file);
01696 
01697                                         /* copy the logo image to the canvas image... */
01698                                         if(logo_image!=NULL){
01699                                                 gdImageCopy(map_image,logo_image,x1,y1,0,0,logo_image->sx,logo_image->sy);
01700                                                 gdImageDestroy(logo_image);
01701                                                 }
01702                                         else
01703                                                 has_image=FALSE;
01704                                         }
01705 
01706                                 /* 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 */
01707                                 if(has_image==FALSE){
01708 
01709                                         if(unknown_logo_image!=NULL)
01710                                                 gdImageCopy(map_image,unknown_logo_image,x1,y1,0,0,unknown_logo_image->sx,unknown_logo_image->sy);
01711 
01712                                         else{
01713 
01714                                                 /* last ditch effort - draw a host bounding box */
01715                                                 draw_line(x1,y1,x1,y1+DEFAULT_NODE_WIDTH,color_black);
01716                                                 draw_line(x1,y1+DEFAULT_NODE_WIDTH,x2,y1+DEFAULT_NODE_WIDTH,color_black);
01717                                                 draw_line(x2,y1+DEFAULT_NODE_WIDTH,x2,y1,color_black);
01718                                                 draw_line(x2,y1,x1,y1,color_black);
01719                                                 }
01720                                         }
01721                                 }
01722 
01723 
01724                         /* draw host name, status, etc. */
01725                         draw_host_text((temp_host->display_name!=NULL)?temp_host->display_name:temp_host->name,x1+(DEFAULT_NODE_WIDTH/2),y1+DEFAULT_NODE_HEIGHT);
01726                         }
01727 
01728                 /* we're creating HTML image map... */
01729                 else{
01730                         printf("<AREA shape='rect' ");
01731 
01732                         /* coordinates */
01733                         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));
01734 
01735                         /* URL */
01736                         if(!strcmp(host_name,temp_host->name))
01737                                 printf("href='%s?host=%s' ",STATUS_CGI,url_encode(temp_host->name));
01738                         else{
01739                                 printf("href='%s?host=%s&layout=%d&max_width=%d&max_height=%d&proximity_width=%d&proximity_height=%d%s%s%s%s%s",STATUSMAP_CGI,url_encode(temp_host->name),layout_method,max_image_width,max_image_height,proximity_width,proximity_height,(display_header==TRUE)?"":"&noheader",(use_links==FALSE)?"&nolinks":"",(use_text==FALSE)?"&notext":"",(use_highlights==FALSE)?"&nohighlights":"",(display_popups==FALSE)?"&nopopups":"");
01740                                 if(user_supplied_scaling==TRUE)
01741                                         printf("&scaling_factor=%2.1f",user_scaling_factor);
01742                                 print_layer_url(TRUE);
01743                                 printf("' ");
01744                                 }
01745 
01746                         /* popup text */
01747                         if(display_popups==TRUE){
01748 
01749                                 printf("onMouseOver='showPopup(\"");
01750                                 write_host_popup_text(find_host(temp_host->name));
01751                                 printf("\",event)' onMouseOut='hidePopup()'");
01752                                 }
01753 
01754                         printf(">\n");
01755                         }
01756 
01757                 }
01758 
01759         return;
01760         }
01761 
01762 
01763 /* draws text */
01764 void draw_text(char *buffer,int x,int y,int text_color){
01765         int string_width=0;
01766         int string_height=0;
01767 
01768         /* write the string to the generated image... */
01769         string_height=gdFontSmall->h;
01770         string_width=gdFontSmall->w*strlen(buffer);
01771         if(layout_method!=LAYOUT_CIRCULAR_MARKUP)
01772                 gdImageFilledRectangle(map_image,x-(string_width/2)-2,y-(2*string_height),x+(string_width/2)+2,y-string_height,color_white);
01773         gdImageString(map_image,gdFontSmall,x-(string_width/2),y-(2*string_height),(unsigned char *)buffer,text_color);
01774 
01775         return;
01776         }
01777 
01778 
01779 /* draws host text */
01780 void draw_host_text(char *name,int x,int y){
01781         hoststatus *temp_hoststatus;
01782         int status_color=color_black;
01783         char temp_buffer[MAX_INPUT_BUFFER];
01784 
01785         if(use_text==FALSE)
01786                 return;
01787 
01788         strncpy(temp_buffer,name,sizeof(temp_buffer)-1);
01789         temp_buffer[sizeof(temp_buffer)-1]='\x0';
01790 
01791         /* write the host status string to the generated image... */
01792         draw_text(temp_buffer,x,y,color_black);
01793 
01794         /* find the status entry for this host */
01795         temp_hoststatus=find_hoststatus(name);
01796 
01797         /* get the status of the host (pending, up, down, or unreachable) */
01798         if(temp_hoststatus!=NULL){
01799 
01800                 /* draw the status string */
01801                 if(temp_hoststatus->status==HOST_DOWN){
01802                         strncpy(temp_buffer,"Down",sizeof(temp_buffer));
01803                         status_color=color_red;
01804                         }
01805                 else if(temp_hoststatus->status==HOST_UNREACHABLE){
01806                         strncpy(temp_buffer,"Unreachable",sizeof(temp_buffer));
01807                         status_color=color_red;
01808                         }
01809                 else if(temp_hoststatus->status==HOST_UP){
01810                         strncpy(temp_buffer,"Up",sizeof(temp_buffer));
01811                         status_color=color_green;
01812                         }
01813                 else if(temp_hoststatus->status==HOST_PENDING){
01814                         strncpy(temp_buffer,"Pending",sizeof(temp_buffer));
01815                         status_color=color_grey;
01816                         }
01817                 else{
01818                         strncpy(temp_buffer,"Unknown",sizeof(temp_buffer));
01819                         status_color=color_orange;
01820                         }
01821 
01822                 temp_buffer[sizeof(temp_buffer)-1]='\x0';
01823 
01824                 /* write the host status string to the generated image... */
01825                 draw_text(temp_buffer,x,y+gdFontSmall->h,status_color);
01826                 }
01827 
01828         return;
01829         }
01830 
01831 
01832 /* writes popup text for a specific host */
01833 void write_host_popup_text(host *hst){
01834         hoststatus *temp_status=NULL;
01835         hostsmember *temp_hostsmember=NULL;
01836         char *processed_string=NULL;
01837         int service_totals;
01838         char date_time[48];
01839         time_t current_time;
01840         time_t t;
01841         char state_duration[48];
01842         int days;
01843         int hours;
01844         int minutes;
01845         int seconds;
01846 
01847         if(hst==NULL){
01848                 printf("Host data not found");
01849                 return;
01850                 }
01851 
01852         /* find the status entry for this host */
01853         temp_status=find_hoststatus(hst->name);
01854         if(temp_status==NULL){
01855                 printf("Host status information not found");
01856                 return;
01857                 }
01858 
01859         /* grab macros */
01860         grab_host_macros_r(mac, hst);
01861 
01862         /* strip nasty stuff from plugin output */
01863         sanitize_plugin_output(temp_status->plugin_output);
01864 
01865         printf("<table border=0 cellpadding=0 cellspacing=5>");
01866 
01867         printf("<tr><td><img src=\\\"%s",url_logo_images_path);
01868         if(hst->icon_image==NULL)
01869                 printf("%s",UNKNOWN_ICON_IMAGE);
01870         else{
01871                 process_macros_r(mac, hst->icon_image,&processed_string,0);
01872                 printf("%s",processed_string);
01873                 free(processed_string);
01874                 }
01875         printf("\\\" border=0 width=40 height=40></td>");
01876         printf("<td class=\\\"popupText\\\"><i>%s</i></td></tr>",(hst->icon_image_alt==NULL)?"":html_encode(hst->icon_image_alt,TRUE));
01877 
01878         printf("<tr><td class=\\\"popupText\\\">Name:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",escape_string(hst->name));
01879         printf("<tr><td class=\\\"popupText\\\">Alias:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",escape_string(hst->alias));
01880         printf("<tr><td class=\\\"popupText\\\">Address:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",html_encode(hst->address,TRUE));
01881         printf("<tr><td class=\\\"popupText\\\">Address6:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",html_encode(hst->address6,TRUE));
01882         printf("<tr><td class=\\\"popupText\\\">State:</td><td class=\\\"popupText\\\"><b>");
01883 
01884         /* get the status of the host (pending, up, down, or unreachable) */
01885         if(temp_status->status==HOST_DOWN){
01886                 printf("<font color=red>Down");
01887                 if(temp_status->problem_has_been_acknowledged==TRUE)
01888                         printf(" (Acknowledged)");
01889                 printf("</font>");
01890                 }
01891 
01892         else if(temp_status->status==HOST_UNREACHABLE){
01893                 printf("<font color=red>Unreachable");
01894                 if(temp_status->problem_has_been_acknowledged==TRUE)
01895                         printf(" (Acknowledged)");
01896                 printf("</font>");
01897                 }
01898 
01899         else if(temp_status->status==HOST_UP)
01900                 printf("<font color=green>Up</font>");
01901 
01902         else if(temp_status->status==HOST_PENDING)
01903                 printf("Pending");
01904 
01905         printf("</b></td></tr>");
01906         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);
01907 
01908         current_time=time(NULL);
01909         if(temp_status->last_state_change==(time_t)0)
01910                 t=current_time-program_start;
01911         else
01912                 t=current_time-temp_status->last_state_change;
01913         get_time_breakdown((unsigned long)t,&days,&hours,&minutes,&seconds);
01914         snprintf(state_duration,sizeof(state_duration)-1,"%2dd %2dh %2dm %2ds%s",days,hours,minutes,seconds,(temp_status->last_state_change==(time_t)0)?"+":"");
01915         state_duration[sizeof(state_duration)-1]='\x0';
01916         printf("<tr><td class=\\\"popupText\\\">State Duration:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",state_duration);
01917 
01918         get_time_string(&temp_status->last_check,date_time,(int)sizeof(date_time),SHORT_DATE_TIME);
01919         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);
01920         get_time_string(&temp_status->last_state_change,date_time,(int)sizeof(date_time),SHORT_DATE_TIME);
01921         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);
01922 
01923         printf("<tr><td class=\\\"popupText\\\">Parent Host(s):</td><td class=\\\"popupText\\\"><b>");
01924         if(hst->parent_hosts==NULL)
01925                 printf("None (This is a root host)");
01926         else{
01927                 for(temp_hostsmember=hst->parent_hosts;temp_hostsmember!=NULL;temp_hostsmember=temp_hostsmember->next)
01928                         printf("%s%s",(temp_hostsmember==hst->parent_hosts)?"":", ",html_encode(temp_hostsmember->host_name,TRUE));
01929                 }
01930         printf("</b></td></tr>");
01931 
01932         printf("<tr><td class=\\\"popupText\\\">Immediate Child Hosts:</td><td class=\\\"popupText\\\"><b>");
01933         printf("%d",number_of_immediate_child_hosts(hst));
01934         printf("</b></td></tr>");
01935 
01936         printf("</table>");
01937 
01938         printf("<br><b><u>Services:</u></b><br>");
01939 
01940         service_totals=get_servicestatus_count(hst->name,SERVICE_OK);
01941         if(service_totals>0)
01942                 printf("- <font color=green>%d ok</font><br>",service_totals);
01943         service_totals=get_servicestatus_count(hst->name,SERVICE_CRITICAL);
01944         if(service_totals>0)
01945                 printf("- <font color=red>%d critical</font><br>",service_totals);
01946         service_totals=get_servicestatus_count(hst->name,SERVICE_WARNING);
01947         if(service_totals>0)
01948                 printf("- <font color=orange>%d warning</font><br>",service_totals);
01949         service_totals=get_servicestatus_count(hst->name,SERVICE_UNKNOWN);
01950         if(service_totals>0)
01951                 printf("- <font color=orange>%d unknown</font><br>",service_totals);
01952         service_totals=get_servicestatus_count(hst->name,SERVICE_PENDING);
01953         if(service_totals>0)
01954                 printf("- %d pending<br>",service_totals);
01955 
01956         return;
01957         }
01958 
01959 
01960 
01961 /* draws a solid line */
01962 void draw_line(int x1,int y1,int x2,int y2,int color){
01963 
01964         if(content_type==HTML_CONTENT)
01965                 return;
01966 
01967         gdImageLine(map_image,x1,y1,x2,y2,color);
01968 
01969         return;
01970         }
01971 
01972 
01973 /* draws a dotted line */
01974 void draw_dotted_line(int x1,int y1,int x2,int y2,int color){
01975         int styleDotted[12];
01976 
01977         styleDotted[0]=color;
01978         styleDotted[1]=gdTransparent;
01979         styleDotted[2]=gdTransparent;
01980         styleDotted[3]=gdTransparent;
01981         styleDotted[4]=gdTransparent;
01982         styleDotted[5]=gdTransparent;
01983         styleDotted[6]=color;
01984         styleDotted[7]=gdTransparent;
01985         styleDotted[8]=gdTransparent;
01986         styleDotted[9]=gdTransparent;
01987         styleDotted[10]=gdTransparent;
01988         styleDotted[11]=gdTransparent;
01989 
01990         /* sets current style to a dashed line */
01991         gdImageSetStyle(map_image,styleDotted,12);
01992 
01993         /* draws a line (dotted) */
01994         gdImageLine(map_image,x1,y1,x2,y2,gdStyled);
01995 
01996         return;
01997         }
01998 
01999 /* draws a dashed line */
02000 void draw_dashed_line(int x1,int y1,int x2,int y2,int color){
02001         int styleDashed[12];
02002 
02003         styleDashed[0]=color;
02004         styleDashed[1]=color;
02005         styleDashed[2]=color;
02006         styleDashed[3]=color;
02007         styleDashed[4]=gdTransparent;
02008         styleDashed[5]=gdTransparent;
02009         styleDashed[6]=color;
02010         styleDashed[7]=color;
02011         styleDashed[8]=color;
02012         styleDashed[9]=color;
02013         styleDashed[10]=gdTransparent;
02014         styleDashed[11]=gdTransparent;
02015 
02016         /* sets current style to a dashed line */
02017         gdImageSetStyle(map_image,styleDashed,12);
02018 
02019         /* draws a line (dashed) */
02020         gdImageLine(map_image,x1,y1,x2,y2,gdStyled);
02021 
02022         return;
02023         }
02024 
02025 
02026 
02027 /******************************************************************/
02028 /*********************** GRAPHICS FUNCTIONS ***********************/
02029 /******************************************************************/
02030 
02031 /* initialize graphics */
02032 int initialize_graphics(void){
02033         char image_input_file[MAX_INPUT_BUFFER];
02034 
02035         if(content_type==HTML_CONTENT)
02036                 return ERROR;
02037 
02038         /* allocate buffer for storing image */
02039 #ifndef HAVE_GDIMAGECREATETRUECOLOR
02040         map_image=gdImageCreate(canvas_width,canvas_height);
02041 #else
02042         map_image=gdImageCreateTrueColor(canvas_width,canvas_height);
02043 #endif
02044         if(map_image==NULL)
02045                 return ERROR;
02046 
02047         /* allocate colors used for drawing */
02048         color_white=gdImageColorAllocate(map_image,255,255,255);
02049         color_black=gdImageColorAllocate(map_image,0,0,0);
02050         color_grey=gdImageColorAllocate(map_image,128,128,128);
02051         color_lightgrey=gdImageColorAllocate(map_image,210,210,210);
02052         color_red=gdImageColorAllocate(map_image,255,0,0);
02053         color_lightred=gdImageColorAllocate(map_image,215,175,175);
02054         color_green=gdImageColorAllocate(map_image,0,175,0);
02055         color_lightgreen=gdImageColorAllocate(map_image,210,255,215);
02056         color_blue=gdImageColorAllocate(map_image,0,0,255);
02057         color_yellow=gdImageColorAllocate(map_image,255,255,0);
02058         color_orange=gdImageColorAllocate(map_image,255,100,25);
02059         color_transparency_index=gdImageColorAllocate(map_image,color_transparency_index_r,color_transparency_index_g,color_transparency_index_b);              
02060 
02061         /* set transparency index */
02062 #ifndef HAVE_GDIMAGECREATETRUECOLOR
02063         gdImageColorTransparent(map_image,color_white);
02064 #else
02065         gdImageColorTransparent(map_image,color_transparency_index);
02066         
02067         /* set background */
02068         gdImageFill(map_image, 0, 0, color_transparency_index);
02069 #endif
02070 
02071         /* make sure the graphic is interlaced */
02072         gdImageInterlace(map_image,1);
02073 
02074         /* get the path where we will be reading logo images from (GD2 format)... */
02075         snprintf(physical_logo_images_path,sizeof(physical_logo_images_path)-1,"%slogos/",physical_images_path);
02076         physical_logo_images_path[sizeof(physical_logo_images_path)-1]='\x0';
02077 
02078         /* load the unknown icon to use for hosts that don't have pretty images associated with them... */
02079         snprintf(image_input_file,sizeof(image_input_file)-1,"%s%s",physical_logo_images_path,UNKNOWN_GD2_ICON);
02080         image_input_file[sizeof(image_input_file)-1]='\x0';
02081         unknown_logo_image=load_image_from_file(image_input_file);
02082 
02083         return OK;
02084         }
02085 
02086 
02087 
02088 /* loads a graphic image (GD2, JPG or PNG) from file into memory */
02089 gdImagePtr load_image_from_file(char *filename){
02090         FILE *fp;
02091         gdImagePtr im=NULL;
02092         char *ext;
02093 
02094         /* make sure we were passed a file name */
02095         if(filename==NULL)
02096                 return NULL;
02097 
02098         /* find the file extension */
02099         if((ext=rindex(filename,'.'))==NULL)
02100                 return NULL;
02101 
02102         /* open the file for reading (binary mode) */
02103         fp=fopen(filename,"rb");
02104         if(fp==NULL)
02105                 return NULL;
02106 
02107         /* attempt to read files in various formats */
02108         if(!strcasecmp(ext,".png"))
02109                 im=gdImageCreateFromPng(fp);
02110         else if(!strcasecmp(ext,".jpg") || !strcasecmp(ext,".jpeg"))
02111                 im=gdImageCreateFromJpeg(fp);
02112         else if(!strcasecmp(ext,".xbm"))
02113                 im=gdImageCreateFromXbm(fp);
02114         else if(!strcasecmp(ext,".gd2"))
02115                 im=gdImageCreateFromGd2(fp);
02116         else if(!strcasecmp(ext,".gd"))
02117                 im=gdImageCreateFromGd(fp);
02118 
02119         /* fall back to GD2 image format */
02120         else
02121                 im=gdImageCreateFromGd2(fp);
02122 
02123         /* close the file */
02124         fclose(fp);
02125 
02126         return im;
02127         }
02128 
02129 
02130 
02131 /* draw graphics */
02132 void write_graphics(void){
02133         FILE *image_output_file=NULL;
02134 
02135         if(content_type==HTML_CONTENT)
02136                 return;
02137 
02138         /* use STDOUT for writing the image data... */
02139         image_output_file=stdout;
02140 
02141         /* write the image out in PNG format */
02142         gdImagePng(map_image,image_output_file);
02143 
02144         /* or we could write the image out in JPG format... */
02145         /*gdImageJpeg(map_image,image_output_file,99);*/
02146 
02147         return;
02148         }
02149 
02150 
02151 /* cleanup graphics resources */
02152 void cleanup_graphics(void){
02153 
02154         if(content_type==HTML_CONTENT)
02155                 return;
02156 
02157         /* free memory allocated to image */
02158         gdImageDestroy(map_image);
02159 
02160         return;
02161         }
02162 
02163 
02164 
02165 
02166 /******************************************************************/
02167 /************************* MISC FUNCTIONS *************************/
02168 /******************************************************************/
02169 
02170 /* adds a layer to the list in memory */
02171 int add_layer(char *group_name){
02172         layer *new_layer;
02173 
02174         if(group_name==NULL)
02175                 return ERROR;
02176 
02177         /* allocate memory for a new layer */
02178         new_layer=(layer *)malloc(sizeof(layer));
02179         if(new_layer==NULL)
02180                 return ERROR;
02181 
02182         new_layer->layer_name=(char *)malloc(strlen(group_name)+1);
02183         if(new_layer->layer_name==NULL){
02184                 free(new_layer);
02185                 return ERROR;
02186                 }
02187 
02188         strcpy(new_layer->layer_name,group_name);
02189 
02190         /* add new layer to head of layer list */
02191         new_layer->next=layer_list;
02192         layer_list=new_layer;
02193 
02194         return OK;
02195         }
02196 
02197 
02198 
02199 /* frees memory allocated to the layer list */
02200 void free_layer_list(void){
02201         layer *this_layer;
02202         layer *next_layer;
02203 
02204         return;
02205 
02206         for(this_layer=layer_list;layer_list!=NULL;this_layer=next_layer){
02207                 next_layer=this_layer->next;
02208                 free(this_layer->layer_name);
02209                 free(this_layer);
02210                 }
02211 
02212         return;
02213         }
02214 
02215 
02216 /* checks to see if a host is in the layer list */
02217 int is_host_in_layer_list(host *hst){
02218         hostgroup *temp_hostgroup;
02219         layer *temp_layer;
02220 
02221         if(hst==NULL)
02222                 return FALSE;
02223 
02224         /* check each layer... */
02225         for(temp_layer=layer_list;temp_layer!=NULL;temp_layer=temp_layer->next){
02226 
02227                 /* find the hostgroup */
02228                 temp_hostgroup=find_hostgroup(temp_layer->layer_name);
02229                 if(temp_hostgroup==NULL)
02230                         continue;
02231                 
02232                 /* is the requested host a member of the hostgroup/layer? */
02233                 if(is_host_member_of_hostgroup(temp_hostgroup,hst)==TRUE)
02234                         return TRUE;
02235                 }
02236 
02237         return FALSE;
02238         }
02239 
02240 
02241 /* print layer url info */
02242 void print_layer_url(int get_method){
02243         layer *temp_layer;
02244 
02245         for(temp_layer=layer_list;temp_layer!=NULL;temp_layer=temp_layer->next){
02246                 if(get_method==TRUE)
02247                         printf("&layer=%s",escape_string(temp_layer->layer_name));
02248                 else
02249                         printf("<input type='hidden' name='layer' value='%s'>\n",escape_string(temp_layer->layer_name));
02250                 }
02251 
02252         if(get_method==TRUE)
02253                 printf("&layermode=%s",(exclude_layers==TRUE)?"exclude":"include");
02254         else
02255                 printf("<input type='hidden' name='layermode' value='%s'>\n",(exclude_layers==TRUE)?"exclude":"include");
02256 
02257         return;
02258         }
02259         
02260 
02261 
02262 
02263 /******************************************************************/
02264 /************************ UTILITY FUNCTIONS ***********************/
02265 /******************************************************************/
02266 
02267 /* calculates how many "layers" separate parent and child - used by collapsed tree layout method */
02268 int host_child_depth_separation(host *parent, host *child){
02269         int this_depth=0;
02270         int min_depth=0;
02271         int have_min_depth=FALSE;
02272         host *temp_host;
02273 
02274         if(child==NULL)
02275                 return -1;
02276 
02277         if(parent==child)
02278                 return 0;
02279 
02280         if(is_host_immediate_child_of_host(parent,child)==TRUE)
02281                 return 1;
02282 
02283         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02284 
02285                 if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){
02286 
02287                         this_depth=host_child_depth_separation(temp_host,child);
02288 
02289                         if(this_depth>=0 && (have_min_depth==FALSE || (have_min_depth==TRUE && (this_depth<min_depth)))){
02290                                 have_min_depth=TRUE;
02291                                 min_depth=this_depth;
02292                                 }
02293                         }
02294                 }
02295 
02296         if(have_min_depth==FALSE)
02297                 return -1;
02298         else
02299                 return min_depth+1;
02300         }
02301 
02302 
02303 
02304 /* calculates how many hosts reside on a specific "layer" - used by collapsed tree layout method */
02305 int number_of_host_layer_members(host *parent, int layer){
02306         int current_layer;
02307         int layer_members=0;
02308         host *temp_host;
02309 
02310         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02311 
02312                 current_layer=host_child_depth_separation(parent,temp_host);
02313 
02314                 if(current_layer==layer)
02315                         layer_members++;
02316                 }
02317 
02318         return layer_members;
02319         }
02320 
02321 
02322 
02323 /* calculate max number of members on all "layers" beneath and including parent host - used by collapsed tree layout method */
02324 int max_child_host_layer_members(host *parent){
02325         int current_layer;
02326         int max_members=1;
02327         int current_members=0;
02328 
02329         for(current_layer=1;;current_layer++){
02330 
02331                 current_members=number_of_host_layer_members(parent,current_layer);
02332 
02333                 if(current_members<=0)
02334                         break;
02335 
02336                 if(current_members>max_members)
02337                         max_members=current_members;
02338                 }
02339 
02340         return max_members;
02341         }
02342 
02343 
02344 
02345 /* calculate max drawing width for host and children - used by balanced tree layout method */
02346 int max_child_host_drawing_width(host *parent){
02347         host *temp_host;
02348         int child_width=0;
02349 
02350 
02351         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02352                 
02353                 if(is_host_immediate_child_of_host(parent,temp_host)==TRUE)
02354                         child_width+=max_child_host_drawing_width(temp_host);
02355                 }
02356 
02357         /* no children, so set width to 1 for this host */
02358         if(child_width==0)
02359                 return 1;
02360 
02361         else
02362                 return child_width;
02363         }
02364 
02365 
02366 
02367 /* calculates number of services associated with a particular service */
02368 int number_of_host_services(host *hst){
02369         service *temp_service;
02370         int total_services=0;
02371 
02372         if(hst==NULL)
02373                 return 0;
02374 
02375         /* check all the services */
02376         for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
02377                 if(!strcmp(temp_service->host_name,hst->name))
02378                         total_services++;
02379                 }
02380 
02381         return total_services;
02382         }
02383         
02384 
02385 
02386 /******************************************************************/
02387 /***************** COORDINATE CALCULATION FUNCTIONS ***************/
02388 /******************************************************************/
02389 
02390 /* calculates coords of a host's children - used by balanced tree layout method */
02391 void calculate_balanced_tree_coords(host *parent, int x, int y){
02392         int parent_drawing_width;
02393         int start_drawing_x;
02394         int current_drawing_x;
02395         int this_drawing_width;
02396         host *temp_host;
02397 
02398         /* calculate total drawing width of parent host */
02399         parent_drawing_width=max_child_host_drawing_width(parent);
02400 
02401         /* calculate starting x coord */
02402         start_drawing_x=x-(((DEFAULT_NODE_WIDTH*parent_drawing_width)+(DEFAULT_NODE_HSPACING*(parent_drawing_width-1)))/2);
02403         current_drawing_x=start_drawing_x;
02404 
02405 
02406         /* calculate coords for children */
02407         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02408 
02409                 if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){
02410 
02411                         /* get drawing width of child host */
02412                         this_drawing_width=max_child_host_drawing_width(temp_host);
02413 
02414                         temp_host->x_2d=current_drawing_x+(((DEFAULT_NODE_WIDTH*this_drawing_width)+(DEFAULT_NODE_HSPACING*(this_drawing_width-1)))/2);
02415                         temp_host->y_2d=y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
02416                         temp_host->have_2d_coords=TRUE;
02417                         temp_host->should_be_drawn=TRUE;
02418                         
02419                         current_drawing_x+=(this_drawing_width*DEFAULT_NODE_WIDTH)+((this_drawing_width-1)*DEFAULT_NODE_HSPACING)+DEFAULT_NODE_HSPACING;
02420 
02421                         /* recurse into child host ... */
02422                         calculate_balanced_tree_coords(temp_host,temp_host->x_2d,temp_host->y_2d);
02423                         }
02424 
02425                 }
02426 
02427         return;
02428         }
02429 
02430 
02431 /* calculate coords of all hosts in circular layout method */
02432 void calculate_circular_coords(void){
02433         int min_x=0;
02434         int min_y=0;
02435         int have_min_x=FALSE;
02436         int have_min_y=FALSE;
02437         host *temp_host;
02438 
02439         /* calculate all host coords, starting with first layer */
02440         calculate_circular_layer_coords(NULL,0.0,360.0,1,CIRCULAR_DRAWING_RADIUS);
02441 
02442         /* adjust all calculated coords so none are negative in x or y axis... */
02443 
02444         /* calculate min x, y coords */
02445         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02446                 if(have_min_x==FALSE || temp_host->x_2d<min_x){
02447                         have_min_x=TRUE;
02448                         min_x=temp_host->x_2d;
02449                         }
02450                 if(have_min_y==FALSE || temp_host->y_2d<min_y){
02451                         have_min_y=TRUE;
02452                         min_y=temp_host->y_2d;
02453                         }
02454                 }
02455         
02456         /* offset all drawing coords by the min x,y coords we found */
02457         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02458                 if(min_x<0)
02459                         temp_host->x_2d-=min_x;
02460                 if(min_y<0)
02461                         temp_host->y_2d-=min_y;
02462                 }
02463 
02464         if(min_x<0)
02465                 nagios_icon_x-=min_x;
02466         if(min_y<0)
02467                 nagios_icon_y-=min_y;
02468 
02469         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02470                 temp_host->x_2d+=(DEFAULT_NODE_WIDTH/2);
02471                 temp_host->y_2d+=(DEFAULT_NODE_HEIGHT/2);
02472                 }
02473         nagios_icon_x+=(DEFAULT_NODE_WIDTH/2);
02474         nagios_icon_y+=(DEFAULT_NODE_HEIGHT/2);
02475 
02476         return;
02477         }
02478         
02479 
02480 /* calculates coords of all hosts in a particular "layer" in circular layout method */
02481 void calculate_circular_layer_coords(host *parent, double start_angle, double useable_angle, int layer, int radius){
02482         int parent_drawing_width=0;
02483         int this_drawing_width=0;
02484         int immediate_children=0;
02485         double current_drawing_angle=0.0;
02486         double this_drawing_angle=0.0;
02487         double available_angle=0.0;
02488         double clipped_available_angle=0.0;
02489         double average_child_angle=0.0;
02490         double x_coord=0.0;
02491         double y_coord=0.0;
02492         host *temp_host;
02493 
02494 
02495         /* get the total number of immediate children to this host */
02496         immediate_children=number_of_immediate_child_hosts(parent);
02497 
02498         /* bail out if we're done */
02499         if(immediate_children==0)
02500                 return;
02501 
02502         /* calculate total drawing "width" of parent host */
02503         parent_drawing_width=max_child_host_drawing_width(parent);
02504 
02505         /* calculate average angle given to each child host */
02506         average_child_angle=(double)(useable_angle/(double)immediate_children);
02507 
02508         /* calculate initial drawing angle */
02509         current_drawing_angle=start_angle;
02510 
02511 
02512         /* calculate coords for children */
02513         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02514 
02515                 if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){
02516 
02517                         /* get drawing width of child host */
02518                         this_drawing_width=max_child_host_drawing_width(temp_host);
02519 
02520                         /* calculate angle this host gets for drawing */
02521                         available_angle=useable_angle*((double)this_drawing_width/(double)parent_drawing_width);
02522 
02523                         /* clip available angle if necessary */
02524                         /* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */
02525                         clipped_available_angle=360.0/layer;
02526                         if(available_angle<clipped_available_angle)
02527                                 clipped_available_angle=available_angle;
02528 
02529                         /* calculate the exact angle at which we should draw this child */
02530                         this_drawing_angle=current_drawing_angle+(available_angle/2.0);
02531 
02532                         /* compensate for angle overflow */
02533                         while(this_drawing_angle>=360.0)
02534                                 this_drawing_angle-=360.0;
02535                         while(this_drawing_angle<0.0)
02536                                 this_drawing_angle+=360.0;
02537 
02538                         /* calculate drawing coords of this host using good ol' geometry... */
02539                         x_coord=-(sin(-this_drawing_angle*(M_PI/180.0))*radius);
02540                         y_coord=-(sin((90+this_drawing_angle)*(M_PI/180.0))*radius);
02541 
02542                         temp_host->x_2d=(int)x_coord;
02543                         temp_host->y_2d=(int)y_coord;
02544                         temp_host->have_2d_coords=TRUE;
02545                         temp_host->should_be_drawn=TRUE;
02546 
02547                         /* recurse into child host ... */
02548                         calculate_circular_layer_coords(temp_host,current_drawing_angle+((available_angle-clipped_available_angle)/2),clipped_available_angle,layer+1,radius+CIRCULAR_DRAWING_RADIUS);
02549 
02550                         /* increment current drawing angle */
02551                         current_drawing_angle+=available_angle;
02552                         }
02553                 }
02554 
02555         return;
02556         }
02557 
02558 
02559 
02560 /* draws background "extras" for all hosts in circular markup layout */
02561 void draw_circular_markup(void){
02562 
02563         /* calculate all host sections, starting with first layer */
02564         draw_circular_layer_markup(NULL,0.0,360.0,1,CIRCULAR_DRAWING_RADIUS);
02565 
02566         return;
02567         }
02568 
02569 
02570 /* draws background "extras" for all hosts in a particular "layer" in circular markup layout */
02571 void draw_circular_layer_markup(host *parent, double start_angle, double useable_angle, int layer, int radius){
02572         int parent_drawing_width=0;
02573         int this_drawing_width=0;
02574         int immediate_children=0;
02575         double current_drawing_angle=0.0;
02576         double available_angle=0.0;
02577         double clipped_available_angle=0.0;
02578         double average_child_angle=0.0;
02579         double x_coord[4]={0.0,0.0,0.0,0.0};
02580         double y_coord[4]={0.0,0.0,0.0,0.0};
02581         hoststatus *temp_hoststatus;
02582         host *temp_host;
02583         int x_offset=0;
02584         int y_offset=0;
02585         int center_x=0;
02586         int center_y=0;
02587         int bgcolor=0;
02588         double arc_start_angle=0.0;
02589         double arc_end_angle=0.0;
02590         int translated_x=0;
02591         int translated_y=0;
02592 
02593         /* get the total number of immediate children to this host */
02594         immediate_children=number_of_immediate_child_hosts(parent);
02595 
02596         /* bail out if we're done */
02597         if(immediate_children==0)
02598                 return;
02599 
02600         /* calculate total drawing "width" of parent host */
02601         parent_drawing_width=max_child_host_drawing_width(parent);
02602 
02603         /* calculate average angle given to each child host */
02604         average_child_angle=(double)(useable_angle/(double)immediate_children);
02605 
02606         /* calculate initial drawing angle */
02607         current_drawing_angle=start_angle;
02608 
02609         /* calculate coords for children */
02610         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
02611 
02612                 if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){
02613 
02614                         /* get drawing width of child host */
02615                         this_drawing_width=max_child_host_drawing_width(temp_host);
02616 
02617                         /* calculate angle this host gets for drawing */
02618                         available_angle=useable_angle*((double)this_drawing_width/(double)parent_drawing_width);
02619 
02620                         /* clip available angle if necessary */
02621                         /* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */
02622                         clipped_available_angle=360.0/layer;
02623                         if(available_angle<clipped_available_angle)
02624                                 clipped_available_angle=available_angle;
02625 
02626                         /* calculate drawing coords of "leftmost" divider using good ol' geometry... */
02627                         x_coord[0]=-(sin(-current_drawing_angle*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
02628                         y_coord[0]=-(sin((90+current_drawing_angle)*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
02629                         x_coord[1]=-(sin(-current_drawing_angle*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));
02630                         y_coord[1]=-(sin((90+current_drawing_angle)*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));
02631 
02632                         /* calculate drawing coords of "rightmost" divider using good ol' geometry... */
02633                         x_coord[2]=-(sin((-(current_drawing_angle+available_angle))*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
02634                         y_coord[2]=-(sin((90+current_drawing_angle+available_angle)*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
02635                         x_coord[3]=-(sin((-(current_drawing_angle+available_angle))*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));
02636                         y_coord[3]=-(sin((90+current_drawing_angle+available_angle)*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));
02637 
02638 
02639                         x_offset=nagios_icon_x+(DEFAULT_NODE_WIDTH/2)-canvas_x;
02640                         y_offset=nagios_icon_y+(DEFAULT_NODE_HEIGHT/2)-canvas_y;
02641 
02642                         /* if the host should be drawn */
02643                         /* this enforces the privacy of hosts that are not eligble to be drawn */
02644                         if(temp_host->should_be_drawn==TRUE){
02645 
02646                                 /* draw "slice" dividers */
02647                                 if(immediate_children>1 || layer>1){
02648 
02649                                         /* draw "leftmost" divider */
02650                                         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);
02651 
02652                                         /* draw "rightmost" divider */
02653                                         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);
02654                                         }
02655 
02656 
02657                                 /* determine arc drawing angles */
02658                                 arc_start_angle=current_drawing_angle-90.0;
02659                                 while(arc_start_angle<0.0)
02660                                         arc_start_angle+=360.0;
02661                                 arc_end_angle=arc_start_angle+available_angle;
02662 
02663                                 /* draw inner arc */
02664                                 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);
02665 
02666                                 /* draw outer arc */
02667                                 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);
02668 
02669 
02670                                 /* determine center of "slice" and fill with appropriate color */
02671                                 center_x=-(sin(-(current_drawing_angle+(available_angle/2.0))*(M_PI/180.0))*(radius));
02672                                 center_y=-(sin((90+current_drawing_angle+(available_angle/2.0))*(M_PI/180.0))*(radius));
02673                                 translated_x=center_x+x_offset;
02674                                 translated_y=center_y+y_offset;
02675 
02676                                 /* determine background color */
02677                                 temp_hoststatus=find_hoststatus(temp_host->name);
02678                                 if(temp_hoststatus==NULL)
02679                                         bgcolor=color_lightgrey;
02680                                 else if(temp_hoststatus->status==HOST_DOWN || temp_hoststatus->status==HOST_UNREACHABLE)
02681                                         bgcolor=color_lightred;
02682                                 else
02683                                         bgcolor=color_lightgreen;
02684 
02685 
02686                                 /* fill slice with background color */
02687                                 /* the fill function only works with coordinates that are in bounds of the actual image */
02688                                 if(translated_x>0 && translated_y>0 && translated_x<canvas_width && translated_y<canvas_height)
02689                                         gdImageFillToBorder(map_image,translated_x,translated_y,color_lightgrey,bgcolor);
02690 
02691                                 }
02692 
02693                         /* recurse into child host ... */
02694                         draw_circular_layer_markup(temp_host,current_drawing_angle+((available_angle-clipped_available_angle)/2),clipped_available_angle,layer+1,radius+CIRCULAR_DRAWING_RADIUS);
02695 
02696                         /* increment current drawing angle */
02697                         current_drawing_angle+=available_angle;
02698                         }
02699                 }
02700 
02701         return;
02702         }
02703 
 All Data Structures Files Functions Variables Typedefs Defines