Logo Search packages:      
Sourcecode: nagios version File versions  Download package

statusmap.c

/*****************************************************************************
 *
 * STATUSMAP.C - Nagios Network Status Map CGI
 *
 * Copyright (c) 1999-2005 Ethan Galstad (nagios@nagios.org)
 * Last Modified: 03-05-2005
 *
 * Description:
 *
 * This CGI will create a map of all hosts that are being monitored on your
 * network.
 *
 * License:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *****************************************************************************/

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

#include "cgiutils.h"
#include "getcgi.h"
#include "auth.h"
#include "edata.h"

#include <gd.h>               /* Boutell's GD library function */
#include <gdfonts.h>          /* GD library small font definition */

extern int             refresh_rate;

/*#define DEBUG*/

#define UNKNOWN_GD2_ICON      "unknown.gd2"
#define UNKNOWN_ICON_IMAGE    "unknown.gif"
#define NAGIOS_GD2_ICON       "nagios.gd2"

extern char main_config_file[MAX_FILENAME_LENGTH];
extern char physical_images_path[MAX_FILENAME_LENGTH];
extern char url_images_path[MAX_FILENAME_LENGTH];
extern char url_logo_images_path[MAX_FILENAME_LENGTH];
extern char url_stylesheets_path[MAX_FILENAME_LENGTH];

extern hostgroup *hostgroup_list;
extern hoststatus *hoststatus_list;
extern host *host_list;
extern servicestatus *servicestatus_list;
extern service *service_list;

extern char *statusmap_background_image;

extern int default_statusmap_layout_method;

#define DEFAULT_NODE_WIDTH          40
#define DEFAULT_NODE_HEIGHT         65

#define DEFAULT_NODE_VSPACING           15
#define DEFAULT_NODE_HSPACING           45

#define DEFAULT_PROXIMITY_WIDTH           1000
#define DEFAULT_PROXIMITY_HEIGHT    800

#define MINIMUM_PROXIMITY_WIDTH         250
#define MINIMUM_PROXIMITY_HEIGHT        200

#define COORDS_WARNING_WIDTH            650
#define COORDS_WARNING_HEIGHT           60

#define CIRCULAR_DRAWING_RADIUS         100

#define CREATE_HTML     0
#define CREATE_IMAGE    1

#define LAYOUT_USER_SUPPLIED            0
#define LAYOUT_SUBLAYERS                1
#define LAYOUT_COLLAPSED_TREE           2
#define LAYOUT_BALANCED_TREE            3
#define LAYOUT_CIRCULAR                 4
#define LAYOUT_CIRCULAR_MARKUP          5
#define LAYOUT_CIRCULAR_BALLOON         6


typedef struct layer_struct{
      char *layer_name;
      struct layer_struct *next;
        }layer;


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

void display_page_header(void);
void display_map(void);
void calculate_host_coords(void);
void calculate_total_image_bounds(void);
void calculate_canvas_bounds(void);
void calculate_canvas_bounds_from_host(char *);
void calculate_scaling_factor(void);
void find_eligible_hosts(void);
void load_background_image(void);
void draw_background_image(void);
void draw_background_extras(void);
void draw_host_links(void);
void draw_hosts(void);
void draw_host_text(char *,int,int);
void draw_text(char *,int,int,int);
void write_popup_code(void);
void write_host_popup_text(host *);

int initialize_graphics(void);
gdImagePtr load_image_from_file(char *);
void write_graphics(void);
void cleanup_graphics(void);
void draw_line(int,int,int,int,int);
void draw_dotted_line(int,int,int,int,int);
void draw_dashed_line(int,int,int,int,int);

int is_host_in_layer_list(host *);
int add_layer(char *);
void free_layer_list(void);
void print_layer_url(int);

int number_of_host_layer_members(host *,int);
int max_child_host_layer_members(host *);
int host_child_depth_separation(host *, host *);
int max_child_host_drawing_width(host *);
int number_of_host_services(host *);

void calculate_balanced_tree_coords(host *,int,int);
void calculate_circular_coords(void);
void calculate_circular_layer_coords(host *,double,double,int,int);

void draw_circular_markup(void);
void draw_circular_layer_markup(host *,double,double,int,int);


char physical_logo_images_path[MAX_FILENAME_LENGTH];

authdata current_authdata;

int create_type=CREATE_HTML;

gdImagePtr unknown_logo_image=NULL;
gdImagePtr logo_image=NULL;
gdImagePtr map_image=NULL;
gdImagePtr background_image=NULL;
int color_white=0;
int color_black=0;
int color_red=0;
int color_lightred=0;
int color_green=0;
int color_lightgreen=0;
int color_blue=0;
int color_yellow=0;
int color_orange=0;
int color_grey=0;
int color_lightgrey=0;

int show_all_hosts=TRUE;
char *host_name="all";

int embedded=FALSE;
int display_header=TRUE;
int display_popups=TRUE;
int use_links=TRUE;
int use_text=TRUE;
int use_highlights=TRUE;
int user_supplied_canvas=FALSE;
int user_supplied_scaling=FALSE;

int layout_method=LAYOUT_USER_SUPPLIED;

int proximity_width=DEFAULT_PROXIMITY_WIDTH;
int proximity_height=DEFAULT_PROXIMITY_HEIGHT;

int coordinates_were_specified=FALSE;   /* were any coordinates specified in extended host information entries? */

int scaled_image_width=0;        /* size of the image actually displayed on the screen (after scaling) */
int scaled_image_height=0;
int canvas_width=0;              /* actual size of the image (or portion thereof) that we are drawing */
int canvas_height=0;
int total_image_width=0;         /* actual size of the image that would be created if we drew all hosts */
int total_image_height=0;
int max_image_width=0;           /* max image size the user wants (scaled) */
int max_image_height=0;
double scaling_factor=1.0;       /* scaling factor to use */
double user_scaling_factor=1.0;  /* user-supplied scaling factor */
int background_image_width=0;
int background_image_height=0;

int canvas_x=0;                     /* upper left coords of drawing canvas */
int canvas_y=0;

int bottom_margin=0;

int draw_child_links=FALSE;
int draw_parent_links=FALSE;

int draw_nagios_icon=FALSE;    /* should we drawn the Nagios process icon? */
int nagios_icon_x=0;           /* coords of Nagios icon */
int nagios_icon_y=0;

extern hostextinfo *hostextinfo_list;
extern host *host_list;
extern hoststatus *hoststatus_list;

extern time_t program_start;

layer *layer_list=NULL;
int exclude_layers=TRUE;
int all_layers=FALSE;





int main(int argc, char **argv){
      int result;

      /* reset internal variables */
      reset_cgi_vars();

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

      /* defaults from CGI config file */
      layout_method=default_statusmap_layout_method;

      /* get the arguments passed in the URL */
      process_cgivars();

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

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

      /* read all status data */
      result=read_all_status_data(DEFAULT_CGI_CONFIG_FILE,READ_ALL_STATUS_DATA);
      if(result==ERROR){
            document_header(FALSE);
            if(create_type==CREATE_HTML)
                  status_data_error();
            document_footer();
            free_memory();
            return ERROR;
                }


      document_header(TRUE);

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

      /* read in extended host information */
      read_extended_object_config_data(DEFAULT_CGI_CONFIG_FILE,READ_EXTENDED_HOST_INFO);

      /* display the network map... */
      display_map();

      document_footer();

      /* free all allocated memory */
      free_memory();
      free_extended_data();
      free_layer_list();

      return OK;
        }



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

      if(create_type==CREATE_HTML){
            printf("Cache-Control: no-store\n");
            printf("Pragma: no-cache\n");
            printf("Refresh: %d\n",refresh_rate);

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

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

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

            if(embedded==TRUE)
                  return;

            printf("<html>\n");
            printf("<head>\n");
            printf("<title>\n");
            printf("Network Map\n");
            printf("</title>\n");

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

            /* write JavaScript code for popup window */
            write_popup_code();

            printf("</head>\n");
            
            printf("<body CLASS='statusmap' name='mappage' id='mappage'>\n");

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

            printf("<div id=\"popup\" style=\"position:absolute; z-index:1; visibility: hidden\"></div>\n");
              }

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

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

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

            printf("Content-Type: image/png\n\n");
              }

      return;
        }


void document_footer(void){

      if(embedded==TRUE)
            return;

      if(create_type==CREATE_HTML){

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

            printf("</body>\n");
            printf("</html>\n");
              }

      return;
        }



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

      variables=getcgivars();

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

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

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

                  host_name=(char *)malloc(strlen(variables[x])+1);
                  if(host_name==NULL)
                        host_name="all";
                  else
                        strcpy(host_name,variables[x]);

                  if(!strcmp(host_name,"all"))
                        show_all_hosts=TRUE;
                  else
                        show_all_hosts=FALSE;
                    }

            /* we found the image creation option */
            else if(!strcmp(variables[x],"createimage")){
                  create_type=CREATE_IMAGE;
                    }

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

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

            /* we found the canvas origin */
            else if(!strcmp(variables[x],"canvas_x")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  canvas_x=atoi(variables[x]);
                  user_supplied_canvas=TRUE;
                    }
            else if(!strcmp(variables[x],"canvas_y")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  canvas_y=atoi(variables[x]);
                  user_supplied_canvas=TRUE;
                    }

            /* we found the canvas size */
            else if(!strcmp(variables[x],"canvas_width")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  canvas_width=atoi(variables[x]);
                  user_supplied_canvas=TRUE;
                    }
            else if(!strcmp(variables[x],"canvas_height")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  canvas_height=atoi(variables[x]);
                  user_supplied_canvas=TRUE;
                    }
            else if(!strcmp(variables[x],"proximity_width")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  proximity_width=atoi(variables[x]);
                  if(proximity_width<0)
                        proximity_width=DEFAULT_PROXIMITY_WIDTH;
                    }
            else if(!strcmp(variables[x],"proximity_height")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  proximity_height=atoi(variables[x]);
                  if(proximity_height<0)
                        proximity_height=DEFAULT_PROXIMITY_HEIGHT;
                    }

            /* we found the scaling factor */
            else if(!strcmp(variables[x],"scaling_factor")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  user_scaling_factor=strtod(variables[x],NULL);
                  if(user_scaling_factor>0.0)
                        user_supplied_scaling=TRUE;
                    }

            /* we found the max image size */
            else if(!strcmp(variables[x],"max_width")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  max_image_width=atoi(variables[x]);
                    }
            else if(!strcmp(variables[x],"max_height")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  max_image_height=atoi(variables[x]);
                    }

            /* we found the layout method option */
            else if(!strcmp(variables[x],"layout")){
                  x++;
                  if(variables[x]==NULL){
                        error=TRUE;
                        break;
                          }
                  layout_method=atoi(variables[x]);
                    }

            /* we found the no links argument*/
            else if(!strcmp(variables[x],"nolinks"))
                  use_links=FALSE;

            /* we found the no text argument*/
            else if(!strcmp(variables[x],"notext"))
                  use_text=FALSE;

            /* we found the no highlights argument*/
            else if(!strcmp(variables[x],"nohighlights"))
                  use_highlights=FALSE;

            /* we found the no popups argument*/
            else if(!strcmp(variables[x],"nopopups"))
                  display_popups=FALSE;

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

                  if(!strcmp(variables[x],"include"))
                        exclude_layers=FALSE;
                  else
                        exclude_layers=TRUE;
                    }

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

                  add_layer(variables[x]);
                    }
              }

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

      return error;
        }



