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 fd13554f904ddb4564a2b98a6bbf2f10dd72d784..8f1cb1ba18c6fcdc1c5ec0213b2a869bd191f5c0 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,12 +1,11 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.206 2000/08/15 21:03:16 deniel Exp $
+ * $Id: file.c,v 1.270 2002/04/24 05:48:43 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * 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/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 "util.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 "dfilter.h"
-#include "conversation.h"
+#include "gtk/packet_win.h"
+#include <epan/dfilter/dfilter.h>
+#include <epan/conversation.h>
 #include "globals.h"
+#include "gtk/colors.h"
+#include <epan/epan_dissect.h>
 
-#include "plugins.h"
-
-extern GtkWidget *packet_list, *info_bar, *byte_view, *tree_view;
-extern guint      file_ctx;
+extern GtkWidget *packet_list, *byte_nb_ptr, *tree_view;
 
-gboolean auto_scroll_live = FALSE;
+#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 refilter, gboolean redissect);
 
 static void set_selected_row(int row);
 
@@ -120,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;
 
@@ -129,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;
@@ -139,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. */
-  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;
@@ -167,10 +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;
@@ -192,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);
@@ -221,7 +232,7 @@ close_cap_file(capture_file *cf, void *w)
     cf->plist_chunk = NULL;
   }
   if (cf->rfcode != NULL) {
-    dfilter_destroy(cf->rfcode);
+    dfilter_free(cf->rfcode);
     cf->rfcode = NULL;
   }
   cf->plist = NULL;
@@ -238,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");
@@ -262,7 +273,8 @@ set_display_filename(capture_file *cf)
 {
   gchar  *name_ptr;
   size_t  msg_len;
-  gchar  *done_fmt = " File: %s  Drops: %u";
+  static const gchar done_fmt_nodrops[] = " File: %s";
+  static const gchar done_fmt_drops[] = " File: %s  Drops: %u";
   gchar  *done_msg;
   gchar  *win_name_fmt = "%s - Ethereal";
   gchar  *win_name;
@@ -277,10 +289,16 @@ set_display_filename(capture_file *cf)
     name_ptr = "<capture>";
   }
 
-  msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
-  done_msg = g_malloc(msg_len);
-  snprintf(done_msg, msg_len, done_fmt, name_ptr, cf->drops);
-  gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, done_msg);
+  if (cf->drops_known) {
+    msg_len = strlen(name_ptr) + strlen(done_fmt_drops) + 64;
+    done_msg = g_malloc(msg_len);
+    snprintf(done_msg, msg_len, done_fmt_drops, name_ptr, cf->drops);
+  } else {
+    msg_len = strlen(name_ptr) + strlen(done_fmt_nodrops);
+    done_msg = g_malloc(msg_len);
+    snprintf(done_msg, msg_len, done_fmt_nodrops, name_ptr);
+  }
+  statusbar_push_file_msg(done_msg);
   g_free(done_msg);
 
   msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
@@ -293,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;
@@ -327,7 +347,7 @@ read_cap_file(capture_file *cf, int *err)
   progbar = create_progress_dlg(load_msg, "Stop", &stop_flag);
   g_free(load_msg);
 
-  while ((data_offset = wtap_read(cf->wth, err)) > 0) {
+  while ((wtap_read(cf->wth, err, &data_offset))) {
     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
        when we update it, we have to run the GTK+ main loop to get it
        to repaint what's pending, and doing so may involve an "ioctl()"
@@ -336,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;
     }
@@ -347,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);
@@ -362,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
@@ -371,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
@@ -387,7 +426,7 @@ read_cap_file(capture_file *cf, int *err)
   if (cf->first_displayed != NULL)
     gtk_signal_emit_by_name(GTK_OBJECT(packet_list), "select_row", 0);
 
-  if (data_offset < 0) {
+  if (*err != 0) {
     /* Put up a message box noting that the read failed somewhere along
        the line.  Don't throw out the stuff we managed to read, though,
        if any. */
@@ -412,8 +451,9 @@ read_cap_file(capture_file *cf, int *err)
       break;
 
     default:
-      sprintf(errmsg_errno, "An error occurred while reading the"
-                              " capture file: %s.", wtap_strerror(*err));
+      snprintf(errmsg_errno, sizeof(errmsg_errno),
+              "An error occurred while reading the"
+              " capture file: %s.", wtap_strerror(*err));
       errmsg = errmsg_errno;
       break;
     }
@@ -452,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;
 }
