Add support for Banyan Vines addresses to the code that handles the
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 24670409c5eb951331bfacdb958c3cf309ff6879..d8e920c183eeee1648e01b4852cfde7c896304dd 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.33 1999/06/22 22:02:11 gram Exp $
+ * $Id: file.c,v 1.112 1999/10/22 08:30:02 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 
 #include <gtk/gtk.h>
 
-#ifdef WITH_WIRETAP
-#include <pcap.h>
-#endif
-
 #include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+
+#include <time.h>
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 
 #ifdef NEED_SNPRINTF_H
 # ifdef HAVE_STDARG_H
 # include <netinet/in.h>
 #endif
 
-#include "ethereal.h"
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include "gtk/main.h"
 #include "column.h"
-#include "menu.h"
+#include "gtk/menu.h"
 #include "packet.h"
+#include "print.h"
 #include "file.h"
 #include "util.h"
+#include "gtk/proto_draw.h"
+#include "dfilter.h"
+#include "timestamp.h"
+#include "conversation.h"
 
-#include "packet-ncp.h"
+#ifndef __RESOLV_H__
+#include "resolv.h"
+#endif
+
+#include "packet-atalk.h"
+
+#include "packet-ipv6.h"
 
-#define TAIL_TIMEOUT   2000  /* msec */
+#include "packet-ncp.h"
 
 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
-extern GtkStyle  *pl_style;
 extern guint      file_ctx;
-extern int       sync_mode;
 extern int        sync_pipe[];
 
-guint cap_input_id, tail_timeout_id;
+guint cap_input_id;
+gboolean auto_scroll_live = FALSE;
 
 static guint32 firstsec, firstusec;
-static guint32 lastsec, lastusec;
+static guint32 prevsec, prevusec;
 
-#ifdef WITH_WIRETAP
 static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
     const u_char *);
-#else
-static void pcap_dispatch_cb(u_char *, const struct pcap_pkthdr *,
-    const u_char *);
-#endif
 
-static void init_col_widths(capture_file *);
-static void set_col_widths(capture_file *);
+static void freeze_clist(capture_file *cf);
+static void thaw_clist(capture_file *cf);
 
-static gint tail_timeout_cb(gpointer);
+/* Update the progress bar this many times when reading a file. */
+#define N_PROGBAR_UPDATES      100
 
 int
 open_cap_file(char *fname, capture_file *cf) {
-#ifndef WITH_WIRETAP
-  guint32     magic[2];
-  char        err_str[PCAP_ERRBUF_SIZE];
-#endif
+  wtap       *wth;
+  int         err;
+  FILE_T      fh;
+  int         fd;
   struct stat cf_stat;
 
-  /* First, make sure the file is valid */
-  if (stat(fname, &cf_stat))
-    return (errno);
-  if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode))
-    return (OPEN_CAP_FILE_NOT_REGULAR);
-
-  /* Next, try to open the file */
-  cf->fh = fopen(fname, "r");
-  if (cf->fh == NULL)
-    return (errno);
-
-  fseek(cf->fh, 0L, SEEK_END);
-  cf->f_len = ftell(cf->fh);
-#ifndef WITH_WIRETAP
-  fseek(cf->fh, 0L, SEEK_SET);
-  fread(magic, sizeof(guint32), 2, cf->fh);
-  fseek(cf->fh, 0L, SEEK_SET);
-#endif
-  fclose(cf->fh);
-  cf->fh = NULL;
-  /* set the file name beacuse we need it to set the follow stream filter */
-  cf->filename = g_strdup( fname );
-
-  /* Next, find out what type of file we're dealing with */
-#ifdef WITH_WIRETAP 
-  cf->cd_t  = WTAP_FILE_UNKNOWN;
-#else
-  cf->cd_t  = CD_UNKNOWN;
-  cf->lnk_t = DLT_NULL;
-  cf->swap  = 0;
-#endif
-  cf->count = 0;
-  cf->drops = 0;
-  cf->esec  = 0;
-  cf->eusec = 0;
-  cf->snap  = 0;
-  firstsec = 0, firstusec = 0;
-  lastsec = 0, lastusec = 0;
-#ifndef WITH_WIRETAP
-  if (magic[0] == PCAP_MAGIC || magic[0] == SWAP32(PCAP_MAGIC)) {
-
-    /* Pcap/Tcpdump file */
-    cf->pfh = pcap_open_offline(fname, err_str);
-    if (cf->pfh == NULL) {
-#else
-       cf->wth = wtap_open_offline(fname);
-       if (cf->wth == NULL) {
-#endif
-
-      /* XXX - we assume that, because we were able to open it above,
-         this must have failed because it's not a capture file in
-        a format we can read. */
-      return (OPEN_CAP_FILE_UNKNOWN_FORMAT);
-    }
+  wth = wtap_open_offline(fname, &err);
+  if (wth == NULL)
+    goto fail;
+
+  /* Find the size of the file. */
+  fh = wtap_file(wth);
+  fd = wtap_fd(wth);
+  if (fstat(fd, &cf_stat) < 0) {
+    err = errno;
+    wtap_close(wth);
+    goto fail;
+  }
 
-#ifndef WITH_WIRETAP
-    if (cf->dfilter) {
-      if (pcap_compile(cf->pfh, &cf->fcode, cf->dfilter, 1, 0) < 0) {
-        simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string "
-          "\"%s\".", cf->dfilter);
-      } else if (pcap_setfilter(cf->pfh, &cf->fcode) < 0) {
-        simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter.");
-      }
-    }
+  /* The open succeeded.  Close whatever capture file we had open,
+     and fill in the information for this file. */
+  close_cap_file(cf, info_bar, file_ctx);
 
-    cf->fh   = pcap_file(cf->pfh);
-    cf->swap = pcap_is_swapped(cf->pfh);    
-    if ((cf->swap && BYTE_ORDER == BIG_ENDIAN) ||
-      (!cf->swap && BYTE_ORDER == LITTLE_ENDIAN)) {
-      /* Data is big-endian */
-      cf->cd_t = CD_PCAP_BE;
-    } else {
-      cf->cd_t = CD_PCAP_LE;
-    }
-    cf->vers  = ( ((pcap_major_version(cf->pfh) & 0x0000ffff) << 16) |
-                  pcap_minor_version(cf->pfh) );
-    cf->snap  = pcap_snapshot(cf->pfh);
-    cf->lnk_t = pcap_datalink(cf->pfh);
-  } else if (ntohl(magic[0]) == SNOOP_MAGIC_1 && ntohl(magic[1]) == SNOOP_MAGIC_2) {
-    return (OPEN_CAP_FILE_UNKNOWN_FORMAT);
-  }
-  
-  if (cf->cd_t == CD_UNKNOWN)
-    return (OPEN_CAP_FILE_UNKNOWN_FORMAT);
-#else
-    if (cf->dfilter) {
-      if (wtap_offline_filter(cf->wth, cf->dfilter) < 0) {
-        simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string "
-          "\"%s\".", cf->dfilter);
-      }
-    }
-  cf->fh = wtap_file(cf->wth);
-  cf->cd_t = wtap_file_type(cf->wth);
-  cf->snap = wtap_snapshot_length(cf->wth);
-#endif
+  /* Initialize the table of conversations. */
+  conversation_init();
 
+  /* Initialize protocol-specific variables */
+  afs_init_protocol();
+  ncp_init_protocol();
+  smb_init_protocol();
+
+  cf->wth = wth;
+  cf->fh = fh;
+  cf->filed = fd;
+  cf->f_len = cf_stat.st_size;
+
+  /* set the file name because we need it to set the follow stream filter */
+  cf->filename = g_strdup(fname);
+
+  cf->cd_t      = wtap_file_type(cf->wth);
+  cf->cd_t_desc = wtap_file_type_string(cf->wth);
+  cf->count     = 0;
+  cf->drops     = 0;
+  cf->esec      = 0;
+  cf->eusec     = 0;
+  cf->snap      = wtap_snapshot_length(cf->wth);
+  cf->update_progbar = FALSE;
+  cf->progbar_quantum = 0;
+  cf->progbar_nextstep = 0;
+  firstsec = 0, firstusec = 0;
+  prevsec = 0, prevusec = 0;
   return (0);
