Note in a comment that the display filter code has its own mechanism for
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 9e506d8d5ee60b1bc35aaadef33b5202fe5c7ec1..8f1cb1ba18c6fcdc1c5ec0213b2a869bd191f5c0 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,12 +1,11 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.237 2001/05/27 21:33:16 guy Exp $
+ * $Id: file.c,v 1.270 2002/04/24 05:48:43 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- *
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 # include <netinet/in.h>
 #endif
 
-#include <epan.h>
+#include <epan/epan.h>
+#include <epan/filesystem.h>
 
 #include "gtk/main.h"
 #include "color.h"
 #include "gtk/color_utils.h"
 #include "column.h"
-#include "packet.h"
+#include <epan/packet.h>
 #include "print.h"
 #include "file.h"
 #include "menu.h"
 #include "simple_dialog.h"
 #include "progress_dlg.h"
 #include "ui_util.h"
+#include "statusbar.h"
 #include "prefs.h"
 #include "gtk/proto_draw.h"
 #include "gtk/packet_win.h"
-#include "dfilter/dfilter.h"
-#include "conversation.h"
+#include <epan/dfilter/dfilter.h>
+#include <epan/conversation.h>
 #include "globals.h"
 #include "gtk/colors.h"
+#include <epan/epan_dissect.h>
+
+extern GtkWidget *packet_list, *byte_nb_ptr, *tree_view;
 
-extern GtkWidget *packet_list, *info_bar, *byte_nb_ptr, *tree_view;
-extern guint      file_ctx;
+#ifdef HAVE_LIBPCAP
+gboolean auto_scroll_live;
+#endif
 
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
 
-static void read_packet(capture_file *cf, int offset);
+static void read_packet(capture_file *cf, long offset);
 
 static void rescan_packets(capture_file *cf, const char *action,
        gboolean refilter, gboolean redissect);
