Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 4aa801ec5e57115dc796f1c7843ddd5336843302..9b3db605baa6c17fc9374fb9c425e053d0aa2957 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.246 2001/10/26 18:28:15 gram Exp $
+ * $Id: file.c,v 1.286 2002/08/28 10:07:26 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include "strerror.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#include <epan.h>
-#include <filesystem.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 "prefs.h"
 #include "gtk/proto_draw.h"
 #include "gtk/packet_win.h"
-#include "dfilter/dfilter.h"
-#include "conversation.h"
-#include "reassemble.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;
 
+#ifdef HAVE_LIBPCAP
+gboolean auto_scroll_live;
+#endif
+
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
 
 static void read_packet(capture_file *cf, long offset);
 
-static void rescan_packets(capture_file *cf, const char *action,
+static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
        gboolean refilter, gboolean redissect);
 
 static void set_selected_row(int row);
@@ -143,17 +139,8 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
      and fill in the information for this file. */
   close_cap_file(cf);
 
-  /* Initialize the table of conversations. */
-  epan_conversation_init();
-
-  /* Initialize protocol-specific variables */
-  init_all_protocols();
-
-  /* Initialize the common data structures for fragment reassembly.
-     Must be done *after* "init_all_protocols()", as "init_all_protocols()"
-     may free up space for fragments, which it finds by using the
-     data structures that "reassemble_init()" frees. */
-  reassemble_init();
+  /* Initialize all data structures used for dissection. */
+  init_dissection();
 
   /* We're about to start reading the file. */
   cf->state = FILE_READ_IN_PROGRESS;
@@ -175,11 +162,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;
@@ -195,7 +189,7 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 
 fail:
   simple_dialog(ESD_TYPE_CRIT, NULL,
-                       file_open_error_message(err, FALSE), fname);
+                       file_open_error_message(err, FALSE, 0), fname);
   return (err);
 }
 
@@ -309,16 +303,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];
-  long      data_offset;
-  progdlg_t *progbar;
-  gboolean  stop_flag;
-  int       file_pos;
-  float     prog_val;
+  gchar      *name_ptr, *load_msg, *load_fmt = "%s";
+  size_t      msg_len;
+  char       *errmsg;
+  char        errmsg_errno[1024+1];
+  gchar       err_str[2048+1];
+  long        data_offset;
+  progdlg_t  *progbar = NULL;
+  gboolean    stop_flag;
+  /*
+   * XXX - should be "off_t", but Wiretap would need more work to handle
+   * the full size of "off_t" on platforms where it's more than a "long"
+   * as well.
+   */
+  long        file_pos;
+  float       prog_val;
+  int         fd;
+  struct stat cf_stat;
+  GTimeVal    start_time;
+  gchar       status_str[100];
 
   name_ptr = get_basename(cf->filename);
 
@@ -340,8 +343,7 @@ read_cap_file(capture_file *cf, int *err)
   freeze_clist(cf);
 
   stop_flag = FALSE;
-  progbar = create_progress_dlg(load_msg, "Stop", &stop_flag);
-  g_free(load_msg);
+  g_get_current_time(&start_time);
 
   while ((wtap_read(cf->wth, err, &data_offset))) {
     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
@@ -352,7 +354,33 @@ 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;
-        update_progress_dlg(progbar, prog_val);
+        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;
+        }
+        if (progbar == NULL) {
+          /* Create the progress bar if necessary */
+          progbar = delayed_create_progress_dlg("Loading", load_msg, "Stop",
+            &stop_flag, &start_time, prog_val);
+          if (progbar != NULL)
+            g_free(load_msg);
+        }
+        if (progbar != NULL) {
+          g_snprintf(status_str, sizeof(status_str), 
+                     "%luKB of %luKB", file_pos / 1024, cf->f_len / 1024);
+          update_progress_dlg(progbar, prog_val, status_str);
+        }
         cf->progbar_nextstep += cf->progbar_quantum;
     }
 
@@ -369,8 +397,11 @@ read_cap_file(capture_file *cf, int *err)
     read_packet(cf, data_offset);
   }
 