-}
 
-static void
-free_packets_cb(gpointer data, gpointer user_data)
-{
-  g_free(data);
+fail:
+  simple_dialog(ESD_TYPE_WARN, NULL,
+                       file_open_error_message(err, FALSE), fname);
+  return (err);
 }
 
 /* Reset everything to a pristine state */
 void
 close_cap_file(capture_file *cf, void *w, guint context) {
+  frame_data *fd, *fd_next;
+
   if (cf->fh) {
-    fclose(cf->fh);
+    file_close(cf->fh);
     cf->fh = NULL;
   }
-#ifdef WITH_WIRETAP
   if (cf->wth) {
     wtap_close(cf->wth);
     cf->wth = NULL;
   }
-#else
-  if (cf->pfh) {
-    pcap_close(cf->pfh);
-    cf->pfh = NULL;
+  for (fd = cf->plist; fd != NULL; fd = fd_next) {
+    fd_next = fd->next;
+    g_free(fd);
   }
-#endif
-  if (cf->plist) {
-    g_list_foreach(cf->plist, free_packets_cb, NULL);
-    g_list_free(cf->plist);
-    cf->plist = NULL;
+  if (cf->rfcode != NULL) {
+    dfilter_destroy(cf->rfcode);
+    cf->rfcode = NULL;
   }
-  gtk_text_freeze(GTK_TEXT(byte_view));
-  gtk_text_set_point(GTK_TEXT(byte_view), 0);
-  gtk_text_forward_delete(GTK_TEXT(byte_view),
-    gtk_text_get_length(GTK_TEXT(byte_view)));
-  gtk_text_thaw(GTK_TEXT(byte_view));
-  gtk_tree_clear_items(GTK_TREE(tree_view), 0,
-    g_list_length(GTK_TREE(tree_view)->children));
+  cf->plist = NULL;
+  cf->plist_end = NULL;
+  unselect_packet(cf); /* nothing to select */
 
   gtk_clist_freeze(GTK_CLIST(packet_list));
   gtk_clist_clear(GTK_CLIST(packet_list));
   gtk_clist_thaw(GTK_CLIST(packet_list));
   gtk_statusbar_pop(GTK_STATUSBAR(w), context);
+
+  /* Disable all menu items that make sense only if you have a capture. */
+  set_menu_sensitivity("/File/Save", FALSE);
+  set_menu_sensitivity("/File/Save As...", FALSE);
+  set_menu_sensitivity("/File/Close", FALSE);
+  set_menu_sensitivity("/File/Reload", FALSE);
+  set_menu_sensitivity("/File/Print...", FALSE);
+  set_menu_sensitivity("/Display/Options...", FALSE);
+  set_menu_sensitivity("/Tools/Summary", FALSE);
 }
 
 int
-load_cap_file(char *fname, capture_file *cf) {
+read_cap_file(capture_file *cf) {
   gchar  *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
   gchar  *done_fmt = " File: %s  Drops: %d";
-  gchar  *err_fmt  = " Error: Could not load '%s'";
-  gint    timeout;
-  size_t  msg_len;
+  int     success;
   int     err;
+  size_t  msg_len;
+  char   *errmsg;
+  char    errmsg_errno[1024+1];
+  gchar   err_str[2048+1];
 
-  close_cap_file(cf, info_bar, file_ctx);
-
-  /* Initialize protocol-specific variables */
-  ncp_init_protocol();
-
-  if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
-    name_ptr = fname;
+  if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
+    name_ptr = cf->filename;
   else
     name_ptr++;
+
   load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
   sprintf(load_msg, load_fmt, name_ptr);
   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
-  
-  timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) &cf);
-  
-  err = open_cap_file(fname, cf);
-#ifdef WITH_WIRETAP
-  if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
-#else
-  if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
-#endif
-    gtk_clist_freeze(GTK_CLIST(packet_list));
-    init_col_widths(cf);
-#ifdef WITH_WIRETAP
-    wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);
-    wtap_close(cf->wth);
-    cf->wth = NULL;
-#else
-    pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
-    pcap_close(cf->pfh);
-    cf->pfh = NULL;
-#endif
-    cf->fh = fopen(fname, "r");
 
-    set_col_widths(cf);
-    gtk_clist_thaw(GTK_CLIST(packet_list));
-  }
-  
-  gtk_timeout_remove(timeout);
-  gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
+  cf->update_progbar = TRUE;
+  /* Update the progress bar when it gets to this value. */
+  cf->progbar_nextstep = 0;
+  /* When we reach the value that triggers a progress bar update,
+     bump that value by this amount. */
+  cf->progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
+
+  freeze_clist(cf);
+  proto_tree_is_visible = FALSE;
+  success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
+  wtap_close(cf->wth);
+  cf->wth = NULL;
+  cf->filed = open(cf->filename, O_RDONLY);
+  cf->fh = filed_open(cf->filed, "r");
+  cf->unfiltered_count = cf->count;
+  thaw_clist(cf);
+
+  gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
+  gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
 
   gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
 
-  if (err == 0) {
-    msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
-    load_msg = g_realloc(load_msg, msg_len);
+  msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
+  load_msg = g_realloc(load_msg, msg_len);
 
-    if (cf->user_saved || !cf->save_file)
-           snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
-    else
-           snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
-
-    gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
-    g_free(load_msg);
+  if (cf->user_saved || !cf->save_file)
+    snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
+  else
+    snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
 
-/*    name_ptr[-1] = '\0';  Why is this here? It causes problems with capture files */
-#ifdef USE_ITEM
-    set_menu_sensitivity("/File/Close", TRUE);
-    set_menu_sensitivity("/File/Reload", TRUE);
-    set_menu_sensitivity("/Tools/Summary", TRUE);
-#else
-    set_menu_sensitivity("<Main>/File/Close", TRUE);
-    set_menu_sensitivity("<Main>/File/Reload", TRUE);
-    set_menu_sensitivity("<Main>/Tools/Summary", TRUE);
-#endif
-  } else {
-    msg_len = strlen(name_ptr) + strlen(err_fmt) + 2;
-    load_msg = g_realloc(load_msg, msg_len);
-    snprintf(load_msg, msg_len, err_fmt, name_ptr);
-    gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
-    g_free(load_msg);
-#ifdef USE_ITEM
-    set_menu_sensitivity("/File/Close", FALSE);
-    set_menu_sensitivity("/File/Save", FALSE);
-    set_menu_sensitivity("/File/Save As...", FALSE);
-    set_menu_sensitivity("/File/Reload", FALSE);
-    set_menu_sensitivity("/Tools/Summary", FALSE);
-
-#else
-    set_menu_sensitivity("<Main>/File/Close", FALSE);
-    set_menu_sensitivity("<Main>/File/Save", FALSE);
-    set_menu_sensitivity("<Main>/File/Save As...", FALSE);
-    set_menu_sensitivity("<Main>/File/Reload", FALSE);
-    set_menu_sensitivity("<Main>/Tools/Summary", FALSE);
-#endif
-  }
-  return err;
+  gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
+  g_free(load_msg);
+
+  /* Enable menu items that make sense if you have a capture. */
+  set_menu_sensitivity("/File/Close", TRUE);
+  set_menu_sensitivity("/File/Reload", TRUE);
+  set_menu_sensitivity("/File/Print...", TRUE);
+  set_menu_sensitivity("/Display/Options...", TRUE);
+  set_menu_sensitivity("/Tools/Summary", TRUE);
+
+  if (!success) {
+    /* 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. */
+    switch (err) {
+
+    case WTAP_ERR_CANT_READ:
+      errmsg = "An attempt to read from the file failed for"
+               " some unknown reason.";
+      break;
+
+    case WTAP_ERR_SHORT_READ:
+      errmsg = "The capture file appears to have been cut short"
+               " in the middle of a packet.";
+      break;
+
+    case WTAP_ERR_BAD_RECORD:
+      errmsg = "The capture file appears to be damaged or corrupt.";
+      break;
+
+    default:
+      sprintf(errmsg_errno, "An error occurred while reading the"
+                              " capture file: %s.", wtap_strerror(err));
+      errmsg = errmsg_errno;
+      break;
+    }
+    snprintf(err_str, sizeof err_str, errmsg);
+    simple_dialog(ESD_TYPE_WARN, NULL, err_str);
+    return (err);
+  } else
+    return (0);
 }
 
+#ifdef HAVE_LIBPCAP
 void 
 cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
   
   capture_file *cf = (capture_file *)data;
-  char buffer[256];
+  char buffer[256+1], *p = buffer, *q = buffer;
+  int  nread;
+  int  to_read = 0;
+  gboolean exit_loop = FALSE;
+  int  err;
+  int  wstatus;
+  int  wsignal;
+  char *msg;
+  char *sigmsg;
+  char sigmsg_buf[6+1+3+1];
+  char *coredumped;
 
   /* avoid reentrancy problems and stack overflow */
   gtk_input_remove(cap_input_id);
-  if (tail_timeout_id != -1) gtk_timeout_remove(tail_timeout_id);
-
-  if (read(sync_pipe[0], buffer, 256) <= 0) {
 
-    /* process data until end of file and stop capture (restore menu items) */
+  if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
+
+    /* The child has closed the sync pipe, meaning it's not going to be
+       capturing any more packets.  Pick up its exit status, and
+       complain if it died of a signal. */
+    if (wait(&wstatus) != -1) {
+      /* XXX - are there any platforms on which we can run that *don't*
+         support POSIX.1's <sys/wait.h> and macros therein? */
+      wsignal = wstatus & 0177;
+      coredumped = "";
+      if (wstatus == 0177) {
+       /* It stopped, rather than exiting.  "Should not happen." */
+       msg = "stopped";
+       wsignal = (wstatus >> 8) & 0xFF;
+      } else {
+        msg = "terminated";
+        if (wstatus & 0200)
+          coredumped = " - core dumped";
+      }
+      if (wsignal != 0) {
+        switch (wsignal) {
+
+        case SIGHUP:
+          sigmsg = "Hangup";
+          break;
+
+        case SIGINT:
+          sigmsg = "Interrupted";
+          break;
+
+        case SIGQUIT:
+          sigmsg = "Quit";
+          break;
+
+        case SIGILL:
+          sigmsg = "Illegal instruction";
+          break;
+
+        case SIGTRAP:
+          sigmsg = "Trace trap";
+          break;
+
+        case SIGABRT:
+          sigmsg = "Abort";
+          break;
+
+        case SIGFPE:
+          sigmsg = "Arithmetic exception";
+          break;
+
+        case SIGKILL:
+          sigmsg = "Killed";
+          break;
+
+        case SIGBUS:
+          sigmsg = "Bus error";
+          break;
+
+        case SIGSEGV:
+          sigmsg = "Segmentation violation";
+          break;
+
+       /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO 
+               Linux is POSIX compliant.  These are not POSIX-defined signals ---
+                 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
+
+              ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
+               were omitted from POSIX.1 because their behavior is
+               implementation dependent and could not be adequately catego-
+               rized.  Conforming implementations may deliver these sig-
+               nals, but must document the circumstances under which they
+               are delivered and note any restrictions concerning their
+               delivery.''
+       */
+
+       #ifdef SIGSYS
+        case SIGSYS:
+          sigmsg = "Bad system call";
+          break;
+       #endif
+
+        case SIGPIPE:
+          sigmsg = "Broken pipe";
+          break;
+
+        case SIGALRM:
+          sigmsg = "Alarm clock";
+          break;
+
+        case SIGTERM:
+          sigmsg = "Terminated";
+          break;
+
+        default:
+          sprintf(sigmsg_buf, "Signal %d", wsignal);
+          sigmsg = sigmsg_buf;
+          break;
+        }
+       simple_dialog(ESD_TYPE_WARN, NULL,
+               "Child capture process %s: %s%s", msg, sigmsg, coredumped);
+      }
+    }
+      
+    /* Read what remains of the capture file, and stop capture (restore
+       menu items) */
     gtk_clist_freeze(GTK_CLIST(packet_list));
-    init_col_widths(cf);
-#ifdef WITH_WIRETAP
-    wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
-#else
-    pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
-#endif
 
-    set_col_widths(cf);
-    gtk_clist_thaw(GTK_CLIST(packet_list));
+    /* XXX - do something if this fails? */
+    wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
+
+    thaw_clist(cf);
+    if (auto_scroll_live)
+      gtk_clist_moveto(GTK_CLIST(packet_list), 
+                      cf->plist_end->row, -1, 1.0, 1.0);
 
-#ifdef WITH_WIRETAP
     wtap_close(cf->wth);
     cf->wth = NULL;
-#else
-    pcap_close(cf->pfh);
-    cf->pfh = NULL;
-#endif
-#ifdef USE_ITEM
     set_menu_sensitivity("/File/Open...", TRUE);
     set_menu_sensitivity("/File/Close", TRUE);
     set_menu_sensitivity("/File/Save As...", TRUE);
+    set_menu_sensitivity("/File/Print...", TRUE);
     set_menu_sensitivity("/File/Reload", TRUE);
     set_menu_sensitivity("/Capture/Start...", TRUE);
-    set_menu_sensitivity("/Tools/Capture...", TRUE);
     set_menu_sensitivity("/Tools/Summary", TRUE);
-
-#else
-    set_menu_sensitivity("<Main>/File/Open...", TRUE);
-    set_menu_sensitivity("<Main>/File/Close", TRUE);
-    set_menu_sensitivity("<Main>/File/Save As...", TRUE);
-    set_menu_sensitivity("<Main>/File/Reload", TRUE);
-    set_menu_sensitivity("<Main>/Capture/Start...", TRUE);
-    set_menu_sensitivity("<Main>/Tools/Capture...", TRUE);
-    set_menu_sensitivity("<Main>/Tools/Summary", TRUE);
-#endif
     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
     return;
   }
 
-  gtk_clist_freeze(GTK_CLIST(packet_list));
-  init_col_widths(cf);
-#ifdef WITH_WIRETAP
-  wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
-#else
-  pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
-#endif
-
-  set_col_widths(cf);
-  gtk_clist_thaw(GTK_CLIST(packet_list));
-
-  /* restore pipe handler */
-  cap_input_id = gtk_input_add_full (sync_pipe[0],
-                                    GDK_INPUT_READ,
-                                    cap_file_input_cb,
-                                    NULL,
-                                    (gpointer) cf,
-                                    NULL);
-
-  /* only useful in case of low amount of captured data */
-  tail_timeout_id = gtk_timeout_add(TAIL_TIMEOUT, tail_timeout_cb, (gpointer) cf);
-
-}
-
-gint
-tail_timeout_cb(gpointer data) {
-
-  capture_file *cf = (capture_file *)data;
-
-  /* avoid reentrancy problems and stack overflow */
-  gtk_input_remove(cap_input_id);
+  buffer[nread] = '\0';
+
+  while(!exit_loop) {
+    /* look for (possibly multiple) '*' */
+    switch (*q) {
+    case '*' :
+      to_read += atoi(p);
+      p = q + 1; 
+      q++;
+      break;
+    case '\0' :
+      /* XXX should handle the case of a pipe full (i.e. no star found) */
+      exit_loop = TRUE;
+      break;
+    default :
+      q++;
+      break;
+    } 
+  }
 
   gtk_clist_freeze(GTK_CLIST(packet_list));
-  init_col_widths(cf);
-#ifdef WITH_WIRETAP
-  wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
-#else
-  pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
-#endif
-
-  set_col_widths(cf);
+  /* XXX - do something if this fails? */
+  wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
   gtk_clist_thaw(GTK_CLIST(packet_list));
+  if (auto_scroll_live)
+    gtk_clist_moveto(GTK_CLIST(packet_list), cf->plist_end->row, -1, 1.0, 1.0);
 
+  /* restore pipe handler */
   cap_input_id = gtk_input_add_full (sync_pipe[0],
                                     GDK_INPUT_READ,
                                     cap_file_input_cb,
                                     NULL,
                                     (gpointer) cf,
                                     NULL);
-
-  return TRUE;
 }
 
 int
 tail_cap_file(char *fname, capture_file *cf) {
   int     err;
+  int     i;
 
-  close_cap_file(cf, info_bar, file_ctx);
-
-  /* Initialize protocol-speficic variables */
-  ncp_init_protocol();
-  
   err = open_cap_file(fname, cf);
-#ifdef WITH_WIRETAP
   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
-#else
-  if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
-#endif
 
-#ifdef USE_ITEM
     set_menu_sensitivity("/File/Open...", FALSE);
-    set_menu_sensitivity("/File/Close", FALSE);
-    set_menu_sensitivity("/File/Reload", FALSE);
+    set_menu_sensitivity("/Display/Options...", TRUE);
     set_menu_sensitivity("/Capture/Start...", FALSE);
-    set_menu_sensitivity("/Tools/Capture...", FALSE);
-    set_menu_sensitivity("/Tools/Summary", FALSE);
 
-#else
-    set_menu_sensitivity("<Main>/File/Open...", FALSE);
-    set_menu_sensitivity("<Main>/File/Close", FALSE);
-    set_menu_sensitivity("<Main>/File/Reload", FALSE);
-    set_menu_sensitivity("<Main>/Capture/Start...", FALSE);
-    set_menu_sensitivity("<Main>/Tools/Capture...", FALSE);
-    set_menu_sensitivity("<Main>/Tools/Summary", FALSE);
+    for (i = 0; i < cf->cinfo.num_cols; i++) {
+      if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
+        gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
+      else {
+        gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
+        gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
+                               cf->cinfo.col_width[i]);
+        gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
+      }
+    }
+
+    cf->fh = file_open(fname, "r");
 
-#endif
-    cf->fh = fopen(fname, "r");
-    tail_timeout_id = -1;
     cap_input_id = gtk_input_add_full (sync_pipe[0],
                                       GDK_INPUT_READ,
                                       cap_file_input_cb,
@@ -496,175 +528,500 @@ tail_cap_file(char *fname, capture_file *cf) {
                       " <live capture in progress>");
   }
   else {
-#ifdef USE_ITEM
-    set_menu_sensitivity("/File/Close", FALSE);
-    set_menu_sensitivity("/File/Save", FALSE);
-    set_menu_sensitivity("/File/Save As...", FALSE);
-    set_menu_sensitivity("/File/Reload", FALSE);
-    set_menu_sensitivity("/Tools/Summary", FALSE);
-#else
-    set_menu_sensitivity("<Main>/File/Close", FALSE);
-    set_menu_sensitivity("<Main>/File/Save", FALSE);
-    set_menu_sensitivity("<Main>/File/Save As...", FALSE);
-    set_menu_sensitivity("<Main>/File/Reload", FALSE);
-    set_menu_sensitivity("<Main>/Tools/Summary", FALSE);
-#endif
     close(sync_pipe[0]);
   }
   return err;
 }
+#endif /* HAVE_LIBPCAP */
+
+/* To do: Add check_col checks to the col_add* routines */
+
+static void
+col_set_abs_time(frame_data *fd, int col)
+{
+  struct tm *tmp;
+  time_t then;
+
+  then = fd->abs_secs;
+  tmp = localtime(&then);
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
+    tmp->tm_hour,
+    tmp->tm_min,
+    tmp->tm_sec,
+    (long)fd->abs_usecs/100);
+}
 
 static void
-compute_time_stamps(frame_data *fdata, capture_file *cf)
+col_set_rel_time(frame_data *fd, int col)
 {
-  /* If we don't have the time stamp of the first packet, it's because this
-     is the first packet.  Save the time stamp of this packet as the time
-     stamp of the first packet. */
-  if (!firstsec && !firstusec) {
-    firstsec  = fdata->abs_secs;
-    firstusec = fdata->abs_usecs;
-  }
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
+    fd->rel_usecs);
+}
 
-  /* Do the same for the time stamp of the previous packet. */
-  if (!lastsec && !lastusec) {
-    lastsec  = fdata->abs_secs;
-    lastusec = fdata->abs_usecs;
-  }
+static void
+col_set_delta_time(frame_data *fd, int col)
+{
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
+    fd->del_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->rel_secs = cf->esec;
-  fdata->rel_usecs = cf->eusec;
-  
-  /* Do the same for the previous packet */
-  fdata->del_secs = fdata->abs_secs - lastsec;
-  if (lastusec <= fdata->abs_usecs) {
-    fdata->del_usecs = fdata->abs_usecs - lastusec;
-  } else {
-    fdata->del_usecs = (fdata->abs_usecs + 1000000) - lastusec;
-    fdata->del_secs--;
+/* Add "command-line-specified" time. */
+static void
+col_set_cls_time(frame_data *fd, int col)
+{
+  switch (timestamp_type) {
+    case ABSOLUTE:
+      col_set_abs_time(fd, col);
+      break;
+
+    case RELATIVE:
+      col_set_rel_time(fd, col);
+      break;
+
+    case DELTA:
+      col_set_delta_time(fd, col);
+      break;
   }
-  lastsec = fdata->abs_secs;
-  lastusec = fdata->abs_usecs;
 }
 
 static void
-change_time_format_in_packet_list(frame_data *fdata, capture_file *cf)
+col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
 {
-  gint          i, col_width;
+  u_int ipv4_addr;
+  struct e_in6_addr ipv6_addr;
+  struct atalk_ddp_addr ddp_addr;
 
-  /* 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 no columns that show the time in the "command-line-specified"
-       format, so there's nothing we need to do. */
-    return;
+  switch (addr->type) {
+
+  case AT_ETHER:
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN);
+    else
+      strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN);
+    break;
+
+  case AT_IPv4:
+    memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN);
+    else
+      strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN);
+    break;
+
+  case AT_IPv6:
+    memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr);
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN);
+    else
+      strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
+    break;
+
+  case AT_IPX:
+    strncpy(fd->cinfo->col_data[col],
+      ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
+    break;
+
+  case AT_SNA:
+    switch (addr->len) {
+
+    case 1:
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", addr->data[0]);
+      break;
+
+    case 2:
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X",
+        pntohs(&addr->data[0]));
+      break;
+    }
+    break;
+
+  case AT_ATALK:
+    memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
+    strncpy(fd->cinfo->col_data[col], atalk_addr_to_str(&ddp_addr),
+      COL_MAX_LEN);
+    break;
+
+  case AT_VINES:
+    strncpy(fd->cinfo->col_data[col], vines_addr_to_str(&addr->data[0]),
+      COL_MAX_LEN);
+    break;
+
+  default:
+    break;
   }
+  fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+}
 
-  compute_time_stamps(fdata, cf);
+static void
+col_set_port(frame_data *fd, int col, port_type ptype, guint32 port,
+               gboolean is_res)
+{
+  switch (ptype) {
 
-  for (i = 0; i < fdata->cinfo->num_cols; i++) {
-    fdata->cinfo->col_data[i][0] = '\0';
+  case PT_TCP:
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_tcp_port(port), COL_MAX_LEN);
+    else
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+    break;
+
+  case PT_UDP:
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_udp_port(port), COL_MAX_LEN);
+    else
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+    break;
+
+  default:
+    break;
   }
-  col_add_cls_time(fdata);
-  for (i = 0; i < fdata->cinfo->num_cols; i++) {
-    if (fdata->cinfo->fmt_matx[i][COL_CLS_TIME]) {
-      /* This is one of the columns that shows the time in
-         "command-line-specified" format; update it. */
-      col_width = gdk_string_width(pl_style->font, fdata->cinfo->col_data[i]);
-      if (col_width > fdata->cinfo->col_width[i])
-        fdata->cinfo->col_width[i] = col_width;
-      gtk_clist_set_text(GTK_CLIST(packet_list), cf->count - 1, i,
-                         fdata->cinfo->col_data[i]);
+  fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+}
+
+static void
+fill_in_columns(frame_data *fd)
+{
+  int i;
+
+  for (i = 0; i < fd->cinfo->num_cols; i++) {
+    switch (fd->cinfo->col_fmt[i]) {
+
+    case COL_NUMBER:
+      snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num);
+      break;
+
+    case COL_CLS_TIME:
+      col_set_cls_time(fd, i);
+      break;
+
+    case COL_ABS_TIME:
+      col_set_abs_time(fd, i);
+      break;
+
+    case COL_REL_TIME:
+      col_set_rel_time(fd, i);
+      break;
+
+    case COL_DELTA_TIME:
+      col_set_delta_time(fd, i);
+      break;
+
+    case COL_DEF_SRC:
+    case COL_RES_SRC:  /* COL_DEF_SRC is currently just like COL_RES_SRC */
+      col_set_addr(fd, i, &pi.src, TRUE);
+      break;
+
+    case COL_UNRES_SRC:
+      col_set_addr(fd, i, &pi.src, FALSE);
+      break;
+
+    case COL_DEF_DL_SRC:
+    case COL_RES_DL_SRC:
+      col_set_addr(fd, i, &pi.dl_src, TRUE);
+      break;
+
+    case COL_UNRES_DL_SRC:
+      col_set_addr(fd, i, &pi.dl_src, FALSE);
+      break;
+
+    case COL_DEF_NET_SRC:
+    case COL_RES_NET_SRC:
+      col_set_addr(fd, i, &pi.net_src, TRUE);
+      break;
+
+    case COL_UNRES_NET_SRC:
+      col_set_addr(fd, i, &pi.net_src, FALSE);
+      break;
+
+    case COL_DEF_DST:
+    case COL_RES_DST:  /* COL_DEF_DST is currently just like COL_RES_DST */
+      col_set_addr(fd, i, &pi.dst, TRUE);
+      break;
+
+    case COL_UNRES_DST:
+      col_set_addr(fd, i, &pi.dst, FALSE);
+      break;
+
+    case COL_DEF_DL_DST:
+    case COL_RES_DL_DST:
+      col_set_addr(fd, i, &pi.dl_dst, TRUE);
+      break;
+
+    case COL_UNRES_DL_DST:
+      col_set_addr(fd, i, &pi.dl_dst, FALSE);
+      break;
+
+    case COL_DEF_NET_DST:
+    case COL_RES_NET_DST:
+      col_set_addr(fd, i, &pi.net_dst, TRUE);
+      break;
+
+    case COL_UNRES_NET_DST:
+      col_set_addr(fd, i, &pi.net_dst, FALSE);
+      break;
+
+    case COL_DEF_SRC_PORT:
+    case COL_RES_SRC_PORT:     /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
+      col_set_port(fd, i, pi.ptype, pi.srcport, TRUE);
+      break;
+
+    case COL_UNRES_SRC_PORT:
+      col_set_port(fd, i, pi.ptype, pi.srcport, FALSE);
+      break;
+
+    case COL_DEF_DST_PORT:
+    case COL_RES_DST_PORT:     /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
+      col_set_port(fd, i, pi.ptype, pi.destport, TRUE);
+      break;
+
+    case COL_UNRES_DST_PORT:
+      col_set_port(fd, i, pi.ptype, pi.destport, FALSE);
+      break;
+
+    case COL_PROTOCOL: /* currently done by dissectors */
+    case COL_INFO:     /* currently done by dissectors */
+      break;
+
+    case COL_PACKET_LENGTH:
+      snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len);
+      break;
+
+    case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
+      break;
     }
   }
-  fdata->cinfo = NULL;
 }
 
 static void
 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
 {
-  gint          i, row, col_width;
+  gint          i, row;
+  gint         crow;
+  gint                 color;
+  proto_tree   *protocol_tree;
+
+  fdata->num = cf->count;
+
+  /* If we don't have the time stamp of the first packet in the
+     capture, it's because this is the first packet.  Save the time
+     stamp of this packet as the time stamp of the first packet. */
+  if (!firstsec && !firstusec) {
+    firstsec  = fdata->abs_secs;
+    firstusec = fdata->abs_usecs;
+  }
 
-  compute_time_stamps(fdata, cf);
+  /* 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 (check_col(fdata, COL_NUMBER))
-    col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
-  dissect_packet(buf, fdata, NULL);
-  for (i = 0; i < fdata->cinfo->num_cols; i++) {
-    col_width = gdk_string_width(pl_style->font, fdata->cinfo->col_data[i]);
-    if (col_width > fdata->cinfo->col_width[i])
-      fdata->cinfo->col_width[i] = col_width;
+
+  /* Apply the filters */
+  if (cf->dfcode != NULL ||
+      CFILTERS_CONTAINS_FILTER(cf)) {
+       protocol_tree = proto_tree_create_root();
+       dissect_packet(buf, fdata, protocol_tree);
+       if (cf->dfcode != NULL)
+               fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
+       else
+               fdata->passed_dfilter = TRUE;
+       /* Apply color filters. */
+       color = -1;
+        for(crow = 0; cf->colors->num_of_filters && 
+             crow < cf->colors->num_of_filters; crow++) {
+
+            if(color_filter(cf,crow)->c_colorfilter == NULL) {
+               continue;
+           }
+            if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
+                cf->pd)){
+                color = crow;
+               break;
+            }
+        }
+
+       proto_tree_free(protocol_tree);
+  }
+  else {
+       dissect_packet(buf, fdata, NULL);
+       fdata->passed_dfilter = TRUE;
+       color = -1;
   }
-  row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
+  if (fdata->passed_dfilter) {
+    /* If we don't have the time stamp of the previous displayed packet,
+       it's because this is the first displayed packet.  Save the time
+       stamp of this packet as the time stamp of the previous displayed
+       packet. */
+    if (!prevsec && !prevusec) {
+      prevsec  = fdata->abs_secs;
+      prevusec = fdata->abs_usecs;
+    }
+
+    /* Get the time elapsed between the first packet and this packet. */
+    fdata->rel_secs = cf->esec;
+    fdata->rel_usecs = cf->eusec;
+  
+    /* 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--;
+    }
+    prevsec = fdata->abs_secs;
+    prevusec = fdata->abs_usecs;
+
+    fill_in_columns(fdata);
+
+    row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
+    fdata->row = row;
+
+    if (cf->colors->color_filters && (color != -1)){
+        gtk_clist_set_background(GTK_CLIST(packet_list), row,
+                   &(color_filter(cf,color)->bg_color));
+        gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
+                   &(color_filter(cf,color)->fg_color));
+    } else {
+        gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
+        gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
+    }
+
+    /* If this was the selected packet, remember the row it's in, so
+       we can re-select it.  ("selected_packet" is 0-origin, as it's
+       a GList index; "num", however, is 1-origin.) */
+    if (cf->selected_packet == fdata->num - 1)
+      cf->selected_row = row;
+  } else
+    fdata->row = -1;   /* not in the display */
   fdata->cinfo = NULL;
 }
 
 static void
-#ifdef WITH_WIRETAP
 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
-#else
-pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *phdr,
-#endif
   const u_char *buf) {
   frame_data   *fdata;
   capture_file *cf = (capture_file *) user;
-
-  while (gtk_events_pending())
-    gtk_main_iteration();
+  int           passed;
+  proto_tree   *protocol_tree;
+  frame_data   *plist_end;
+  int file_pos;
+  float prog_val;
+
+  /* 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()"
+     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.
+     
+     Do so only if we were told to do so; when reading a capture file
+     being updated by a live capture, we don't do so (as we're not
+     "done" until the capture stops, so we don't know how close to
+     "done" we are. */
+
+  if (cf->update_progbar && offset >= cf->progbar_nextstep) {
+      file_pos = lseek(cf->filed, 0, SEEK_CUR);
+      prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
+      gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), prog_val);
+      cf->progbar_nextstep += cf->progbar_quantum;
+      while (gtk_events_pending())
+      gtk_main_iteration();
+  }
 
   /* Allocate the next list entry, and add it to the list. */
   fdata = (frame_data *) g_malloc(sizeof(frame_data));
-  cf->plist = g_list_append(cf->plist, (gpointer) fdata);
-
-  cf->cur = fdata;
-  cf->count++;
 
+  fdata->next = NULL;
   fdata->pkt_len  = phdr->len;
   fdata->cap_len  = phdr->caplen;
-#ifdef WITH_WIRETAP
   fdata->file_off = offset;
   fdata->lnk_t = phdr->pkt_encap;
-#else
-  fdata->file_off = ftell(pcap_file(cf->pfh)) - phdr->caplen;
-#endif
   fdata->abs_secs  = phdr->ts.tv_sec;
   fdata->abs_usecs = phdr->ts.tv_usec;
+  fdata->pseudo_header = phdr->pseudo_header;
+  fdata->cinfo = NULL;
+
+  passed = TRUE;
+  if (cf->rfcode) {
+    protocol_tree = proto_tree_create_root();
+    dissect_packet(buf, fdata, protocol_tree);
+    passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
+    proto_tree_free(protocol_tree);
+  }   
+  if (passed) {
+    plist_end = cf->plist_end;
+    if (plist_end != NULL)
+      plist_end->next = fdata;
+    else
+      cf->plist = fdata;
+    cf->plist_end = fdata;
 
-  add_packet_to_packet_list(fdata, cf, buf);
+    cf->count++;
+    add_packet_to_packet_list(fdata, cf, buf);
+  } else
+    g_free(fdata);
 }
 
-static void
-filter_packets_cb(gpointer data, gpointer user_data)
+void
+filter_packets(capture_file *cf, gchar *dftext)
 {
-  frame_data *fd = data;
-  capture_file *cf = user_data;
+  dfilter *dfcode;
 
-  cf->cur = fd;
-  cf->count++;
+  if (dftext == NULL) {
+    /* The new filter is an empty filter (i.e., display all packets). */
+    dfcode = NULL;
+  } else {
+    /*
+     * We have a filter; try to compile it.
+     */
+    if (dfilter_compile(dftext, &dfcode) != 0) {
+      /* The attempt failed; report an error. */
+      simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+      return;
+    }
 
-  fseek(cf->fh, fd->file_off, SEEK_SET);
-  fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh);
+    /* Was it empty? */
+    if (dfcode == NULL) {
+      /* Yes - free the filter text, and set it to null. */
+      g_free(dftext);
+      dftext = NULL;
+    }
+  }
 
-  add_packet_to_packet_list(fd, cf, cf->pd);
+  /* We have a valid filter.  Replace the current filter. */
+  if (cf->dfilter != NULL)
+    g_free(cf->dfilter);
+  cf->dfilter = dftext;
+  if (cf->dfcode != NULL)
+    dfilter_destroy(cf->dfcode);
+  cf->dfcode = dfcode;
+
+  /* Now go through the list of packets we've read from the capture file,
+     applying the current display filter, and, if the packet passes the
+     display filter, add it to the summary display, appropriately
+     colored.  (That's how we colorize the display - it's like filtering
+     the display, only we don't install a new filter.) */
+  colorize_packets(cf);
 }
 
 void
-filter_packets(capture_file *cf)
+colorize_packets(capture_file *cf)
 {
+  frame_data *fd;
+  guint32 progbar_quantum;
+  guint32 progbar_nextstep;
+
+  gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
+
   /* Freeze the packet list while we redo it, so we don't get any
      screen updates while it happens. */
   gtk_clist_freeze(GTK_CLIST(packet_list));
@@ -672,35 +1029,219 @@ filter_packets(capture_file *cf)
   /* Clear it out. */
   gtk_clist_clear(GTK_CLIST(packet_list));
 
-  /*
-   * Iterate through the list of packets, calling a routine
-   * to run the filter on the packet, see if it matches, and
-   * put it in the display list if so.
-   *
-   * XXX - we don't yet have anything to run a filter on a packet;
-   * this code awaits the arrival of display filter code.
-   */
+  /* If a packet was selected, we don't know yet what row, if any, it'll
+     get. */
+  cf->selected_row = -1;
+
+  /* Iterate through the list of packets, calling a routine
+     to run the filter on the packet, see if it matches, and
+     put it in the display list if so.  */
   firstsec = 0;
   firstusec = 0;
-  lastsec = 0;
-  lastusec = 0;
+  prevsec = 0;
+  prevusec = 0;
+  cf->unfiltered_count = cf->count;
   cf->count = 0;
-  g_list_foreach(cf->plist, filter_packets_cb, cf);
+
+  proto_tree_is_visible = FALSE;
+
+  /* Update the progress bar when it gets to this value. */
+  progbar_nextstep = 0;
+  /* When we reach the value that triggers a progress bar update,
+     bump that value by this amount. */
+  progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
+  gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
+
+  for (fd = cf->plist; fd != NULL; fd = fd->next) {
+    /* 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()"
+       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 (cf->count >= progbar_nextstep) {
+      /* let's not divide by zero. I should never be started
+       * with unfiltered_count == 0, so let's assert that
+       */
+      g_assert(cf->unfiltered_count > 0);
+
+       gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
+               (gfloat) cf->count / cf->unfiltered_count);
+
+      progbar_nextstep += progbar_quantum;
+      while (gtk_events_pending())
+        gtk_main_iteration();
+    }
+
+    cf->count++;
+
+    wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+
+    add_packet_to_packet_list(fd, cf, cf->pd);
+  }
+  gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
+
+  if (cf->selected_row != -1) {
+    /* We had a selected packet and it passed the filter. */
+    gtk_clist_select_row(GTK_CLIST(packet_list), cf->selected_row, -1);
+  } else {
+    /* If we had one, it didn't pass the filter. */
+    unselect_packet(cf);
+  }
 
   /* Unfreeze the packet list. */
   gtk_clist_thaw(GTK_CLIST(packet_list));
 }
 
-static void
-change_time_formats_cb(gpointer data, gpointer user_data)
+int
+print_packets(capture_file *cf, print_args_t *print_args)
 {
-  frame_data *fd = data;
-  capture_file *cf = user_data;
+  int         i;
+  frame_data *fd;
+  guint32     progbar_quantum;
+  guint32     progbar_nextstep;
+  guint32     count;
+  proto_tree *protocol_tree;
+  gint       *col_widths = NULL;
+  gint        data_width;
+  gboolean    print_separator;
+
+  cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
+  if (cf->print_fh == NULL)
+    return FALSE;      /* attempt to open destination failed */
+
+  /* XXX - printing multiple frames in PostScript looks as if it's
+     tricky - you have to deal with page boundaries, I think -
+     and I'll have to spend some time learning enough about
+     PostScript to figure it out, so, for now, we only print
+     multiple frames as text. */
+#if 0
+  print_preamble(cf->print_fh);
+#endif
 
-  cf->cur = fd;
-  cf->count++;
+  if (print_args->print_summary) {
+    /* We're printing packet summaries.
+
+       Find the widths for each of the columns - maximum of the
+       width of the title and the width of the data - and print
+       the column titles. */
+    col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
+    for (i = 0; i < cf->cinfo.num_cols; i++) {
+      /* Don't pad the last column. */
+      if (i == cf->cinfo.num_cols - 1)
+        col_widths[i] = 0;
+      else {
+        col_widths[i] = strlen(cf->cinfo.col_title[i]);
+        data_width = get_column_char_width(get_column_format(i));
+        if (data_width > col_widths[i])
+          col_widths[i] = data_width;
+      }
+
+      /* Right-justify the packet number column. */
+      if (cf->cinfo.col_fmt[i] == COL_NUMBER)
+        fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_title[i]);
+      else
+        fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_title[i]);
+      if (i == cf->cinfo.num_cols - 1)
+        fputc('\n', cf->print_fh);
+      else
+        fputc(' ', cf->print_fh);
+    }
+  }
+
+  print_separator = FALSE;
+  proto_tree_is_visible = TRUE;
+
+  /* Update the progress bar when it gets to this value. */
+  progbar_nextstep = 0;
+  /* When we reach the value that triggers a progress bar update,
+     bump that value by this amount. */
+  progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
+  /* Count of packets we've looked at. */
+  count = 0;
+
+  /* Iterate through the list of packets, printing the packets that
+     were selected by the current display filter.  */
+  for (fd = cf->plist; fd != NULL; fd = fd->next) {
+    /* 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()"
+       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) {
+      /* let's not divide by zero. I should never be started
+       * with unfiltered_count == 0, so let's assert that
+       */
+      g_assert(cf->unfiltered_count > 0);
+
+      gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
+        (gfloat) count / cf->unfiltered_count);
+      progbar_nextstep += progbar_quantum;
+      while (gtk_events_pending())
+        gtk_main_iteration();
+    }
+    count++;
+
+    if (fd->passed_dfilter) {
+      wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+      if (print_args->print_summary) {
+        /* Fill in the column information, but don't bother creating
+           the logical protocol tree. */
+        fd->cinfo = &cf->cinfo;
+        for (i = 0; i < fd->cinfo->num_cols; i++) {
+          fd->cinfo->col_data[i][0] = '\0';
+        }
+        dissect_packet(cf->pd, fd, NULL);
+        fill_in_columns(fd);
+        for (i = 0; i < cf->cinfo.num_cols; i++) {
+          /* Right-justify the packet number column. */
+          if (cf->cinfo.col_fmt[i] == COL_NUMBER)
+            fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_data[i]);
+          else
+            fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_data[i]);
+          if (i == cf->cinfo.num_cols - 1)
+            fputc('\n', cf->print_fh);
+          else
+            fputc(' ', cf->print_fh);
+        }
+      } else {
+        if (print_separator)
+          fputc('\n', cf->print_fh);
+
+        /* Create the logical protocol tree. */
+        protocol_tree = proto_tree_create_root();
+        dissect_packet(cf->pd, fd, protocol_tree);
+
+        /* Print the information in that tree. */
+        proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
+                       cf->pd, fd, cf->print_fh);
+
+        proto_tree_free(protocol_tree);
+
+       if (print_args->print_hex) {
+         /* Print the full packet data as hex. */
+         print_hex_data(cf->print_fh, cf->pd, fd->cap_len);
+       }
+
+        /* Print a blank line if we print anything after this. */
+        print_separator = TRUE;
+      }
+    }
+  }
 
-  change_time_format_in_packet_list(fd, cf);
+  if (col_widths != NULL)
+    g_free(col_widths);
+
+#if 0
+  print_finale(cf->print_fh);
+#endif
+
+  close_print_dest(print_args->to_file, cf->print_fh);
+  gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
+
+  cf->print_fh = NULL;
+  return TRUE;
 }
 
 /* Scan through the packet list and change all columns that use the
@@ -709,69 +1250,200 @@ change_time_formats_cb(gpointer data, gpointer user_data)
 void
 change_time_formats(capture_file *cf)
 {
+  frame_data *fd;
   int i;
+  GtkStyle  *pl_style;
 
   /* Freeze the packet list while we redo it, so we don't get any
      screen updates while it happens. */
-  gtk_clist_freeze(GTK_CLIST(packet_list));
-
-  /* Zero out the column widths. */
-  init_col_widths(cf);
-
-  /*
-   * Iterate through the list of packets, calling a routine
-   * to run the filter on the packet, see if it matches, and
-   * put it in the display list if so.
-   */
-  firstsec = 0;
-  firstusec = 0;
-  lastsec = 0;
-  lastusec = 0;
-  cf->count = 0;
-  g_list_foreach(cf->plist, change_time_formats_cb, cf);
+  freeze_clist(cf);
+
+  /* Iterate through the list of packets, checking whether the packet
+     is in a row of the summary list and, if so, whether there are
+     any columns that show the time in the "command-line-specified"
+     format and, if so, update that row. */
+  for (fd = cf->plist; fd != NULL; fd = fd->next) {
+    if (fd->row != -1) {
+      /* This packet is in the summary list, on row "fd->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. */
+      fd->cinfo = &cf->cinfo;
+      if (check_col(fd, 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(fd, i);
+            gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
+                         cf->cinfo.col_data[i]);
+         }
+        }
+      }
+    }
+  }
 
   /* Set the column widths of those columns that show the time in
      "command-line-specified" format. */
+  pl_style = gtk_widget_get_style(packet_list);
   for (i = 0; i < cf->cinfo.num_cols; i++) {
     if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
       gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
-        cf->cinfo.col_width[i]);
+        get_column_width(COL_CLS_TIME, pl_style->font));
     }
   }
 
   /* Unfreeze the packet list. */
-  gtk_clist_thaw(GTK_CLIST(packet_list));
+  thaw_clist(cf);
 }
 
-/* Initialize the maximum widths of the columns to the widths of their
-   titles. */
 static void
-init_col_widths(capture_file *cf)
+clear_tree_and_hex_views(void)
+{
+  GList *selection;
+  GtkWidget *tmp_item;
+
+  /* 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));
+
+  /* Deselect any selected tree item. gtktree.c should
+   * do this when we clear_items, but it doesn't. I copied
+   * this while() loop from gtktree.c, gtk_real_tree_select_child()
+   */
+  if (GTK_TREE(tree_view)->root_tree) {
+         selection = GTK_TREE(tree_view)->root_tree->selection;
+         while (selection) {
+                 tmp_item = selection->data;
+                 gtk_tree_item_deselect(GTK_TREE_ITEM(tmp_item));
+                 gtk_widget_unref(tmp_item);
+                 selection = selection->next;
+         }
+         g_list_free(GTK_TREE(tree_view)->root_tree->selection);
+         GTK_TREE(tree_view)->root_tree->selection = NULL;
+  }
+
+  /* Clear the protocol tree view. The length arg of -1
+   * means to clear all items up to the end. */
+  gtk_tree_clear_items(GTK_TREE(tree_view), 0, -1);
+}
+
+
+/* Select the packet on a given row. */
+void
+select_packet(capture_file *cf, int row)
 {
+  frame_data *fd;
   int i;
 
-  /* XXX - this should use the column *title* font, not the font for
-     the items in the list.
+  /* Clear out whatever's currently in 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)));
+
+  /* Search through the list of frames to see which one is in
+     this row. */
+  for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
+    if (fd->row == row)
+      break;
+  }
+
+  g_assert(fd != NULL);
+
+  cf->fd = fd;
+
+  /* Remember the ordinal number of that frame. */
+  cf->selected_packet = i;
+
+  /* Get the data in that frame. */
+  wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+
+  /* 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->pd, cf->fd, cf->protocol_tree);
+
+  /* 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->fd->cap_len, -1, -1);
+  gtk_text_thaw(GTK_TEXT(byte_view));
+
+  /* A packet is selected, so "File/Print Packet" has something to print. */
+  set_menu_sensitivity("/File/Print Packet", TRUE);
+  set_menu_sensitivity("/Display/Collapse All", TRUE);
+  set_menu_sensitivity("/Display/Expand All", TRUE);
+}
+
+/* Unselect the selected packet, if any. */
+void
+unselect_packet(capture_file *cf)
+{
+  cf->selected_packet = -1;    /* nothing there to be selected */
+  cf->selected_row = -1;
+
+  /* Destroy the protocol tree for that packet. */
+  if (cf->protocol_tree != NULL) {
+    proto_tree_free(cf->protocol_tree);
+    cf->protocol_tree = NULL;
+  }
+
+  /* Clear out the display of that packet. */
+  clear_tree_and_hex_views();
+
+  /* No packet is selected, so "File/Print Packet" has nothing to print. */
+  set_menu_sensitivity("/File/Print Packet", FALSE);
+  set_menu_sensitivity("/Display/Collapse All", FALSE);
+  set_menu_sensitivity("/Display/Expand All", FALSE);
+}
+
+static void
+freeze_clist(capture_file *cf)
+{
+  int i;
 
-     Unfortunately, it's not clear how to get that font - it'd be
-     the font used for buttons; there doesn't seem to be a way to get
-     that from a clist, or to get one of the buttons in that clist from
-     the clist in order to get its font. */
+  /* Make the column sizes static, so they don't adjust while
+     we're reading the capture file (freezing the clist doesn't
+     seem to suffice). */
   for (i = 0; i < cf->cinfo.num_cols; i++)
-    cf->cinfo.col_width[i] = gdk_string_width(pl_style->font,
-                                               cf->cinfo.col_title[i]);
+    gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
+  gtk_clist_freeze(GTK_CLIST(packet_list));
 }
 
-/* Set the widths of the columns to the maximum widths we found. */
 static void
-set_col_widths(capture_file *cf)
+thaw_clist(capture_file *cf)
 {
   int i;
 
   for (i = 0; i < cf->cinfo.num_cols; i++) {
-    gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
-      cf->cinfo.col_width[i]);
+    if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
+      /* Set this column's width to the appropriate value. */
+      gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
+                               cf->cinfo.col_width[i]);
+    } else {
+      /* Make this column's size dynamic, so that it adjusts to the
+         appropriate size. */
+      gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
+    }
   }
+  gtk_clist_thaw(GTK_CLIST(packet_list));
+
+  /* Hopefully, the columns have now gotten their appropriate sizes;
+     make them resizeable - a column that auto-resizes cannot be
+     resized by the user, and *vice versa*. */
+  for (i = 0; i < cf->cinfo.num_cols; i++)
+    gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
 }
 
 /* Tries to mv a file. If unsuccessful, tries to cp the file.
@@ -785,16 +1457,20 @@ file_mv(char *from, char *to)
 
        int retval;
 
+#ifndef WIN32
        /* try a hard link */
        retval = link(from, to);
 
        /* or try a copy */
        if (retval < 0) {
+#endif
                retval = file_cp(from, to);
                if (!retval) {
                        return 0;
                }
+#ifndef WIN32
        }
+#endif
 
        unlink(from);
        return 1;
@@ -811,20 +1487,19 @@ file_cp(char *from, char *to)
 
        int from_fd, to_fd, nread, nwritten;
        char *buffer;
-       gint dialogue_button = ESD_BTN_OK;
 
        buffer = g_malloc(COPY_BUFFER_SIZE);
 
        from_fd = open(from, O_RDONLY);
        if (from_fd < 0) {
-               simple_dialog(ESD_TYPE_WARN, &dialogue_button,
+               simple_dialog(ESD_TYPE_WARN, NULL,
                        file_open_error_message(errno, TRUE), from);
                return 0;
        }
 
        to_fd = creat(to, 0644);
        if (to_fd < 0) {
-               simple_dialog(ESD_TYPE_WARN, &dialogue_button,
+               simple_dialog(ESD_TYPE_WARN, NULL,
                        file_open_error_message(errno, TRUE), to);
                close(from_fd);
                return 0;
@@ -834,10 +1509,10 @@ file_cp(char *from, char *to)
                nwritten = write(to_fd, buffer, nread);
                if (nwritten < nread) {
                        if (nwritten < 0) {
-                               simple_dialog(ESD_TYPE_WARN, &dialogue_button,
+                               simple_dialog(ESD_TYPE_WARN, NULL,
                                        file_write_error_message(errno), to);
                        } else {
-                               simple_dialog(ESD_TYPE_WARN, &dialogue_button,
+                               simple_dialog(ESD_TYPE_WARN, NULL,
 "The file \"%s\" could not be saved: tried writing %d, wrote %d.\n",
                                        to, nread, nwritten);
                        }
@@ -847,7 +1522,7 @@ file_cp(char *from, char *to)
                }
        }
        if (nread < 0) {
-               simple_dialog(ESD_TYPE_WARN, &dialogue_button,
+               simple_dialog(ESD_TYPE_WARN, NULL,
                        file_read_error_message(errno), from);
                close(from_fd);
                close(to_fd);
@@ -867,14 +1542,31 @@ file_open_error_message(int err, int for_writing)
 
   switch (err) {
 
-  case OPEN_CAP_FILE_NOT_REGULAR:
+  case WTAP_ERR_NOT_REGULAR_FILE:
     errmsg = "The file \"%s\" is invalid.";
     break;
 
-  case OPEN_CAP_FILE_UNKNOWN_FORMAT:
+  case WTAP_ERR_FILE_UNKNOWN_FORMAT:
+  case WTAP_ERR_UNSUPPORTED:
     errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
     break;
 
+  case WTAP_ERR_BAD_RECORD:
+    errmsg = "The file \"%s\" appears to be damaged or corrupt.";
+    break;
+
+  case WTAP_ERR_CANT_OPEN:
+    if (for_writing)
+      errmsg = "The file \"%s\" could not be created for some unknown reason.";
+    else
+      errmsg = "The file \"%s\" could not be opened for some unknown reason.";
+    break;
+
+  case WTAP_ERR_SHORT_READ:
+    errmsg = "The file \"%s\" appears to have been cut short"
+             " in the middle of a packet.";
+    break;
+
   case ENOENT:
     if (for_writing)
       errmsg = "The path to the file \"%s\" does not exist.";
@@ -886,11 +1578,12 @@ file_open_error_message(int err, int for_writing)
     if (for_writing)
       errmsg = "You do not have permission to create or write to the file \"%s\".";
     else
-      errmsg = "You do not have permission to open the file \"%s\".";
+      errmsg = "You do not have permission to read the file \"%s\".";
     break;
 
   default:
-    sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.", strerror(err));
+    sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
+                               wtap_strerror(err));
     errmsg = errmsg_errno;
     break;
   }
@@ -902,7 +1595,8 @@ file_read_error_message(int err)
 {
   static char errmsg_errno[1024+1];
 
-  sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.", strerror(err));
+  sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
+                               wtap_strerror(err));
   return errmsg_errno;
 }
 
@@ -925,7 +1619,8 @@ file_write_error_message(int err)
 #endif
 
   default:
-    sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.", strerror(err));
+    sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
+                               wtap_strerror(err));
     errmsg = errmsg_errno;
     break;
   }