/* top of page */
void display_page_header(void){
      char temp_buffer[MAX_INPUT_BUFFER];
      int zoom;
      int zoom_width, zoom_height;
      int zoom_width_granularity=0;
      int zoom_height_granularity=0;
      int current_zoom_granularity=0;
      hostgroup *temp_hostgroup;
      layer *temp_layer;
      int found=0;


      if(create_type!=CREATE_HTML)
            return;

      if(display_header==TRUE){

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

            /* left column of the first row */
            printf("<td align=left valign=top>\n");

            if(show_all_hosts==TRUE)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Network Map For All Hosts");
            else
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Network Map For Host <I>%s</I>",host_name);
            temp_buffer[sizeof(temp_buffer)-1]='\x0';
            display_info_table(temp_buffer,TRUE,&current_authdata);

            printf("<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 CLASS='linkBox'>\n");
            printf("<TR><TD CLASS='linkBox'>\n");

            if(show_all_hosts==FALSE){
                  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);
                  printf("<a href='%s?host=%s'>View Status Detail For This Host</a><BR>\n",STATUS_CGI,url_encode(host_name));
                    }
            printf("<a href='%s?host=all'>View Status Detail For All Hosts</a><BR>\n",STATUS_CGI);
            printf("<a href='%s?hostgroup=all'>View Status Overview For All Hosts</a>\n",STATUS_CGI);

            printf("</TD></TR>\n");
            printf("</TABLE>\n");

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



            /* center column of top row */
            printf("<td align=center valign=center>\n");

            /* print image size and scaling info */
#ifdef DEBUG
            printf("<p><div align=center><font size=-1>\n");
            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));
            printf("</font></div></p>\n");

            printf("<p><div align=center><font size=-1>\n");
            printf("[ Canvas_x: %d | Canvas_y: %d | Canvas_width: %d | Canvas_height: %d ]",canvas_x,canvas_y,canvas_width,canvas_height);
            printf("</font></div></p>\n");
#endif

            /* zoom links */
            if(user_supplied_canvas==FALSE && strcmp(host_name,"all") && display_header==TRUE){
                  
                  printf("<p><div align=center>\n");

                  zoom_width_granularity=((total_image_width-MINIMUM_PROXIMITY_WIDTH)/11);
                  if(zoom_width_granularity==0)
                        zoom_width_granularity=1;
                  zoom_height_granularity=((total_image_height-MINIMUM_PROXIMITY_HEIGHT)/11);

                  if(proximity_width<=0)
                        current_zoom_granularity=0;
                  else
                        current_zoom_granularity=(total_image_width-proximity_width)/zoom_width_granularity;
                  if(current_zoom_granularity>10)
                        current_zoom_granularity=10;

                  printf("<table border=0 cellpadding=0 cellspacing=2>\n");
                  printf("<tr>\n");
                  printf("<td valign=center class='zoomTitle'>Zoom Out&nbsp;&nbsp;</td>\n");

                  for(zoom=0;zoom<=10;zoom++){

                        zoom_width=total_image_width-(zoom*zoom_width_granularity);
                        zoom_height=total_image_height-(zoom*zoom_height_granularity);

                        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":"");
                        if(user_supplied_scaling==TRUE)
                              printf("&scaling_factor=%2.1f",user_scaling_factor);
                        print_layer_url(TRUE);
                        printf("'>");
                        printf("<img src='%s%s' border=0 alt='%d'></a></td>\n",url_images_path,(current_zoom_granularity==zoom)?ZOOM2_ICON:ZOOM1_ICON,zoom);
                            }

                  printf("<td valign=center class='zoomTitle'>&nbsp;&nbsp;Zoom In</td>\n");
                  printf("</tr>\n");
                  printf("</table>\n");

                  printf("</div></p>\n");
                      }

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



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

            printf("<table border=0 CLASS='optBox'>\n");
            printf("<tr><td valign=top>\n");
            printf("<form method=\"POST\" action=\"%s\">\n",STATUSMAP_CGI);
            printf("<input type='hidden' name='host' value='%s'>\n",host_name);
            printf("<input type='hidden' name='layout' value='%d'>\n",layout_method);

            printf("</td><td valign=top>\n");

            printf("<table border=0>\n");

            printf("<tr><td CLASS='optBoxItem'>\n");
            printf("Layout Method:<br>\n");
            printf("<select name='layout'>\n");
#ifndef DUMMY_INSTALL
            printf("<option value=%d %s>User-supplied coords\n",LAYOUT_USER_SUPPLIED,(layout_method==LAYOUT_USER_SUPPLIED)?"selected":"");
#endif
            printf("<option value=%d %s>Depth layers\n",LAYOUT_SUBLAYERS,(layout_method==LAYOUT_SUBLAYERS)?"selected":"");
            printf("<option value=%d %s>Collapsed tree\n",LAYOUT_COLLAPSED_TREE,(layout_method==LAYOUT_COLLAPSED_TREE)?"selected":"");
            printf("<option value=%d %s>Balanced tree\n",LAYOUT_BALANCED_TREE,(layout_method==LAYOUT_BALANCED_TREE)?"selected":"");
            printf("<option value=%d %s>Circular\n",LAYOUT_CIRCULAR,(layout_method==LAYOUT_CIRCULAR)?"selected":"");
            printf("<option value=%d %s>Circular (Marked Up)\n",LAYOUT_CIRCULAR_MARKUP,(layout_method==LAYOUT_CIRCULAR_MARKUP)?"selected":"");
            printf("<option value=%d %s>Circular (Balloon)\n",LAYOUT_CIRCULAR_BALLOON,(layout_method==LAYOUT_CIRCULAR_BALLOON)?"selected":"");
            printf("</select>\n");
            printf("</td>\n");
            printf("<td CLASS='optBoxItem'>\n");
            printf("Scaling factor:<br>\n");
            printf("<input type='text' name='scaling_factor' maxlength='5' size='4' value='%2.1f'>\n",(user_supplied_scaling==TRUE)?user_scaling_factor:0.0);
            printf("</td></tr>\n");

            /*
            printf("<tr><td CLASS='optBoxItem'>\n");
            printf("Max image width:<br>\n");
            printf("<input type='text' name='max_width' maxlength='5' size='4' value='%d'>\n",max_image_width);
            printf("</td>\n");
            printf("<td CLASS='optBoxItem'>\n");
            printf("Max image height:<br>\n");
            printf("<input type='text' name='max_height' maxlength='5' size='4' value='%d'>\n",max_image_height);
            printf("</td></tr>\n");

            printf("<tr><td CLASS='optBoxItem'>\n");
            printf("Proximity width:<br>\n");
            printf("<input type='text' name='proximity_width' maxlength='5' size='4' value='%d'>\n",proximity_width);
            printf("</td>\n");
            printf("<td CLASS='optBoxItem'>\n");
            printf("Proximity height:<br>\n");
            printf("<input type='text' name='proximity_height' maxlength='5' size='4' value='%d'>\n",proximity_height);
            printf("</td></tr>\n");
            */

            printf("<input type='hidden' name='max_width' value='%d'>\n",max_image_width);
            printf("<input type='hidden' name='max_height' value='%d'>\n",max_image_height);
            printf("<input type='hidden' name='proximity_width' value='%d'>\n",proximity_width);
            printf("<input type='hidden' name='proximity_height' value='%d'>\n",proximity_height);

            printf("<tr><td CLASS='optBoxItem'>Drawing Layers:<br>\n");
            printf("<select multiple name='layer' size='4'>\n");
            for(temp_hostgroup=hostgroup_list;temp_hostgroup!=NULL;temp_hostgroup=temp_hostgroup->next){
                  if(is_authorized_for_hostgroup(temp_hostgroup,&current_authdata)==FALSE)
                        continue;
                  found=0;
                  for(temp_layer=layer_list;temp_layer!=NULL;temp_layer=temp_layer->next){
                        if(!strcmp(temp_layer->layer_name,temp_hostgroup->group_name)){
                              found=1;
                              break;
                                }
                          }
                  printf("<option value='%s' %s>%s\n",temp_hostgroup->group_name,(found==1)?"SELECTED":"",temp_hostgroup->alias);
                    }
            printf("</select>\n");
            printf("</td><td CLASS='optBoxItem' valign=top>Layer mode:<br>");
            printf("<input type='radio' name='layermode' value='include' %s>Include<br>\n",(exclude_layers==FALSE)?"CHECKED":"");
            printf("<input type='radio' name='layermode' value='exclude' %s>Exclude\n",(exclude_layers==TRUE)?"CHECKED":"");
            printf("</td></tr>\n");

            printf("<tr><td CLASS='optBoxItem'>\n");
            printf("Supress popups:<br>\n");
            printf("<input type='checkbox' name='nopopups' %s>\n",(display_popups==FALSE)?"CHECKED":"");
            printf("</td><td CLASS='optBoxItem'>\n");
            printf("<input type='submit' value='Update'>\n");
            printf("</td></tr>\n");

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

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

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

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


      return;
        }



/* top-level map generation... */
void display_map(void){

      load_background_image();
      calculate_host_coords();
      calculate_total_image_bounds();
      calculate_canvas_bounds();
      calculate_scaling_factor();
      find_eligible_hosts();

      /* display page header */
      display_page_header();

      initialize_graphics();
      draw_background_image();
      draw_background_extras();
      draw_host_links();

      if(create_type==CREATE_HTML)
            printf("<map name='statusmap'>\n");

      draw_hosts();

      if(create_type==CREATE_HTML)
            printf("</map>\n");

      write_graphics();
      cleanup_graphics();


      /* write the URL location for the image we just generated - the web browser will come and get it... */
      if(create_type==CREATE_HTML){
            printf("<P><DIV ALIGN=center>\n");
            printf("<img src='%s?host=%s&createimage",STATUSMAP_CGI,url_encode(host_name));
            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":"");
            print_layer_url(TRUE);
            printf("' width=%d height=%d border=0 name='statusimage' useMap='#statusmap'>\n",(int)(canvas_width*scaling_factor),(int)(canvas_height*scaling_factor));
            printf("</DIV></P>\n");
              }
      
      return;
        }



/******************************************************************/
/********************* CALCULATION FUNCTIONS **********************/
/******************************************************************/

