/*
    ettercap -- gtk interface for data sniffing-logging

    Copyright (C) 2001  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>
    GTK+ 2.0 interface by daten <daten@dnetc.org>

    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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <ec_main.h>

#include <sys/types.h>
#if defined(HAVE_SYS_POLL_H)
   #include <sys/poll.h>
#elif defined (HAVE_POLL_H)
   #include <poll.h>
#endif

#include <ec_gtk.h>
#include <ec_gtk_inject.h>
#include <ec_gtk_sniff.h>
#include <ec_gtk_plugins.h>
#include <ec_gtk_icons.h>
#include <ec_decodedata.h>
#include <ec_dissector.h>
#include <ec_filterdrop.h>
#include <ec_illithid.h>
#include <ec_buffer.h>
#include <ec_inet_structures.h>
#include <ec_binder.h>
#include <ec_thread.h>

#define PAD_BUFFER 1000        // buffered lines for sniffing

#define ASCII_VIEW   0        // data in the sniffing windows...
#define HEX_VIEW     1
#define TEXT_VIEW    2
#define EBCDIC_VIEW  3
#define JOINED_VIEW  4

// protos...

void Ginterface_Sniff_Data_Run(char *ips, int psource, char *ipd, int pdest, char *macs, char *macd, char proto, char *type, short mode, int connection);
void Ginterface_Sniff_Data_SniffData(void);
void Ginterface_Sniff_Data_LogToFile(char proto);
void Ginterface_Sniff_Data_StopCont(void);
void Ginterface_Sniff_Data_View(short mode);
void Ginterface_Sniff_Data_Inject(char proto, char *app);
void Ginterface_Sniff_Data_Kill(char proto);
void Ginterface_Sniff_Data_Bind(char proto, char *ipsource, char *ipdest);
u_short Ginterface_Sniff_Data_WaitPort(void);

gboolean Ginterface_Sniff_Data_Watch(gpointer data);
void Ginterface_Sniff_Data_Callback(gpointer data, guint action, GtkWidget *widget);
void Ginterface_Sniff_Data_Reset(void);
void Ginterface_Sniff_Data_Scroll (GtkWidget *textview, GtkTextMark *mark);
void Ginterface_Sniff_Data_Stop (void);
void Ginterface_Sniff_Data_ToolBar(GtkItemFactory *host_menu);

/* sd_ naming to avoid conflicts with other variables */
GtkWidget *sd_frame[3];     // 0 source, 1 dest, 2 joined
GtkWidget *sd_table[2];     // 0 split, 1 joined
GtkWidget *logged_label[3]; // 0 source, 1 dest, 2 joined
GtkWidget *view_label;      // STOPPED, ASCII, TEXT, etc
GtkWidget *sd_textview[3];  // 3 textviews to check for focus
GtkWidget *sd_scrolled[3];     // provides scrollbars
GtkWidget *label, *box[3];
GtkTextBuffer *sd_textbuf[3]; // 0 source, 1 dest, 2 joined
GtkTextMark *sd_mark[3];    // for autoscroll

extern int gConn_Pointer;

short log_source, log_dest, log_joined;
short view;
short gstop = 0;
short ginject = 0;
short gjoined = 0;

int ginject_tos=0;
int sd_watch=0;
int autoscroll=1;

short gmode;

FILE *file_source, *file_dest, *file_joined;

char ipsource[16];
char ipdest[16];
char app[18];
char gproto;
u_short portsource;
u_short portdest;

pthread_t gBinder_pid=0;
int Connection_Sniffed;

//---------------------------