-  /* We're done reading the file; destroy the progress bar. */
-  destroy_progress_dlg(progbar);
+  /* We're done reading the file; destroy the progress bar if it was created. */
+  if (progbar == NULL)
+    g_free(load_msg);
+  else
+    destroy_progress_dlg(progbar);
 
   /* We're done reading sequentially through the file. */
   cf->state = FILE_READ_DONE;
@@ -378,6 +409,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
@@ -496,7 +531,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);
 
@@ -543,7 +578,7 @@ finish_tail_cap_file(capture_file *cf, int *err)
   }
 
   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), 
@@ -556,6 +591,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
@@ -609,12 +648,12 @@ apply_color_filter(gpointer filter_arg, gpointer argp)
 
 static int
 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
-       union wtap_pseudo_header *pseudo_header, const u_char *buf,
+       union wtap_pseudo_header *pseudo_header, const guchar *buf,
        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;
 
@@ -629,12 +668,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;
@@ -645,10 +678,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.
@@ -673,12 +715,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. */
@@ -712,7 +748,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.
 
@@ -733,7 +769,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) {
@@ -753,7 +789,7 @@ 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;
 }
 
@@ -762,10 +798,9 @@ 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);
+  const guchar *buf = wtap_buf_ptr(cf->wth);
   frame_data   *fdata;
   int           passed;
-  proto_tree   *protocol_tree;
   frame_data   *plist_end;
   epan_dissect_t *edt;
 
