The dfilter yacc grammar now keeps track of every GNode that it allocates.
[obnox/wireshark/wip.git] / ethereal.c
index 99b7630ff4a7ede43e8b17bbb635969503d8d167..cf342c03d71b380bec61822a2c5227742efc1f5a 100644 (file)
@@ -1,6 +1,6 @@
 /* ethereal.c
  *
- * $Id: ethereal.c,v 1.43 1999/06/19 03:14:31 guy Exp $
+ * $Id: ethereal.c,v 1.108 1999/08/26 06:20:49 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -32,7 +32,6 @@
  * - Playback window
  * - Multiple window support
  * - Add cut/copy/paste
- * - Fix progress/status bar glitches?  (GTK+ bug?)
  * - Create header parsing routines
  * - Check fopens, freads, fwrites
  * - Make byte view scrollbars automatic?
 #endif
 
 #include <gtk/gtk.h>
-#include <pcap.h> /* needed for capture.h */
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+
 #include <signal.h>
 
 #ifdef NEED_SNPRINTF_H
@@ -75,9 +85,9 @@
 #include "timestamp.h"
 #include "packet.h"
 #include "capture.h"
+#include "summary.h"
 #include "file.h"
 #include "menu.h"
-#include "etypes.h"
 #include "prefs.h"
 #include "column.h"
 #include "print.h"
 #include "follow.h"
 #include "util.h"
 #include "gtkpacket.h"
+#include "dfilter.h"
 
+static void file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs);
 static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs);
 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
+static void print_cmd_toggle_dest(GtkWidget *widget, gpointer data);
+static void print_file_cb(GtkWidget *file_bt, gpointer file_te);
+static void print_fs_ok_cb(GtkWidget *w, gpointer data);
+static void print_fs_cancel_cb(GtkWidget *w, gpointer data);
+static void print_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
+static void print_close_cb(GtkWidget *close_bt, gpointer parent_w);
 
 FILE        *data_out_file = NULL;
 packet_info  pi;
@@ -95,26 +113,31 @@ capture_file cf;
 GtkWidget   *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
             *info_bar;
 GdkFont     *m_r_font, *m_b_font;
-GtkStyle    *pl_style;
 guint        main_ctx, file_ctx;
-frame_data  *fd;
 gint         start_capture = 0;
 gchar        comp_info_str[256];
 gchar       *ethereal_path = NULL;
 gchar       *medium_font = MONO_MEDIUM_FONT;
 gchar       *bold_font = MONO_BOLD_FONT;
+gchar       *last_open_dir = NULL;
 
 ts_type timestamp_type = RELATIVE;
 
 GtkStyle *item_style;
 
+#ifdef HAVE_LIBPCAP
 int sync_mode; /* allow sync */
 int sync_pipe[2]; /* used to sync father */
 int fork_mode; /* fork a child to do the capture */
 int sigusr2_received = 0;
 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
+#endif
+
+/* Specifies byte offsets for object selected in tree */
+static gint tree_selected_start=-1, tree_selected_len=-1; 
 
 #define E_DFILTER_TE_KEY "display_filter_te"
+#define E_RFILTER_TE_KEY "read_filter_te"
 
 /* About Ethereal window */
 void
@@ -142,86 +165,71 @@ about_ethereal( GtkWidget *w, gpointer data ) {
                "Jeff Jahr                <jjahr@shastanets.com>\n"
                "Brad Robel-Forrest       <bradr@watchguard.com>\n"
                "Ashok Narayanan          <ashokn@cisco.com>\n"
+               "Aaron Hillegass          <aaron@classmax.com>\n"
+               "Jason Lango              <jal@netapp.com>\n"
+               "Johan Feyaerts           <Johan.Feyaerts@siemens.atea.be>\n"
+               "Olivier Abad             <abad@daba.dhis.org>\n"
+               "Thierry Andry            <Thierry.Andry@advalvas.be>\n"
+               "Jeff Foster              <jfoste@woodward.com>\n"
 
                "\nSee http://ethereal.zing.org for more information",
                 VERSION, comp_info_str);
 }
 
-/* Things to do when the OK button is pressed */
-void
-file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
-  gchar     *cf_name;
-  int        err;
-
-  cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
-  gtk_widget_hide(GTK_WIDGET (fs));
-  gtk_widget_destroy(GTK_WIDGET (fs));
-
-  /* this depends upon load_cap_file removing the filename from
-   * cf_name, leaving only the path to the directory. */
-  if ((err = load_cap_file(cf_name, &cf)) == 0)
-    chdir(cf_name);
-  else {
-    simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
-               cf_name);
-  }
-  g_free(cf_name);
-#ifdef USE_ITEM
-    set_menu_sensitivity("/File/Save", FALSE);
-    set_menu_sensitivity("/File/Save As...", TRUE);
-#else
-    set_menu_sensitivity("<Main>/File/Save", FALSE);
-    set_menu_sensitivity("<Main>/File/Save As...", TRUE);
-#endif
-}
-
 /* Update the progress bar */
 gint
 file_progress_cb(gpointer p) {
+  capture_file *cf = (capture_file*) p;
   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
-    (gfloat) ftell(cf.fh) / (gfloat) cf.f_len);
+    (gfloat) ftell(cf->fh) / (gfloat) cf->f_len);
   return TRUE;
 }
 