/* calculates host drawing coordinates */
void calculate_host_coords(void){
      hostextinfo *temp_hostextinfo;
      host *this_host;
      host *temp_host;
      int child_hosts=0;
      int parent_hosts=0;
      int max_layer_width=1;
      int current_child_host=0;
      int current_parent_host=0;
      int center_x=0;
      int offset_x=DEFAULT_NODE_WIDTH/2;
      int offset_y=DEFAULT_NODE_WIDTH/2;
      int current_layer=0;
      int layer_members=0;
      int current_layer_member=0;
      int max_drawing_width=0;
  

      /******************************/
      /***** MANUAL LAYOUT MODE *****/
      /******************************/

      /* user-supplied coords */
      if(layout_method==LAYOUT_USER_SUPPLIED){

            /* see which hosts we should draw and calculate drawing coords */
            for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){
                  
                  if(temp_hostextinfo->have_2d_coords==TRUE)
                        temp_hostextinfo->should_be_drawn=TRUE;
                  else
                        temp_hostextinfo->should_be_drawn=FALSE;
                    }

            return;
              }


      /*****************************/
      /***** AUTO-LAYOUT MODES *****/
      /*****************************/

      /* add empty extended host info entries for all hosts that don't have any */
      for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){

            /* find the corresponding hostextinfo definition */
            temp_hostextinfo=find_hostextinfo(temp_host->name);

            /* none was found, so add a blank one */
            if(temp_hostextinfo==NULL)
                  add_extended_host_info(temp_host->name,NULL,NULL,NULL,NULL,NULL,0,0,0.0,0.0,0.0,0,0);
              }


      /***** DEPTH LAYER MODE *****/
      if(layout_method==LAYOUT_SUBLAYERS){

            /* find the "main" host we're displaying */
            if(show_all_hosts==TRUE)
                  this_host=NULL;
            else
                  this_host=find_host(host_name,NULL);

            /* find total number of immediate parents/children for this host */
            child_hosts=number_of_immediate_child_hosts(this_host);
            parent_hosts=number_of_immediate_parent_hosts(this_host);

            if(child_hosts==0 && parent_hosts==0)
                  max_layer_width=1;
            else
                  max_layer_width=(child_hosts>parent_hosts)?child_hosts:parent_hosts;

            /* calculate center x coord */
            center_x=(((DEFAULT_NODE_WIDTH*max_layer_width)+(DEFAULT_NODE_HSPACING*(max_layer_width-1)))/2)+offset_x;

            /* coords for Nagios icon if necessary */
            if(this_host==NULL || this_host->parent_hosts==NULL){
                  nagios_icon_x=center_x;
                  nagios_icon_y=offset_y;
                  draw_nagios_icon=TRUE;
                    }

            /* do we need to draw a link to parent(s)? */
            if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE){
                  draw_parent_links=TRUE;
                  offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
                    }

            /* see which hosts we should draw and calculate drawing coords */
            for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){

                  /* find the host that matches this entry */
                  temp_host=find_host(temp_hostextinfo->host_name,NULL);

                  if(temp_host==NULL)
                        continue;
                  
                  /* this is an immediate parent of the "main" host we're drawing */
                  else if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){
                        temp_hostextinfo->should_be_drawn=TRUE;
                        temp_hostextinfo->have_2d_coords=TRUE;
                        temp_hostextinfo->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);
                        temp_hostextinfo->y_2d=offset_y;
                        current_parent_host++;
                          }
                  
                  /* this is the "main" host we're drawing */
                  else if(this_host==temp_host){
                        temp_hostextinfo->should_be_drawn=TRUE;
                        temp_hostextinfo->have_2d_coords=TRUE;
                        temp_hostextinfo->x_2d=center_x;
                        temp_hostextinfo->y_2d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y;
                          }

                  /* this is an immediate child of the "main" host we're drawing */
                  else if(is_host_immediate_child_of_host(this_host,temp_host)==TRUE){
                        temp_hostextinfo->should_be_drawn=TRUE;
                        temp_hostextinfo->have_2d_coords=TRUE;
                        temp_hostextinfo->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);
                        if(this_host==NULL)
                              temp_hostextinfo->y_2d=(DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)+offset_y;
                        else
                              temp_hostextinfo->y_2d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*2)+offset_y;
                        current_child_host++;
                        if(number_of_immediate_child_hosts(temp_host)>0){
                              bottom_margin=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
                              draw_child_links=TRUE;
                                }
                          }

                  /* else do not draw this host */
                  else{
                        temp_hostextinfo->should_be_drawn=FALSE;
                        temp_hostextinfo->have_2d_coords=FALSE;
                          }
                    }
              }



      /***** COLLAPSED TREE MODE *****/
      else if(layout_method==LAYOUT_COLLAPSED_TREE){

            /* find the "main" host we're displaying  - DO NOT USE THIS (THIS IS THE OLD METHOD) */
            /*
            if(show_all_hosts==TRUE)
                  this_host=NULL;
            else
                  this_host=find_host(host_name,NULL);
            */

            /* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
            this_host=NULL;

            /* find total number of immediate parents for this host */
            parent_hosts=number_of_immediate_parent_hosts(this_host);

            /* find the max layer width we have... */
            max_layer_width=max_child_host_layer_members(this_host);
            if(parent_hosts>max_layer_width)
                  max_layer_width=parent_hosts;

            /* calculate center x coord */
            center_x=(((DEFAULT_NODE_WIDTH*max_layer_width)+(DEFAULT_NODE_HSPACING*(max_layer_width-1)))/2)+offset_x;

            /* coords for Nagios icon if necessary */
            if(this_host==NULL || this_host->parent_hosts==NULL){
                  nagios_icon_x=center_x;
                  nagios_icon_y=offset_y;
                  draw_nagios_icon=TRUE;
                    }

            /* do we need to draw a link to parent(s)? */
            if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE){
                  draw_parent_links=TRUE;
                  offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
                    }

            /* see which hosts we should draw and calculate drawing coords */
            for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){

                  /* find the host that matches this entry */
                  temp_host=find_host(temp_hostextinfo->host_name,NULL);

                  if(temp_host==NULL)
                        continue;
                  
                  /* this is an immediate parent of the "main" host we're drawing */
                  else if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){
                        temp_hostextinfo->should_be_drawn=TRUE;
                        temp_hostextinfo->have_2d_coords=TRUE;
                        temp_hostextinfo->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);
                        temp_hostextinfo->y_2d=offset_y;
                        current_parent_host++;
                          }
                  
                  /* this is the "main" host we're drawing */
                  else if(this_host==temp_host){
                        temp_hostextinfo->should_be_drawn=TRUE;
                        temp_hostextinfo->have_2d_coords=TRUE;
                        temp_hostextinfo->x_2d=center_x;
                        temp_hostextinfo->y_2d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y;
                          }

                  /* else do not draw this host (we might if its a child - see below, but assume no for now) */
                  else{
                        temp_hostextinfo->should_be_drawn=FALSE;
                        temp_hostextinfo->have_2d_coords=FALSE;
                          }
                    }


            /* TODO: REORDER CHILD LAYER MEMBERS SO THAT WE MINIMIZE LINK CROSSOVERS FROM PARENT HOSTS */

            /* draw hosts in child "layers" */
            for(current_layer=1;;current_layer++){
                  
                  /* how many members in this layer? */
                  layer_members=number_of_host_layer_members(this_host,current_layer);

                  if(layer_members==0)
                        break;

                  current_layer_member=0;

                  /* see which hosts are members of this layer and calculate drawing coords */
                  for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){

                        /* find the host that matches this entry */
                        temp_host=find_host(temp_hostextinfo->host_name,NULL);

                        if(temp_host==NULL)
                              continue;

                        /* is this host a member of the current child layer? */
                        if(host_child_depth_separation(this_host,temp_host)==current_layer){
                              temp_hostextinfo->should_be_drawn=TRUE;
                              temp_hostextinfo->have_2d_coords=TRUE;
                              temp_hostextinfo->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);
                              if(this_host==NULL)
                                    temp_hostextinfo->y_2d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*current_layer)+offset_y;
                              else
                                    temp_hostextinfo->y_2d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*(current_layer+1))+offset_y;
                              current_layer_member++;
                                }
                          }
                    }

              }


      /***** "BALANCED" TREE MODE *****/
      else if(layout_method==LAYOUT_BALANCED_TREE){

            /* find the "main" host we're displaying  - DO NOT USE THIS (THIS IS THE OLD METHOD) */
            /*
            if(show_all_hosts==TRUE)
                  this_host=NULL;
            else
                  this_host=find_host(host_name,NULL);
            */
            
            /* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */
            this_host=NULL;

            /* find total number of immediate parents for this host */
            parent_hosts=number_of_immediate_parent_hosts(this_host);

            /* find the max drawing width we have... */
            max_drawing_width=max_child_host_drawing_width(this_host);
            if(parent_hosts>max_drawing_width)
                  max_drawing_width=parent_hosts;

            /* calculate center x coord */
            center_x=(((DEFAULT_NODE_WIDTH*max_drawing_width)+(DEFAULT_NODE_HSPACING*(max_drawing_width-1)))/2)+offset_x;

            /* coords for Nagios icon if necessary */
            if(this_host==NULL || this_host->parent_hosts==NULL){
                  nagios_icon_x=center_x;
                  nagios_icon_y=offset_y;
                  draw_nagios_icon=TRUE;
                    }

            /* do we need to draw a link to parent(s)? */
            if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE){
                  draw_parent_links=TRUE;
                  offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
                    }

            /* see which hosts we should draw and calculate drawing coords */
            for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){

                  /* find the host that matches this entry */
                  temp_host=find_host(temp_hostextinfo->host_name,NULL);

                  if(temp_host==NULL)
                        continue;
                  
                  /* this is an immediate parent of the "main" host we're drawing */
                  else if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){
                        temp_hostextinfo->should_be_drawn=TRUE;
                        temp_hostextinfo->have_2d_coords=TRUE;
                        temp_hostextinfo->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);
                        temp_hostextinfo->y_2d=offset_y;
                        current_parent_host++;
                          }
                  
                  /* this is the "main" host we're drawing */
                  else if(this_host==temp_host){
                        temp_hostextinfo->should_be_drawn=TRUE;
                        temp_hostextinfo->have_2d_coords=TRUE;
                        temp_hostextinfo->x_2d=center_x;
                        temp_hostextinfo->y_2d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y;
                          }

                  /* else do not draw this host (we might if its a child - see below, but assume no for now) */
                  else{
                        temp_hostextinfo->should_be_drawn=FALSE;
                        temp_hostextinfo->have_2d_coords=FALSE;
                          }
                    }

            /* draw all children hosts */
            calculate_balanced_tree_coords(this_host,center_x,DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y);

              }


      /***** CIRCULAR LAYOUT MODE *****/
      else if(layout_method==LAYOUT_CIRCULAR || layout_method==LAYOUT_CIRCULAR_MARKUP || layout_method==LAYOUT_CIRCULAR_BALLOON){

            /* draw process icon */
            nagios_icon_x=0;
            nagios_icon_y=0;
            draw_nagios_icon=TRUE;

            /* calculate coordinates for all hosts */
            calculate_circular_coords();
              }

      return;
        }



/* calculates max possible image dimensions */
void calculate_total_image_bounds(void){
      hostextinfo *temp_hostextinfo;

      total_image_width=0;
      total_image_height=0;

      /* check all extended host information entries... */
      for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){

            /* only check entries that have 2-D coords specified */
            if(temp_hostextinfo->have_2d_coords==FALSE)
                  continue;

            /* skip hosts we shouldn't be drawing */
            if(temp_hostextinfo->should_be_drawn==FALSE)
                  continue;
            
            if(temp_hostextinfo->x_2d>total_image_width)
                  total_image_width=temp_hostextinfo->x_2d;
            if(temp_hostextinfo->y_2d>total_image_height)
                  total_image_height=temp_hostextinfo->y_2d;

            coordinates_were_specified=TRUE;
              }

      /* add some space for icon size and overlapping text... */
      if(coordinates_were_specified==TRUE){

            total_image_width+=(DEFAULT_NODE_WIDTH*2);
            total_image_height+=DEFAULT_NODE_HEIGHT;

            /* add space for bottom margin if necessary */
            total_image_height+=bottom_margin;
              }

      /* image size should be at least as large as dimensions of background image */
      if(total_image_width<background_image_width)
            total_image_width=background_image_width;
      if(total_image_height<background_image_height)
            total_image_height=background_image_height;

      /* we didn't find any hosts that had user-supplied coordinates, so we're going to display a warning */
      if(coordinates_were_specified==FALSE){
            coordinates_were_specified=FALSE;
            total_image_width=COORDS_WARNING_WIDTH;
            total_image_height=COORDS_WARNING_HEIGHT;
              }

      return;
        }