@@ -123,7 +128,6 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 {
   wtap       *wth;
   int         err;
-  FILE_T      fh;
   int         fd;
   struct stat cf_stat;
 
@@ -132,7 +136,6 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
     goto fail;
 
   /* Find the size of the file. */
-  fh = wtap_file(wth);
   fd = wtap_fd(wth);
   if (fstat(fd, &cf_stat) < 0) {
     err = errno;
@@ -142,13 +145,10 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 
   /* The open succeeded.  Close whatever capture file we had open,
      and fill in the information for this file. */
-  close_cap_file(cf, info_bar);
-
-  /* Initialize the table of conversations. */
-  epan_conversation_init();
+  close_cap_file(cf);
 
-  /* Initialize protocol-specific variables */
-  init_all_protocols();
+  /* Initialize all data structures used for dissection. */
+  init_dissection();
 
   /* We're about to start reading the file. */
   cf->state = FILE_READ_IN_PROGRESS;
@@ -170,11 +170,18 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 
   cf->cd_t      = wtap_file_type(cf->wth);
   cf->count     = 0;
+  cf->marked_count = 0;
   cf->drops_known = FALSE;
   cf->drops     = 0;
   cf->esec      = 0;
   cf->eusec     = 0;
   cf->snap      = wtap_snapshot_length(cf->wth);
+  if (cf->snap == 0) {
+    /* Snapshot length not known. */
+    cf->has_snap = FALSE;
+    cf->snap = WTAP_MAX_PACKET_SIZE;
+  } else
+    cf->has_snap = TRUE;
   cf->progbar_quantum = 0;
   cf->progbar_nextstep = 0;
   firstsec = 0, firstusec = 0;
@@ -196,7 +203,7 @@ fail:
 
 /* Reset everything to a pristine state */
 void
-close_cap_file(capture_file *cf, void *w)
+close_cap_file(capture_file *cf)
 {
   /* Die if we're in the middle of reading a file. */
   g_assert(cf->state != FILE_READ_IN_PROGRESS);
@@ -242,7 +249,7 @@ close_cap_file(capture_file *cf, void *w)
   /* Clear any file-related status bar messages.
      XXX - should be "clear *ALL* file-related status bar messages;
      will there ever be more than one on the stack? */
-  gtk_statusbar_pop(GTK_STATUSBAR(w), file_ctx);
+  statusbar_pop_file_msg();
 
   /* Restore the standard title bar message. */
   set_main_window_name("The Ethereal Network Analyzer");
@@ -291,7 +298,7 @@ set_display_filename(capture_file *cf)
     done_msg = g_malloc(msg_len);
     snprintf(done_msg, msg_len, done_fmt_nodrops, name_ptr);
   }
-  gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, done_msg);
+  statusbar_push_file_msg(done_msg);
   g_free(done_msg);
 
   msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
@@ -304,23 +311,25 @@ set_display_filename(capture_file *cf)
 read_status_t
 read_cap_file(capture_file *cf, int *err)
 {
-  gchar    *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
-  size_t    msg_len;
-  char     *errmsg;
-  char      errmsg_errno[1024+1];
-  gchar     err_str[2048+1];
-  int       data_offset;
-  progdlg_t *progbar;
-  gboolean  stop_flag;
-  int       file_pos;
-  float     prog_val;
+  gchar      *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
+  size_t      msg_len;
+  char       *errmsg;
+  char        errmsg_errno[1024+1];
+  gchar       err_str[2048+1];
+  long        data_offset;
+  progdlg_t  *progbar;
+  gboolean    stop_flag;
+  int         file_pos;
+  float       prog_val;
+  int         fd;
+  struct stat cf_stat;
 
   name_ptr = get_basename(cf->filename);
 
   msg_len = strlen(name_ptr) + strlen(load_fmt) + 2;
   load_msg = g_malloc(msg_len);
   snprintf(load_msg, msg_len, load_fmt, name_ptr);
-  gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
+  statusbar_push_file_msg(load_msg);
 
   /* Update the progress bar when it gets to this value. */
   cf->progbar_nextstep = 0;
@@ -347,6 +356,21 @@ read_cap_file(capture_file *cf, int *err)
     if (data_offset >= cf->progbar_nextstep) {
         file_pos = lseek(cf->filed, 0, SEEK_CUR);
         prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
+        if (prog_val > 1.0) {
+          /* The file probably grew while we were reading it.
+             Update "cf->f_len", and try again. */
+          fd = wtap_fd(cf->wth);
+          if (fstat(fd, &cf_stat) >= 0) {
+            cf->f_len = cf_stat.st_size;
+            prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
+          }
+          /* If it's still > 1, either the "fstat()" failed (in which
+             case there's not much we can do about it), or the file
+             *shrank* (in which case there's not much we can do about
+             it); just clip the progress value at 1.0. */
+          if (prog_val > 1.0)
+            prog_val = 1.0;
+        }
         update_progress_dlg(progbar, prog_val);
         cf->progbar_nextstep += cf->progbar_quantum;
     }
@@ -358,7 +382,7 @@ read_cap_file(capture_file *cf, int *err)
       destroy_progress_dlg(progbar);
       cf->state = FILE_READ_ABORTED;   /* so that we're allowed to close it */
       gtk_clist_thaw(GTK_CLIST(packet_list));  /* undo our freeze */
-      close_cap_file(cf, info_bar);
+      close_cap_file(cf);
       return (READ_ABORTED);
     }
     read_packet(cf, data_offset);
@@ -373,6 +397,10 @@ read_cap_file(capture_file *cf, int *err)
   /* Close the sequential I/O side, to free up memory it requires. */
   wtap_sequential_close(cf->wth);
 
+  /* Allow the protocol dissectors to free up memory that they
+   * don't need after the sequential run-through of the packets. */
+  postseq_cleanup_all_protocols();
+
   /* Set the file encapsulation type now; we don't know what it is until
      we've looked at all the packets, as we don't know until then whether
      there's more than one type (and thus whether it's
@@ -382,7 +410,7 @@ read_cap_file(capture_file *cf, int *err)
   cf->current_frame = cf->first_displayed;
   thaw_clist(cf);
 
-  gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+  statusbar_pop_file_msg();
   set_display_filename(cf);
 
   /* Enable menu items that make sense if you have a capture file you've
@@ -464,8 +492,7 @@ start_tail_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
       }
     }
 
-    gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, 
-                      " <live capture in progress>");
+    statusbar_push_file_msg(" <live capture in progress>");
   }
   return err;
 }
@@ -473,7 +500,7 @@ start_tail_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 read_status_t
 continue_tail_cap_file(capture_file *cf, int to_read, int *err)
 {
-  int data_offset = 0;
+  long data_offset = 0;
 
   gtk_clist_freeze(GTK_CLIST(packet_list));
 
@@ -492,7 +519,7 @@ continue_tail_cap_file(capture_file *cf, int to_read, int *err)
 
   /* XXX - this cheats and looks inside the packet list to find the final
      row number. */
-  if (prefs.capture_auto_scroll && cf->plist_end != NULL)
+  if (auto_scroll_live && cf->plist_end != NULL)
     gtk_clist_moveto(GTK_CLIST(packet_list), 
                       GTK_CLIST(packet_list)->rows - 1, -1, 1.0, 1.0);
 
@@ -514,7 +541,7 @@ continue_tail_cap_file(capture_file *cf, int to_read, int *err)
 read_status_t
 finish_tail_cap_file(capture_file *cf, int *err)
 {
-  int data_offset;
+  long data_offset;
 
   gtk_clist_freeze(GTK_CLIST(packet_list));
 
@@ -534,12 +561,12 @@ finish_tail_cap_file(capture_file *cf, int *err)
        it's probably exited), so we can just close the capture
        file; we return READ_ABORTED so our caller can do whatever
        is appropriate when that happens. */
-    close_cap_file(cf, info_bar);
+    close_cap_file(cf);
     return READ_ABORTED;
   }
 
   thaw_clist(cf);
-  if (prefs.capture_auto_scroll && cf->plist_end != NULL)
+  if (auto_scroll_live && cf->plist_end != NULL)
     /* XXX - this cheats and looks inside the packet list to find the final
        row number. */
     gtk_clist_moveto(GTK_CLIST(packet_list), 
@@ -552,6 +579,10 @@ finish_tail_cap_file(capture_file *cf, int *err)
      sequential I/O side, to free up memory it requires. */
   wtap_sequential_close(cf->wth);
 
+  /* Allow the protocol dissectors to free up memory that they
+   * don't need after the sequential run-through of the packets. */
+  postseq_cleanup_all_protocols();
+
   /* Set the file encapsulation type now; we don't know what it is until
      we've looked at all the packets, as we don't know until then whether
      there's more than one type (and thus whether it's
@@ -559,7 +590,7 @@ finish_tail_cap_file(capture_file *cf, int *err)
   cf->lnk_t = wtap_file_encap(cf->wth);
 
   /* Pop the "<live capture in progress>" message off the status bar. */
-  gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+  statusbar_pop_file_msg();
 
   set_display_filename(cf);
 
@@ -609,8 +640,8 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
        gboolean refilter)
 {
   apply_color_filter_args args;
-  gint          i, row;
-  proto_tree   *protocol_tree = NULL;
+  gint          row;
+  gboolean     create_proto_tree = FALSE;
   epan_dissect_t *edt;
   GdkColor      fg, bg;
 
@@ -625,12 +656,6 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     firstusec = fdata->abs_usecs;
   }
 
-  fdata->cinfo = &cf->cinfo;
-  for (i = 0; i < fdata->cinfo->num_cols; i++) {
-    fdata->cinfo->col_buf[i][0] = '\0';
-    fdata->cinfo->col_data[i] = fdata->cinfo->col_buf[i];
-  }
-
   /* If either
 
        we have a display filter and are re-applying it;
@@ -641,10 +666,19 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
      a protocol tree against which a filter expression can be
      evaluated. */
   if ((cf->dfcode != NULL && refilter) || filter_list != NULL)
-    protocol_tree = proto_tree_create_root();
+         create_proto_tree = TRUE;
 
   /* Dissect the frame. */
-  edt = epan_dissect_new(pseudo_header, buf, fdata, protocol_tree);
+  edt = epan_dissect_new(create_proto_tree, FALSE);
+
+  if (cf->dfcode != NULL && refilter) {
+      epan_dissect_prime_dfilter(edt, cf->dfcode);
+  }
+  if (filter_list) {
+      filter_list_prime_edt(edt);
+  }
+  epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
+
 
   /* If we have a display filter, apply it if we're refiltering, otherwise
      leave the "passed_dfilter" flag alone.
@@ -669,12 +703,6 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     }
   }
 
-  /* There are no more filters to apply, so we don't need any protocol
-     tree; free it if we created it. */
-  if (protocol_tree != NULL)
-    proto_tree_free(protocol_tree);
-
-  epan_dissect_free(edt);
 
   if (fdata->flags.passed_dfilter) {
     /* This frame passed the display filter, so add it to the clist. */
@@ -695,8 +723,8 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     /* If it's greater than the current elapsed time, set the elapsed time
        to it (we check for "greater than" so as not to be confused by
        time moving backwards). */
-    if (cf->esec < fdata->rel_secs
-       || (cf->esec == fdata->rel_secs && cf->eusec < fdata->rel_usecs)) {
+    if ((gint32)cf->esec < fdata->rel_secs
+       || ((gint32)cf->esec == fdata->rel_secs && (gint32)cf->eusec < fdata->rel_usecs)) {
       cf->esec = fdata->rel_secs;
       cf->eusec = fdata->rel_usecs;
     }
@@ -708,7 +736,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     prevsec = fdata->abs_secs;
     prevusec = fdata->abs_usecs;
 
-    fill_in_columns(fdata);
+    epan_dissect_fill_in_columns(edt);
 
     /* If we haven't yet seen the first frame, this is it.
 
@@ -729,7 +757,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     /* This is the last frame we've seen so far. */
     cf->last_displayed = fdata;
 
-    row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
+    row = gtk_clist_append(GTK_CLIST(packet_list), cf->cinfo.col_data);
     gtk_clist_set_row_data(GTK_CLIST(packet_list), row, fdata);
 
     if (fdata->flags.marked) {
@@ -749,19 +777,18 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
        to the clist, and thus has no row. */
     row = -1;
   }
-  fdata->cinfo = NULL;
+  epan_dissect_free(edt);
   return row;
 }
 
 static void
-read_packet(capture_file *cf, int offset)
+read_packet(capture_file *cf, long offset)
 {
   const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
   union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
   const u_char *buf = wtap_buf_ptr(cf->wth);
   frame_data   *fdata;
   int           passed;
-  proto_tree   *protocol_tree;
   frame_data   *plist_end;
   epan_dissect_t *edt;
 
@@ -781,14 +808,13 @@ read_packet(capture_file *cf, int offset)
   fdata->flags.encoding = CHAR_ASCII;
   fdata->flags.visited = 0;
   fdata->flags.marked = 0;
-  fdata->cinfo = NULL;
 
   passed = TRUE;
   if (cf->rfcode) {
-    protocol_tree = proto_tree_create_root();
-    edt = epan_dissect_new(pseudo_header, buf, fdata, protocol_tree);
+    edt = epan_dissect_new(TRUE, FALSE);
+    epan_dissect_prime_dfilter(edt, cf->rfcode);
+    epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
     passed = dfilter_apply_edt(cf->rfcode, edt);
-    proto_tree_free(protocol_tree);
     epan_dissect_free(edt);
   }   
   if (passed) {
@@ -888,7 +914,8 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
   gboolean stop_flag;
   guint32 progbar_quantum;
   guint32 progbar_nextstep;
-  int count;
+  unsigned int count;
+  int err;
   frame_data *selected_frame;
   int selected_row;
   int row;
@@ -909,11 +936,8 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
        which might cause the state information to be constructed differently
        by that dissector. */
 
-    /* Initialize the table of conversations. */
-    epan_conversation_init();
-
-    /* Initialize protocol-specific variables */
-    init_all_protocols();
+    /* Initialize all data structures used for dissection. */
+    init_dissection();
   }
 
   /* Freeze the packet list while we redo it, so we don't get any
@@ -985,20 +1009,18 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
       /* Since all state for the frame was destroyed, mark the frame
        * as not visited, free the GSList referring to the state
        * data (the per-frame data itself was freed by
-       * "init_all_protocols()"), and null out the GSList pointer. */
+       * "init_dissection()"), and null out the GSList pointer. */
       fdata->flags.visited = 0;
       if (fdata->pfd) {
        g_slist_free(fdata->pfd);
+        fdata->pfd = NULL;
       }
-      fdata->pfd = NULL;
-      if (fdata->data_src) {   /* release data source list */
-       g_slist_free(fdata->data_src);
-      }
-      fdata->data_src = NULL;
+      free_data_sources(fdata);        /* release data source list */
     }
 
+    /* XXX - do something with "err" */
     wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-       cf->pd, fdata->cap_len);