@@ -461,11 +500,11 @@ 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));
 
-  while (to_read != 0 && (data_offset = wtap_read(cf->wth, err)) > 0) {
+  while (to_read != 0 && (wtap_read(cf->wth, err, &data_offset))) {
     if (cf->state == FILE_READ_ABORTED) {
       /* Well, the user decided to exit Ethereal.  Break out of the
          loop, and let the code below (which is called even if there
@@ -491,7 +530,7 @@ continue_tail_cap_file(capture_file *cf, int to_read, int *err)
        "finish_tail_cap_file()" will be called, and it will clean up
        and exit. */
     return READ_ABORTED;
-  } else if (data_offset < 0) {
+  } else if (*err != 0) {
     /* We got an error reading the capture file.
        XXX - pop up a dialog box? */
     return (READ_ERROR);
@@ -502,11 +541,11 @@ 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));
 
-  while ((data_offset = wtap_read(cf->wth, err)) > 0) {
+  while ((wtap_read(cf->wth, err, &data_offset))) {
     if (cf->state == FILE_READ_ABORTED) {
       /* Well, the user decided to abort the read.  Break out of the
          loop, and let the code below (which is called even if there
@@ -522,7 +561,7 @@ 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;
   }
 
@@ -540,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
@@ -547,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);
 
@@ -560,7 +603,7 @@ finish_tail_cap_file(capture_file *cf, int *err)
   set_menus_for_capture_file(TRUE);
   set_menus_for_unsaved_capture_file(!cf->user_saved);
 
-  if (data_offset < 0) {
+  if (*err != 0) {
     /* We got an error reading the capture file.
        XXX - pop up a dialog box? */
     return (READ_ERROR);
@@ -571,9 +614,7 @@ finish_tail_cap_file(capture_file *cf, int *err)
 
 typedef struct {
   color_filter_t *colorf;
-  proto_tree   *protocol_tree;
-  const guint8 *pd;
-  frame_data   *fdata;
+  epan_dissect_t *edt;
 } apply_color_filter_args;
 
 /*
@@ -588,7 +629,7 @@ apply_color_filter(gpointer filter_arg, gpointer argp)
   apply_color_filter_args *args = argp;
 
   if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
-    if (dfilter_apply(colorf->c_colorfilter, args->protocol_tree, args->pd, args->fdata->cap_len))
+    if (dfilter_apply_edt(colorf->c_colorfilter, args->edt))
       args->colorf = colorf;
   }
 }
@@ -599,8 +640,10 @@ 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;
 
   /* We don't yet have a color filter to apply. */
   args.colorf = NULL;
@@ -613,40 +656,29 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     firstusec = fdata->abs_usecs;
   }
 
-  /* Get the time elapsed between the first packet and this packet. */
-  cf->esec = fdata->abs_secs - firstsec;
-  if (firstusec <= fdata->abs_usecs) {
-    cf->eusec = fdata->abs_usecs - firstusec;
-  } else {
-    cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
-    cf->esec--;
-  }
-
-  fdata->cinfo = &cf->cinfo;
-  for (i = 0; i < fdata->cinfo->num_cols; i++) {
-    fdata->cinfo->col_data[i][0] = '\0';
-  }
-
   /* If either
 
        we have a display filter and are re-applying it;
 
        we have a list of color filters;
 
-       we have plugins to apply;
-
      allocate a protocol tree root node, so that we'll construct
      a protocol tree against which a filter expression can be
      evaluated. */
-  if ((cf->dfcode != NULL && refilter) || filter_list != NULL
-#ifdef HAVE_PLUGINS
-       || enabled_plugins_number > 0
-#endif
-       )
-    protocol_tree = proto_tree_create_root();
+  if ((cf->dfcode != NULL && refilter) || filter_list != NULL)
+         create_proto_tree = TRUE;
 
   /* Dissect the frame. */
-  dissect_packet(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.
@@ -655,7 +687,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
   if (cf->dfcode != NULL) {
     if (refilter) {
       if (cf->dfcode != NULL)
-        fdata->flags.passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, buf, fdata->cap_len) ? 1 : 0;
+        fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
       else
         fdata->flags.passed_dfilter = 1;
     }
@@ -666,17 +698,11 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
      the color filters. */
   if (fdata->flags.passed_dfilter) {
     if (filter_list != NULL) {
-      args.protocol_tree = protocol_tree;
-      args.pd = buf;
-      args.fdata = fdata;
+      args.edt = edt;
       g_slist_foreach(filter_list, apply_color_filter, &args);
     }
   }
 
-  /* 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);
 
   if (fdata->flags.passed_dfilter) {
     /* This frame passed the display filter, so add it to the clist. */
@@ -691,22 +717,26 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     }
 
     /* Get the time elapsed between the first packet and this packet. */
-    fdata->rel_secs = cf->esec;
-    fdata->rel_usecs = cf->eusec;
+    compute_timestamp_diff(&fdata->rel_secs, &fdata->rel_usecs,
+               fdata->abs_secs, fdata->abs_usecs, firstsec, firstusec);
+
+    /* 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 ((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;
+    }
   
     /* Get the time elapsed between the previous displayed packet and
        this packet. */
-    fdata->del_secs = fdata->abs_secs - prevsec;
-    if (prevusec <= fdata->abs_usecs) {
-      fdata->del_usecs = fdata->abs_usecs - prevusec;
-    } else {
-      fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
-      fdata->del_secs--;
-    }
+    compute_timestamp_diff(&fdata->del_secs, &fdata->del_usecs,
+               fdata->abs_secs, fdata->abs_usecs, prevsec, prevusec);
     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.
 
@@ -727,37 +757,40 @@ 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 (filter_list != NULL && (args.colorf != NULL)) {
-        gtk_clist_set_background(GTK_CLIST(packet_list), row,
-                   &args.colorf->bg_color);
-        gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
-                   &args.colorf->fg_color);
+    if (fdata->flags.marked) {
+       color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
+       color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
+    } else if (filter_list != NULL && (args.colorf != NULL)) {
+       bg = args.colorf->bg_color;
+       fg = args.colorf->fg_color;
     } else {
-        gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
-        gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
+       bg = WHITE;
+       fg = BLACK;
     }
+    gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
+    gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
   } else {
     /* This frame didn't pass the display filter, so it's not being added
        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;
 
   /* Allocate the next list entry, and add it to the list. */
   fdata = g_mem_chunk_alloc(cf->plist_chunk);
@@ -765,6 +798,7 @@ read_packet(capture_file *cf, int offset)
   fdata->next = NULL;
   fdata->prev = NULL;
   fdata->pfd  = NULL;
+  fdata->data_src  = NULL;
   fdata->pkt_len  = phdr->len;
   fdata->cap_len  = phdr->caplen;
   fdata->file_off = offset;
@@ -773,14 +807,15 @@ read_packet(capture_file *cf, int offset)
   fdata->abs_usecs = phdr->ts.tv_usec;
   fdata->flags.encoding = CHAR_ASCII;
   fdata->flags.visited = 0;
-  fdata->cinfo = NULL;
+  fdata->flags.marked = 0;
 
   passed = TRUE;
   if (cf->rfcode) {
-    protocol_tree = proto_tree_create_root();
-    dissect_packet(pseudo_header, buf, fdata, protocol_tree);
-    passed = dfilter_apply(cf->rfcode, protocol_tree, buf, fdata->cap_len);
-    proto_tree_free(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);
+    epan_dissect_free(edt);
   }   
   if (passed) {
     plist_end = cf->plist_end;
@@ -810,7 +845,7 @@ read_packet(capture_file *cf, int offset)
 int
 filter_packets(capture_file *cf, gchar *dftext)
 {
-  dfilter *dfcode;
+  dfilter_t *dfcode;
 
   if (dftext == NULL) {
     /* The new filter is an empty filter (i.e., display all packets). */
@@ -819,7 +854,7 @@ filter_packets(capture_file *cf, gchar *dftext)
     /*
      * We have a filter; try to compile it.
      */
-    if (dfilter_compile(dftext, &dfcode) != 0) {
+    if (!dfilter_compile(dftext, &dfcode)) {
       /* The attempt failed; report an error. */
       simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
       return 0;
@@ -838,24 +873,25 @@ filter_packets(capture_file *cf, gchar *dftext)
     g_free(cf->dfilter);
   cf->dfilter = dftext;
   if (cf->dfcode != NULL)
-    dfilter_destroy(cf->dfcode);
+    dfilter_free(cf->dfcode);
   cf->dfcode = dfcode;
 
-  /* Now rescan the packet list, applying the new filter. */
-  rescan_packets(cf, "Filtering", TRUE);
+  /* Now rescan the packet list, applying the new filter, but not
+     throwing away information constructed on a previous pass. */
+  rescan_packets(cf, "Filtering", TRUE, FALSE);
   return 1;
 }
 
 void
 colorize_packets(capture_file *cf)
 {
-  rescan_packets(cf, "Colorizing", FALSE);
+  rescan_packets(cf, "Colorizing", FALSE, FALSE);
 }
 
 void
 redissect_packets(capture_file *cf)
 {
-  rescan_packets(cf, "Reprocessing", TRUE);
+  rescan_packets(cf, "Reprocessing", TRUE, TRUE);
 }
 
 /* Rescan the list of packets, reconstructing the CList.
@@ -863,16 +899,23 @@ redissect_packets(capture_file *cf)
    "action" describes why we're doing this; it's used in the progress
    dialog box.
 
-   "refilter" is TRUE if we need to re-evaluate the filter expression. */
+   "refilter" is TRUE if we need to re-evaluate the filter expression.
+
+   "redissect" is TRUE if we need to make the dissectors reconstruct
+   any state information they have (because a preference that affects
+   some dissector has changed, meaning some dissector might construct
+   its state differently from the way it was constructed the last time). */
 static void
-rescan_packets(capture_file *cf, const char *action, gboolean refilter)
+rescan_packets(capture_file *cf, const char *action, gboolean refilter,
+               gboolean redissect)
 {
   frame_data *fdata;
   progdlg_t *progbar;
   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;
@@ -887,14 +930,15 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter)
      rebuild the clist, however. */
   selected_row = -1;
 
-  /* We need to re-initialize all the state information that protocols
-     keep, because we're making a fresh pass through all the packets. */
-
-  /* Initialize the table of conversations. */
-  conversation_init();
+  if (redissect) {
+    /* We need to re-initialize all the state information that protocols
+       keep, because some preference that controls a dissector has changed,
+       which might cause the state information to be constructed differently
+       by that dissector. */
 
-  /* 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
      screen updates while it happens. */
@@ -961,12 +1005,22 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter)
 
     count++;
 
-    /* Since all state for the frame was destroyed, mark the frame
-     * as not visited. */
-    fdata->flags.visited = 0;
+    if (redissect) {
+      /* 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_dissection()"), and null out the GSList pointer. */
+      fdata->flags.visited = 0;
+      if (fdata->pfd) {
+       g_slist_free(fdata->pfd);
+        fdata->pfd = 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);
@@ -974,6 +1028,26 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter)
       selected_row = row;
   }
  
+  if (redissect) {
+    /* Clear out what remains of the visited flags and per-frame data
+       pointers.
+
+       XXX - that may cause various forms of bogosity when dissecting
+       these frames, as they won't have been seen by this sequential
+       pass, but the only alternative I see is to keep scanning them
+       even though the user requested that the scan stop, and that
+       would leave the user stuck with an Ethereal grinding on
+       until it finishes.  Should we just stick them with that? */
+    for (; fdata != NULL; fdata = fdata->next) {
+      fdata->flags.visited = 0;
+      if (fdata->pfd) {
+       g_slist_free(fdata->pfd);
+        fdata->pfd = NULL;
+      }
+      free_data_sources(fdata);        /* release data source list */
+    }
+  }
+
   /* We're done filtering the packets; destroy the progress bar. */
   destroy_progress_dlg(progbar);
 
@@ -1003,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;
@@ -1012,6 +1086,7 @@ print_packets(capture_file *cf, print_args_t *print_args)
   char        *cp;
   int         column_len;
   int         line_len;
+  epan_dissect_t *edt = NULL;
 
   cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
   if (cf->print_fh == NULL)
@@ -1071,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,
@@ -1116,19 +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_data[i][0] = '\0';
-        }
-        dissect_packet(&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++) {
@@ -1162,25 +1234,25 @@ 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();
-        dissect_packet(&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. */
-         print_hex_data(cf->print_fh, print_args->format, cf->pd,
-                       fdata->cap_len, fdata->flags.encoding);
+         print_hex_data(cf->print_fh, print_args->format, fdata);
        }
 
         /* Print a blank line if we print anything after this. */
         print_separator = TRUE;
       }
+      epan_dissect_free(edt);
     }
   }
 
@@ -1198,8 +1270,6 @@ print_packets(capture_file *cf, print_args_t *print_args)
  
   cf->print_fh = NULL;
 
-  proto_tree_is_visible = FALSE;
-
   return TRUE;
 }
 
@@ -1214,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);
@@ -1272,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_data[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]);
         }
       }
     }