/* calculates canvas coordinates/dimensions */
void calculate_canvas_bounds(void){

      if(user_supplied_canvas==FALSE && strcmp(host_name,"all"))
            calculate_canvas_bounds_from_host(host_name);

      /* calculate canvas origin (based on total image bounds) */
      if(canvas_x<=0 || canvas_width>total_image_width)
            canvas_x=0;
      if(canvas_y<=0 || canvas_height>total_image_height)
            canvas_y=0;

      /* calculate canvas dimensions */
      if(canvas_height<=0)
            canvas_height=(total_image_height-canvas_y);
      if(canvas_width<=0)
            canvas_width=(total_image_width-canvas_x);

      if(canvas_x+canvas_width>total_image_width)
            canvas_width=total_image_width-canvas_x;
      if(canvas_y+canvas_height>total_image_height)
            canvas_height=total_image_height-canvas_y;

      return;
        }


/* calculates canvas coordinates/dimensions around a particular host */
void calculate_canvas_bounds_from_host(char *host_name){
      hostextinfo *temp_hostextinfo;
      int zoom_width;
      int zoom_height;

      /* find the extended host info */
      temp_hostextinfo=find_hostextinfo(host_name);
      if(temp_hostextinfo==NULL)
            return;

      /* make sure we have 2-D coords */
      if(temp_hostextinfo->have_2d_coords==FALSE)
            return;
      
      if(max_image_width>0 && proximity_width>max_image_width)
            zoom_width=max_image_width;
      else
            zoom_width=proximity_width;
      if(max_image_height>0 && proximity_height>max_image_height)
            zoom_height=max_image_height;
      else
            zoom_height=proximity_height;

      canvas_width=zoom_width;
      if(canvas_width>=total_image_width)
            canvas_x=0;
      else
            canvas_x=(temp_hostextinfo->x_2d-(zoom_width/2));

      canvas_height=zoom_height;
      if(canvas_height>=total_image_height)
            canvas_y=0;
      else
            canvas_y=(temp_hostextinfo->y_2d-(zoom_height/2));


      return;
        }


/* calculates scaling factor used in image generation */
void calculate_scaling_factor(void){
      double x_scaling=1.0;
      double y_scaling=1.0;

      /* calculate horizontal scaling factor */
      if(max_image_width<=0 || canvas_width<=max_image_width)
            x_scaling=1.0;
      else
            x_scaling=(double)((double)max_image_width/(double)canvas_width);

      /* calculate vertical scaling factor */
      if(max_image_height<=0 || canvas_height<=max_image_height)
            y_scaling=1.0;
      else
            y_scaling=(double)((double)max_image_height/(double)canvas_height);

      /* calculate general scaling factor to use */
      if(x_scaling<y_scaling)
            scaling_factor=x_scaling;
      else
            scaling_factor=y_scaling;

      /*** USER-SUPPLIED SCALING FACTOR ***/
      if(user_supplied_scaling==TRUE)
            scaling_factor=user_scaling_factor;

      return;
        }


/* finds hosts that can be drawn in the canvas area */
void find_eligible_hosts(void){
      hostextinfo *temp_hostextinfo;
      int total_eligible_hosts=0;
      host *temp_host;

      /* check all extended host information entries... */
      for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){

            /* find the host */
            temp_host=find_host(temp_hostextinfo->host_name,NULL);

            if(temp_host==NULL)
                  temp_hostextinfo->should_be_drawn=FALSE;

            /* only include hosts that have 2-D coords supplied */
            else if(temp_hostextinfo->have_2d_coords==FALSE)
                  temp_hostextinfo->should_be_drawn=FALSE;

            /* make sure coords are all positive */
            else if(temp_hostextinfo->x_2d<0 || temp_hostextinfo->y_2d<0)
                  temp_hostextinfo->should_be_drawn=FALSE;

            /* make sure x coordinates fall within canvas bounds */
            else if(temp_hostextinfo->x_2d<(canvas_x-DEFAULT_NODE_WIDTH) || temp_hostextinfo->x_2d>(canvas_x+canvas_width))
                  temp_hostextinfo->should_be_drawn=FALSE;

            /* make sure y coordinates fall within canvas bounds */
            else if(temp_hostextinfo->y_2d<(canvas_y-DEFAULT_NODE_HEIGHT) || temp_hostextinfo->y_2d>(canvas_y+canvas_height))
                  temp_hostextinfo->should_be_drawn=FALSE;

            /* see if the user is authorized to view the host */
            else if(is_authorized_for_host(temp_host,&current_authdata)==FALSE)
                  temp_hostextinfo->should_be_drawn=FALSE;

            /* all checks passed, so we can draw the host! */
            else{
                  temp_hostextinfo->should_be_drawn=TRUE;
                  total_eligible_hosts++;
                    }
              }

      return;
        }



/******************************************************************/
/*********************** DRAWING FUNCTIONS ************************/
/******************************************************************/


/* loads background image from file */
void load_background_image(void){
      char temp_buffer[MAX_INPUT_BUFFER];

      /* bail out if we shouldn't be drawing a background image */
      if(layout_method!=LAYOUT_USER_SUPPLIED || statusmap_background_image==NULL)
            return;

      snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s%s",physical_images_path,statusmap_background_image);
      temp_buffer[sizeof(temp_buffer)-1]='\x0';

      /* read the background image into memory */
      background_image=load_image_from_file(temp_buffer);

      /* grab background image dimensions for calculating total image width later */
      if(background_image!=NULL){
            background_image_width=background_image->sx;
            background_image_height=background_image->sy;
              }

      /* if we are just creating the html, we don't need the image anymore */
      if(create_type==CREATE_HTML && background_image!=NULL)
            gdImageDestroy(background_image);

      return;
      }


/* draws background image on drawing canvas */
void draw_background_image(void){

      /* bail out if we shouldn't be drawing a background image */
      if(create_type==CREATE_HTML || layout_method!=LAYOUT_USER_SUPPLIED || statusmap_background_image==NULL)
            return;

      /* bail out if we don't have an image */
      if(background_image==NULL)
            return;

      /* copy the background image to the canvas */
      gdImageCopy(map_image,background_image,0,0,canvas_x,canvas_y,canvas_width,canvas_height);

      /* free memory for background image, as we don't need it anymore */
      gdImageDestroy(background_image);

      return;
        }



/* draws background "extras" */
void draw_background_extras(void){

      /* bail out if we shouldn't be here */
      if(create_type==CREATE_HTML)
            return;

      /* circular layout stuff... */
      if(layout_method==LAYOUT_CIRCULAR_MARKUP){

            /* draw colored sections... */
            draw_circular_markup();
              }

      return;
        }


/* draws host links */
void draw_host_links(void){
      hostextinfo *temp_hostextinfo;
      hostextinfo *temp_parent_hostextinfo;
      host *this_host;
      host *main_host;
      host *parent_host;
      hostsmember *temp_hostsmember;
      int status_color=color_black;
      hoststatus *this_hoststatus;
      hoststatus *parent_hoststatus;
      int child_in_layer_list=FALSE;
      int parent_in_layer_list=FALSE;
      int dotted_line=FALSE;
      int x=0;
      int y=0;

      if(create_type==CREATE_HTML)
            return;

      if(use_links==FALSE)
            return;

      /* find the "main" host we're drawing */
      main_host=find_host(host_name,NULL);
      if(show_all_hosts==TRUE)
            main_host=NULL;

      /* check all extended host information entries... */
      for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){

            /* find the config entry for this host */
            this_host=find_host(temp_hostextinfo->host_name,NULL);
            if(this_host==NULL)
                  continue;

            /* only draw link if user is authorized to view this host */
            if(is_authorized_for_host(this_host,&current_authdata)==FALSE)
                  continue;

            /* this is a "root" host, so draw link to Nagios process icon if using auto-layout mode */
            if(this_host->parent_hosts==NULL && layout_method!=LAYOUT_USER_SUPPLIED && draw_nagios_icon==TRUE){

                  x=temp_hostextinfo->x_2d+(DEFAULT_NODE_WIDTH/2)-canvas_x;
                  y=temp_hostextinfo->y_2d+(DEFAULT_NODE_WIDTH/2)-canvas_y;

                  draw_line(x,y,nagios_icon_x+(DEFAULT_NODE_WIDTH/2)-canvas_x,nagios_icon_y+(DEFAULT_NODE_WIDTH/2)-canvas_y,color_black);
                    }

            /* this is a child of the main host we're drawing in auto-layout mode... */
            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){
                  /* determine color to use when drawing links to children  */
                  this_hoststatus=find_hoststatus(temp_hostextinfo->host_name);
                  if(this_hoststatus!=NULL){
                        if(this_hoststatus->status==HOST_DOWN || this_hoststatus->status==HOST_UNREACHABLE)
                              status_color=color_red;
                        else
                              status_color=color_black;
                            }
                  else
                        status_color=color_black;

                  x=temp_hostextinfo->x_2d+(DEFAULT_NODE_WIDTH/2)-canvas_x;
                  y=(temp_hostextinfo->y_2d+(DEFAULT_NODE_WIDTH)/2)-canvas_y;

                  draw_dashed_line(x,y,x,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING,status_color);

                  /* draw arrow tips */
                  draw_line(x,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING,x-5,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING-5,color_black);
                  draw_line(x,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING,x+5,y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING-5,color_black);
                    }

            /* this is a parent of the main host we're drawing in auto-layout mode... */
            if(layout_method!=LAYOUT_USER_SUPPLIED && draw_parent_links==TRUE && is_host_immediate_child_of_host(this_host,main_host)==TRUE){

                  x=temp_hostextinfo->x_2d+(DEFAULT_NODE_WIDTH/2)-canvas_x;
                  y=temp_hostextinfo->y_2d+(DEFAULT_NODE_WIDTH/2)-canvas_y;

                  draw_dashed_line(x,y,x,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING,color_black);

                  /* draw arrow tips */
                  draw_line(x,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING,x-5,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING+5,color_black);
                  draw_line(x,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING,x+5,y-DEFAULT_NODE_HEIGHT-DEFAULT_NODE_VSPACING+5,color_black);
                    }

            /* draw links to all parent hosts */
            for(temp_hostsmember=this_host->parent_hosts;temp_hostsmember!=NULL;temp_hostsmember=temp_hostsmember->next){

                  /* find extended info entry for this parent host */
                  temp_parent_hostextinfo=find_hostextinfo(temp_hostsmember->host_name);
                  if(temp_parent_hostextinfo==NULL)
                        continue;

                  /* don't draw the link if we don't have the coords */
                  if(temp_parent_hostextinfo->have_2d_coords==FALSE || temp_hostextinfo->have_2d_coords==FALSE)
                        continue;

                  /* find the parent host config entry */
                  parent_host=find_host(temp_parent_hostextinfo->host_name,NULL);
                  if(parent_host==NULL)
                        continue;

                  /* only draw link if user is authorized for this parent host */
                  if(is_authorized_for_host(parent_host,&current_authdata)==FALSE)
                        continue;

                  /* are the hosts in the layer list? */
                  child_in_layer_list=is_host_in_layer_list(this_host);
                  parent_in_layer_list=is_host_in_layer_list(parent_host);

                  /* use dotted or solid line? */
                  /* either the child or parent should not be drawn, so use a dotted line */
                  if((child_in_layer_list==TRUE && parent_in_layer_list==FALSE) || (child_in_layer_list==FALSE && parent_in_layer_list==TRUE))
                        dotted_line=TRUE;
                  /* both hosts should not be drawn, so use a dotted line */
                  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))
                        dotted_line=TRUE;
                  /* both hosts should be drawn, so use a solid line */
                  else
                        dotted_line=FALSE;

                  /* determine color to use when drawing links to parent host */
                  parent_hoststatus=find_hoststatus(temp_parent_hostextinfo->host_name);
                  if(parent_hoststatus!=NULL){
                        if(parent_hoststatus->status==HOST_DOWN || parent_hoststatus->status==HOST_UNREACHABLE)
                              status_color=color_red;
                        else
                              status_color=color_black;
                            }
                  else
                        status_color=color_black;

                  /* draw the link */
                  if(dotted_line==TRUE)
                        draw_dotted_line((temp_hostextinfo->x_2d+(DEFAULT_NODE_WIDTH/2))-canvas_x,(temp_hostextinfo->y_2d+(DEFAULT_NODE_WIDTH)/2)-canvas_y,(temp_parent_hostextinfo->x_2d+(DEFAULT_NODE_WIDTH/2))-canvas_x,(temp_parent_hostextinfo->y_2d+(DEFAULT_NODE_WIDTH/2))-canvas_y,status_color);
                  else
                        draw_line((temp_hostextinfo->x_2d+(DEFAULT_NODE_WIDTH/2))-canvas_x,(temp_hostextinfo->y_2d+(DEFAULT_NODE_WIDTH)/2)-canvas_y,(temp_parent_hostextinfo->x_2d+(DEFAULT_NODE_WIDTH/2))-canvas_x,(temp_parent_hostextinfo->y_2d+(DEFAULT_NODE_WIDTH/2))-canvas_y,status_color);
                    }

              }

      return;
        }