+       cf->pd, fdata->cap_len, &err);
 
     row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
                                        refilter);
@@ -1020,12 +1042,9 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
       fdata->flags.visited = 0;
       if (fdata->pfd) {
        g_slist_free(fdata->pfd);
+        fdata->pfd = NULL;
       }
-      fdata->pfd = NULL;
-      if (fdata->data_src) {
-       g_slist_free(fdata->data_src);
-      }
-      fdata->data_src = NULL;
+      free_data_sources(fdata);        /* release data source list */
     }
   }
 
@@ -1058,7 +1077,7 @@ print_packets(capture_file *cf, print_args_t *print_args)
   guint32     progbar_quantum;
   guint32     progbar_nextstep;
   guint32     count;
-  proto_tree *protocol_tree;
+  int         err;
   gint       *col_widths = NULL;
   gint        data_width;
   gboolean    print_separator;
@@ -1127,10 +1146,6 @@ print_packets(capture_file *cf, print_args_t *print_args)
 
   print_separator = FALSE;
 
-  /* The protocol tree will be "visible", i.e., printed, only if we're
-     not printing a summary. */
-  proto_tree_is_visible = !print_args->print_summary;
-
   /* Update the progress bar when it gets to this value. */
   progbar_nextstep = 0;
   /* When we reach the value that triggers a progress bar update,
@@ -1172,20 +1187,20 @@ print_packets(capture_file *cf, print_args_t *print_args)
     }
 
     count++;
-
-    if (fdata->flags.passed_dfilter) {
+    /* Check to see if we are suppressing unmarked packets, if so, 
+     * suppress them and then proceed to check for visibility.
+     */
+    if (((print_args->suppress_unmarked && fdata->flags.marked ) ||
+        !(print_args->suppress_unmarked)) && fdata->flags.passed_dfilter) {
+      /* XXX - do something with "err" */
       wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-                       cf->pd, fdata->cap_len);