@@ -1311,23 +1384,8 @@ change_time_formats(capture_file *cf)
   thaw_clist(cf);
 }
 
-static void
-clear_tree_and_hex_views(void)
-{
-  /* Clear the hex dump. */
-  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 *sfcode)
+find_packet(capture_file *cf, dfilter_t *sfcode)
 {
   frame_data *start_fd;
   frame_data *fdata;
@@ -1336,10 +1394,11 @@ find_packet(capture_file *cf, dfilter *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;
 
   start_fd = cf->current_frame;
   if (start_fd != NULL)  {
@@ -1401,12 +1460,14 @@ find_packet(capture_file *cf, dfilter *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);
-        dissect_packet(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
-        frame_matched = dfilter_apply(sfcode, protocol_tree, cf->pd, fdata->cap_len);
-        proto_tree_free(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);
+        epan_dissect_free(edt);
         if (frame_matched) {
           new_fd = fdata;
           break;       /* found it! */
@@ -1465,6 +1526,7 @@ void
 select_packet(capture_file *cf, int row)
 {
   frame_data *fdata;
+  int err;
 
   /* Get the frame data struct pointer for this frame */
   fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
@@ -1504,23 +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;
-  dissect_packet(&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();
-  proto_tree_draw(cf->protocol_tree, tree_view);
-  packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->current_frame->cap_len,
-                       -1, -1, cf->current_frame->flags.encoding);
+  if (cf->edt != NULL) {
+    epan_dissect_free(cf->edt);
+    cf->edt = NULL;
+  }
+  /* 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);
@@ -1530,19 +1595,20 @@ select_packet(capture_file *cf, int row)
 void
 unselect_packet(capture_file *cf)
 {
-  /* Destroy the protocol tree 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
@@ -1566,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)
 {
@@ -1605,7 +1700,7 @@ thaw_clist(capture_file *cf)
 }
 
 int
-save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
+save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean save_marked,
                guint save_format)
 {
   gchar        *from_filename;
@@ -1623,10 +1718,10 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
   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_format == cf->cd_t) {
+  if (!save_filtered && !save_marked && save_format == cf->cd_t) {
     /* We're not filtering packets, and we're saving it in the format
        it's already in, so we can just move or copy the raw data. */
 
@@ -1672,8 +1767,18 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
       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;
            }
@@ -1690,23 +1795,36 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
     }
 
     /* XXX - have a way to save only the packets currently selected by
-       the display filter.
+       the display filter or the marked ones.
 
        If we do that, should we make that file the current file?  If so,
        it means we can no longer get at the other packets.  What does
        NetMon do? */
     for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
       /* XXX - do a progress bar */
-      if (!save_filtered || fdata->flags.passed_dfilter) {
-       /* Either we're saving all frames, or we're saving filtered frames
-          and this one passed the display filter - save it. */
+      if ((!save_filtered && !save_marked) ||
+         (save_filtered && fdata->flags.passed_dfilter && !save_marked) ||
+         (save_marked && fdata->flags.marked && !save_filtered) ||
+         (save_filtered && save_marked && fdata->flags.passed_dfilter &&
+          fdata->flags.marked)) {
+       /* Either :
+          - we're saving all frames, or
+          - we're saving filtered frames and this one passed the display filter or
+          - we're saving marked frames (and it has been marked) or
+          - we're saving filtered _and_ marked frames,
+          save it. */
         hdr.ts.tv_sec = fdata->abs_secs;
         hdr.ts.tv_usec = fdata->abs_usecs;
         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,
@@ -1727,9 +1845,9 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
 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) {
+    if (!save_filtered && !save_marked) {
       /* We saved the entire capture, not just some packets from it.
          Open and read the file we saved it to.
 
@@ -1811,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:
@@ -1928,7 +2046,7 @@ file_close_error_message(int err)
     break;
 
   case WTAP_ERR_SHORT_WRITE:
-    errmsg = "Not all the data could be written to the file \"%s\".";
+    errmsg = "Not all the packets could be written to the file \"%s\".";
     break;
 
   case ENOSPC: