/* 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 "attack.h"
#include "xstuff.h"
#include "comm.h"
#include "auth.h"
#include "parser.h"             
#include "report.h"
#include "globals.h"

static char ** plugins_order_table = NULL;
static int plugins_in_table = 0;

static void monitor_input_callback(struct arglist *, int, int);
static void monitor_add_host(struct arglist *, char *, int);
static void monitor_stop_test(GtkWidget *, char *);
static void monitor_list_update(struct arglist *, char *);
static int monitor_stop_whole_test(GtkWidget * , struct arglist *);
static void build_plugins_order_table(char *);

/*
 * monitor_dialog_setup
 *
 * This function draws the window which will
 * show the attack status
 */
void 
monitor_dialog_setup(victim)
     char * victim;
{
  struct arglist * ctrls = emalloc(sizeof(struct arglist));
  GtkWidget * scrolled_window; 
  GtkWidget * w, * box;
  int tag;
  Hosts = emalloc(sizeof(struct arglist));
  arg_add_value(ctrls, "HOSTS", ARG_ARGLIST, -1, Hosts);
  
  w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_signal_connect(GTK_OBJECT(w), "delete_event",
		     (GtkSignalFunc)monitor_stop_whole_test,ctrls);
  gtk_window_set_title(GTK_WINDOW(w), "Nessus portscanning/attack status");
  gtk_container_border_width(GTK_CONTAINER(w), 10);
  arg_add_value(ctrls, "WINDOW", ARG_PTR, -1, w);
  gtk_widget_show(w);
  
  box = gtk_vbox_new(FALSE,10);
  gtk_container_add(GTK_CONTAINER(w), box);
  gtk_widget_show(box);
  
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
				
  gtk_container_border_width(GTK_CONTAINER(scrolled_window), 10);   
  gtk_widget_set_usize(scrolled_window, 500,300); 
  gtk_box_pack_start(GTK_BOX(box), scrolled_window, TRUE, TRUE, 0);
  
  w = gtk_list_new();
  gtk_container_add(GTK_CONTAINER(scrolled_window), w);
  gtk_widget_show(w);
  gtk_widget_show (scrolled_window);
  arg_add_value(ctrls, "LIST", ARG_PTR, -1, w);
                    
  tag = gdk_input_add (GlobalSocket, GDK_INPUT_READ,
			    (GdkInputFunction)monitor_input_callback,
			    ctrls);
  arg_add_value(ctrls, "TAG", ARG_INT, sizeof(int), (void *)tag);     
  
  w = gtk_button_new_with_label("Stop the whole test");
  gtk_signal_connect(GTK_OBJECT(w), "clicked",
		     (GtkSignalFunc)monitor_stop_whole_test,ctrls);
  gtk_box_pack_start(GTK_BOX(box), w, FALSE, TRUE, 0);
  gtk_widget_show(w);
  
  attack_host(victim, Prefs);
}

/*
 * monitor_list_update
 *
 * Updates the progress bars
 */	
static void 
monitor_list_update(ctrls,msg)
	struct arglist * ctrls;
	char * msg;
{
 char * hostname;
 char * action;
 int current;
 int max;
 gfloat gmax;
 gfloat gcurrent;
 GList * dlist;
 GtkObject * item;
 GtkWidget * gtkw;
 char * list_hostname;
 int flag = 0;
 
 
 hostname = emalloc(strlen(msg)+1);
 action = emalloc(strlen(msg)+1);
 parse_nessusd_status(msg, hostname, action, &current, &max);
 gtkw = arg_get_value(ctrls, "LIST");
 dlist = GTK_LIST(gtkw)->children;
 while(dlist && !flag)
 {
  item = GTK_OBJECT(dlist->data);
  list_hostname = gtk_object_get_data(item, "hostname");
  if(!list_hostname){
  	fprintf(stderr, "Error ! Null hostname in the list\n");
  	exit(1);
  	}
  if(!strcmp(list_hostname, hostname))
  {
   GtkWidget * progress_bar;
   gfloat f;
   
   if(!strcmp(action, "portscan"))
    progress_bar = gtk_object_get_data(item, "progress_bar_portscan");
   else
   {
    GtkWidget * label = gtk_object_get_data(item, "current_plugin");
    progress_bar = gtk_object_get_data(item, "progress_bar_attack");
    if((current> 0) && (current <= plugins_in_table))
     gtk_label_set(GTK_LABEL(label), plugins_order_table[current-1]);
    else gtk_label_set(GTK_LABEL(label), "???");
    }
   gmax = max;
   gcurrent = current;
   f = (gcurrent/gmax);
   if(f>1)f=1;
   if(f<0.0)f=0.0;
   gtk_progress_bar_update (GTK_PROGRESS_BAR(progress_bar), f);
   flag = 1;
  }
  dlist = dlist->next;
 }
 
 if(!flag)
 {
 /* the host was not found, we must add one... */
 monitor_add_host(ctrls, hostname, current);
 }
 
}
 