/* draws hosts */
void draw_hosts(void){
      hostextinfo *temp_hostextinfo;
      host *temp_host;
      int x1, x2;
      int y1, y2;
      int has_image=FALSE;
      char image_input_file[MAX_INPUT_BUFFER];
      int current_radius=0;
      int status_color=color_black;
      hoststatus *temp_hoststatus;
      int in_layer_list=FALSE;
      int average_host_services;
      int host_services;
      double host_services_ratio;
      int outer_radius;
      int inner_radius;
      int time_color=0;
      time_t current_time;
      int translated_x;
      int translated_y;

      
      /* user didn't supply any coordinates for hosts, so display a warning */
      if(coordinates_were_specified==FALSE){

            if(create_type==CREATE_IMAGE){
                  draw_text("You have not supplied any host drawing coordinates, so you cannot use this layout method.",(COORDS_WARNING_WIDTH/2),30,color_black);
                  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);
                    }

            return;
              }

      /* draw Nagios process icon if using auto-layout mode */
      if(layout_method!=LAYOUT_USER_SUPPLIED && draw_nagios_icon==TRUE){

            /* get coords of bounding box */
            x1=nagios_icon_x-canvas_x;
            x2=x1+DEFAULT_NODE_WIDTH;
            y1=nagios_icon_y-canvas_y;
            y2=y1+DEFAULT_NODE_HEIGHT;

            /* get the name of the image file to open for the logo */
            snprintf(image_input_file,sizeof(image_input_file)-1,"%s%s",physical_logo_images_path,NAGIOS_GD2_ICON);
            image_input_file[sizeof(image_input_file)-1]='\x0';

            /* read in the image from file... */
            logo_image=load_image_from_file(image_input_file);

              /* copy the logo image to the canvas image... */
            if(logo_image!=NULL){
                  gdImageCopy(map_image,logo_image,x1,y1,0,0,logo_image->sx,logo_image->sy);
                  gdImageDestroy(logo_image);
                        }

            /* if we don't have an image, draw a bounding box */
            else{
                  draw_line(x1,y1,x1,y1+DEFAULT_NODE_WIDTH,color_black);
                  draw_line(x1,y1+DEFAULT_NODE_WIDTH,x2,y1+DEFAULT_NODE_WIDTH,color_black);
                  draw_line(x2,y1+DEFAULT_NODE_WIDTH,x2,y1,color_black);
                  draw_line(x2,y1,x1,y1,color_black);
                      }

            if(create_type==CREATE_IMAGE)
                  draw_text("Nagios Process",x1+(DEFAULT_NODE_WIDTH/2),y1+DEFAULT_NODE_HEIGHT,color_black);
              }

      /* calculate average services per host */
      average_host_services=4;

      /* draw all hosts... */
      for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){
            
            /* skip hosts that should not be drawn */
            if(temp_hostextinfo->should_be_drawn==FALSE)
                  continue;

            /* find the host */
            temp_host=find_host(temp_hostextinfo->host_name,NULL);

            /* is this host in the layer inclusion/exclusion list? */
            in_layer_list=is_host_in_layer_list(temp_host);
            if((in_layer_list==TRUE && exclude_layers==TRUE) || (in_layer_list==FALSE && exclude_layers==FALSE))
                  continue;

            /* get coords of host bounding box */
            x1=temp_hostextinfo->x_2d-canvas_x;
            x2=x1+DEFAULT_NODE_WIDTH;
            y1=temp_hostextinfo->y_2d-canvas_y;
            y2=y1+DEFAULT_NODE_HEIGHT;

            if(create_type==CREATE_IMAGE){


                  temp_hoststatus=find_hoststatus(temp_hostextinfo->host_name);
                  if(temp_hoststatus!=NULL){
                        if(temp_hoststatus->status==HOST_DOWN)
                              status_color=color_red;
                        else if(temp_hoststatus->status==HOST_UNREACHABLE)
                              status_color=color_red;
                        else if(temp_hoststatus->status==HOST_UP)
                              status_color=color_green;
                        else if(temp_hoststatus->status==HOST_PENDING)
                              status_color=color_grey;
                          }
                  else
                        status_color=color_black;


                  /* use balloons instead of icons... */
                  if(layout_method==LAYOUT_CIRCULAR_BALLOON){

                        /* get the number of services associated with the host */
                        host_services=number_of_host_services(temp_host);

                        if(average_host_services==0)
                              host_services_ratio=0.0;
                        else
                              host_services_ratio=(double)((double)host_services/(double)average_host_services);

                        /* calculate size of node */
                        if(host_services_ratio>=2.0)
                              outer_radius=DEFAULT_NODE_WIDTH;
                        else if(host_services_ratio>=1.5)
                              outer_radius=DEFAULT_NODE_WIDTH*0.8;
                        else if(host_services_ratio>=1.0)
                              outer_radius=DEFAULT_NODE_WIDTH*0.6;
                        else if(host_services_ratio>=0.5)
                              outer_radius=DEFAULT_NODE_WIDTH*0.4;
                        else
                              outer_radius=DEFAULT_NODE_WIDTH*0.2;

                        /* calculate width of border */
                        if(temp_hoststatus==NULL)
                              inner_radius=outer_radius;
                        else if((temp_hoststatus->status==HOST_DOWN || temp_hoststatus->status==HOST_UNREACHABLE) && temp_hoststatus->problem_has_been_acknowledged==FALSE)
                              inner_radius=outer_radius-3;
                        else
                              inner_radius=outer_radius;

                        /* fill node with color based on how long its been in this state... */
                        gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),outer_radius,outer_radius,0,360,color_blue);

                        /* determine fill color */
                        time(&current_time);
                        if(temp_hoststatus==NULL)
                              time_color=color_white;
                        else if(current_time-temp_hoststatus->last_state_change<=900)
                              time_color=color_orange;
                        else if(current_time-temp_hoststatus->last_state_change<=3600)
                              time_color=color_yellow;
                        else
                              time_color=color_white;

                        /* fill node with appropriate time color */
                        /* the fill function only works with coordinates that are in bounds of the actual image */
                        translated_x=x1+(DEFAULT_NODE_WIDTH/2);
                        translated_y=y1+(DEFAULT_NODE_WIDTH/2);
                        if(translated_x>0 && translated_y>0 && translated_x<canvas_width && translated_y<canvas_height)
                              gdImageFillToBorder(map_image,translated_x,translated_y,color_blue,time_color);

                        /* border of node should reflect current state */
                        for(current_radius=outer_radius;current_radius>=inner_radius;current_radius--)
                              gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),current_radius,current_radius,0,360,status_color);

                        /* draw circles around the selected host (if there is one) */
                        if(!strcmp(host_name,temp_hostextinfo->host_name) && use_highlights==TRUE){
                              for(current_radius=DEFAULT_NODE_WIDTH*2;current_radius>0;current_radius-=10)
                                    gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),current_radius,current_radius,0,360,status_color);
                                  }
                          }


                  /* normal method is to use icons for hosts... */
                  else{

                        /* draw a target around root hosts (hosts with no parents) */
                        if(temp_host!=NULL && use_highlights==TRUE){
                              if(temp_host->parent_hosts==NULL){
                                    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);
                                    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);
                                    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);
                                        }
                                  }

                        /* draw circles around the selected host (if there is one) */
                        if(!strcmp(host_name,temp_hostextinfo->host_name) && use_highlights==TRUE){
                              for(current_radius=DEFAULT_NODE_WIDTH*2;current_radius>0;current_radius-=10)
                                    gdImageArc(map_image,x1+(DEFAULT_NODE_WIDTH/2),y1+(DEFAULT_NODE_WIDTH/2),current_radius,current_radius,0,360,status_color);
                                  }


                        if(temp_hostextinfo->gd2_icon_image!=NULL)
                              has_image=TRUE;
                        else
                              has_image=FALSE;
                        
                        /* load the logo associated with this host */
                        if(has_image==TRUE){

                                /* get the name of the image file to open for the logo */
                              snprintf(image_input_file,sizeof(image_input_file)-1,"%s%s",physical_logo_images_path,temp_hostextinfo->gd2_icon_image);
                              image_input_file[sizeof(image_input_file)-1]='\x0';

                                /* read in the logo image from file... */
                              logo_image=load_image_from_file(image_input_file);

                                  /* copy the logo image to the canvas image... */
                              if(logo_image!=NULL){
                                    gdImageCopy(map_image,logo_image,x1,y1,0,0,logo_image->sx,logo_image->sy);
                                    gdImageDestroy(logo_image);
                                            }
                              else
                                    has_image=FALSE;
                                  }

                        /* 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 */
                        if(has_image==FALSE){

                              if(unknown_logo_image!=NULL)
                                    gdImageCopy(map_image,unknown_logo_image,x1,y1,0,0,unknown_logo_image->sx,unknown_logo_image->sy);

                              else{

                                    /* last ditch effort - draw a host bounding box */
                                    draw_line(x1,y1,x1,y1+DEFAULT_NODE_WIDTH,color_black);
                                    draw_line(x1,y1+DEFAULT_NODE_WIDTH,x2,y1+DEFAULT_NODE_WIDTH,color_black);
                                    draw_line(x2,y1+DEFAULT_NODE_WIDTH,x2,y1,color_black);
                                    draw_line(x2,y1,x1,y1,color_black);
                                        }
                                    }
                          }


                  /* draw host name, status, etc. */
                  draw_host_text(temp_hostextinfo->host_name,x1+(DEFAULT_NODE_WIDTH/2),y1+DEFAULT_NODE_HEIGHT);
                    }

            /* we're creating HTML image map... */
            else{
                  printf("<AREA shape='rect' ");

                  /* coordinates */
                  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));

                  /* URL */
                  if(!strcmp(host_name,temp_hostextinfo->host_name))
                        printf("href='%s?host=%s' ",STATUS_CGI,url_encode(temp_hostextinfo->host_name));
                  else{
                        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_hostextinfo->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":"");
                        if(user_supplied_scaling==TRUE)
                              printf("&scaling_factor=%2.1f",user_scaling_factor);
                        print_layer_url(TRUE);
                        printf("' ");
                          }

                  /* popup text */
                  if(display_popups==TRUE){

                        printf("onMouseOver='showPopup(\"");
                        write_host_popup_text(find_host(temp_hostextinfo->host_name,NULL));
                        printf("\",event)' onMouseOut='hidePopup()'");
                          }

                  printf(">\n");
                    }

              }

      return;
        }