@@ -775,7 +810,6 @@ read_packet(capture_file *cf, long 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;
@@ -785,14 +819,13 @@ read_packet(capture_file *cf, long 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) {
@@ -830,8 +863,10 @@ filter_packets(capture_file *cf, gchar *dftext)
     dfcode = NULL;
   } else {
     /*
-     * We have a filter; try to compile it.
+     * We have a filter; make a copy of it (as we'll be saving it),
+     * and try to compile it.
      */
+    dftext = g_strdup(dftext);
     if (!dfilter_compile(dftext, &dfcode)) {
       /* The attempt failed; report an error. */
       simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
@@ -856,20 +891,24 @@ filter_packets(capture_file *cf, gchar *dftext)
 
   /* 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);
+  if (dftext == NULL) {
+    rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
+  } else {
+    rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
+  }
   return 1;
 }
 
 void
 colorize_packets(capture_file *cf)
 {
-  rescan_packets(cf, "Colorizing", FALSE, FALSE);
+  rescan_packets(cf, "Colorizing", "all frames", FALSE, FALSE);
 }
 
 void
 redissect_packets(capture_file *cf)
 {
-  rescan_packets(cf, "Reprocessing", TRUE, TRUE);
+  rescan_packets(cf, "Reprocessing", "all frames", TRUE, TRUE);
 }
 
 /* Rescan the list of packets, reconstructing the CList.
@@ -877,6 +916,9 @@ redissect_packets(capture_file *cf)
    "action" describes why we're doing this; it's used in the progress
    dialog box.
 
+   "action_item" describes what we're doing; it's used in the progress
+   dialog box.
+
    "refilter" is TRUE if we need to re-evaluate the filter expression.
 
    "redissect" is TRUE if we need to make the dissectors reconstruct
@@ -884,18 +926,20 @@ redissect_packets(capture_file *cf)
    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,
-               gboolean redissect)
+rescan_packets(capture_file *cf, const char *action, const char *action_item,
+               gboolean refilter, gboolean redissect)
 {
   frame_data *fdata;
-  progdlg_t *progbar;
-  gboolean stop_flag;
-  guint32 progbar_quantum;
-  guint32 progbar_nextstep;
-  unsigned int count;
+  progdlg_t  *progbar = NULL;
+  gboolean    stop_flag;
+  int         count;
+  int         err;
   frame_data *selected_frame;
-  int selected_row;
-  int row;
+  int         selected_row;
+  int         row;
+  float       prog_val;
+  GTimeVal    start_time;
+  gchar       status_str[100];
 
   /* Which frame, if any, is the currently selected frame?
      XXX - should the selected frame or the focus frame be the "current"
@@ -913,17 +957,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 the common data structures for fragment reassembly.
-       Must be done *after* "init_all_protocols()", as "init_all_protocols()"
-       may free up space for fragments, which it finds by using the
-       data structures that "reassemble_init()" frees. */
-    reassemble_init();
+    /* Initialize all data structures used for dissection. */
+    init_dissection();
   }
 
   /* Freeze the packet list while we redo it, so we don't get any
@@ -946,15 +981,15 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
   prevusec = 0;
 
   /* Update the progress bar when it gets to this value. */
-  progbar_nextstep = 0;
+  cf->progbar_nextstep = 0;
   /* When we reach the value that triggers a progress bar update,
      bump that value by this amount. */
-  progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+  cf->progbar_quantum = cf->count/N_PROGBAR_UPDATES;
   /* Count of packets at which we've looked. */
   count = 0;
 
   stop_flag = FALSE;
-  progbar = create_progress_dlg(action, "Stop", &stop_flag);
+  g_get_current_time(&start_time);
 
   for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
@@ -962,15 +997,25 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
        to repaint what's pending, and doing so may involve an "ioctl()"
        to see if there's any pending input from an X server, and doing
        that for every packet can be costly, especially on a big file. */
-    if (count >= progbar_nextstep) {
+    if (count >= cf->progbar_nextstep) {
       /* let's not divide by zero. I should never be started
        * with count == 0, so let's assert that
        */
       g_assert(cf->count > 0);
+      prog_val = (gfloat) count / cf->count;
 
-      update_progress_dlg(progbar, (gfloat) count / cf->count);
+      if (progbar == NULL)
+        /* Create the progress bar if necessary */
+        progbar = delayed_create_progress_dlg(action, action_item, "Stop", &stop_flag,
+          &start_time, prog_val);
 
-      progbar_nextstep += progbar_quantum;
+      if (progbar != NULL) {
+        g_snprintf(status_str, sizeof(status_str),
+                  "%4u of %u frames", count, cf->count);
+        update_progress_dlg(progbar, prog_val, status_str);
+      }
+
+      cf->progbar_nextstep += cf->progbar_quantum;
     }
 
     if (stop_flag) {
@@ -995,20 +1040,17 @@ 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;
     }
 
+    /* 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);
@@ -1030,17 +1072,15 @@ 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;
     }
   }
 
-  /* We're done filtering the packets; destroy the progress bar. */
-  destroy_progress_dlg(progbar);
+  /* We're done filtering the packets; destroy the progress bar if it
+     was created. */
+  if (progbar != NULL)
+    destroy_progress_dlg(progbar);
 
   /* Unfreeze the packet list. */
   gtk_clist_thaw(GTK_CLIST(packet_list));
@@ -1063,12 +1103,10 @@ print_packets(capture_file *cf, print_args_t *print_args)
 {
   int         i;
   frame_data *fdata;
-  progdlg_t  *progbar;
+  progdlg_t  *progbar = NULL;
   gboolean    stop_flag;
-  guint32     progbar_quantum;
-  guint32     progbar_nextstep;
-  guint32     count;
-  proto_tree *protocol_tree;
+  int         count;
+  int         err;
   gint       *col_widths = NULL;
   gint        data_width;
   gboolean    print_separator;
@@ -1078,6 +1116,9 @@ print_packets(capture_file *cf, print_args_t *print_args)
   int         column_len;
   int         line_len;
   epan_dissect_t *edt = NULL;
+  float       prog_val;
+  GTimeVal    start_time;
+  gchar       status_str[100];
 
   cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
   if (cf->print_fh == NULL)
@@ -1114,7 +1155,7 @@ print_packets(capture_file *cf, print_args_t *print_args)
 
       /* Make sure there's room in the line buffer for the column; if not,
          double its length. */
-      line_len += column_len + 1;      /* "+1" for space or \n */
+      line_len += column_len + 1;      /* "+1" for space */
       if (line_len > line_buf_len) {
         line_buf_len *= 2;
         line_buf = g_realloc(line_buf, line_buf_len + 1);
@@ -1126,31 +1167,25 @@ print_packets(capture_file *cf, print_args_t *print_args)
       else
         sprintf(cp, "%-*s", col_widths[i], cf->cinfo.col_title[i]);
       cp += column_len;
-      if (i == cf->cinfo.num_cols - 1)
-        *cp++ = '\n';
-      else
+      if (i != cf->cinfo.num_cols - 1)
         *cp++ = ' ';
     }
     *cp = '\0';
-    print_line(cf->print_fh, print_args->format, line_buf);
+    print_line(cf->print_fh, 0, print_args->format, line_buf);
   }
 
   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;
+  cf->progbar_nextstep = 0;
   /* When we reach the value that triggers a progress bar update,
      bump that value by this amount. */
-  progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+  cf->progbar_quantum = cf->count/N_PROGBAR_UPDATES;
   /* Count of packets at which we've looked. */
   count = 0;
 
   stop_flag = FALSE;
-  progbar = create_progress_dlg("Printing", "Stop", &stop_flag);
+  g_get_current_time(&start_time);
 
   /* Iterate through the list of packets, printing the packets that
      were selected by the current display filter.  */
@@ -1160,15 +1195,25 @@ print_packets(capture_file *cf, print_args_t *print_args)
        to repaint what's pending, and doing so may involve an "ioctl()"
        to see if there's any pending input from an X server, and doing
        that for every packet can be costly, especially on a big file. */
-    if (count >= progbar_nextstep) {
+    if (count >= cf->progbar_nextstep) {
       /* let's not divide by zero. I should never be started
        * with count == 0, so let's assert that
        */
       g_assert(cf->count > 0);
+      prog_val = (gfloat) count / cf->count;
 
-      update_progress_dlg(progbar, (gfloat) count / cf->count);
+      if (progbar == NULL)
+        /* Create the progress bar if necessary */
+        progbar = delayed_create_progress_dlg("Printing", "selected frames", "Stop", &stop_flag,
+          &start_time, prog_val);
+
+      if (progbar != NULL) {
+        g_snprintf(status_str, sizeof(status_str),
+                   "%4u of %u frames", count, cf->count);
+        update_progress_dlg(progbar, prog_val, status_str);
+      }
 
-      progbar_nextstep += progbar_quantum;
+      cf->progbar_nextstep += cf->progbar_quantum;
     }
 
     if (stop_flag) {
@@ -1185,19 +1230,17 @@ print_packets(capture_file *cf, print_args_t *print_args)
     /* 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) {
+    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++) {
@@ -1208,7 +1251,7 @@ print_packets(capture_file *cf, print_args_t *print_args)
 
           /* Make sure there's room in the line buffer for the column; if not,
              double its length. */
-          line_len += column_len + 1;  /* "+1" for space or \n */
+          line_len += column_len + 1;  /* "+1" for space */
           if (line_len > line_buf_len) {
             line_buf_len *= 2;
             line_buf = g_realloc(line_buf, line_buf_len + 1);
@@ -1220,30 +1263,27 @@ print_packets(capture_file *cf, print_args_t *print_args)
           else
             sprintf(cp, "%-*s", col_widths[i], cf->cinfo.col_data[i]);
           cp += column_len;
-          if (i == cf->cinfo.num_cols - 1)
-            *cp++ = '\n';
-          else
+          if (i != cf->cinfo.num_cols - 1)
             *cp++ = ' ';
         }
         *cp = '\0';
-        print_line(cf->print_fh, print_args->format, line_buf);
+        print_line(cf->print_fh, 0, print_args->format, line_buf);
       } else {
         if (print_separator)
-          print_line(cf->print_fh, print_args->format, "\n");
+          print_line(cf->print_fh, 0, print_args->format, "");
 
-        /* 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,
-                       fdata, cf->print_fh);
-
-        proto_tree_free(protocol_tree);
+        proto_tree_print(print_args, edt, cf->print_fh);
 
        if (print_args->print_hex) {
          /* Print the full packet data as hex. */
-         print_hex_data(cf->print_fh, print_args->format, fdata);
+         print_hex_data(cf->print_fh, print_args->format, edt);
        }
 
         /* Print a blank line if we print anything after this. */
@@ -1253,8 +1293,10 @@ print_packets(capture_file *cf, print_args_t *print_args)
     }
   }
 
-  /* We're done printing the packets; destroy the progress bar. */
-  destroy_progress_dlg(progbar);
+  /* We're done printing the packets; destroy the progress bar if
+     it was created. */
+  if (progbar != NULL)
+    destroy_progress_dlg(progbar);
 
   if (col_widths != NULL)
     g_free(col_widths);
@@ -1267,8 +1309,6 @@ print_packets(capture_file *cf, print_args_t *print_args)
  
   cf->print_fh = NULL;
 
-  proto_tree_is_visible = FALSE;
-
   return TRUE;
 }
 
@@ -1279,29 +1319,42 @@ void
 change_time_formats(capture_file *cf)
 {
   frame_data *fdata;
-  progdlg_t *progbar;
-  gboolean stop_flag;
-  guint32 progbar_quantum;
-  guint32 progbar_nextstep;
-  unsigned int count;
-  int row;
-  int i;
-  GtkStyle  *pl_style;
+  progdlg_t  *progbar = NULL;
+  gboolean    stop_flag;
+  int         count;
+  int         row;
+  int         i;
+  GtkStyle   *pl_style;
+  float       prog_val;
+  GTimeVal    start_time;
+  gchar       status_str[100];
+
+  /* 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);
 
   /* Update the progress bar when it gets to this value. */
-  progbar_nextstep = 0;
+  cf->progbar_nextstep = 0;
   /* When we reach the value that triggers a progress bar update,
      bump that value by this amount. */
-  progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+  cf->progbar_quantum = cf->count/N_PROGBAR_UPDATES;
   /* Count of packets at which we've looked. */
   count = 0;
 
   stop_flag = FALSE;
-  progbar = create_progress_dlg("Changing time display", "Stop", &stop_flag);
+  g_get_current_time(&start_time);
 
   /* Iterate through the list of packets, checking whether the packet
      is in a row of the summary list and, if so, whether there are
@@ -1313,15 +1366,26 @@ change_time_formats(capture_file *cf)
        to repaint what's pending, and doing so may involve an "ioctl()"
        to see if there's any pending input from an X server, and doing
        that for every packet can be costly, especially on a big file. */
-    if (count >= progbar_nextstep) {
+    if (count >= cf->progbar_nextstep) {
       /* let's not divide by zero. I should never be started
        * with count == 0, so let's assert that
        */
       g_assert(cf->count > 0);
 
-      update_progress_dlg(progbar, (gfloat) count / cf->count);
+      prog_val = (gfloat) count / cf->count;
 
-      progbar_nextstep += progbar_quantum;
+      if (progbar == NULL)
+        /* Create the progress bar if necessary */
+        progbar = delayed_create_progress_dlg("Changing", "time display", "Stop",
+          &stop_flag, &start_time, prog_val);
+
+      if (progbar != NULL) {
+        g_snprintf(status_str, sizeof(status_str),
+                   "%4u of %u frames", count, cf->count);
+        update_progress_dlg(progbar, prog_val, status_str);
+      }
+
+      cf->progbar_nextstep += cf->progbar_quantum;
     }
 
     if (stop_flag) {
@@ -1341,30 +1405,23 @@ 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]);
         }
       }
     }
   }
 
-  /* We're done redisplaying the packets; destroy the progress bar. */
-  destroy_progress_dlg(progbar);
+  /* We're done redisplaying the packets; destroy the progress bar if it
+     was created. */
+  if (progbar != NULL)
+    destroy_progress_dlg(progbar);
 
   /* Set the column widths of those columns that show the time in
      "command-line-specified" format. */
@@ -1386,15 +1443,16 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
   frame_data *start_fd;
   frame_data *fdata;
   frame_data *new_fd = NULL;
-  progdlg_t *progbar;
-  gboolean stop_flag;
-  guint32 progbar_quantum;
-  guint32 progbar_nextstep;
-  unsigned int count;
-  proto_tree *protocol_tree;
-  gboolean frame_matched;
-  int row;
+  progdlg_t  *progbar = NULL;
+  gboolean    stop_flag;
+  int         count;
+  int         err;
+  gboolean    frame_matched;
+  int         row;
   epan_dissect_t       *edt;
+  float       prog_val;
+  GTimeVal    start_time;
+  gchar       status_str[100];
 
   start_fd = cf->current_frame;
   if (start_fd != NULL)  {
@@ -1404,14 +1462,13 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
     count = 0;
     fdata = start_fd;
 
-    /* Update the progress bar when it gets to this value. */
-    progbar_nextstep = 0;
+    cf->progbar_nextstep = 0;
     /* When we reach the value that triggers a progress bar update,
        bump that value by this amount. */
-    progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+    cf->progbar_quantum = cf->count/N_PROGBAR_UPDATES;
 
     stop_flag = FALSE;
-    progbar = create_progress_dlg("Searching", "Cancel", &stop_flag);
+    g_get_current_time(&start_time);
 
     fdata = start_fd;
     for (;;) {
@@ -1420,15 +1477,26 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
          to repaint what's pending, and doing so may involve an "ioctl()"
          to see if there's any pending input from an X server, and doing
          that for every packet can be costly, especially on a big file. */
-      if (count >= progbar_nextstep) {
+      if (count >= cf->progbar_nextstep) {
         /* let's not divide by zero. I should never be started
          * with count == 0, so let's assert that
          */
         g_assert(cf->count > 0);
 
-        update_progress_dlg(progbar, (gfloat) count / cf->count);
+        prog_val = (gfloat) count / cf->count;
+
+        /* Create the progress bar if necessary */
+        if (progbar == NULL)
+           progbar = delayed_create_progress_dlg("Searching", cf->sfilter, "Cancel",
+             &stop_flag, &start_time, prog_val);
+        
+        if (progbar != NULL) {
+          g_snprintf(status_str, sizeof(status_str),
+                     "%4u of %u frames", count, cf->count);
+          update_progress_dlg(progbar, prog_val, status_str);
+        }
 
-        progbar_nextstep += progbar_quantum;
+        cf->progbar_nextstep += cf->progbar_quantum;
       }
 
       if (stop_flag) {
@@ -1456,13 +1524,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! */
@@ -1476,8 +1545,10 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
       }
     }
 
-    /* We're done scanning the packets; destroy the progress bar. */
-    destroy_progress_dlg(progbar);
+    /* We're done scanning the packets; destroy the progress bar if it
+       was created. */
+    if (progbar != NULL)
+      destroy_progress_dlg(progbar);
   }
 
   if (new_fd != NULL) {
@@ -1521,8 +1592,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);
@@ -1562,33 +1632,25 @@ 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();
+  /* 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);
 
-  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);
+  /* 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->edt, tree_view, byte_nb_ptr);
+  proto_tree_draw(cf->edt->tree, tree_view);
 
   /* A packet is selected. */
   set_menus_for_selected_packet(TRUE);
@@ -1598,11 +1660,7 @@ 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;
@@ -1648,6 +1706,26 @@ unselect_field(void)
   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)
 {
@@ -1686,9 +1764,16 @@ thaw_clist(capture_file *cf)
     gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
 }
 
-int
-save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean save_marked,
-               guint save_format)
+/*
+ * Save a capture to a file, in a particular format, saving either
+ * all packets, all currently-displayed packets, or all marked packets.
+ *
+ * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
+ * up a message box for the failure.
+ */
+gboolean
+save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
+               gboolean save_marked, guint save_format)
 {
   gchar        *from_filename;
   gchar        *name_ptr, *save_msg, *save_fmt = " Saving: %s...";
@@ -1700,6 +1785,7 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
   struct wtap_pkthdr hdr;
   union wtap_pseudo_header pseudo_header;
   guint8        pd[65536];
+  struct stat   infile, outfile;
 
   name_ptr = get_basename(fname);
   msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
@@ -1708,13 +1794,28 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
   statusbar_push_file_msg(save_msg);
   g_free(save_msg);
 
+  /* 
+   * Check that the from file is not the same as to file 
+   * We do it here so we catch all cases ...
+   * Unfortunately, the file requester gives us an absolute file
+   * name and the read file name may be relative (if supplied on
+   * the command line). From Joerg Mayer.
+   */
+   infile.st_ino = 1;   /* These prevent us from getting equality         */
+   outfile.st_ino = 2;  /* If one or other of the files is not accessible */
+   stat(cf->filename, &infile);
+   stat(fname, &outfile);
+   if (infile.st_ino == outfile.st_ino) {
+    simple_dialog(ESD_TYPE_CRIT, NULL, 
+                     "Can't save over current capture file: %s!",
+                     cf->filename);
+    goto fail;
+  }
+
   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. */
 
-    /* In this branch, we set "err" only if we get an error, so we
-       must first clear it. */
-    err = 0;
     if (cf->is_tempfile) {
       /* The file being saved is a temporary file from a live
          capture, so it doesn't need to stay around under that name;
@@ -1738,10 +1839,9 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
             be if we didn't have permission to remove the file from
             the temporary directory, and that might be fixable - but
             is it worth requiring the user to go off and fix it?) */
-         err = errno;
          simple_dialog(ESD_TYPE_CRIT, NULL,
-                               file_rename_error_message(err), fname);
-         goto done;
+                               file_rename_error_message(errno), fname);
+         goto fail;
        }
       }
 #else
@@ -1754,11 +1854,11 @@ 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. */
+
     if (do_copy) {
-           if (!copy_binary_file(from_filename, fname)) {
-               goto done;
-           }
+      /* Copy the file, if we haven't moved it. */
+      if (!copy_binary_file(from_filename, fname))
+       goto fail;
     }
   } else {
     /* Either we're filtering packets, or we're saving in a different
@@ -1767,8 +1867,8 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
     pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
     if (pdh == NULL) {
       simple_dialog(ESD_TYPE_CRIT, NULL,
-                       file_open_error_message(err, TRUE), fname);
-      goto done;
+                       file_open_error_message(err, TRUE, save_format), fname);
+      goto fail;
     }
 
     /* XXX - have a way to save only the packets currently selected by
@@ -1795,14 +1895,19 @@ 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 fail;
+       }
 
         if (!wtap_dump(pdh, &hdr, &pseudo_header, pd, &err)) {
-           simple_dialog(ESD_TYPE_CRIT, NULL,
+         simple_dialog(ESD_TYPE_CRIT, NULL,
                                file_write_error_message(err), fname);
-           wtap_dump_close(pdh, &err);
-           goto done;
+         wtap_dump_close(pdh, &err);
+          goto fail;
        }
       }
     }
@@ -1810,55 +1915,57 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
     if (!wtap_dump_close(pdh, &err)) {
       simple_dialog(ESD_TYPE_WARN, NULL,
                file_close_error_message(err), fname);
-      goto done;
+      goto fail;
     }
   }
 
-done:
-
   /* Pop the "Saving:" message off the status bar. */
   statusbar_pop_file_msg();
-  if (err == 0) {
-    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.
-
-        XXX - this is somewhat of a waste; we already have the
-        packets, all this gets us is updated file type information
-        (which we could just stuff into "cf"), and having the new
-        file be the one we have opened and from which we're reading
-        the data, and it means we have to spend time opening and
-        reading the file, which could be a significant amount of
-        time if the file is large. */
-      cf->user_saved = TRUE;
-
-      if ((err = open_cap_file(fname, FALSE, cf)) == 0) {
-       /* XXX - report errors if this fails? */
-       switch (read_cap_file(cf, &err)) {
-
-       case READ_SUCCESS:
-       case READ_ERROR:
-         /* Just because we got an error, that doesn't mean we were unable
-            to read any of the file; we handle what we could get from the
-            file. */
-         break;
-
-       case READ_ABORTED:
-         /* The user bailed out of re-reading the capture file; the
-            capture file has been closed - just return (without
-            changing any menu settings; "close_cap_file()" set them
-            correctly for the "no capture file open" state). */
-         return 0;
-       }
-       set_menus_for_unsaved_capture_file(FALSE);
+  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.
+
+       XXX - this is somewhat of a waste; we already have the
+       packets, all this gets us is updated file type information
+       (which we could just stuff into "cf"), and having the new
+       file be the one we have opened and from which we're reading
+       the data, and it means we have to spend time opening and
+       reading the file, which could be a significant amount of
+       time if the file is large. */
+    cf->user_saved = TRUE;
+
+    if ((err = open_cap_file(fname, FALSE, cf)) == 0) {
+      /* XXX - report errors if this fails?
+         What should we return if it fails or is aborted? */
+      switch (read_cap_file(cf, &err)) {
+
+      case READ_SUCCESS:
+      case READ_ERROR:
+       /* Just because we got an error, that doesn't mean we were unable
+          to read any of the file; we handle what we could get from the
+          file. */
+       break;
+
+      case READ_ABORTED:
+       /* The user bailed out of re-reading the capture file; the
+          capture file has been closed - just return (without
+          changing any menu settings; "close_cap_file()" set them
+          correctly for the "no capture file open" state). */
+       break;
       }
+      set_menus_for_unsaved_capture_file(FALSE);
     }
   }
-  return err;
+  return TRUE;
+
+fail:
+  /* Pop the "Saving:" message off the status bar. */
+  statusbar_pop_file_msg();
+  return FALSE;
 }
 
 char *
-file_open_error_message(int err, gboolean for_writing)
+file_open_error_message(int err, gboolean for_writing, int file_type)
 {
   char *errmsg;
   static char errmsg_errno[1024+1];
@@ -1869,12 +1976,25 @@ file_open_error_message(int err, gboolean for_writing)
     errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file.";
     break;
 
+  case WTAP_ERR_RANDOM_OPEN_PIPE:
+    /* Seen only when opening a capture file for reading. */
+    errmsg = "The file \"%s\" is a pipe or FIFO; Ethereal cannot read pipe or FIFO files.";
+    break;
+
   case WTAP_ERR_FILE_UNKNOWN_FORMAT:
   case WTAP_ERR_UNSUPPORTED:
     /* Seen only when opening a capture file for reading. */
     errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
     break;
 
+  case WTAP_ERR_CANT_WRITE_TO_PIPE:
+    /* Seen only when opening a capture file for writing. */
+    snprintf(errmsg_errno, sizeof(errmsg_errno),
+            "The file \"%%s\" is a pipe, and %s capture files cannot be "
+            "written to a pipe.", wtap_file_type_string(file_type));
+    errmsg = errmsg_errno;
+    break;
+
   case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
     /* Seen only when opening a capture file for writing. */
     errmsg = "Ethereal does not support writing capture files in that format.";
@@ -1901,7 +2021,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 +2048,8 @@ file_open_error_message(int err, gboolean for_writing)
 
   default:
     snprintf(errmsg_errno, sizeof(errmsg_errno),
-                   "The file \"%%s\" could not be opened: %s.",
+                   "The file \"%%s\" could not be %s: %s.",
+                               for_writing ? "created" : "opened",
                                wtap_strerror(err));
     errmsg = errmsg_errno;
     break;
@@ -2059,7 +2180,7 @@ copy_binary_file(char *from_filename, char *to_filename)
       if (from_fd < 0) {
        err = errno;
        simple_dialog(ESD_TYPE_CRIT, NULL,
-                       file_open_error_message(err, TRUE), from_filename);
+                       file_open_error_message(err, TRUE, 0), from_filename);
        goto done;
       }
 
@@ -2072,7 +2193,7 @@ copy_binary_file(char *from_filename, char *to_filename)
       if (to_fd < 0) {
        err = errno;
        simple_dialog(ESD_TYPE_CRIT, NULL,
-                       file_open_error_message(err, TRUE), to_filename);
+                       file_open_error_message(err, TRUE, 0), to_filename);
        close(from_fd);
        goto done;
       }