void Ginterface_Sniff_Data_LogToFile(char proto)
{
   char question[100];
   char filename[60];
   char answer;
   time_t tt;
   struct tm *dd;
   char date[8];

   DEBUG_MSG("Ginterface_Sniff_Data_LogToFile");

   tt = time(NULL);
   dd = localtime(&tt);

   snprintf(date, sizeof(date), "%04d%02d%02d", dd->tm_year+1900, dd->tm_mon+1, dd->tm_mday);

   if (gjoined)
   {
      strcpy(question, "Do you want to log the trafic to this file ? (y/n)");
      snprintf(filename, sizeof(filename), "%s-%c-%s:%d-%s:%d-FULL.log", date, proto, ipsource, portsource, ipdest, portdest);
   }
   else
   {
      if (gtk_widget_is_focus(GTK_WIDGET(sd_textview[0])))
      {
         strcpy(question, "Do you want to log SOURCE-to-DEST to this file ? (y/n)");
         snprintf(filename, sizeof(filename), "%s-%c-%s:%d-%s:%d.log", date, proto, ipsource, portsource, ipdest, portdest);
      }
      else if (gtk_widget_is_focus(GTK_WIDGET(sd_textview[1])))
      {
         strcpy(question, "Do you want to log DEST-to-SOURCE to this file ? (y/n)");
         snprintf(filename, sizeof(filename), "%s-%c-%s:%d-%s:%d.log", date, proto, ipdest, portdest, ipsource, portsource);
      }
   }

   strcat(question, "\n\n");
   strcat(question, filename); 
   answer = Ginterface_PopUpQ(question);

   if ( (answer == 'y') || (answer == 'Y') )
   {
      if (gjoined)
      {
         file_joined = fopen(filename, "a");
         if (file_joined == NULL)
            ERROR_MSG("fopen()");
         log_joined = 1;
         gtk_widget_show(logged_label[2]);
      }
      else if (gtk_widget_is_focus(sd_textview[0]))
      {
         file_source = fopen(filename, "a");
         if (file_source == NULL)
            ERROR_MSG("fopen()");
         log_source = 1;
         gtk_widget_show(logged_label[0]);
      }
      else if (gtk_widget_is_focus(sd_textview[1]))
      {
         file_dest = fopen(filename, "a");
         if (file_dest == NULL)
            ERROR_MSG("fopen()");
         log_dest = 1;
         gtk_widget_show(logged_label[1]);
      }
   }
   else
   {
      if (gjoined)
      {
         if (log_joined) fclose(file_joined);
         log_joined = 0;
         gtk_widget_hide(logged_label[2]);
      }
      else if (gtk_widget_is_focus(sd_textview[0]))
      {
         if (log_source) fclose(file_source);
         log_source = 0;
         gtk_widget_hide(logged_label[0]);
      }
      else if (gtk_widget_is_focus(sd_textview[1]))
      {
         if (log_dest) fclose(file_dest);
         log_dest = 0;
         gtk_widget_hide(logged_label[1]);
      }
   }


#ifdef DEBUG
   DEBUG_MSG("Ginterface_Sniff_Data_LogToFile returns -- %c", answer);
   if ( (answer == 'y') || (answer == 'Y') ) DEBUG_MSG("\t %s", filename);
#endif

}


void Ginterface_Sniff_Data_StopCont(void)
{
   DEBUG_MSG("Ginterface_Sniff_Data_StopCont");


   if (gstop == 0)
   {
      gtk_label_set_text(GTK_LABEL (view_label), "STOPPED");
      gstop = 1;
   }
   else
   {
      /* set label back to former */
      Ginterface_Sniff_Data_View(view);
      gstop = 0;
   }
}



void Ginterface_Sniff_Data_View(short mode)
{
   DEBUG_MSG("Ginterface_Sniff_Data_View -- %d", mode);


   switch(mode)
   {
      case ASCII_VIEW:
         gtk_label_set_text(GTK_LABEL (view_label), "ASCII");
         break;

      case HEX_VIEW:
         gtk_label_set_text(GTK_LABEL (view_label), "HEX");
         break;

      case EBCDIC_VIEW:
         gtk_label_set_text(GTK_LABEL (view_label), "EBCDIC");
         break;
                        
      case TEXT_VIEW:
         gtk_label_set_text(GTK_LABEL (view_label), "TEXT");
         break;

      case JOINED_VIEW:
         if (gjoined)
         {
            /* if already joined, switch back to split */
            gjoined = 0;
            g_object_ref(G_OBJECT(sd_table[1]));
            gtk_container_remove(GTK_CONTAINER (ec_table), sd_table[1]);
            g_object_ref(G_OBJECT(view_label));
            gtk_container_remove(GTK_CONTAINER (box[2]), view_label);

            gtk_table_attach (GTK_TABLE (ec_table), sd_table[0], 0, 1, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 10, 0);
            gtk_widget_show(sd_table[0]);
            gtk_box_pack_start_defaults (GTK_BOX(box[0]), view_label);
         }
         else
         {
            char temp[100];
            gjoined = 1;
            
            gtk_widget_hide (sd_table[0]);
            g_object_ref(G_OBJECT(sd_table[0]));
            gtk_container_remove(GTK_CONTAINER (ec_table), sd_table[0]);
            g_object_ref(G_OBJECT(view_label));
            gtk_container_remove(GTK_CONTAINER (box[0]), view_label);

            gtk_table_attach (GTK_TABLE (ec_table), sd_table[1], 0, 1, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 10, 0);
            gtk_widget_show (sd_table[1]);
            gtk_box_pack_start_defaults (GTK_BOX(box[2]), view_label);
            snprintf(temp, 100, "%s:%d - %s:%d", ipsource, portsource, ipdest, portdest);
            gtk_frame_set_label (GTK_FRAME (sd_frame[2]), temp);

            Ginterface_Sniff_Data_View(ASCII_VIEW);
         }

         return;
         break;
   }

   view = mode; // <-- the important part
}