-/* Follow a TCP stream */
+/* Follow the TCP stream, if any, to which the last packet that we called
+   a dissection routine on belongs (this might be the most recently
+   selected packet, or it might be the last packet in the file). */
 void
 follow_stream_cb( GtkWidget *w, gpointer data ) {
-  char filename1[128];
+  char      filename1[128+1];
   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
-  GtkWidget *filter_te = NULL;
-  int err;
-
-  if (w)
-       filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
+  int        tmp_fd;
 
   if( pi.ipproto == 6 ) {
     /* we got tcp so we can follow */
-    /* check to see if we are using a filter */
-    if( cf.dfilter != NULL ) {
-      /* get rid of this one */
-      g_free( cf.dfilter );
-      cf.dfilter = NULL;
+    /* Create a temporary file into which to dump the reassembled data
+       from the TCP stream, and set "data_out_file" to refer to it, so
+       that the TCP code will write to it.
+
+       XXX - it might be nicer to just have the TCP code directly
+       append stuff to the text widget for the TCP stream window,
+       if we can arrange that said window not pop up until we're
+       done. */
+    tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
+    if (tmp_fd == -1) {
+      simple_dialog(ESD_TYPE_WARN, NULL,
+        "Could not create temporary file %s: %s", filename1, strerror(errno));
+      return;
     }
-    /* create a new one and set the display filter entry accordingly */
-    cf.dfilter = build_follow_filter( &pi );
-    if (filter_te)
-           gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
-    /* reload so it goes in effect. Also we set data_out_file which 
-       tells the tcp code to output the data */
-    close_cap_file( &cf, info_bar, file_ctx);
-    strcpy( filename1, tmpnam(NULL) );
-    data_out_file = fopen( filename1, "a" );
+    data_out_file = fdopen( tmp_fd, "w" );
     if( data_out_file == NULL ) {
-      fprintf( stderr, "Could not open tmp file %s\n", filename1 );
+      simple_dialog(ESD_TYPE_WARN, NULL,
+        "Could not create temporary file %s: %s", filename1, strerror(errno));
+      close(tmp_fd);
+      unlink(filename1);
+      return;
     }
+
+    /* Create a new filter that matches all packets in the TCP stream,
+       and set the display filter entry accordingly */
     reset_tcp_reassembly();
-    err = load_cap_file( cf.filename, &cf );
-    if (err != 0) {
-      simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
-               cf.filename);
-    }
+    cf.dfilter = build_follow_filter( &pi );
+
+    /* Run the display filter so it goes in effect. */
+    filter_packets(&cf);
+
     /* the data_out_file should now be full of the streams information */
     fclose( data_out_file );
+
     /* the filename1 file now has all the text that was in the session */
     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
     gtk_widget_set_name( streamwindow, "TCP stream window" );
@@ -238,15 +246,18 @@ follow_stream_cb( GtkWidget *w, gpointer data ) {
     }
     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
+
     /* setup the container */
     box = gtk_vbox_new( FALSE, 0 );
     gtk_container_add( GTK_CONTAINER(streamwindow), box );
     gtk_widget_show( box );
+
     /* set up the table we attach to */
     table = gtk_table_new( 1, 2, FALSE );
     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
     gtk_widget_show( table );
+
     /* create a text box */
     text = gtk_text_new( NULL, NULL );
     gtk_text_set_editable( GTK_TEXT(text), FALSE);
@@ -254,15 +265,16 @@ follow_stream_cb( GtkWidget *w, gpointer data ) {
                      GTK_EXPAND | GTK_SHRINK | GTK_FILL,
                      GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
     gtk_widget_show(text);
+
     /* create the scrollbar */
     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
                      GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
     gtk_widget_show( vscrollbar );
     gtk_widget_realize( text );
+
     /* stop the updates while we fill the text box */
     gtk_text_freeze( GTK_TEXT(text) );
-    data_out_file = NULL;
     data_out_file = fopen( filename1, "r" );
     if( data_out_file ) {
       char buffer[1024];
@@ -274,16 +286,19 @@ follow_stream_cb( GtkWidget *w, gpointer data ) {
          break;
        }
       }
+      if( ferror( data_out_file ) ) {
+        simple_dialog(ESD_TYPE_WARN, NULL,
+          "Error reading temporary file %s: %s", filename1, strerror(errno));
+      }
       fclose( data_out_file );
-      unlink( filename1 );
+    } else {
+      simple_dialog(ESD_TYPE_WARN, NULL,
+        "Could not open temporary file %s: %s", filename1, strerror(errno));
     }
     gtk_text_thaw( GTK_TEXT(text) );
+    unlink( filename1 );
     data_out_file = NULL;
     gtk_widget_show( streamwindow );
-    if( cf.dfilter != NULL ) {
-      g_free( cf.dfilter );
-      cf.dfilter = NULL;
-    }
   } else {
     simple_dialog(ESD_TYPE_WARN, NULL,
       "Error following stream.  Please make\n"
@@ -291,27 +306,108 @@ follow_stream_cb( GtkWidget *w, gpointer data ) {
   }
 }
 
+/* Match selected byte pattern */
+void
+match_selected_cb(GtkWidget *w, gpointer data)
+{
+    char *buf = g_malloc(1024);
+    GtkWidget *filter_te = NULL;
+    char *ptr;
+    int i;
+    guint8 *c;
+
+    filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
+
+    if (tree_selected_start<0) {
+       simple_dialog(ESD_TYPE_WARN, NULL,
+                     "Error determining selected bytes.  Please make\n"
+                     "sure you have selected a field within the tree\n"
+                     "view to be matched.");
+       return;
+    }
+
+    c = cf.pd + tree_selected_start;
+    ptr = buf;
+
+    sprintf(ptr, "frame[%d : %d] == ", tree_selected_start, tree_selected_len);
+    ptr = buf+strlen(buf);
+
+    if (tree_selected_len == 1) {
+        sprintf(ptr, "0x%02x", *c++);
+    }
+    else {
+           for (i=0;i<tree_selected_len; i++) {
+               if (i == 0 ) {
+                       sprintf(ptr, "%02x", *c++);
+               }
+               else {
+                       sprintf(ptr, ":%02x", *c++);
+               }
+               ptr = buf+strlen(buf);
+           }
+    }
+
+    if( cf.dfilter != NULL ) {
+      /* get rid of this one */
+      g_free( cf.dfilter );
+    }
+    /* create a new one and set the display filter entry accordingly */
+    cf.dfilter = buf;
+    if (filter_te) {
+       gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
+    }
+    /* Run the display filter so it goes in effect. */
+    filter_packets(&cf);
+}
+
 /* Open a file */
 void
 file_open_cmd_cb(GtkWidget *w, gpointer data) {
+  GtkWidget *filter_hbox, *filter_bt, *filter_te;
+
+  if (last_open_dir)
+         chdir(last_open_dir);
+
   file_sel = gtk_file_selection_new ("Ethereal: Open Capture File");
   
-  /* Connect the ok_button to file_ok_sel_cb function and pass along the
-     pointer to the filter entry */
+  /* Connect the ok_button to file_open_ok_cb function and pass along a
+     pointer to the file selection box widget */
   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
-    "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel );
+    "clicked", (GtkSignalFunc) file_open_ok_cb, file_sel );
 
-  /* Gilbert --- I added this if statement. Is this right? */
-  if (w)
   gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
-    E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
+      E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
+
+  filter_hbox = gtk_hbox_new(FALSE, 1);
+  gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
+  gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_sel)->action_area),
+    filter_hbox, FALSE, FALSE, 0);
+  gtk_widget_show(filter_hbox);
+
+  filter_bt = gtk_button_new_with_label("Filter:");
+  gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
+    GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
+  gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
+  gtk_widget_show(filter_bt);
+  
+  filter_te = gtk_entry_new();
+  gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
+  gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
+  gtk_widget_show(filter_te);
+
+  gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
+    E_RFILTER_TE_KEY, filter_te);
 
   /* Connect the cancel_button to destroy the widget */
   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
     gtk_widget_destroy, GTK_OBJECT (file_sel));
 
+#ifdef HAVE_LIBPCAP
   if( fork_mode && (cf.save_file != NULL) )
+#else
+  if( cf.save_file != NULL )
+#endif
     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file);
   else
     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
@@ -319,25 +415,79 @@ file_open_cmd_cb(GtkWidget *w, gpointer data) {
   gtk_widget_show(file_sel);
 }
 
+static void
+file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
+  gchar     *cf_name, *rfilter, *s;
+  GtkWidget *filter_te;
+  dfilter   *rfcode = NULL;
+  int        err;
+
+  cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
+  filter_te = gtk_object_get_data(GTK_OBJECT(w), E_RFILTER_TE_KEY);
+  rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
+  if (rfilter[0] != '\0') {
+       rfcode = dfilter_new();
+       if (dfilter_compile(rfcode, rfilter) != 0) {
+               simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+               dfilter_destroy(rfcode);
+               return;
+       }
+  }
+
+  /* Try to open the capture file. */
+  if ((err = open_cap_file(cf_name, &cf)) != 0) {
+    /* We couldn't open it; don't dismiss the open dialog box,
+       just leave it around so that the user can, after they
+       dismiss the alert box popped up for the open error,
+       try again. */
+    if (rfcode != NULL)
+      dfilter_destroy(rfcode);
+    return;
+  }
+
+  /* Attach the new read filter to "cf" ("open_cap_file()" succeeded, so
+     it closed the previous capture file, and thus destroyed any
+     previous read filter attached to "cf"). */
+  cf.rfcode = rfcode;
+
+  /* We've crossed the Rubicon; get rid of the file selection box. */
+  gtk_widget_hide(GTK_WIDGET (fs));
+  gtk_widget_destroy(GTK_WIDGET (fs));
+
+  err = read_cap_file(&cf);
+  /* Save the directory name; we can write over cf_name. */
+  s = strrchr(cf_name, '/');
+  if (s && last_open_dir) {
+         *s = '\0';
+         if (strcmp(last_open_dir, cf_name) != 0) {
+                 g_free(last_open_dir);
+                 last_open_dir = g_strdup(cf_name);
+         }
+  }
+  else if (s) { /* ! last_open_dir */
+         *s = '\0';
+         last_open_dir = g_strdup(cf_name);
+  }
+  else {
+         last_open_dir = NULL;
+  }
+  set_menu_sensitivity("/File/Save", FALSE);
+  set_menu_sensitivity("/File/Save As...", TRUE);
+  g_free(cf_name);
+}
+
 /* Close a file */
 void
 file_close_cmd_cb(GtkWidget *widget, gpointer data) {
   close_cap_file(&cf, info_bar, file_ctx);
-#ifdef USE_ITEM
-  set_menu_sensitivity("/File/Close", FALSE);
-  set_menu_sensitivity("/File/Reload", FALSE);
-#else
-  set_menu_sensitivity("<Main>/File/Close", FALSE);
-  set_menu_sensitivity("<Main>/File/Reload", FALSE);
-#endif
 }
 
 void
 file_save_cmd_cb(GtkWidget *w, gpointer data) {
   file_sel = gtk_file_selection_new ("Ethereal: Save Capture File");
-  
-  /* Connect the ok_button to file_ok_sel_cb function and pass along the
-     pointer to the filter entry */
+  /* Connect the ok_button to file_save_ok_cb function and pass along a
+     pointer to the file selection box widget */
   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
     "clicked", (GtkSignalFunc) file_save_ok_cb, file_sel );
 
@@ -353,10 +503,10 @@ file_save_cmd_cb(GtkWidget *w, gpointer data) {
 
 void
 file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
-  file_sel = gtk_file_selection_new ("Ethereal: Save Capture File as");
+  file_sel = gtk_file_selection_new ("Ethereal: Save Capture File As");
 
-  /* Connect the ok_button to file_ok_sel_cb function and pass along the
-     pointer to the filter entry */
+  /* Connect the ok_button to file_save_as_ok_cb function and pass along a
+     pointer to the file selection box widget */
   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
     "clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel );
 
@@ -380,22 +530,15 @@ file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
 
        if (!file_mv(cf.save_file, cf_name))
                return;
+
        g_free(cf.save_file);
        cf.save_file = g_strdup(cf_name);
        cf.user_saved = 1;
-       err = load_cap_file(cf_name, &cf);
-       if (err != 0) {
-               simple_dialog(ESD_TYPE_WARN, NULL,
-                   file_open_error_message(err, FALSE), cf_name);
+        if ((err = open_cap_file(cf_name, &cf)) == 0) {
+               err = read_cap_file(&cf);
+               set_menu_sensitivity("/File/Save", FALSE);
+               set_menu_sensitivity("/File/Save As...", TRUE);
        }
-
-#ifdef USE_ITEM
-       set_menu_sensitivity("/File/Save", FALSE);
-       set_menu_sensitivity("/File/Save As...", TRUE);
-#else
-       set_menu_sensitivity("<Main>/File/Save", FALSE);
-       set_menu_sensitivity("<Main>/File/Save As...", TRUE);
-#endif
 }
 
 static void
@@ -406,106 +549,419 @@ file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
        cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
        gtk_widget_hide(GTK_WIDGET (fs));
        gtk_widget_destroy(GTK_WIDGET (fs));
-
-       if (!file_cp(cf.save_file, cf_name))
+       if (!file_cp(cf.filename, cf_name))
                return;
-       g_free(cf.save_file);
-       cf.save_file = g_strdup(cf_name);
+       g_free(cf.filename);
+       cf.filename = g_strdup(cf_name);
        cf.user_saved = 1;
-       err = load_cap_file(cf_name, &cf);
-       if (err != 0) {
-               simple_dialog(ESD_TYPE_WARN, NULL,
-                   file_open_error_message(err, FALSE), cf_name);
+        if ((err = open_cap_file(cf.filename, &cf)) == 0) {
+               err = read_cap_file(&cf);
+               set_menu_sensitivity("/File/Save", FALSE);
+               set_menu_sensitivity("/File/Save As...", TRUE);
        }
-
-#ifdef USE_ITEM
-       set_menu_sensitivity("/File/Save", FALSE);
-       set_menu_sensitivity("/File/Save As...", TRUE);
-#else
-       set_menu_sensitivity("<Main>/File/Save", FALSE);
-       set_menu_sensitivity("<Main>/File/Save As...", TRUE);
-#endif
 }
 
-/* Reload a file using the current display filter */
+/* Reload a file using the current read and display filters */
 void
 file_reload_cmd_cb(GtkWidget *w, gpointer data) {
   /*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/
   GtkWidget *filter_te;
-  int err;
 
   filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
 
   if (cf.dfilter) g_free(cf.dfilter);
   cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
-  err = load_cap_file(cf.filename, &cf);
-  if (err != 0) {
-    simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
-               cf.filename);
+  if (open_cap_file(cf.filename, &cf) == 0)
+    read_cap_file(&cf);
+  /* XXX - change the menu if the open fails? */
+}
+
+/* Run the current display filter on the current packet set, and
+   redisplay. */
+static void
+filter_activate_cb(GtkWidget *w, gpointer data)
+{
+  char *s = gtk_entry_get_text(GTK_ENTRY(w));
+
+  if (cf.dfilter)
+       g_free(cf.dfilter);
+
+  /* simple check for empty string. XXX - need to modify to search for /^\s+$/ */
+  if (s[0] == '\0' ) {
+       cf.dfilter = NULL;
+  }
+  else {
+       cf.dfilter = g_strdup(s);
+  }
+
+  filter_packets(&cf);
+}
+
+/*
+ * Remember whether we printed to a printer or a file the last time we
+ * printed something.
+ */
+static int     print_to_file;
+
+/* Keys for gtk_object_set_data */
+#define PRINT_CMD_LB_KEY  "printer_command_label"
+#define PRINT_CMD_TE_KEY  "printer_command_entry"
+#define PRINT_FILE_BT_KEY "printer_file_button"
+#define PRINT_FILE_TE_KEY "printer_file_entry"
+#define PRINT_DEST_RB_KEY "printer_destination_radio_button"
+
+/* Print the capture */
+void
+file_print_cmd_cb(GtkWidget *widget, gpointer data)
+{
+  GtkWidget     *print_w;
+  GtkWidget     *main_vb, *main_tb, *button;
+#if 0
+  GtkWidget     *format_hb, *format_lb;
+  GSList        *format_grp;
+#endif
+  GtkWidget     *dest_rb;
+  GtkWidget     *dest_hb, *dest_lb;
+  GtkWidget     *cmd_lb, *cmd_te;
+  GtkWidget     *file_bt_hb, *file_bt, *file_te;
+  GSList        *dest_grp;
+  GtkWidget     *bbox, *ok_bt, *cancel_bt;
+
+  /* XXX - don't pop up one if there's already one open; instead,
+       give it the input focus if that's possible. */
+
+  print_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title(GTK_WINDOW(print_w), "Ethereal: Print");
+
+  /* Enclosing containers for each row of widgets */
+  main_vb = gtk_vbox_new(FALSE, 5);
+  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+  gtk_container_add(GTK_CONTAINER(print_w), main_vb);
+  gtk_widget_show(main_vb);
+  
+  main_tb = gtk_table_new(4, 2, FALSE);
+  gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
+  gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
+  gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
+  gtk_widget_show(main_tb);
+
+  /* XXX - printing multiple frames in PostScript looks as if it's
+     tricky - you have to deal with page boundaries, I think -
+     and I'll have to spend some time learning enough about
+     PostScript to figure it out, so, for now, we only print
+     multiple frames as text. */
+#if 0
+  /* Output format */
+  format_lb = gtk_label_new("Format:");
+  gtk_misc_set_alignment(GTK_MISC(format_lb), 1.0, 0.5);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), format_lb, 0, 1, 0, 1);
+  gtk_widget_show(format_lb);
+
+  format_hb = gtk_hbox_new(FALSE, 0);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), format_hb, 1, 2, 0, 1);
+  gtk_widget_show(format_hb);
+
+  button = gtk_radio_button_new_with_label(NULL, "Plain Text");
+  if (prefs.pr_format == PR_FMT_TEXT)
+    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
+  format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
+  gtk_box_pack_start(GTK_BOX(format_hb), button, FALSE, FALSE, 10);
+  gtk_widget_show(button);
+
+  button = gtk_radio_button_new_with_label(format_grp, "PostScript");
+  if (prefs.pr_format == PR_FMT_PS)
+    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
+  gtk_box_pack_start(GTK_BOX(format_hb), button, FALSE, FALSE, 10);
+  gtk_widget_show(button);
+#endif
+
+  /* Output destination */
+  dest_lb = gtk_label_new("Print to:");
+  gtk_misc_set_alignment(GTK_MISC(dest_lb), 1.0, 0.5);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), dest_lb, 0, 1, 1, 2);
+  gtk_widget_show(dest_lb);
+
+  dest_hb = gtk_hbox_new(FALSE, 0);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), dest_hb, 1, 2, 1, 2);
+  gtk_widget_show(dest_hb);
+
+  button = gtk_radio_button_new_with_label(NULL, "Command");
+  if (!print_to_file)
+    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
+  dest_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
+  gtk_box_pack_start(GTK_BOX(dest_hb), button, FALSE, FALSE, 10);
+  gtk_widget_show(button);
+
+  dest_rb = gtk_radio_button_new_with_label(dest_grp, "File");
+  if (print_to_file)
+    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dest_rb), TRUE);
+  gtk_signal_connect(GTK_OBJECT(dest_rb), "toggled",
+                       GTK_SIGNAL_FUNC(print_cmd_toggle_dest), NULL);
+  gtk_box_pack_start(GTK_BOX(dest_hb), dest_rb, FALSE, FALSE, 10);
+  gtk_widget_show(dest_rb);
+
+  /* Command text entry */
+  cmd_lb = gtk_label_new("Command:");
+  gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_CMD_LB_KEY, cmd_lb);
+  gtk_misc_set_alignment(GTK_MISC(cmd_lb), 1.0, 0.5);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), cmd_lb, 0, 1, 2, 3);
+  gtk_widget_set_sensitive(cmd_lb, !print_to_file);
+  gtk_widget_show(cmd_lb);
+
+  cmd_te = gtk_entry_new();
+  gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_CMD_TE_KEY, cmd_te);
+  if (prefs.pr_cmd)
+    gtk_entry_set_text(GTK_ENTRY(cmd_te), prefs.pr_cmd);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), cmd_te, 1, 2, 2, 3);
+  gtk_widget_set_sensitive(cmd_te, !print_to_file);
+  gtk_widget_show(cmd_te);
+
+  /* File button and text entry */
+  file_bt_hb = gtk_hbox_new(FALSE, 0);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), file_bt_hb, 0, 1, 3, 4);
+  gtk_widget_show(file_bt_hb);
+
+  file_bt = gtk_button_new_with_label("File:");
+  gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_FILE_BT_KEY, file_bt);
+  gtk_box_pack_end(GTK_BOX(file_bt_hb), file_bt, FALSE, FALSE, 0);
+  gtk_widget_set_sensitive(file_bt, print_to_file);
+  gtk_widget_show(file_bt);
+
+  file_te = gtk_entry_new();
+  gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_FILE_TE_KEY, file_te);
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), file_te, 1, 2, 3, 4);
+  gtk_widget_set_sensitive(file_te, print_to_file);
+  gtk_widget_show(file_te);
+
+  gtk_signal_connect(GTK_OBJECT(file_bt), "clicked",
+               GTK_SIGNAL_FUNC(print_file_cb), GTK_OBJECT(file_te));
+
+  /* Button row: OK and Cancel buttons */
+  bbox = gtk_hbutton_box_new();
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+  gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+  gtk_container_add(GTK_CONTAINER(main_vb), bbox);
+  gtk_widget_show(bbox);
+
+  ok_bt = gtk_button_new_with_label ("OK");
+  gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_DEST_RB_KEY, dest_rb);
+  gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_CMD_TE_KEY, cmd_te);
+  gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_FILE_TE_KEY, file_te);
+  gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+    GTK_SIGNAL_FUNC(print_ok_cb), GTK_OBJECT(print_w));
+  GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
+  gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
+  gtk_widget_grab_default(ok_bt);
+  gtk_widget_show(ok_bt);
+
+  cancel_bt = gtk_button_new_with_label ("Cancel");
+  gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
+    GTK_SIGNAL_FUNC(print_close_cb), GTK_OBJECT(print_w));
+  GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
+  gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
+  gtk_widget_show(cancel_bt);
+
+#if 0
+  display_opt_window_active = TRUE;
+#endif
+  gtk_widget_show(print_w);
+}
+
+static void
+print_cmd_toggle_dest(GtkWidget *widget, gpointer data)
+{
+  GtkWidget     *cmd_lb, *cmd_te, *file_bt, *file_te;
+  int            to_file;
+
+  cmd_lb = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
+    PRINT_CMD_LB_KEY));
+  cmd_te = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
+    PRINT_CMD_TE_KEY));
+  file_bt = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
+    PRINT_FILE_BT_KEY));
+  file_te = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
+    PRINT_FILE_TE_KEY));
+  if (GTK_TOGGLE_BUTTON (widget)->active) {
+    /* They selected "Print to File" */
+    to_file = TRUE;
+  } else {
+    /* They selected "Print to Command" */
+    to_file = FALSE;
   }
+  gtk_widget_set_sensitive(cmd_lb, !to_file);
+  gtk_widget_set_sensitive(cmd_te, !to_file);
+  gtk_widget_set_sensitive(file_bt, to_file);
+  gtk_widget_set_sensitive(file_te, to_file);
+}
+
+static void
+print_file_cb(GtkWidget *file_bt, gpointer file_te)
+{
+  GtkWidget *fs;
+
+  fs = gtk_file_selection_new ("Ethereal: Print to File");
+       gtk_object_set_data(GTK_OBJECT(fs), PRINT_FILE_TE_KEY, file_te);
+
+  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
+    "clicked", (GtkSignalFunc) print_fs_ok_cb, fs);
+
+  /* Connect the cancel_button to destroy the widget */
+  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
+    "clicked", (GtkSignalFunc) print_fs_cancel_cb, fs);
+
+  gtk_widget_show(fs);
+}
+
+static void
+print_fs_ok_cb(GtkWidget *w, gpointer data)
+{
+  
+  gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(data),
+      PRINT_FILE_TE_KEY)),
+      gtk_file_selection_get_filename (GTK_FILE_SELECTION(data)));
+  gtk_widget_destroy(GTK_WIDGET(data));
+}
+
+static void
+print_fs_cancel_cb(GtkWidget *w, gpointer data)
+{
+  gtk_widget_destroy(GTK_WIDGET(data));
+}
+
+static void
+print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
+{
+  GtkWidget *button;
+  char *dest;
+
+  button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(ok_bt),
+                                              PRINT_DEST_RB_KEY);
+  if (GTK_TOGGLE_BUTTON (button)->active)
+    print_to_file = TRUE;
+  else
+    print_to_file = FALSE;
+
+  if (print_to_file)
+    dest = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(ok_bt),
+      PRINT_FILE_TE_KEY))));
+  else
+    dest = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(ok_bt),
+      PRINT_CMD_TE_KEY))));
+
+  gtk_widget_destroy(GTK_WIDGET(parent_w));
+#if 0
+  display_opt_window_active = FALSE;
+#endif
+
+  /* Now print the packets */
+  if (!print_packets(&cf, print_to_file, dest)) {
+    if (print_to_file)
+      simple_dialog(ESD_TYPE_WARN, NULL,
+        file_write_error_message(errno), dest);
+    else
+      simple_dialog(ESD_TYPE_WARN, NULL, "Couldn't run print command %s.",
+        prefs.pr_cmd);
+  }
+
+  g_free(dest);
+}
+
+static void
+print_close_cb(GtkWidget *close_bt, gpointer parent_w)
+{
+
+  gtk_grab_remove(GTK_WIDGET(parent_w));
+  gtk_widget_destroy(GTK_WIDGET(parent_w));
+#if 0
+  display_opt_window_active = FALSE;
+#endif
 }
 
 /* Print a packet */
 void
-file_print_cmd_cb(GtkWidget *widget, gpointer data) {
-    print_tree(cf.pd, fd, GTK_TREE(tree_view));
+file_print_packet_cmd_cb(GtkWidget *widget, gpointer data) {
+  FILE *fh;
+
+  switch (prefs.pr_dest) {
+
+  case PR_DEST_CMD:
+    fh = popen(prefs.pr_cmd, "w");
+    break;
+
+  case PR_DEST_FILE:
+    fh = fopen(prefs.pr_file, "w");
+    break;
+
+  default:
+    fh = NULL; /* XXX - "can't happen" */
+    break;
+  }
+  if (fh == NULL) {
+    switch (prefs.pr_dest) {
+
+    case PR_DEST_CMD:
+      simple_dialog(ESD_TYPE_WARN, NULL, "Couldn't run print command %s.",
+        prefs.pr_cmd);
+      break;
+
+    case PR_DEST_FILE:
+      simple_dialog(ESD_TYPE_WARN, NULL, file_write_error_message(errno),
+        prefs.pr_file);
+      break;
+    }
+    return;
+  }
+
+  print_preamble(fh);
+  proto_tree_print(-1, (GNode*) cf.protocol_tree, cf.pd, cf.fd, fh);
+  print_finale(fh);
+  close_print_dest(prefs.pr_dest == PR_DEST_FILE, fh);
 }
 
 /* What to do when a list item is selected/unselected */
 void
 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
-  GList      *l;
 
+#ifdef HAVE_LIBPCAP
   if (!sync_mode) {
-#ifdef WITH_WIRETAP
-  if (cf.wth) return; 
-#else
-  if (cf.pfh) return;
 #endif
+    if (cf.wth)
+      return; 
+#ifdef HAVE_LIBPCAP
   }
+#endif
   blank_packetinfo();
-  gtk_text_freeze(GTK_TEXT(byte_view));
-  gtk_text_set_point(GTK_TEXT(byte_view), 0);
-  gtk_text_forward_delete(GTK_TEXT(byte_view),
-    gtk_text_get_length(GTK_TEXT(byte_view)));
-  l = g_list_nth(cf.plist, row);
-  if (l) {
-    fd = (frame_data *) l->data;
-    fseek(cf.fh, fd->file_off, SEEK_SET);
-    fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh);
-    dissect_packet(cf.pd, fd, (proto_tree*)tree_view);
-    packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1);
-  }
-  gtk_text_thaw(GTK_TEXT(byte_view));
+  select_packet(&cf, row);
 }
 
 void
 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
-  gtk_text_freeze(GTK_TEXT(byte_view));
-  gtk_text_set_point(GTK_TEXT(byte_view), 0);
-  gtk_text_forward_delete(GTK_TEXT(byte_view),
-    gtk_text_get_length(GTK_TEXT(byte_view)));
-  gtk_text_thaw(GTK_TEXT(byte_view));
-  gtk_tree_clear_items(GTK_TREE(tree_view), 0,
-    g_list_length(GTK_TREE(tree_view)->children));
+  unselect_packet(&cf);
 }
 
 void
-tree_view_cb(GtkWidget *w) {
-  gint       start = -1, len = -1;
+tree_view_cb(GtkWidget *w, gpointer data) {
+
+  tree_selected_start = -1;
+  tree_selected_len = -1;
 
   if (GTK_TREE(w)->selection) {
-    start = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
-      E_TREEINFO_START_KEY);
-    len   = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
-      E_TREEINFO_LEN_KEY);
+    tree_selected_start = 
+       (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
+                                  E_TREEINFO_START_KEY);
+    tree_selected_len   = 
+       (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
+                                  E_TREEINFO_LEN_KEY);
   }
 
   gtk_text_freeze(GTK_TEXT(byte_view));
   gtk_text_set_point(GTK_TEXT(byte_view), 0);
   gtk_text_forward_delete(GTK_TEXT(byte_view),
     gtk_text_get_length(GTK_TEXT(byte_view)));
-  packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, start, len);
+  packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.fd->cap_len, 
+                  tree_selected_start, 
+                  tree_selected_len);
+  
   gtk_text_thaw(GTK_TEXT(byte_view));
 }
 
@@ -518,8 +974,8 @@ file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
 }
 
 void blank_packetinfo() {
-  pi.srcip    = 0;
-  pi.destip   = 0;
+  pi.ip_src   = 0;
+  pi.ip_dst   = 0;
   pi.ipproto  = 0;
   pi.srcport  = 0;
   pi.destport = 0;
@@ -528,23 +984,34 @@ void blank_packetinfo() {
 /* Things to do when the main window is realized */
 void
 main_realize_cb(GtkWidget *w, gpointer data) {
+#ifdef HAVE_LIBPCAP
   if (start_capture) {
     capture();
     start_capture = 0;
   }
+#endif
 }
 
+#ifdef HAVE_LIBPCAP
 static void 
 sigusr2_handler(int sig) {
   sigusr2_received = 1;
   signal(SIGUSR2, sigusr2_handler);
 }
+#endif
 
+/* call initialization routines at program startup time */
 static void
 ethereal_proto_init(void) {
-
+  proto_init();
   init_dissect_udp();
+  dfilter_init();
+}
 
+static void
+ethereal_proto_cleanup(void) {
+       proto_cleanup();
+       dfilter_cleanup();
 }
 
 static void 
@@ -563,34 +1030,50 @@ print_usage(void) {
 int
 main(int argc, char *argv[])
 {
-  int                  opt, i;
+  char               *command_name, *s;
+  int                  i;
+#ifndef WIN32
+  int                  opt;
   extern char         *optarg;
+#endif
   char                *pf_path;
   int                 pf_open_errno = 0;
   int                 err;
   GtkWidget           *window, *main_vbox, *menubar, *u_pane, *l_pane,
                       *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, 
                       *tv_scrollw, *filter_bt, *filter_te;
-#ifdef GTK_HAVE_FEATURES_1_1_0
-  GtkAccelGroup *accel;
-#else
-  GtkAcceleratorTable *accel;
-#endif
-
-#ifdef GTK_HAVE_FEATURES_1_1_4
-  GtkWidget    *packet_sw;
-#endif
+  GtkStyle            *pl_style;
+  GtkAccelGroup       *accel;
+  GtkWidget          *packet_sw;
   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
-  gchar               *rc_file, *cf_name = NULL;
+  gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
+  dfilter             *rfcode = NULL;
+  gboolean             rfilter_parse_failed = FALSE;
   e_prefs             *prefs;
-  gint                *col_fmt;
+  gchar              **col_title;
 
   ethereal_path = argv[0];
 
+  /* If invoked as "ethereal-dump-fields", we dump out a glossary of
+     display filter symbols; we specify that by checking the name,
+     so that we can do so before looking at the argument list -
+     we don't want to look at the argument list, because we don't
+     want to call "gtk_init()", because we don't want to have to
+     do any X stuff just to do a build. */
+  command_name = strrchr(ethereal_path, '/');
+  if (command_name == NULL)
+    command_name = ethereal_path;
+  else
+    command_name++;
+  if (strcmp(command_name, "ethereal-dump-fields") == 0) {
+    ethereal_proto_init();
+    proto_registrar_dump();
+    exit(0);
+  }
+  
   /* Let GTK get its args */
   gtk_init (&argc, &argv);
   
-
   prefs = read_prefs(&pf_path);
   if (pf_path != NULL) {
     /* The preferences file exists, but couldn't be opened; "pf_path" is
@@ -598,24 +1081,26 @@ main(int argc, char *argv[])
        failed. */
     pf_open_errno = errno;
   }
-    
+
   /* Initialize the capture file struct */
   cf.plist             = NULL;
-#ifdef WITH_WIRETAP
+  cf.plist_end         = NULL;
   cf.wth               = NULL;
-#else
-  cf.pfh               = NULL;
-#endif
   cf.fh                        = NULL;
+  cf.rfcode            = NULL;
   cf.dfilter           = NULL;
+  cf.dfcode            = dfilter_new();
+#ifdef HAVE_LIBPCAP
   cf.cfilter           = NULL;
+#endif
   cf.iface             = NULL;
   cf.save_file         = NULL;
+  cf.save_file_fd      = -1;
   cf.user_saved                = 0;
-  cf.snap              = MAX_PACKET_SIZE;
+  cf.snap              = WTAP_MAX_PACKET_SIZE;
   cf.count             = 0;
   cf.cinfo.num_cols    = prefs->num_cols;
-  cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
+  cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
   cf.cinfo.fmt_matx    = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
   cf.cinfo.col_data    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
   cf.cinfo.col_width   = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
@@ -623,19 +1108,22 @@ main(int argc, char *argv[])
   /* Assemble the compile-time options */
   snprintf(comp_info_str, 256,
 #ifdef GTK_MAJOR_VERSION
-    "GTK+ %d.%d.%d and %s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
+    "GTK+ %d.%d.%d, %s libpcap", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
     GTK_MICRO_VERSION,
 #else
-    "GTK+ (version unknown) and %s",
+    "GTK+ (version unknown), %s libpcap",
 #endif
-#ifdef WITH_WIRETAP
-    "wiretap");
+
+#ifdef HAVE_LIBPCAP
+   "with"
 #else
-    "libpcap");
+   "without"
 #endif
+   );
 
+#ifndef WIN32
   /* Now get our args */
-  while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:Ss:t:T:w:v")) != EOF) {
+  while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
     switch (opt) {
       case 'b':               /* Bold font */
        bold_font = g_strdup(optarg);
@@ -646,12 +1134,14 @@ main(int argc, char *argv[])
       case 'c':        /* Capture xxx packets */
         cf.count = atoi(optarg);
         break;
+#ifdef HAVE_LIBPCAP
       case 'f':
        cf.cfilter = g_strdup(optarg);
        break;
       case 'F':               /* Fork to capture */
         fork_mode = 1;
         break;
+#endif
       case 'h':        /* Print help and exit */
        print_usage();
        exit(0);
@@ -665,19 +1155,27 @@ main(int argc, char *argv[])
       case 'n':        /* No name resolution */
        g_resolving_actif = 0;
        break;
+#ifdef HAVE_LIBPCAP
       case 'k':        /* Start capture immediately */
         start_capture = 1;
         break;
+#endif
       case 'P':        /* Packet list pane height */
         pl_size = atoi(optarg);
         break;
+#ifdef HAVE_LIBPCAP
       case 'Q':        /* Quit after capture (just capture to file) */
         quit_after_cap = 1;
         start_capture = 1;  /*** -Q implies -k !! ***/
         break;
+#endif
       case 'r':        /* Read capture file xxx */
         cf_name = g_strdup(optarg);
         break;
+      case 'R':        /* Read file filter */
+        rfilter = optarg;
+        break;
+#ifdef HAVE_LIBPCAP
       case 's':        /* Set the snapshot (capture) length */
         cf.snap = atoi(optarg);
         break;
@@ -685,6 +1183,7 @@ main(int argc, char *argv[])
         sync_mode = 1;
         fork_mode = 1; /* -S implies -F */
         break;
+#endif
       case 't':        /* Time stamp type */
         if (strcmp(optarg, "r") == 0)
           timestamp_type = RELATIVE;
@@ -707,11 +1206,17 @@ main(int argc, char *argv[])
         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
         exit(0);
         break;
-      case 'w':        /* Write capture file xxx */
+#ifdef HAVE_LIBPCAP
+      case 'w':        /* Write to capture file xxx */
         cf.save_file = g_strdup(optarg);
        break;
+      case 'W':        /* Write to capture file FD xxx */
+        cf.save_file_fd = atoi(optarg);
+       break;
+#endif
     }
   }
+#endif
 
   if (start_capture) {
     if (cf.iface == NULL) {
@@ -722,26 +1227,36 @@ main(int argc, char *argv[])
       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-w\" flag\n");
       exit(1);
     }
+#ifdef HAVE_LIBPCAP
+    if (fork_mode) {
+      if (cf.save_file_fd == -1) {
+        fprintf(stderr, "ethereal: \"-k\" flag was specified with \"-%c\" flag but without \"-W\" flag\n",
+            (sync_mode ? 'S' : 'F'));
+        exit(1);
+      }
+    }
+#endif
   }
 
+#ifdef HAVE_LIBPCAP
   if (sync_mode)
     signal(SIGUSR2, sigusr2_handler);
+#endif
 
   /* Build the column format array */  
-  col_fmt   = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
+  col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
   
   for (i = 0; i < cf.cinfo.num_cols; i++) {
-    col_fmt[i]   = get_column_format(i);
-    cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
+    cf.cinfo.col_fmt[i] = get_column_format(i);
+    col_title[i] = g_strdup(get_column_title(i));
     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
       NUM_COL_FMTS);
-    get_column_format_matches(cf.cinfo.fmt_matx[i], col_fmt[i]);
+    get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
     cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
-    cf.cinfo.col_width[i] = 0;
   }
 
   if (cf.snap < 1)
-    cf.snap = MAX_PACKET_SIZE;
+    cf.snap = WTAP_MAX_PACKET_SIZE;
   else if (cf.snap < MIN_PACKET_SIZE)
     cf.snap = MIN_PACKET_SIZE;
   
@@ -780,11 +1295,7 @@ main(int argc, char *argv[])
 
   /* Menu bar */
   get_main_menu(&menubar, &accel);
-#ifdef GTK_HAVE_FEATURES_1_1_0
   gtk_window_add_accel_group(GTK_WINDOW(window), accel);
-#else
-  gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
-#endif
   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
   gtk_widget_show(menubar);
 
@@ -799,14 +1310,11 @@ main(int argc, char *argv[])
   gtk_widget_show(l_pane);
 
   /* Packet list */
-  packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols,
-    cf.cinfo.col_title);
+  packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, col_title);
   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
-#ifdef GTK_HAVE_FEATURES_1_1_4
   packet_sw = gtk_scrolled_window_new(NULL, NULL);
   gtk_widget_show(packet_sw);
   gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
-#endif
   pl_style = gtk_style_new();
   gdk_font_unref(pl_style->font);
   pl_style->font = m_r_font;
@@ -817,18 +1325,21 @@ main(int argc, char *argv[])
   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
   for (i = 0; i < cf.cinfo.num_cols; i++) {
-    gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
-      gdk_string_width(pl_style->font, cf.cinfo.col_title[i]));
-    if (col_fmt[i] == COL_NUMBER)
+    if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
+      gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
+
+    /* Right-justify the packet number column. */
+    if (cf.cinfo.col_fmt[i] == COL_NUMBER)
       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
         GTK_JUSTIFY_RIGHT);
+
+    /* Save static column sizes to use during a "-S" capture, so that
+       the columns don't resize during a live capture. */
+    cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
+                                               pl_style->font);
   }
   gtk_widget_set_usize(packet_list, -1, pl_size);
-#ifdef GTK_HAVE_FEATURES_1_1_4
   gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
-#else
-  gtk_paned_add1(GTK_PANED(u_pane), packet_list);
-#endif
   gtk_widget_show(packet_list);
   
   /* Tree view */
@@ -840,15 +1351,14 @@ main(int argc, char *argv[])
   gtk_widget_show(tv_scrollw);
   
   tree_view = gtk_tree_new();
-#ifdef GTK_HAVE_FEATURES_1_1_4
   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
                  tree_view);
-#else
-  gtk_container_add(GTK_CONTAINER(tv_scrollw), tree_view);
-#endif
   gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
+
+  /* XXX - what's the difference between the next two lines? */
   gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
-  gtk_tree_set_view_mode(GTK_TREE(tree_view), TRUE);
+  gtk_tree_set_view_mode(GTK_TREE(tree_view), GTK_TREE_VIEW_ITEM);
+
   gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
     GTK_SIGNAL_FUNC(tree_view_cb), NULL);
   gtk_widget_show(tree_view);
@@ -899,19 +1409,18 @@ main(int argc, char *argv[])
   filter_te = gtk_entry_new();
   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
+  gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
+    GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
   gtk_widget_show(filter_te);
 
-#ifdef USE_ITEM
+  /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
+   * of any widget that ends up calling a callback which needs
+   * that text entry pointer */
   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
-  set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
+  set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY,
     filter_te);
-#else
-  set_menu_object_data("<Main>/File/Open...", E_DFILTER_TE_KEY, filter_te);
-  set_menu_object_data("<Main>/File/Reload", E_DFILTER_TE_KEY, filter_te);
-  set_menu_object_data("<Main>/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
-    filter_te);
-#endif
+
   info_bar = gtk_statusbar_new();
   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
@@ -927,24 +1436,35 @@ main(int argc, char *argv[])
 
   gtk_widget_show(window);
 
+  colors_init(&cf);
+
   /* If we were given the name of a capture file, read it in now;
      we defer it until now, so that, if we can't open it, and pop
-     up an alert box, the alert box is more likely to cmoe up on
+     up an alert box, the alert box is more likely to come up on
      top of the main window - but before the preference-file-error
      alert box, so, if we get one of those, it's more likely to come
      up on top of us. */
   if (cf_name) {
-    err = load_cap_file(cf_name, &cf);
-    if (err != 0) {
-      simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
-               cf_name);
+    if (rfilter != NULL) {
+      rfcode = dfilter_new();
+      if (dfilter_compile(rfcode, rfilter) != 0) {
+        simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+        dfilter_destroy(rfcode);
+        rfilter_parse_failed = TRUE;
+      }
+    }
+    if (!rfilter_parse_failed) {
+      if ((err = open_cap_file(cf_name, &cf)) == 0) {
+        cf.rfcode = rfcode;
+        err = read_cap_file(&cf);
+        s = strrchr(cf_name, '/');
+        if (s) {
+          last_open_dir = cf_name;
+          *s = '\0';
+        }
+        set_menu_sensitivity("/File/Save As...", TRUE);
+      }
     }
-    cf_name[0] = '\0';
-#ifdef USE_ITEM
-    set_menu_sensitivity("/File/Save As...", TRUE);
-#else
-    set_menu_sensitivity("<Main>/File/Save As...", TRUE);
-#endif
   }
 
   /* If we failed to open the preferences file, pop up an alert box;
@@ -952,11 +1472,13 @@ main(int argc, char *argv[])
      come up on top of the main window. */
   if (pf_path != NULL) {
       simple_dialog(ESD_TYPE_WARN, NULL,
-        "Can't open preferences file\n\"%s\": %s.", pf_path,
+        "Could not open preferences file\n\"%s\": %s.", pf_path,
         strerror(pf_open_errno));
   }
 
   gtk_main();
 
+  ethereal_proto_cleanup();
+
   exit(0);
 }