/* draws text */
void draw_text(char *buffer,int x,int y,int text_color){
      int string_width=0;
      int string_height=0;

      /* write the string to the generated image... */
      string_height=gdFontSmall->h;
      string_width=gdFontSmall->w*strlen(buffer);
      if(layout_method!=LAYOUT_CIRCULAR_MARKUP)
            gdImageFilledRectangle(map_image,x-(string_width/2)-2,y-(2*string_height),x+(string_width/2)+2,y-string_height,color_white);
      gdImageString(map_image,gdFontSmall,x-(string_width/2),y-(2*string_height),(unsigned char *)buffer,text_color);

      return;
        }


/* draws host text */
void draw_host_text(char *name,int x,int y){
      hoststatus *temp_hoststatus;
      int status_color=color_black;
      char temp_buffer[MAX_INPUT_BUFFER];

      if(use_text==FALSE)
            return;

      strncpy(temp_buffer,name,sizeof(temp_buffer)-1);
      temp_buffer[sizeof(temp_buffer)-1]='\x0';

      /* write the host status string to the generated image... */
      draw_text(temp_buffer,x,y,color_black);

      /* find the status entry for this host */
      temp_hoststatus=find_hoststatus(name);

      /* get the status of the host (pending, up, down, or unreachable) */
      if(temp_hoststatus!=NULL){

            /* draw the status string */
            if(temp_hoststatus->status==HOST_DOWN){
                  strncpy(temp_buffer,"Down",sizeof(temp_buffer));
                  status_color=color_red;
                        }
            else if(temp_hoststatus->status==HOST_UNREACHABLE){
                  strncpy(temp_buffer,"Unreachable",sizeof(temp_buffer));
                  status_color=color_red;
                        }
            else if(temp_hoststatus->status==HOST_UP){
                  strncpy(temp_buffer,"Up",sizeof(temp_buffer));
                  status_color=color_green;
                        }
            else if(temp_hoststatus->status==HOST_PENDING){
                  strncpy(temp_buffer,"Pending",sizeof(temp_buffer));
                  status_color=color_grey;
                        }
            else{
                  strncpy(temp_buffer,"Unknown",sizeof(temp_buffer));
                  status_color=color_orange;
                      }

            temp_buffer[sizeof(temp_buffer)-1]='\x0';

            /* write the host status string to the generated imate... */
            draw_text(temp_buffer,x,y+gdFontSmall->h,status_color);
                }

      return;
        }


/* writes popup text for a specific host */
void write_host_popup_text(host *hst){
      hostextinfo *temp_hostextinfo;
      hoststatus *temp_status;
      hostsmember *temp_hostsmember;
      int service_totals;
      char date_time[48];
      time_t current_time;
      time_t t;
      char state_duration[48];
      int days;
      int hours;
      int minutes;
      int seconds;

      if(hst==NULL){
            printf("Host data not found");
            return;
              }

      /* find the status entry for this host */
      temp_status=find_hoststatus(hst->name);
      if(temp_status==NULL){
            printf("Host status information not found");
            return;
              }

      /* strip nasty stuff from plugin output */
      sanitize_plugin_output(temp_status->information);

      printf("<table border=0 cellpadding=0 cellspacing=5>");

      temp_hostextinfo=find_hostextinfo(hst->name);
      if(temp_hostextinfo!=NULL){
            printf("<tr><td><img src=%s%s border=0 width=40 height=40></td>",url_logo_images_path,(temp_hostextinfo->icon_image==NULL)?UNKNOWN_ICON_IMAGE:temp_hostextinfo->icon_image);
            printf("<td class=\\\"popupText\\\"><i>%s</i></td></tr>",(temp_hostextinfo->icon_image_alt==NULL)?"":html_encode(temp_hostextinfo->icon_image_alt));
              }

      printf("<tr><td class=\\\"popupText\\\">Name:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",html_encode(hst->name));
      printf("<tr><td class=\\\"popupText\\\">Alias:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",html_encode(hst->alias));
      printf("<tr><td class=\\\"popupText\\\">Address:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",html_encode(hst->address));
      printf("<tr><td class=\\\"popupText\\\">State:</td><td class=\\\"popupText\\\"><b>");

      /* get the status of the host (pending, up, down, or unreachable) */
      if(temp_status->status==HOST_DOWN){
            printf("<font color=red>Down");
            if(temp_status->problem_has_been_acknowledged==TRUE)
                  printf(" (Acknowledged)");
            printf("</font>");
              }

      else if(temp_status->status==HOST_UNREACHABLE){
            printf("<font color=red>Unreachable");
            if(temp_status->problem_has_been_acknowledged==TRUE)
                  printf(" (Acknowledged)");
            printf("</font>");
              }

      else if(temp_status->status==HOST_UP)
            printf("<font color=green>Up</font>");

      else if(temp_status->status==HOST_PENDING)
            printf("Pending");

      printf("</b></td></tr>");
      printf("<tr><td class=\\\"popupText\\\">Status Information:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",(temp_status->information==NULL)?"":temp_status->information);

      current_time=time(NULL);
      if(temp_status->last_state_change==(time_t)0)
            t=current_time-program_start;
      else
            t=current_time-temp_status->last_state_change;
      get_time_breakdown((unsigned long)t,&days,&hours,&minutes,&seconds);
      snprintf(state_duration,sizeof(state_duration)-1,"%2dd %2dh %2dm %2ds%s",days,hours,minutes,seconds,(temp_status->last_state_change==(time_t)0)?"+":"");
      state_duration[sizeof(state_duration)-1]='\x0';
      printf("<tr><td class=\\\"popupText\\\">State Duration:</td><td class=\\\"popupText\\\"><b>%s</b></td></tr>",state_duration);

      get_time_string(&temp_status->last_check,date_time,(int)sizeof(date_time),SHORT_DATE_TIME);
      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);
      get_time_string(&temp_status->last_state_change,date_time,(int)sizeof(date_time),SHORT_DATE_TIME);
      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);

      printf("<tr><td class=\\\"popupText\\\">Parent Host(s):</td><td class=\\\"popupText\\\"><b>");
      if(hst->parent_hosts==NULL)
            printf("None (This is a root host)");
      else{
            for(temp_hostsmember=hst->parent_hosts;temp_hostsmember!=NULL;temp_hostsmember=temp_hostsmember->next)
                  printf("%s%s",(temp_hostsmember==hst->parent_hosts)?"":", ",html_encode(temp_hostsmember->host_name));
              }
      printf("</b></td></tr>");

      printf("<tr><td class=\\\"popupText\\\">Immediate Child Hosts:</td><td class=\\\"popupText\\\"><b>");
      printf("%d",number_of_immediate_child_hosts(hst));
      printf("</b></td></tr>");

      printf("</table>");

      printf("<br><b><u>Services:</u></b><br>");

      service_totals=get_servicestatus_count(hst->name,SERVICE_OK)+get_servicestatus_count(hst->name,SERVICE_RECOVERY);
      if(service_totals>0)
            printf("- <font color=green>%d ok</font><br>",service_totals);
      service_totals=get_servicestatus_count(hst->name,SERVICE_CRITICAL)+get_servicestatus_count(hst->name,SERVICE_UNREACHABLE)+get_servicestatus_count(hst->name,SERVICE_HOST_DOWN);
      if(service_totals>0)
            printf("- <font color=red>%d critical</font><br>",service_totals);
      service_totals=get_servicestatus_count(hst->name,SERVICE_WARNING);
      if(service_totals>0)
            printf("- <font color=orange>%d warning</font><br>",service_totals);
      service_totals=get_servicestatus_count(hst->name,SERVICE_UNKNOWN);
      if(service_totals>0)
            printf("- <font color=orange>%d unknown</font><br>",service_totals);
      service_totals=get_servicestatus_count(hst->name,SERVICE_PENDING);
      if(service_totals>0)
            printf("- %d pending<br>",service_totals);

      return;
        }



/* draws a solid line */
void draw_line(int x1,int y1,int x2,int y2,int color){

      if(create_type==CREATE_HTML)
            return;

      gdImageLine(map_image,x1,y1,x2,y2,color);

      return;
      }


/* draws a dotted line */
void draw_dotted_line(int x1,int y1,int x2,int y2,int color){
      int styleDotted[12];

      styleDotted[0]=color;
      styleDotted[1]=gdTransparent;
      styleDotted[2]=gdTransparent;
      styleDotted[3]=gdTransparent;
      styleDotted[4]=gdTransparent;
      styleDotted[5]=gdTransparent;
      styleDotted[6]=color;
      styleDotted[7]=gdTransparent;
      styleDotted[8]=gdTransparent;
      styleDotted[9]=gdTransparent;
      styleDotted[10]=gdTransparent;
      styleDotted[11]=gdTransparent;

      /* sets current style to a dashed line */
      gdImageSetStyle(map_image,styleDotted,12);

      /* draws a line (dotted) */
      gdImageLine(map_image,x1,y1,x2,y2,gdStyled);

      return;
      }

/* draws a dashed line */
void draw_dashed_line(int x1,int y1,int x2,int y2,int color){
      int styleDashed[12];

      styleDashed[0]=color;
      styleDashed[1]=color;
      styleDashed[2]=color;
      styleDashed[3]=color;
      styleDashed[4]=gdTransparent;
      styleDashed[5]=gdTransparent;
      styleDashed[6]=color;
      styleDashed[7]=color;
      styleDashed[8]=color;
      styleDashed[9]=color;
      styleDashed[10]=gdTransparent;
      styleDashed[11]=gdTransparent;

      /* sets current style to a dashed line */
      gdImageSetStyle(map_image,styleDashed,12);

      /* draws a line (dashed) */
      gdImageLine(map_image,x1,y1,x2,y2,gdStyled);

      return;
      }



/******************************************************************/
/*********************** GRAPHICS FUNCTIONS ***********************/
/******************************************************************/

/* initialize graphics */
int initialize_graphics(void){
      char image_input_file[MAX_INPUT_BUFFER];

      if(create_type==CREATE_HTML)
            return ERROR;

      /* allocate buffer for storing image */
      map_image=gdImageCreate(canvas_width,canvas_height);
      if(map_image==NULL)
            return ERROR;

      /* allocate colors used for drawing */
      color_white=gdImageColorAllocate(map_image,255,255,255);
      color_black=gdImageColorAllocate(map_image,0,0,0);
      color_grey=gdImageColorAllocate(map_image,128,128,128);
      color_lightgrey=gdImageColorAllocate(map_image,210,210,210);
      color_red=gdImageColorAllocate(map_image,255,0,0);
      color_lightred=gdImageColorAllocate(map_image,215,175,175);
      color_green=gdImageColorAllocate(map_image,0,175,0);
      color_lightgreen=gdImageColorAllocate(map_image,210,255,215);
      color_blue=gdImageColorAllocate(map_image,0,0,255);
      color_yellow=gdImageColorAllocate(map_image,255,255,0);
      color_orange=gdImageColorAllocate(map_image,255,100,25);

      /* set transparency index */
      gdImageColorTransparent(map_image,color_white);

      /* make sure the graphic is interlaced */
      gdImageInterlace(map_image,1);

      /* get the path where we will be reading logo images from (GD2 format)... */
      snprintf(physical_logo_images_path,sizeof(physical_logo_images_path)-1,"%slogos/",physical_images_path);
      physical_logo_images_path[sizeof(physical_logo_images_path)-1]='\x0';

      /* load the unknown icon to use for hosts that don't have pretty images associated with them... */
      snprintf(image_input_file,sizeof(image_input_file)-1,"%s%s",physical_logo_images_path,UNKNOWN_GD2_ICON);
      image_input_file[sizeof(image_input_file)-1]='\x0';
      unknown_logo_image=load_image_from_file(image_input_file);

      return OK;
        }



/* loads a graphic image (GD2, JPG or PNG) from file into memory */
gdImagePtr load_image_from_file(char *filename){
      FILE *fp;
      gdImagePtr im=NULL;
      char *ext;

      /* make sure we were passed a file name */
      if(filename==NULL)
            return NULL;

      /* find the file extension */
      if((ext=rindex(filename,'.'))==NULL)
            return NULL;

      /* open the file for reading (binary mode) */
      fp=fopen(filename,"rb");
      if(fp==NULL)
            return NULL;

      /* attempt to read files in various formats */
      if(!strcasecmp(ext,".png"))
            im=gdImageCreateFromPng(fp);
      else if(!strcasecmp(ext,".jpg") || !strcasecmp(ext,".jpeg"))
            im=gdImageCreateFromJpeg(fp);
      else if(!strcasecmp(ext,".xbm"))
            im=gdImageCreateFromXbm(fp);
      else if(!strcasecmp(ext,".gd2"))
            im=gdImageCreateFromGd2(fp);
      else if(!strcasecmp(ext,".gd"))
            im=gdImageCreateFromGd(fp);

      /* fall back to GD2 image format */
      else
            im=gdImageCreateFromGd2(fp);

      /* close the file */
      fclose(fp);

      return im;
        }



/* draw graphics */
void write_graphics(void){
      FILE *image_output_file=NULL;

      if(create_type==CREATE_HTML)
            return;

      /* use STDOUT for writing the image data... */
      image_output_file=stdout;

      /* write the image out in PNG format */
      gdImagePng(map_image,image_output_file);

      /* or we could write the image out in JPG format... */
      /*gdImageJpeg(map_image,image_output_file,99);*/

      return;
        }


/* cleanup graphics resources */
void cleanup_graphics(void){

      if(create_type==CREATE_HTML)
            return;

      /* free memory allocated to image */
      gdImageDestroy(map_image);

      return;
        }




/******************************************************************/
/************************* MISC FUNCTIONS *************************/
/******************************************************************/


/* write JavaScript code an layer for popup window */
void write_popup_code(void){
      char *border_color="#000000";
      char *background_color="#ffffcc";
      int border=1;
      int padding=3;
      int x_offset=3;
      int y_offset=3;

      printf("<SCRIPT LANGUAGE='JavaScript'>\n");
      printf("<!--\n");
      printf("// JavaScript popup based on code originally found at http://www.helpmaster.com/htmlhelp/javascript/popjbpopup.htm\n");
      printf("function showPopup(text, eventObj){\n");
      printf("if(!document.all && document.getElementById)\n");
      printf("{ document.all=document.getElementsByTagName(\"*\")}\n");
      printf("ieLayer = 'document.all[\\'popup\\']';\n");
      printf("nnLayer = 'document.layers[\\'popup\\']';\n");
      printf("moLayer = 'document.getElementById(\\'popup\\')';\n");

      printf("if(!(document.all||document.layers||document.documentElement)) return;\n");

      printf("if(document.all) { document.popup=eval(ieLayer); }\n");
      printf("else {\n");
      printf("  if (document.documentElement) document.popup=eval(moLayer);\n");
      printf("  else document.popup=eval(nnLayer);\n");
      printf("}\n");

      printf("var table = \"\";\n");

      printf("if (document.all||document.documentElement){\n");
      printf("table += \"<table bgcolor='%s' border=%d cellpadding=%d cellspacing=0>\";\n",background_color,border,padding);
      printf("table += \"<tr><td>\";\n");
      printf("table += \"<table cellspacing=0 cellpadding=%d>\";\n",padding);
      printf("table += \"<tr><td bgcolor='%s' class='popupText'>\" + text + \"</td></tr>\";\n",background_color);
      printf("table += \"</table></td></tr></table>\"\n");
      printf("document.popup.innerHTML = table;\n");
      printf("document.popup.style.left = document.body.scrollLeft + %d;\n",x_offset);
      printf("document.popup.style.top = document.body.scrollTop + %d;\n",y_offset);
      /*
      printf("document.popup.style.left = (document.all ? eventObj.x : eventObj.layerX) + %d;\n",x_offset);
      printf("document.popup.style.top  = (document.all ? eventObj.y : eventObj.layerY) + %d;\n",y_offset);
      */
      printf("document.popup.style.visibility = \"visible\";\n");
      printf("} \n");
 

      printf("else{\n");
      printf("table += \"<table cellpadding=%d border=%d cellspacing=0 bordercolor='%s'>\";\n",padding,border,border_color);
      printf("table += \"<tr><td bgcolor='%s' class='popupText'>\" + text + \"</td></tr></table>\";\n",background_color);
      printf("document.popup.document.open();\n");
      printf("document.popup.document.write(table);\n");
      printf("document.popup.document.close();\n");

      /* set x coordinate */
      printf("document.popup.left = eventObj.layerX + %d;\n",x_offset);
      
      /* make sure we don't overlap the right side of the screen */
      printf("if(document.popup.left + document.popup.document.width + %d > window.innerWidth) document.popup.left = window.innerWidth - document.popup.document.width - %d - 16;\n",x_offset,x_offset);
            
      /* set y coordinate */
      printf("document.popup.top  = eventObj.layerY + %d;\n",y_offset);
      
      /* make sure we don't overlap the bottom edge of the screen */
      printf("if(document.popup.top + document.popup.document.height + %d > window.innerHeight) document.popup.top = window.innerHeight - document.popup.document.height - %d - 16;\n",y_offset,y_offset);
            
      /* make the popup visible */
      printf("document.popup.visibility = \"visible\";\n");
      printf("}\n");
      printf("}\n");

      printf("function hidePopup(){ \n");
      printf("if (!(document.all || document.layers || document.documentElement)) return;\n");
      printf("if (document.popup == null){ }\n");
      printf("else if (document.all||document.documentElement) document.popup.style.visibility = \"hidden\";\n");
      printf("else document.popup.visibility = \"hidden\";\n");
      printf("document.popup = null;\n");
      printf("}\n");
      printf("//-->\n");

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

      return;
        }



/* adds a layer to the list in memory */
int add_layer(char *group_name){
      layer *new_layer;

      if(group_name==NULL)
            return ERROR;

      /* allocate memory for a new layer */
      new_layer=(layer *)malloc(sizeof(layer));
      if(new_layer==NULL)
            return ERROR;

      new_layer->layer_name=(char *)malloc(strlen(group_name)+1);
      if(new_layer->layer_name==NULL){
            free(new_layer);
            return ERROR;
              }

      strcpy(new_layer->layer_name,group_name);

      /* add new layer to head of layer list */
      new_layer->next=layer_list;
      layer_list=new_layer;

      return OK;
        }



/* frees memory allocated to the layer list */
void free_layer_list(void){
      layer *this_layer;
      layer *next_layer;

      return;

      for(this_layer=layer_list;layer_list!=NULL;this_layer=next_layer){
            next_layer=this_layer->next;
            free(this_layer->layer_name);
            free(this_layer);
              }

      return;
        }


/* checks to see if a host is in the layer list */
int is_host_in_layer_list(host *hst){
      hostgroup *temp_hostgroup;
      layer *temp_layer;

      if(hst==NULL)
            return FALSE;

      /* check each layer... */
      for(temp_layer=layer_list;temp_layer!=NULL;temp_layer=temp_layer->next){

            /* find the hostgroup */
            temp_hostgroup=find_hostgroup(temp_layer->layer_name,NULL);
            if(temp_hostgroup==NULL)
                  continue;
            
            /* is the requested host a member of the hostgroup/layer? */
            if(is_host_member_of_hostgroup(temp_hostgroup,hst)==TRUE)
                  return TRUE;
              }

      return FALSE;
        }


/* print layer url info */
void print_layer_url(int get_method){
      layer *temp_layer;

      for(temp_layer=layer_list;temp_layer!=NULL;temp_layer=temp_layer->next){
            if(get_method==TRUE)
                  printf("&layer=%s",temp_layer->layer_name);
            else
                  printf("<input type='hidden' name='layer' value='%s'>\n",temp_layer->layer_name);
              }

      if(get_method==TRUE)
            printf("&layermode=%s",(exclude_layers==TRUE)?"exclude":"include");
      else
            printf("<input type='hidden' name='layermode' value='%s'>\n",(exclude_layers==TRUE)?"exclude":"include");

      return;
        }
      



/******************************************************************/
/************************ UTILITY FUNCTIONS ***********************/
/******************************************************************/

/* calculates how many "layers" separate parent and child - used by collapsed tree layout method */
int host_child_depth_separation(host *parent, host *child){
      int this_depth=0;
      int min_depth=0;
      int have_min_depth=FALSE;
      host *temp_host;

      if(child==NULL)
            return -1;

      if(parent==child)
            return 0;

      if(is_host_immediate_child_of_host(parent,child)==TRUE)
            return 1;

      for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){

            if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){

                  this_depth=host_child_depth_separation(temp_host,child);

                  if(this_depth>=0 && (have_min_depth==FALSE || (have_min_depth==TRUE && (this_depth<min_depth)))){
                        have_min_depth=TRUE;
                        min_depth=this_depth;
                          }
                    }
              }

      if(have_min_depth==FALSE)
            return -1;
      else
            return min_depth+1;
        }



/* calculates how many hosts reside on a specific "layer" - used by collapsed tree layout method */
int number_of_host_layer_members(host *parent, int layer){
      int current_layer;
      int layer_members=0;
      host *temp_host;

      for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
            
            current_layer=host_child_depth_separation(parent,temp_host);

            if(current_layer==layer)
                  layer_members++;
              }

      return layer_members;
        }



/* calculate max number of members on all "layers" beneath and including parent host - used by collapsed tree layout method */
int max_child_host_layer_members(host *parent){
      int current_layer;
      int max_members=1;
      int current_members=0;

      for(current_layer=1;;current_layer++){

            current_members=number_of_host_layer_members(parent,current_layer);

            if(current_members<=0)
                  break;

            if(current_members>max_members)
                  max_members=current_members;
              }

      return max_members;
        }



/* calculate max drawing width for host and children - used by balanced tree layout method */
int max_child_host_drawing_width(host *parent){
      host *temp_host;
      int child_width=0;

      for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
            
            if(is_host_immediate_child_of_host(parent,temp_host)==TRUE)
                  child_width+=max_child_host_drawing_width(temp_host);
              }

      /* no children, so set width to 1 for this host */
      if(child_width==0)
            return 1;

      else
            return child_width;
        }



/* calculates number of services associated with a particular service */
int number_of_host_services(host *hst){
      service *temp_service;
      int total_services=0;

      if(hst==NULL)
            return 0;

      /* check all the services */
      for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
            if(!strcmp(temp_service->host_name,hst->name))
                  total_services++;
              }

      return total_services;
        }
      


/******************************************************************/
/***************** COORDINATE CALCULATION FUNCTIONS ***************/
/******************************************************************/