void Ginterface_Sniff_Data_SniffData(void)
{
   GtkTextIter iter;
   SNIFFED_DATA data_from_illithid;
   int datalen;
   char line[MAX_DATA];
   char *utf8_line = NULL;

   if (Options.buflen)
      datalen = ConnBuffer_Get(Conn_Between_Hosts[Connection_Sniffed].DataBuffer, &data_from_illithid, sizeof(SNIFFED_DATA));
   else
      datalen = Buffer_Get(pipe_with_illithid_data, &data_from_illithid, sizeof(SNIFFED_DATA));

   if (datalen<=0)
   {
       usleep(1);
       return;
   }

   if (binder_pipe != -1 && gBinder_pid)
       Buffer_Put(binder_pipe, &data_from_illithid, sizeof(SNIFFED_DATA));

   if (gjoined)
   {
      if (log_joined) { write(fileno(file_joined), &data_from_illithid.data, data_from_illithid.datasize); fflush(file_joined);}
      if (!gstop)
      {
         switch (view)
         {
            case ASCII_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetAsciiData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case TEXT_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetTextData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case EBCDIC_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetEBCDICData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case HEX_VIEW:
               if (data_from_illithid.proto == 'T') {
                  snprintf(line, sizeof(line), "\n> S %lx A %lx (%s) <\n%s",
                           data_from_illithid.seq,
                           data_from_illithid.ack_seq,
                           Decodedata_TCPFlags(data_from_illithid.flags),
                           Decodedata_GetHexData(data_from_illithid.data, data_from_illithid.datasize, sizeof(line)));
               } else
                  snprintf(line, sizeof(line), "%s", 
                           Decodedata_GetHexData(data_from_illithid.data, data_from_illithid.datasize, sizeof(line)));
                  break;
         }

         gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (sd_textbuf[2]), &iter);
         utf8_line = g_locale_to_utf8 (line, -1, NULL, NULL, NULL);
         if(!utf8_line)
            return;

         if(!g_utf8_validate(utf8_line, -1, NULL)) {
            DEBUG_MSG("Ginterface_Sniff_Data_SniffData - g_utf8_validate failed, string was: %s", utf8_line);
            return;
         }

         if ( current_illithid_data.source_ip == data_from_illithid.fast_source_ip)
            gtk_text_buffer_insert_with_tags_by_name(GTK_TEXT_BUFFER (sd_textbuf[2]), &iter, 
               utf8_line, -1, "blue_fg", "monospace", NULL);
         else
            gtk_text_buffer_insert_with_tags_by_name(GTK_TEXT_BUFFER (sd_textbuf[2]), &iter, 
               utf8_line, -1, "monospace", NULL);

         if(autoscroll) 
            Ginterface_Sniff_Data_Scroll(sd_textview[2], sd_mark[2]);
         
      }
   }
   else if ( current_illithid_data.source_ip == data_from_illithid.fast_source_ip)
   {
      if (log_source) { write(fileno(file_source), &data_from_illithid.data, data_from_illithid.datasize); fflush(file_source);}
      if (!gstop)
         switch (view)
         {
            case ASCII_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetAsciiData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case TEXT_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetTextData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case EBCDIC_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetEBCDICData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case HEX_VIEW:
               if (data_from_illithid.proto == 'T')
                  snprintf(line, sizeof(line), "\n> S %lx A %lx (%s) <\n%s",
                           data_from_illithid.seq,
                           data_from_illithid.ack_seq,
                           Decodedata_TCPFlags(data_from_illithid.flags),
                           Decodedata_GetHexData(data_from_illithid.data, data_from_illithid.datasize, 200));
               else
                  snprintf(line, sizeof(line), "%s", Decodedata_GetHexData(data_from_illithid.data, data_from_illithid.datasize, 200));
               break;
         }
         
         gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (sd_textbuf[0]), &iter);
         utf8_line = g_locale_to_utf8 (line, -1, NULL, NULL, NULL);
         if(!utf8_line)
            return;

         if(!g_utf8_validate(utf8_line, -1, NULL)) {
            DEBUG_MSG("Ginterface_Sniff_Data_SniffData - g_utf8_validate failed, string was: %s", utf8_line);
            return;
         }

         gtk_text_buffer_insert_with_tags_by_name(GTK_TEXT_BUFFER (sd_textbuf[0]), &iter,  
            utf8_line, -1, "monospace", NULL);

         if(autoscroll) 
            Ginterface_Sniff_Data_Scroll(sd_textview[0], sd_mark[0]);

   }
   else
   {
      if (log_dest) { write(fileno(file_dest), &data_from_illithid.data, data_from_illithid.datasize); fflush(file_dest);}
      if (!gstop)
         switch (view)
         {
            case ASCII_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetAsciiData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case TEXT_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetTextData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case EBCDIC_VIEW:
               snprintf(line, sizeof(line), "%s", Decodedata_GetEBCDICData(data_from_illithid.data, data_from_illithid.datasize));
               break;

            case HEX_VIEW:
               if (data_from_illithid.proto == 'T')
                  snprintf(line, sizeof(line), "\n> S %lx A %lx (%s) <\n%s",
                           data_from_illithid.seq,
                           data_from_illithid.ack_seq,
                           Decodedata_TCPFlags(data_from_illithid.flags),
                           Decodedata_GetHexData(data_from_illithid.data, data_from_illithid.datasize, 200));
               else
                  snprintf(line, sizeof(line), "%s", Decodedata_GetHexData(data_from_illithid.data, data_from_illithid.datasize, 200));
               break;
         }
         gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (sd_textbuf[1]), &iter);
         utf8_line = g_locale_to_utf8 (line, -1, NULL, NULL, NULL);
         if(!utf8_line)
            return;

         if(!g_utf8_validate(utf8_line, -1, NULL)) {
            DEBUG_MSG("Ginterface_Sniff_Data_SniffData - g_utf8_validate failed, string was: %s", utf8_line);
            return;
         }

         gtk_text_buffer_insert_with_tags_by_name(GTK_TEXT_BUFFER (sd_textbuf[1]), &iter,  
            utf8_line, -1, "monospace", NULL);

         if(autoscroll) 
            Ginterface_Sniff_Data_Scroll(sd_textview[1], sd_mark[1]);
         
   }

}


