/* Nessus
 * Copyright (C) 1998 Renaud Deraison
 *
 * 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 <includes.h>
#include <gtk/gtk.h>

#include "report.h"
#include "xstuff.h"
#include "families.h"
#include "xpm/black.xpm"
#include "xpm/red.xpm"
#include "report_file.h"
#include "globals.h"

#define HOLE_PRESENT 2
#define WARNING_PRESENT 1


static void save_report_ask(GtkWidget *, GtkWidget *);
static void save_report(GtkWidget *, GtkWidget *);
GtkWidget * report_arglist_to_tree(struct arglist *, GtkWidget *);
int is_there_any_hole(struct arglist *);

/*
 * Creation of the reporting window
 */
static void create_report_window(args)
  struct arglist * args;
{
  
  GtkWidget * window;
  GtkWidget * widget;
  GtkWidget * tree;
  GtkWidget * vbox;
  GtkWidget * hbox;
  GtkWidget * button;
  struct arglist * hosts;
  
  if(!args || !args->next)return;
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  
  gtk_signal_connect(GTK_OBJECT(window), "destroy", 
     	GTK_SIGNAL_FUNC(close_window), window);
  gtk_signal_connect(GTK_OBJECT(window), "delete_event", 
  	GTK_SIGNAL_FUNC(delete_event), window);
       
  gtk_window_set_title(GTK_WINDOW(window), "Nessus Report");
  gtk_container_border_width(GTK_CONTAINER(window), 10);
  
  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);
  
  widget = gtk_scrolled_window_new(NULL,NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), 
  		 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_widget_set_usize(widget, 300,400);
  gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 5);
  gtk_widget_show(widget);
  
  hosts = emalloc(sizeof(struct arglist));
  while(args && args->next)
  {
   struct arglist * ports = arg_get_value(args->value, "PORTS");
   struct arglist * new_ports = emalloc(sizeof(struct arglist));
   
 
   while(ports && ports->next)
   {
    struct arglist * reports = arg_get_value(ports->value, "REPORT");
    struct arglist * infos = arg_get_value(ports->value, "INFO");
    struct arglist * data = emalloc(sizeof(struct arglist));
    
     
    if(reports || infos)
    {
     if(reports)arg_add_value(data, "Security holes", ARG_ARGLIST, -1, reports);
     if(infos)arg_add_value(data, "Security warnings", ARG_ARGLIST, -1, infos);
    }
    arg_add_value(new_ports, ports->name, ARG_ARGLIST, -1, data);
    ports = ports->next;
   }
   arg_add_value(hosts, args->name, ARG_ARGLIST, -1, new_ports);
   args = args->next;
  }
  gtk_widget_realize(widget);
  
  tree = report_arglist_to_tree(hosts, widget);
  gtk_container_add(GTK_CONTAINER(widget), tree);
  gtk_widget_show(tree);
  
  hbox = gtk_hbox_new(TRUE,10);

  button = gtk_button_new_with_label("Save as...");
  gtk_signal_connect(GTK_OBJECT(button),"clicked",
                    GTK_SIGNAL_FUNC(save_report_ask),NULL); 
  gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
  gtk_widget_show(button);

  button = gtk_button_new_with_label("Quit");
  gtk_signal_connect(GTK_OBJECT(button),"clicked",
                    GTK_SIGNAL_FUNC(close_window),(void *) window); 
  gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
  gtk_widget_show(button);
  
  gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
  
  gtk_widget_show(hbox);
  gtk_widget_show(vbox);
  gtk_widget_show(window);
}


GtkWidget * report_arglist_to_tree(arglist, window)
  struct arglist * arglist;
  GtkWidget * window;
{
 GtkWidget * tree;
 GtkWidget * tree_item;
 int count = 0;
 int content;
 tree = gtk_tree_new();
 
 
 
 while(arglist && arglist->next)
 {
  GtkWidget * subtree;
  if((arglist->type != ARG_INT)&&(arglist->type != ARG_PTR))
  {
   int i = 0;
   count++;
   i = strcmp(arglist->name, "item");
   if(i)i = strcmp(arglist->name, "HOLE");
   if(i)i = strcmp(arglist->name, "INFO");
   
   if(!i)i = !(arglist->type == ARG_STRING);
   if(arglist->type == ARG_ARGLIST)content = is_there_any_hole(arglist->value);
   else content = 0;
   if(!content)
    tree_item = gtk_tree_item_new_with_label(i ? arglist->name:arglist->value);
   else
   {
   const char ** pixdata = NULL;
   GdkPixmap * pixmap;
   GtkStyle * style;
   GtkWidget * box;
   GtkWidget * pixmapwid = NULL;
   GtkWidget * label;
   GdkBitmap * mask;
   if(content>1)pixdata = reddot_pixmap;
   else pixdata = blackdot_pixmap;
   style = gtk_widget_get_style(window);
   pixmap = gdk_pixmap_create_from_xpm_d(window->window, &mask,
            &style->bg[GTK_STATE_NORMAL],(gchar **)pixdata); 
            
   pixmapwid = gtk_pixmap_new(pixmap, mask);
   
   box = gtk_hbox_new(FALSE, FALSE);
   tree_item = gtk_tree_item_new();
   gtk_container_add(GTK_CONTAINER(tree_item), box);
   gtk_widget_show(box);
   gtk_box_pack_start(GTK_BOX(box), pixmapwid, FALSE, FALSE, 0);
   gtk_widget_show(pixmapwid);
   label = gtk_label_new(arglist->name);
   gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
   gtk_widget_show(label);
   }
   
   gtk_tree_append(GTK_TREE(tree), tree_item);
   if(arglist->type == ARG_ARGLIST)
    {
     subtree = report_arglist_to_tree(arglist->value, window);
     if(subtree){
       gtk_tree_item_set_subtree(GTK_TREE_ITEM(tree_item),
    		subtree);
       gtk_widget_show(subtree);
       }
    }
   gtk_tree_item_expand(GTK_TREE_ITEM(tree_item));
   gtk_tree_item_collapse(GTK_TREE_ITEM(tree_item));
   gtk_widget_show(tree_item);
   }
   arglist = arglist->next;
 }
 if(!count)return(NULL);
 else return(tree);
}    
  
int is_there_any_hole(arglist)
 struct arglist * arglist;
{
 int ret = 0;
 while(arglist && arglist->next && (ret!=HOLE_PRESENT))
 {
  int tmp = 0;
  
  if(!strcmp(arglist->name, "Security warnings"))ret = WARNING_PRESENT;
  else if(!strcmp(arglist->name, "Security holes"))ret = HOLE_PRESENT;
  /*
   * Check in the sublist
   */
  if(arglist->type == ARG_ARGLIST)tmp = is_there_any_hole(arglist->value);
  if(tmp >= ret)ret = tmp;
  arglist = arglist->next;
 }
 return(ret);
}


/*
 *  Main function of the holes reporter
 *  Pretty clean, huh ? :)
 */
void 
report_tests(hosts)
 struct arglist * hosts;
{
  gtk_widget_show(arg_get_value(MainDialog, "WINDOW"));
  create_report_window(hosts);
}

/*
 * Opens the report
 */
void open_report(GtkWidget * dontcare, GtkWidget *nsr)
{
struct arglist * arguments = emalloc(sizeof(struct arglist));
file_to_arglist(arguments, gtk_file_selection_get_filename(GTK_FILE_SELECTION(nsr)) );
report_tests(arguments);
}

/*
 * Menu selection to open the report
 */
void open_report_selectfile()
{
 GtkWidget * nsr;
 nsr = gtk_file_selection_new ("Load file");
 gtk_file_selection_set_filename (GTK_FILE_SELECTION(nsr), NESSUSD_REPORTS_DIR);
 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (nsr)->ok_button),
                               "clicked", (GtkSignalFunc) open_report,(void *) nsr );
           
 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
           (nsr)->cancel_button),
             "clicked", (GtkSignalFunc)close_window, (void *)nsr);
           
 gtk_widget_show(nsr);
}

/*
 * Saves the report
 */
static void 
save_report_ask(nul,nul2)
  GtkWidget * nul;
  GtkWidget * nul2;
{
 GtkWidget * filew;
 char * filename;
 char * tmp;
 char * hostname;
 
 
 if(!Hosts)return;
 hostname = emalloc(strlen(Hosts->name)+1);
 strncpy(hostname, Hosts->name, strlen(Hosts->name));
 
 while((tmp = strchr(hostname, '.')))tmp[0]='_';
 
 filename = emalloc(strlen(Hosts->name)+6+strlen(NESSUSD_REPORTS_DIR));
 sprintf(filename, "%s/%s.nsr", NESSUSD_REPORTS_DIR, hostname);
 efree(&hostname);
 
 filew = gtk_file_selection_new ("Save file");
 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
                               "clicked", (GtkSignalFunc) save_report, filew );
           
 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
           (filew)->cancel_button),
             "clicked", (GtkSignalFunc)close_window, (void *)filew);
 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), filename);
           
 gtk_widget_show(filew);
}

/*
 * save_report
 *
 * this function is called when the user
 * clicks on the 'save' item of the file
 * menu...
 */
static void 
save_report(nul,filew)
    GtkWidget * nul;
    GtkWidget * filew;
{
 char * fname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filew));
 arglist_to_file(Hosts, fname);
 gtk_widget_hide(filew);
 gtk_widget_destroy(filew);
}
 