/* calculates coords of a host's children - used by balanced tree layout method */
void calculate_balanced_tree_coords(host *parent, int x, int y){
      int parent_drawing_width;
      int start_drawing_x;
      int current_drawing_x;
      int this_drawing_width;
      host *temp_host;
      hostextinfo *temp_hostextinfo;

      /* calculate total drawing width of parent host */
      parent_drawing_width=max_child_host_drawing_width(parent);

      /* calculate starting x coord */
      start_drawing_x=x-(((DEFAULT_NODE_WIDTH*parent_drawing_width)+(DEFAULT_NODE_HSPACING*(parent_drawing_width-1)))/2);
      current_drawing_x=start_drawing_x;


      /* calculate coords for children */
      for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){

            temp_hostextinfo=find_hostextinfo(temp_host->name);
            if(temp_hostextinfo==NULL)
                  continue;

            if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){

                  /* get drawing width of child host */
                  this_drawing_width=max_child_host_drawing_width(temp_host);

                  temp_hostextinfo->x_2d=current_drawing_x+(((DEFAULT_NODE_WIDTH*this_drawing_width)+(DEFAULT_NODE_HSPACING*(this_drawing_width-1)))/2);
                  temp_hostextinfo->y_2d=y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING;
                  temp_hostextinfo->have_2d_coords=TRUE;
                  temp_hostextinfo->should_be_drawn=TRUE;
                  
                  current_drawing_x+=(this_drawing_width*DEFAULT_NODE_WIDTH)+((this_drawing_width-1)*DEFAULT_NODE_HSPACING)+DEFAULT_NODE_HSPACING;

                  /* recurse into child host ... */
                  calculate_balanced_tree_coords(temp_host,temp_hostextinfo->x_2d,temp_hostextinfo->y_2d);
                    }

              }

      return;
        }


/* calculate coords of all hosts in circular layout method */
void calculate_circular_coords(void){
      int min_x=0;
      int min_y=0;
      int have_min_x=FALSE;
      int have_min_y=FALSE;
      hostextinfo *temp_hostextinfo;

      /* calculate all host coords, starting with first layer */
      calculate_circular_layer_coords(NULL,0.0,360.0,1,CIRCULAR_DRAWING_RADIUS);

      /* adjust all calculated coords so none are negative in x or y axis... */

      /* calculate min x, y coords */
      for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){
            if(have_min_x==FALSE || temp_hostextinfo->x_2d<min_x){
                  have_min_x=TRUE;
                  min_x=temp_hostextinfo->x_2d;
                    }
            if(have_min_y==FALSE || temp_hostextinfo->y_2d<min_y){
                  have_min_y=TRUE;
                  min_y=temp_hostextinfo->y_2d;
                    }
              }
      
      /* offset all drawing coords by the min x,y coords we found */
      for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){
            if(min_x<0)
                  temp_hostextinfo->x_2d-=min_x;
            if(min_y<0)
                  temp_hostextinfo->y_2d-=min_y;
              }

      if(min_x<0)
            nagios_icon_x-=min_x;
      if(min_y<0)
            nagios_icon_y-=min_y;

      for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){
            temp_hostextinfo->x_2d+=(DEFAULT_NODE_WIDTH/2);
            temp_hostextinfo->y_2d+=(DEFAULT_NODE_HEIGHT/2);
              }
      nagios_icon_x+=(DEFAULT_NODE_WIDTH/2);
      nagios_icon_y+=(DEFAULT_NODE_HEIGHT/2);

      return;
        }
      

/* calculates coords of all hosts in a particular "layer" in circular layout method */
void calculate_circular_layer_coords(host *parent, double start_angle, double useable_angle, int layer, int radius){
      int parent_drawing_width=0;
      int this_drawing_width=0;
      int immediate_children=0;
      double current_drawing_angle=0.0;
      double this_drawing_angle=0.0;
      double available_angle=0.0;
      double clipped_available_angle=0.0;
      double average_child_angle=0.0;
      double x_coord=0.0;
      double y_coord=0.0;
      host *temp_host;
      hostextinfo *temp_hostextinfo;


      /* get the total number of immediate children to this host */
      immediate_children=number_of_immediate_child_hosts(parent);

      /* bail out if we're done */
      if(immediate_children==0)
            return;

      /* calculate total drawing "width" of parent host */
      parent_drawing_width=max_child_host_drawing_width(parent);

      /* calculate average angle given to each child host */
      average_child_angle=(double)(useable_angle/(double)immediate_children);

      /* calculate initial drawing angle */
      current_drawing_angle=start_angle;


      /* calculate coords for children */
      for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){

            temp_hostextinfo=find_hostextinfo(temp_host->name);
            if(temp_hostextinfo==NULL)
                  continue;

            if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){

                  /* get drawing width of child host */
                  this_drawing_width=max_child_host_drawing_width(temp_host);

                  /* calculate angle this host gets for drawing */
                  available_angle=useable_angle*((double)this_drawing_width/(double)parent_drawing_width);

                  /* clip available angle if necessary */
                  /* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */
                  clipped_available_angle=360.0/layer;
                  if(available_angle<clipped_available_angle)
                        clipped_available_angle=available_angle;

                  /* calculate the exact angle at which we should draw this child */
                  this_drawing_angle=current_drawing_angle+(available_angle/2.0);

                  /* compensate for angle overflow */
                  while(this_drawing_angle>=360.0)
                        this_drawing_angle-=360.0;
                  while(this_drawing_angle<0.0)
                        this_drawing_angle+=360.0;

                  /* calculate drawing coords of this host using good ol' geometry... */
                  x_coord=-(sin(-this_drawing_angle*(M_PI/180.0))*radius);
                  y_coord=-(sin((90+this_drawing_angle)*(M_PI/180.0))*radius);

                  temp_hostextinfo->x_2d=(int)x_coord;
                  temp_hostextinfo->y_2d=(int)y_coord;
                  temp_hostextinfo->have_2d_coords=TRUE;
                  temp_hostextinfo->should_be_drawn=TRUE;

                  /* recurse into child host ... */
                  calculate_circular_layer_coords(temp_host,current_drawing_angle+((available_angle-clipped_available_angle)/2),clipped_available_angle,layer+1,radius+CIRCULAR_DRAWING_RADIUS);

                  /* increment current drawing angle */
                  current_drawing_angle+=available_angle;
                    }
              }

      return;
        }



/* draws background "extras" for all hosts in circular markup layout */
void draw_circular_markup(void){

      /* calculate all host sections, starting with first layer */
      draw_circular_layer_markup(NULL,0.0,360.0,1,CIRCULAR_DRAWING_RADIUS);

      return;
        }


/* draws background "extras" for all hosts in a particular "layer" in circular markup layout */
void draw_circular_layer_markup(host *parent, double start_angle, double useable_angle, int layer, int radius){
      int parent_drawing_width=0;
      int this_drawing_width=0;
      int immediate_children=0;
      double current_drawing_angle=0.0;
      double available_angle=0.0;
      double clipped_available_angle=0.0;
      double average_child_angle=0.0;
      double x_coord[4]={0.0,0.0,0.0,0.0};
      double y_coord[4]={0.0,0.0,0.0,0.0};
      host *temp_host;
      hoststatus *temp_hoststatus;
      hostextinfo *temp_hostextinfo;
      int x_offset=0;
      int y_offset=0;
      int center_x=0;
      int center_y=0;
      int bgcolor=0;
      double arc_start_angle=0.0;
      double arc_end_angle=0.0;
      int translated_x=0;
      int translated_y=0;

      /* get the total number of immediate children to this host */
      immediate_children=number_of_immediate_child_hosts(parent);

      /* bail out if we're done */
      if(immediate_children==0)
            return;

      /* calculate total drawing "width" of parent host */
      parent_drawing_width=max_child_host_drawing_width(parent);

      /* calculate average angle given to each child host */
      average_child_angle=(double)(useable_angle/(double)immediate_children);

      /* calculate initial drawing angle */
      current_drawing_angle=start_angle;

      /* calculate coords for children */
      for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){

            temp_hostextinfo=find_hostextinfo(temp_host->name);
            if(temp_hostextinfo==NULL)
                  continue;

            if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){

                  /* get drawing width of child host */
                  this_drawing_width=max_child_host_drawing_width(temp_host);

                  /* calculate angle this host gets for drawing */
                  available_angle=useable_angle*((double)this_drawing_width/(double)parent_drawing_width);

                  /* clip available angle if necessary */
                  /* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */
                  clipped_available_angle=360.0/layer;
                  if(available_angle<clipped_available_angle)
                        clipped_available_angle=available_angle;

                  /* calculate drawing coords of "leftmost" divider using good ol' geometry... */
                  x_coord[0]=-(sin(-current_drawing_angle*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
                  y_coord[0]=-(sin((90+current_drawing_angle)*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
                  x_coord[1]=-(sin(-current_drawing_angle*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));
                  y_coord[1]=-(sin((90+current_drawing_angle)*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));

                  /* calculate drawing coords of "rightmost" divider using good ol' geometry... */
                  x_coord[2]=-(sin((-(current_drawing_angle+available_angle))*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
                  y_coord[2]=-(sin((90+current_drawing_angle+available_angle)*(M_PI/180.0))*(radius-(CIRCULAR_DRAWING_RADIUS/2)));
                  x_coord[3]=-(sin((-(current_drawing_angle+available_angle))*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));
                  y_coord[3]=-(sin((90+current_drawing_angle+available_angle)*(M_PI/180.0))*(radius+(CIRCULAR_DRAWING_RADIUS/2)));


                  x_offset=nagios_icon_x+(DEFAULT_NODE_WIDTH/2)-canvas_x;
                  y_offset=nagios_icon_y+(DEFAULT_NODE_HEIGHT/2)-canvas_y;

                  /* draw "slice" dividers */
                  if(immediate_children>1 || layer>1){

                        /* draw "leftmost" divider */
                        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);

                        /* draw "rightmost" divider */
                        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);
                          }

                  /* determine arc drawing angles */
                  arc_start_angle=current_drawing_angle-90.0;
                  while(arc_start_angle<0.0)
                        arc_start_angle+=360.0;
                  arc_end_angle=arc_start_angle+available_angle;

                  /* draw inner arc */
                  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);

                  /* draw outer arc */
                  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);


                  /* determine center of "slice" and fill with appropriate color */
                  center_x=-(sin(-(current_drawing_angle+(available_angle/2.0))*(M_PI/180.0))*(radius));
                  center_y=-(sin((90+current_drawing_angle+(available_angle/2.0))*(M_PI/180.0))*(radius));
                  translated_x=center_x+x_offset;
                  translated_y=center_y+y_offset;

                  /* determine background color */
                  temp_hoststatus=find_hoststatus(temp_host->name);
                  if(temp_hoststatus==NULL)
                        bgcolor=color_lightgrey;
                  else if(temp_hoststatus->status==HOST_DOWN || temp_hoststatus->status==HOST_UNREACHABLE)
                        bgcolor=color_lightred;
                  else
                        bgcolor=color_lightgreen;

                  /* fill slice with background color */
                  /* the fill function only works with coordinates that are in bounds of the actual image */
                  if(translated_x>0 && translated_y>0 && translated_x<canvas_width && translated_y<canvas_height)
                        gdImageFillToBorder(map_image,translated_x,translated_y,color_lightgrey,bgcolor);

                  /* recurse into child host ... */
                  draw_circular_layer_markup(temp_host,current_drawing_angle+((available_angle-clipped_available_angle)/2),clipped_available_angle,layer+1,radius+CIRCULAR_DRAWING_RADIUS);

                  /* increment current drawing angle */
                  current_drawing_angle+=available_angle;
                    }
              }

      return;
        }


Generated by  Doxygen 1.6.0   Back to index