void Ginterface_Sniff_Data_Inject(char proto, char *app)
{

   INJECTED_DATA inject_data;
   int data_len;
   char temp[200];

   DEBUG_MSG("Ginterface_Sniff_Data_Inject");

   if (gjoined)
   {
      Ginterface_PopUp("Injection is not possible while in JOINED view");
      return;
   }

   memset(&inject_data, 0, sizeof(INJECTED_DATA));

   data_len = Ginterface_Inject_Run(inject_data.data, proto, app);

   inject_data.proto = proto;
   inject_data.datalen = data_len;

   if (data_len)
   {
      ginject = 1;  // on exit the connection must be RSTted

      if (gtk_widget_is_focus(sd_textview[1]))
      {
         DEBUG_MSG("Ginterface_Sniff_Data_Inject -- INJECT -- %s", ipdest);
         inject_data.source_ip = inet_addr(ipsource);
         inject_data.dest_ip = inet_addr(ipdest);
         inject_data.source_port = htons(portsource);
         inject_data.dest_port = htons(portdest);
         write(pipe_inject[1], &inject_data, sizeof(INJECTED_DATA));

         snprintf(temp, 200, "%d chars injected to %s", ginject_tos += data_len, ipsource);
         Ginterface_EditBottom(0, temp);
      }
      else if (gtk_widget_is_focus(sd_textview[0]))
      {
         DEBUG_MSG("Ginterface_Sniff_Data_Inject -- INJECT -- %s", ipsource);
         inject_data.source_ip = inet_addr(ipdest);
         inject_data.dest_ip = inet_addr(ipsource);
         inject_data.source_port = htons(portdest);
         inject_data.dest_port = htons(portsource);
         write(pipe_inject[1], &inject_data, sizeof(INJECTED_DATA));

         snprintf(temp, 200, "%d chars injected to %s", ginject_tos += data_len, ipsource);
         Ginterface_EditBottom(1, temp);
      }
   }

}


void Ginterface_Sniff_Data_Kill(char proto)
{
   KILL_DATA kill_data;

   if (proto == 'U')
   {
      Ginterface_PopUp("Trying to kill an UDP connection ?!? Hey Kiddie, go home !!");
      return;
   }

   DEBUG_MSG("Ginterface_Sniff_Data_Kill -- %s:%d -> %s:%d ", ipsource, portsource, ipdest, portdest);

   kill_data.source_ip = inet_addr(ipsource);
   kill_data.dest_ip = inet_addr(ipdest);
   kill_data.source_port = htons(portsource);
   kill_data.dest_port = htons(portdest);
   write(pipe_kill[1], &kill_data, sizeof(KILL_DATA));

   strcpy(Conn_Between_Hosts[gConn_Pointer].status, "KILLED");

   Ginterface_PopUp("Connection KILLED !!");

}

u_short Ginterface_Sniff_Data_WaitPort(void)
{
   while(Global_Binder_Port==0)
      usleep(500);
   return (Global_Binder_Port);
}

void Ginterface_Sniff_Data_Bind(char proto, char *ipsource, char *ipdest)
{
   u_long s_ip, d_ip;
                     
   if (gjoined) {
      Ginterface_PopUp("Can't bind while in joined view");
      return;
   }
           
   if (proto != 'T') {
      Ginterface_PopUp("You can only bind TCP connections");
      return;
   }
           
   if (binder_pipe == -1)
      binder_pipe = Buffer_Create(1.0e6);
           
   s_ip = inet_addr(ipsource);
   d_ip = inet_addr(ipdest);
               
   if (gBinder_pid) ECThread_destroy(gBinder_pid); 
   
   Global_Binder_Port = 0;
         
   if (gtk_widget_is_focus (GTK_WIDGET (sd_textview[1]))) { 
      gBinder_pid = Binder_Start(s_ip, d_ip, portsource, portdest, proto);
      Ginterface_PopUp("Binded Connection D-to-S on port %d", Ginterface_Sniff_Data_WaitPort());
   } else if (gtk_widget_is_focus (GTK_WIDGET (sd_textview[0]))) {
      gBinder_pid = Binder_Start(d_ip, s_ip, portdest, portsource, proto);
      Ginterface_PopUp("Binded Connection S-to-D on port %d", Ginterface_Sniff_Data_WaitPort());
   }

}