+                       cf->pd, fdata->cap_len, &err);
       if (print_args->print_summary) {
         /* Fill in the column information, but don't bother creating
            the logical protocol tree. */
-        fdata->cinfo = &cf->cinfo;
-        for (i = 0; i < fdata->cinfo->num_cols; i++) {
-          fdata->cinfo->col_buf[i][0] = '\0';
-          fdata->cinfo->col_data[i] = fdata->cinfo->col_buf[i];
-        }
-        edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, NULL);
-        fill_in_columns(fdata);
+        edt = epan_dissect_new(FALSE, FALSE);
+        epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
+        epan_dissect_fill_in_columns(edt);
         cp = &line_buf[0];
         line_len = 0;
         for (i = 0; i < cf->cinfo.num_cols; i++) {
@@ -1219,15 +1234,15 @@ print_packets(capture_file *cf, print_args_t *print_args)
         if (print_separator)
           print_line(cf->print_fh, print_args->format, "\n");
 
-        /* Create the logical protocol tree. */
-        protocol_tree = proto_tree_create_root();
-        edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
+        /* Create the logical protocol tree, complete with the display
+           representation of the items; we don't need the columns here,
+           however. */
+        edt = epan_dissect_new(TRUE, TRUE);
+        epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
 
         /* Print the information in that tree. */
-        proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
-                       cf->pd, fdata, cf->print_fh);
-
-        proto_tree_free(protocol_tree);
+        proto_tree_print(print_args, (GNode *)edt->tree,
+                       fdata, cf->print_fh);
 
        if (print_args->print_hex) {
          /* Print the full packet data as hex. */
@@ -1255,8 +1270,6 @@ print_packets(capture_file *cf, print_args_t *print_args)
  
   cf->print_fh = NULL;
 
-  proto_tree_is_visible = FALSE;
-
   return TRUE;
 }
 