/*
 * monitor_add_host
 *
 * this function adds a new hostname and progress bar in
 * the monitor window
 */
void 
monitor_add_host(ctrls,hostname,port)
	struct arglist * ctrls;
	char * hostname;
	int port;
{
 GtkWidget * progress_bar_portscan;
 GtkWidget * progress_bar_attack;
 GtkWidget * table;
 GtkWidget * label;
 GtkWidget * item;
 GtkWidget * button;
 GtkWidget * separator;
 GtkWidget * box, * hbox;
 GtkWidget * other_label;
 GList * dlist;
 
 item = gtk_list_item_new();
 dlist = NULL;
 table = gtk_table_new(4, 3, FALSE);
 gtk_table_set_col_spacings(GTK_TABLE(table), 15);
 gtk_table_set_row_spacings(GTK_TABLE(table),5);
 
 gtk_container_add(GTK_CONTAINER(item), table);
 
 hbox = gtk_hbox_new(FALSE,0);
 gtk_widget_show(hbox);
 
 gtk_table_attach_defaults(GTK_TABLE(table), hbox, 0,1,0,3); 
 
 
 box = gtk_vbox_new(TRUE,0);
 gtk_widget_show(box);
 gtk_box_pack_start(GTK_BOX(hbox), box, FALSE, FALSE, 0);
 
 label = gtk_label_new(hostname);
 gtk_widget_set_usize(label, 150, 15);
 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
 gtk_widget_show(label);
 
 box = gtk_vbox_new(TRUE, 0);
 gtk_widget_show(box);
 gtk_box_pack_end(GTK_BOX(hbox), box, FALSE, FALSE, 0);
 
 label = gtk_label_new("Portscan : ");
 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
 gtk_widget_show(label);
 
 label = gtk_label_new("Attack : ");
 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
 gtk_widget_show(label);
 
 label = gtk_label_new("plugin : ");
 gtk_box_pack_end(GTK_BOX(box), label, FALSE, FALSE, 0);
 gtk_widget_show(label);
 
 progress_bar_portscan = gtk_progress_bar_new();
 gtk_table_attach_defaults(GTK_TABLE(table),progress_bar_portscan, 1,2,0,1);
 gtk_widget_show(progress_bar_portscan);
 
 progress_bar_attack = gtk_progress_bar_new();
 gtk_table_attach_defaults(GTK_TABLE(table),progress_bar_attack, 1,2,1,2);
 gtk_widget_show(progress_bar_attack);
 
 
 other_label = gtk_label_new("");
 gtk_table_attach_defaults(GTK_TABLE(table), other_label, 1,2,2,3);
 gtk_widget_show(other_label);
 
 box = gtk_vbox_new(TRUE,0);
 gtk_table_attach_defaults(GTK_TABLE(table), box, 2,3,0,2);
 gtk_widget_show(box);
 
 button = gtk_button_new_with_label("Stop");
 gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     (GtkSignalFunc)monitor_stop_test,hostname);
 gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
 gtk_widget_show(button);
 
 separator = gtk_hseparator_new();
 gtk_table_attach_defaults(GTK_TABLE(table), separator, 0,3,3,4);
 gtk_widget_show(separator);
 
 gtk_object_set_data(GTK_OBJECT(item), "hostname", hostname);
 gtk_object_set_data(GTK_OBJECT(item), "progress_bar_attack", progress_bar_attack);
 gtk_object_set_data(GTK_OBJECT(item), "progress_bar_portscan", progress_bar_portscan);
 gtk_object_set_data(GTK_OBJECT(item), "current_plugin", other_label);
 gtk_widget_show(table);
 gtk_widget_show(item);
 dlist = g_list_append(dlist, item);
 gtk_list_append_items(GTK_LIST(arg_get_value(ctrls, "LIST")), dlist);
 }
 
 
/*  
 * monitor_stop_test
 * 
 * This function will stop the connection between
 * nessusd and the client, and will report the results
 * to the screen
 */
 
static int
monitor_stop_whole_test(w, ctrls)
 GtkWidget * w;
 struct arglist * ctrls;
{
struct arglist * a = arg_get_value(MainDialog, "AUTH");
        	
 gtk_widget_hide(arg_get_value(a, "CONNECTED"));
 gtk_widget_show(arg_get_value(a, "BUTTON"));
 gdk_input_remove((int)arg_get_value(ctrls, "TAG"));
 network_printf( "CLIENT <|> STOP_WHOLE_TEST <|> CLIENT\n");
 shutdown(GlobalSocket, 2);
 close(GlobalSocket);
 GlobalSocket = -1;
 efree(&ArgSock);
 F_nessusd_running = 0;
 gtk_widget_hide(arg_get_value(ctrls, "WINDOW"));
 report_tests(arg_get_value(ctrls, "HOSTS"));
 return(FALSE);
}


/*
 * monitor_input_callback
 *
 * This function is called whenever there is new
 * data coming from the server. 
 */
void 
monitor_input_callback(ctrls, fd, condition)
    struct arglist * ctrls;
    int fd;
    int condition;
{
  int finished = 0;
  char * buf;
  char * msg;
  int type;
  buf = emalloc(4096);
  
  
  network_gets(buf, 4095);
  if(strlen(buf))buf[strlen(buf)-1]=0;
#ifdef DEBUGMORE
  fprintf(stderr, "%s\n", buf);
#endif
  
  msg = emalloc(strlen(buf)+1);
  if(strlen(buf))type=parse_server_message(buf, arg_get_value(ctrls, "HOSTS"), msg);
  else type = MSG_BYE;
  switch(type)
  {
  	case MSG_BYE : 
        	{
                struct arglist * a = arg_get_value(MainDialog, "AUTH");
        	GlobalSocket = -1;
                gtk_widget_hide(arg_get_value(a, "CONNECTED"));
                gtk_widget_show(arg_get_value(a, "BUTTON"));
		network_printf("CLIENT <|> BYE <|> ACK\n");
  		finished = 1;
                }
  		break;
  	case MSG_STAT :
  	 	monitor_list_update(ctrls, msg);
  		break;
        case MSG_PLUGINS_ORDER :
        	build_plugins_order_table(msg);
                break;
  }
  bzero(buf, 1024);
  efree(&msg);
  
  if(finished)
    {
#ifdef DEBUG
      fprintf(stderr, "Scan finished\n");
#endif
      F_nessusd_running = 0;
      gdk_input_remove((int)arg_get_value(ctrls, "TAG"));
      shutdown(GlobalSocket,2);
      gtk_widget_hide(arg_get_value(ctrls, "WINDOW"));
      report_tests(arg_get_value(ctrls, "HOSTS"));
    }
   efree(&buf);
}
 
/*
 * monitor_stop_test
 *
 * this function stops one test
 */
void 
monitor_stop_test(w,hostname)
	GtkWidget * w;
	char * hostname;
{
 network_printf("CLIENT <|> STOP_ATTACK <|> %s <|> CLIENT\n", hostname);
}
 
static void build_plugins_order_table(order)
 char * order;
{
 int num = 0;
 char * t;
 int i = 0;
 int * plugins_order_table_int;
 t = order;
 
 efree(&plugins_order_table);
 
 while((t = strchr(t+1, ';')))num++;
 plugins_order_table_int = emalloc(num*sizeof(int));
 t = order;
 while(t)
 {
  char * next = strchr(t, ';');
  if(next)next[0]=0;
  plugins_order_table_int[i++] = atoi(t);
  if(next)next[0]=';';
  t = next+1;
  next = strchr(next+1, ';');
  if(!next)t = NULL;
 }
 
 /*
  * Now, create the names table
  */
  plugins_order_table = emalloc(num*sizeof(char *));
  for(i=0;i<num;i++)
  {
   struct arglist * plugs = Plugins;
   
   while(plugs && plugs->next && 
        ((int)(arg_get_value(plugs->value, "ID"))!=plugins_order_table_int[i]))
         plugs = plugs->next;
   plugins_order_table[i] = plugs->name;
  }
  plugins_in_table = num;
  efree(&plugins_order_table_int);
}
 