void Ginterface_Sniff_Data_Run(char *ips, int psource, char *ipd, int pdest, char *macs, char *macd, char proto, char *type, short mode, int connection)
{
   GtkTextIter iter;
#if defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H)
   struct pollfd poll_fd;
#else
   fd_set msk_fd;
   struct timeval TimeOut;
#endif
   struct in_addr addr;
   char macsource[20];
   char macdest[20];
   char temp[50];

   gproto = proto;
   gmode = mode;
   gjoined = 0;
   
   Connection_Sniffed = connection;
   if (Options.buflen) ConnBuffer_Flush(Conn_Between_Hosts[Connection_Sniffed].DataBuffer);
   
   strlcpy(ipsource, ips, sizeof(ipsource));     // save locally because other threads can
   strlcpy(ipdest, ipd, sizeof(ipdest));         // realloc the array containing these values
   portsource = psource;
   portdest = pdest;

   strlcpy(macsource, macs, sizeof(macsource));
   strlcpy(macdest, macd, sizeof(macdest));
   strlcpy(app, type, sizeof(app));

   DEBUG_MSG("Ginterface_Sniff_Data_Run -- %d -- %c [%s:%d] [%s:%d] [%s] [%s]", mode, proto, ipsource, portsource, ipdest, portdest, macsource, macdest );

   /* split view */
   sd_table[0] = gtk_table_new (2, 2, FALSE);
   gtk_table_attach (GTK_TABLE (ec_table), sd_table[0], 0, 1, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 10, 0);
   gtk_widget_show(sd_table[0]);


   snprintf(temp, 50, "%s:%d", ipsource, portsource);
   sd_frame[0] = gtk_frame_new (temp);
   gtk_table_attach (GTK_TABLE(sd_table[0]), sd_frame[0], 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
   gtk_widget_show(sd_frame[0]);

   /* make the scrolled window */
        sd_scrolled[0] = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sd_scrolled[0]), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sd_scrolled[0]), GTK_SHADOW_IN);
        gtk_container_add(GTK_CONTAINER (sd_frame[0]), sd_scrolled[0]);
        gtk_widget_show (sd_scrolled[0]);

   /* make the Text View window */
        sd_textview[0] = gtk_text_view_new();
        gtk_text_view_set_editable(GTK_TEXT_VIEW (sd_textview[0]), FALSE);
        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW (sd_textview[0]), FALSE);
        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW (sd_textview[0]), GTK_WRAP_CHAR);
        gtk_text_view_set_left_margin(GTK_TEXT_VIEW (sd_textview[0]), 5);
        gtk_text_view_set_right_margin(GTK_TEXT_VIEW (sd_textview[0]), 5);
        gtk_container_add(GTK_CONTAINER (sd_scrolled[0]), sd_textview[0]);
        gtk_widget_show(sd_textview[0]);

   sd_textbuf[0] = gtk_text_view_get_buffer (GTK_TEXT_VIEW (sd_textview[0]));
   gtk_text_buffer_create_tag (sd_textbuf[0], "monospace", "family", "monospace", NULL);
   gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (sd_textbuf[0]), &iter);
   sd_mark[0] = gtk_text_buffer_create_mark(sd_textbuf[0], "end", &iter, FALSE);

   snprintf(temp, 50, "%s:%d", ipdest, portdest);
   sd_frame[1] = gtk_frame_new (temp);
   gtk_table_attach (GTK_TABLE(sd_table[0]), sd_frame[1], 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
   gtk_widget_show(sd_frame[1]);

   /* make the scrolled window */
        sd_scrolled[1] = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sd_scrolled[1]), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sd_scrolled[1]), GTK_SHADOW_IN);
        gtk_container_add(GTK_CONTAINER (sd_frame[1]), sd_scrolled[1]);
        gtk_widget_show (sd_scrolled[1]);

   /* make the Text View window */
        sd_textview[1] = gtk_text_view_new();
        gtk_text_view_set_editable(GTK_TEXT_VIEW (sd_textview[1]), FALSE);
        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW (sd_textview[1]), FALSE);
        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW (sd_textview[1]), GTK_WRAP_CHAR);
        gtk_text_view_set_left_margin(GTK_TEXT_VIEW (sd_textview[1]), 5);
        gtk_text_view_set_right_margin(GTK_TEXT_VIEW (sd_textview[1]), 5);
        gtk_container_add(GTK_CONTAINER (sd_scrolled[1]), sd_textview[1]);
        gtk_widget_show(sd_textview[1]);

   sd_textbuf[1] = gtk_text_view_get_buffer (GTK_TEXT_VIEW (sd_textview[1]));
   gtk_text_buffer_create_tag (sd_textbuf[1], "monospace", "family", "monospace", NULL);
   gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (sd_textbuf[1]), &iter);
   sd_mark[1] = gtk_text_buffer_create_mark(sd_textbuf[1], "end", &iter, FALSE);

   box[0] = gtk_hbox_new(FALSE, 0);
   gtk_table_attach (GTK_TABLE(sd_table[0]), box[0], 0, 1, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
   gtk_widget_show(box[0]);

   view_label = gtk_label_new ("      ");
   gtk_misc_set_alignment (GTK_MISC (view_label), 0, 0);
   gtk_box_pack_start_defaults (GTK_BOX(box[0]), view_label);
   gtk_widget_show(view_label);

   logged_label[0] = gtk_label_new ("Logged");
   gtk_misc_set_alignment (GTK_MISC (logged_label[0]), 1, 0);
   gtk_box_pack_start_defaults (GTK_BOX(box[0]), logged_label[0]);
   /* don't show yet */

   box[1] = gtk_hbox_new(FALSE, 0);
   gtk_table_attach (GTK_TABLE(sd_table[0]), box[1], 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
   gtk_widget_show(box[1]);

   logged_label[1] = gtk_label_new ("Logged");
   gtk_misc_set_alignment (GTK_MISC (logged_label[1]), 1, 0);
   gtk_box_pack_start_defaults (GTK_BOX(box[1]), logged_label[1]);
   /* don't show yet */

   /* and make joined view stuff too.. just dont display it */
   /* ----------------------------------------------------- */
   sd_table[1] = gtk_table_new (2, 1, FALSE);

   snprintf(temp, 50, "%s:%d  -  %s:%d", ipsource, portsource, ipdest, portdest);
   sd_frame[2] = gtk_frame_new (temp);
   gtk_table_attach (GTK_TABLE(sd_table[1]), sd_frame[2], 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
   gtk_widget_show (sd_frame[2]);

   /* make the scrolled window */
        sd_scrolled[2] = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sd_scrolled[2]), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sd_scrolled[2]), GTK_SHADOW_IN);
        gtk_container_add(GTK_CONTAINER (sd_frame[2]), sd_scrolled[2]);
        gtk_widget_show (sd_scrolled[2]);

   /* make the Text View window */
        sd_textview[2] = gtk_text_view_new();
        gtk_text_view_set_editable(GTK_TEXT_VIEW (sd_textview[2]), FALSE);
        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW (sd_textview[2]), FALSE);
        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW (sd_textview[2]), GTK_WRAP_CHAR);
        gtk_text_view_set_left_margin(GTK_TEXT_VIEW (sd_textview[2]), 5);
        gtk_text_view_set_right_margin(GTK_TEXT_VIEW (sd_textview[2]), 5);
        gtk_container_add(GTK_CONTAINER (sd_scrolled[2]), sd_textview[2]);
        gtk_widget_show(sd_textview[2]);
   
   sd_textbuf[2] = gtk_text_view_get_buffer (GTK_TEXT_VIEW (sd_textview[2]));
   gtk_text_buffer_create_tag (sd_textbuf[2], "blue_fg", "foreground", "blue", NULL); /* joined view colors */
   gtk_text_buffer_create_tag (sd_textbuf[2], "monospace", "family", "monospace", NULL);
   gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (sd_textbuf[2]), &iter);
   sd_mark[2] = gtk_text_buffer_create_mark(sd_textbuf[2], "end", &iter, FALSE);

   box[2] = gtk_hbox_new(FALSE, 0);
   gtk_table_attach (GTK_TABLE(sd_table[1]), box[2], 0, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
   gtk_widget_show(box[2]);

   logged_label[2] = gtk_label_new ("Logged");
   gtk_misc_set_alignment (GTK_MISC (logged_label[2]), 1, 0);
   gtk_box_pack_start_defaults (GTK_BOX(box[2]), logged_label[2]);
   /* don't show yet */

   /* bottom box labels */
   /* ----------------- */
   Ginterface_EditBottom(0, "Protocol: ");
   if (proto == 'T')
      Ginterface_AppendBottom(0, "TCP");
   else
      Ginterface_AppendBottom(0, "UDP");

   Ginterface_EditBottom(1, "Application: ");
   Ginterface_AppendBottom(1, app);

   Ginterface_Sniff_Data_View(view);    // default view

   if (Options.hexview)
   {
      view = HEX_VIEW;
      Options.hexview = 0;
   }


#if defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H)
   poll_fd.fd = 0;
   poll_fd.events = POLLIN;
#else
   memset(&TimeOut, 0, sizeof(TimeOut));  //  timeout = 0
   FD_ZERO(&msk_fd);
#endif

   current_illithid_data.proto = proto;
   current_illithid_data.source_port = portsource;
   current_illithid_data.dest_port = portdest;

   if (inet_aton(ipsource, &addr))
      current_illithid_data.source_ip = ntohl(addr.s_addr);
   if (inet_aton(ipdest, &addr))
      current_illithid_data.dest_ip =  ntohl(addr.s_addr);

   if (!Options.buflen) Buffer_Flush(pipe_with_illithid_data);

   sd_watch = g_timeout_add(300, Ginterface_Sniff_Data_Watch, NULL);
}

gboolean Ginterface_Sniff_Data_Watch(gpointer data)
{
   Ginterface_Sniff_Data_SniffData();

#ifdef PERMIT_PLUGINS
   Ginterface_Plugins_Output_Update();
   // Ginterface_Plugins_HidePluginOutput();
#endif

   return TRUE;
}

void Ginterface_Sniff_Data_ToolBar(GtkItemFactory *host_menu) {
   static GtkItemFactoryEntry action_menu[] = {
      { "/Quit", "q", Ginterface_Sniff_Data_Stop, 'q', "<StockItem>", GTK_STOCK_CLOSE },
      { "/View", NULL, NULL, 0, "<Branch>", NULL},
      { "/View/Ascii", "a", Ginterface_Sniff_Data_Callback, 'a', "<ImageItem>", ascii_icon},
      { "/View/Hex", "x", Ginterface_Sniff_Data_Callback, 'x', "<ImageItem>", hex_icon},
      { "/View/Text", "t", Ginterface_Sniff_Data_Callback, 't', "<ImageItem>", text_icon},
      { "/View/EBCDIC", "e", Ginterface_Sniff_Data_Callback, 'e', "<ImageItem>", bin_icon},
      { "/View/", NULL, NULL, 0, "<Separator>", NULL},
      { "/View/Joined", "j", Ginterface_Sniff_Data_Callback, 'j', "<StockItem>", GTK_STOCK_COPY},
      { "/Action", "h", NULL, 0, "<Branch>", NULL},
      { "/Action/Pause Display", "s", Ginterface_Sniff_Data_Callback, 's', "<StockItem>", GTK_STOCK_STOP},
      { "/Action/Toggle Auto-Scrolling", "o", Ginterface_Sniff_Data_Callback, 'o', "<StockItem>", GTK_STOCK_GOTO_BOTTOM},
      { "/Action/Log to File", "l", Ginterface_Sniff_Data_Callback, 'l', "<StockItem>", GTK_STOCK_SAVE},
      { "/Action/Inject a Packet", "i", Ginterface_Sniff_Data_Callback, 'i', "<StockItem>", GTK_STOCK_EXECUTE},
      { "/Action/Edit Filter Chains", "f", Ginterface_Sniff_Data_Callback, 'f', "<ImageItem>", chain_icon},
      { "/Action/Kill Connection", "k", Ginterface_Sniff_Data_Callback, 'k', "<ImageItem>", kill_icon},
      { "/Help", NULL, NULL, 0, "<LastBranch>", NULL},
      { "/Help/_Manual", NULL, Ginterface_Manual, 0, "<StockItem>", GTK_STOCK_HELP},
      { "/Help/_About", NULL, Ginterface_About, 0, "<StockItem>", GTK_STOCK_DIALOG_INFO}
   };
   gint num_items = 0;

   DEBUG_MSG("Ginterface_Sniff_Data_ToolBar");

   gtk_item_factory_delete_item(host_menu, "/Quit");
   gtk_item_factory_delete_item(host_menu, "/Sniff");
   gtk_item_factory_delete_item(host_menu, "/Action");
   gtk_item_factory_delete_item(host_menu, "/Help");

   num_items = sizeof (action_menu) / sizeof (action_menu[0]);
   gtk_item_factory_create_items (host_menu, num_items, action_menu, NULL);
}