@@ -1271,11 +1284,23 @@ change_time_formats(capture_file *cf)
   gboolean stop_flag;
   guint32 progbar_quantum;
   guint32 progbar_nextstep;
-  int count;
+  unsigned int count;
   int row;
   int i;
   GtkStyle  *pl_style;
 
+  /* Are there any columns with time stamps in the "command-line-specified"
+     format?
+
+     XXX - we have to force the "column is writable" flag on, as it
+     might be off from the last frame that was dissected. */
+  col_set_writable(&cf->cinfo, TRUE);
+  if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
+    /* No, there aren't any columns in that format, so we have no work
+       to do. */
+    return;
+  }
+
   /* Freeze the packet list while we redo it, so we don't get any
      screen updates while it happens. */
   freeze_clist(cf);
@@ -1329,23 +1354,14 @@ change_time_formats(capture_file *cf)
     if (row != -1) {
       /* This packet is in the summary list, on row "row". */
 
-      /* XXX - there really should be a way of checking "cf->cinfo" for this;
-         the answer isn't going to change from packet to packet, so we should
-         simply skip all the "change_time_formats()" work if we're not
-         changing anything. */
-      fdata->cinfo = &cf->cinfo;
-      if (check_col(fdata, COL_CLS_TIME)) {
-        /* There are columns that show the time in the "command-line-specified"
-           format; update them. */
-        for (i = 0; i < cf->cinfo.num_cols; i++) {
-          if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
-            /* This is one of the columns that shows the time in
-               "command-line-specified" format; update it. */
-            cf->cinfo.col_buf[i][0] = '\0';
-            col_set_cls_time(fdata, i);
-            gtk_clist_set_text(GTK_CLIST(packet_list), row, i,
-                         cf->cinfo.col_data[i]);
-         }
+      for (i = 0; i < cf->cinfo.num_cols; i++) {
+        if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
+          /* This is one of the columns that shows the time in
+             "command-line-specified" format; update it. */
+          cf->cinfo.col_buf[i][0] = '\0';
+          col_set_cls_time(fdata, &cf->cinfo, i);
+          gtk_clist_set_text(GTK_CLIST(packet_list), row, i,
+                            cf->cinfo.col_data[i]);
         }
       }
     }
@@ -1368,34 +1384,6 @@ change_time_formats(capture_file *cf)
   thaw_clist(cf);
 }
 
-static void
-clear_tree_and_hex_views(void)
-{
-  /* Clear the hex dump. */
-
-  GtkWidget *byte_view;
-  int i;
-
-/* Get the current tab scroll window, then get the text widget  */
-/* from the E_BYTE_VIEW_TEXT_INFO_KEY data field               */
-
-  i = gtk_notebook_get_current_page( GTK_NOTEBOOK(byte_nb_ptr));
-
-  if ( i >= 0){
-    byte_view = gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), i);
-    byte_view = gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_TEXT_INFO_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)));
-    gtk_text_thaw(GTK_TEXT(byte_view));
-  }
-  /* Remove all nodes in ctree. This is how it's done in testgtk.c in GTK+ */
-  gtk_clist_clear ( GTK_CLIST(tree_view) );
-
-}
-
 gboolean
 find_packet(capture_file *cf, dfilter_t *sfcode)
 {
@@ -1406,8 +1394,8 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
   gboolean stop_flag;
   guint32 progbar_quantum;
   guint32 progbar_nextstep;
-  int count;
-  proto_tree *protocol_tree;
+  unsigned int count;
+  int err;
   gboolean frame_matched;
   int row;
   epan_dissect_t       *edt;
@@ -1472,13 +1460,14 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
       /* Is this packet in the display? */
       if (fdata->flags.passed_dfilter) {
         /* Yes.  Does it match the search filter? */
-        protocol_tree = proto_tree_create_root();
+        /* XXX - do something with "err" */
         wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
-                       cf->pd, fdata->cap_len);
-        edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
+                       cf->pd, fdata->cap_len, &err);
+        edt = epan_dissect_new(TRUE, FALSE);
+        epan_dissect_prime_dfilter(edt, sfcode);
+        epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
         frame_matched = dfilter_apply_edt(sfcode, edt);
-        proto_tree_free(protocol_tree);
-       epan_dissect_free(edt);
+        epan_dissect_free(edt);
         if (frame_matched) {
           new_fd = fdata;
           break;       /* found it! */
@@ -1537,8 +1526,7 @@ void
 select_packet(capture_file *cf, int row)
 {
   frame_data *fdata;
-  tvbuff_t *bv_tvb;
-  int i;
+  int err;
 
   /* Get the frame data struct pointer for this frame */
   fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
@@ -1578,33 +1566,26 @@ select_packet(capture_file *cf, int row)
   cf->current_frame = fdata;
 
   /* Get the data in that frame. */
+  /* XXX - do something with "err" */
   wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-                       cf->pd, fdata->cap_len);
+                       cf->pd, fdata->cap_len, &err);
 
   /* Create the logical protocol tree. */
-  if (cf->protocol_tree)
-      proto_tree_free(cf->protocol_tree);
-  cf->protocol_tree = proto_tree_create_root();
-  proto_tree_is_visible = TRUE;
   if (cf->edt != NULL) {
     epan_dissect_free(cf->edt);
     cf->edt = NULL;
   }
-  cf->edt = epan_dissect_new(&cf->pseudo_header, cf->pd, cf->current_frame,
-               cf->protocol_tree);
-  proto_tree_is_visible = FALSE;
-
-  /* Display the GUI protocol tree and hex dump. */
-  clear_tree_and_hex_views();
-
-  i = 0; 
-  while((bv_tvb = g_slist_nth_data ( cf->current_frame->data_src, i++))){
-       add_byte_view( tvb_get_name( bv_tvb), tvb_get_ptr(bv_tvb, 0, -1), tvb_length(bv_tvb));
-  }
-
-  proto_tree_draw(cf->protocol_tree, tree_view);
-
-  set_notebook_page( byte_nb_ptr, 0);
+  /* We don't need the columns here. */
+  cf->edt = epan_dissect_new(TRUE, TRUE);
+  epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
+          NULL);
+
+  /* Display the GUI protocol tree and hex dump.
+     XXX - why do we dump core if we call "proto_tree_draw()"
+     before calling "add_byte_views()"? */
+  add_byte_views(cf->current_frame, cf->edt->tree, tree_view,
+      byte_nb_ptr);
+  proto_tree_draw(cf->edt->tree, tree_view);
 
   /* A packet is selected. */
   set_menus_for_selected_packet(TRUE);