void Ginterface_Sniff_Data_Reset()
{
   if (Options.buflen)
   {
      ConnBuffer_Flush(Conn_Between_Hosts[Connection_Sniffed].DataBuffer);
      if (!gjoined)
      {
         gtk_text_buffer_set_text(GTK_TEXT_BUFFER (sd_textbuf[2]), "", 0); 
      }
      else
      {
         gtk_text_buffer_set_text(GTK_TEXT_BUFFER (sd_textbuf[0]), "", 0);
         gtk_text_buffer_set_text(GTK_TEXT_BUFFER (sd_textbuf[1]), "", 0);
      }
   }
}

void Ginterface_Sniff_Data_Scroll (GtkWidget *textview, GtkTextMark *mark) {
   gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview), mark, 0, FALSE, 0, 0);
}


void Ginterface_Sniff_Data_Callback(gpointer data, guint action, GtkWidget *widget)
{
   switch (action) {
      case 'L':
      case 'l':
         Ginterface_Sniff_Data_LogToFile(gproto);
         Ginterface_Sniff_Data_Reset();
         break;

      case 'A':
      case 'a':
         Ginterface_Sniff_Data_View(ASCII_VIEW);
         Ginterface_Sniff_Data_Reset();
         break;

      case 'X':
      case 'x':
         Ginterface_Sniff_Data_View(HEX_VIEW);
         Ginterface_Sniff_Data_Reset();
         break;

      case 'T':
      case 't':
         Ginterface_Sniff_Data_View(TEXT_VIEW);
         Ginterface_Sniff_Data_Reset();
         break;

      case 'E':
      case 'e':
         Ginterface_Sniff_Data_View(EBCDIC_VIEW);
         Ginterface_Sniff_Data_Reset();
         break;

      case 'J':
      case 'j':
         Ginterface_Sniff_Data_View(JOINED_VIEW);
         Ginterface_Sniff_Data_Reset();
         break;

      case 'S':
      case 's':
         Ginterface_Sniff_Data_StopCont();
         break;

      case 'I':
      case 'i':
         if ( gmode == ARPBASED )
         {
            if (strstr(app, "ssh") || strstr(app, "SSH") || strstr(app, "HTTPS"))
            {
               Ginterface_PopUp("You CAN'T inject in a crypted connection !!");
            }
            else
               Ginterface_Sniff_Data_Inject(gproto, app);
         }
         else
         {
            Ginterface_PopUp("Characters injection is only supported in ARP Based mode !!");
         }
         break;

      case 'F':
      case 'f':
         Ginterface_Inject_SetFilter(gmode);
         break;

      case 'K':
      case 'k':
         Ginterface_Sniff_Data_Kill(gproto);
         break;

      case 'B':
      case 'b':
            Ginterface_Sniff_Data_Bind(gproto, ipsource, ipdest);
            break;

      case 'o':
            if(autoscroll)
               autoscroll = 0;
            else
               autoscroll = 1;
            break;

      case 'H':
      case 'h':
         {
            static char *help[] = {
            "[qQ][F10] - quit (and stop sniffing)",
            "[tab]     - switch between windows",
            "[pgUp]    - scroll back (as well as UpArrow)",
            "[pgDw]    - scroll forward (as well as DownArrow)",
            "[iI]      - inject characters in the connection",
            "[fF]      - set/edit filters chains",
#ifdef PERMIT_PLUGINS
            "[pP]      - run a plugin",
#endif
            "[kK]      - kill the connection (be careful !)",
            "[aA]      - ASCII view",
            "[xX]      - HEX view",
            "[tT]      - TEXT (readable chars) only view",
            "[jJ]      - join the two windows",
            "[sS]      - stop/cont the sniff (only visualization)",
            "[lL]      - Log to file",
            "[bB]      - Bind the sniffed data to a port",
            NULL};
            Ginterface_HelpWindow(help);
         }
         break;
   }
}

void Ginterface_Sniff_Data_Stop (void) {
   if (log_dest)
      fclose(file_dest);
   if (log_source)
      fclose(file_source);
   if (log_joined)
      fclose(file_joined);
   if (gBinder_pid)
      ECThread_destroy(gBinder_pid);    

   g_source_remove (sd_watch);

   gdk_flush();

   gBinder_pid = 0;
   log_dest = log_source = log_joined = 0;
   gstop = 0;
   ginject_tos=0;  // reset counter

   /* this part was moved from ec_interface_sniff because gtk changes the flow of things */
   /* it has to be run when leaving sniff_data to return to interface_sniff mode */
   Connection_Mode = 1;

   Ginterface_Sniff_ActiveDissector(gmode);
   if (filter_on_source && FilterDrop_CheckMode(Filter_Array_Source, gmode))
   {
      Ginterface_PopUp("The Source filter chain can be used only in ARPBASED mode !!");
      filter_on_source = 0;
      Ginterface_Inject_FilterStatus();
   }
   if (filter_on_dest && FilterDrop_CheckMode(Filter_Array_Dest, gmode))
   {
      Ginterface_PopUp("The Dest filter chain can be used only in ARPBASED mode !!");
      filter_on_dest = 0;
      Ginterface_Inject_FilterStatus();
   }
   /* --- */

   /* removing a table causes it to loose it's last ref and be destroyed */
   /* destroying the other previously ref'd one is up to us */
   if(gjoined) {
      gtk_container_remove(GTK_CONTAINER (ec_table), sd_table[1]);
      if(sd_table[0])
         gtk_widget_destroy(sd_table[0]);
   } else {
      gtk_container_remove(GTK_CONTAINER (ec_table), sd_table[0]);
      if(sd_table[1])
         gtk_widget_destroy(sd_table[1]);
   }

   gjoined = 0;

   gtk_table_attach (GTK_TABLE (ec_table), frame[1], 0, 1, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 10, 0);
   g_object_unref(G_OBJECT (frame[1]));

   Ginterface_Sniff_ToolBar(main_menu);

   DEBUG_MSG("Ginterface_Sniff_Data_End");
}


/* EOF */

// vim:ts=3:expandtab