@@ -1614,23 +1595,20 @@ select_packet(capture_file *cf, int row)
 void
 unselect_packet(capture_file *cf)
 {
-  /* Destroy the protocol tree and epan_dissect_t for that packet. */
-  if (cf->protocol_tree != NULL) {
-    proto_tree_free(cf->protocol_tree);
-    cf->protocol_tree = NULL;
-  }
+  /* Destroy the epan_dissect_t for the unselected packet. */
   if (cf->edt != NULL) {
     epan_dissect_free(cf->edt);
     cf->edt = NULL;
   }
 
-  finfo_selected = NULL;
-
   /* Clear out the display of that packet. */
   clear_tree_and_hex_views();
 
   /* No packet is selected. */
   set_menus_for_selected_packet(FALSE);
+
+  /* No protocol tree means no selected field. */
+  unselect_field();
 }
 
 /* Set the selected row and the focus row of the packet list to the specified
@@ -1654,6 +1632,35 @@ set_selected_row(int row)
   gtk_clist_select_row(GTK_CLIST(packet_list), row, -1);
 }
 
+/* Unset the selected protocol tree field, if any. */
+void
+unselect_field(void)
+{
+  statusbar_pop_field_msg();
+  finfo_selected = NULL;
+  set_menus_for_selected_tree_row(FALSE);
+}
+
+/*
+ * Mark a particular frame.
+ */
+void
+mark_frame(capture_file *cf, frame_data *frame)
+{
+  frame->flags.marked = TRUE;
+  cf->marked_count++;
+}
+
+/*
+ * Unmark a particular frame.
+ */
+void
+unmark_frame(capture_file *cf, frame_data *frame)
+{
+  frame->flags.marked = FALSE;
+  cf->marked_count--;
+}
+
 static void
 freeze_clist(capture_file *cf)
 {
@@ -1711,7 +1718,7 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
   msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
   save_msg = g_malloc(msg_len);
   snprintf(save_msg, msg_len, save_fmt, name_ptr);
-  gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, save_msg);
+  statusbar_push_file_msg(save_msg);
   g_free(save_msg);
 
   if (!save_filtered && !save_marked && save_format == cf->cd_t) {
@@ -1760,8 +1767,18 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
       do_copy = TRUE;
       from_filename = cf->filename;
     }
-    /* Copy the file, if we haven't moved it. */
+
+    /* Check that the from file is not the same as to file */
+
     if (do_copy) {
+
+            /* Copy the file, if we haven't moved it. */
+           if (strncmp(from_filename, fname, sizeof(cf->filename)) == 0) {
+                   simple_dialog(ESD_TYPE_WARN, NULL, 
+                                 "Can't save over current capture file: %s!", from_filename);
+                   goto done;
+           }
+
            if (!copy_binary_file(from_filename, fname)) {
                goto done;
            }
@@ -1801,8 +1818,13 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
         hdr.caplen = fdata->cap_len;
         hdr.len = fdata->pkt_len;
         hdr.pkt_encap = fdata->lnk_t;
-       wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
-               pd, fdata->cap_len);
+       if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
+               pd, fdata->cap_len, &err)) {
+           simple_dialog(ESD_TYPE_CRIT, NULL,
+                               file_read_error_message(err), cf->filename);
+           wtap_dump_close(pdh, &err);
+           goto done;
+       }
 
         if (!wtap_dump(pdh, &hdr, &pseudo_header, pd, &err)) {
            simple_dialog(ESD_TYPE_CRIT, NULL,
@@ -1823,7 +1845,7 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
 done:
 
   /* Pop the "Saving:" message off the status bar. */
-  gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+  statusbar_pop_file_msg();
   if (err == 0) {
     if (!save_filtered && !save_marked) {
       /* We saved the entire capture, not just some packets from it.
@@ -1907,7 +1929,7 @@ file_open_error_message(int err, gboolean for_writing)
 
   case WTAP_ERR_SHORT_READ:
     errmsg = "The file \"%s\" appears to have been cut short"
-             " in the middle of a packet.";
+             " in the middle of a packet or other data.";
     break;
 
   case WTAP_ERR_SHORT_WRITE: