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 69fb4281620f4f6d3aab1a91e778926318c01143..d8e920c183eeee1648e01b4852cfde7c896304dd 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.83 1999/08/26 07:01:42 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>
@@ -46,6 +46,7 @@
 #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 "gtkpacket.h"
+#include "gtk/proto_draw.h"
 #include "dfilter.h"
 #include "timestamp.h"
+#include "conversation.h"
+
+#ifndef __RESOLV_H__
+#include "resolv.h"
+#endif
+
+#include "packet-atalk.h"
+
+#include "packet-ipv6.h"
 
 #include "packet-ncp.h"
 
 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
 extern guint      file_ctx;
-extern int       sync_mode;
 extern int        sync_pipe[];
 
 guint cap_input_id;
+gboolean auto_scroll_live = FALSE;
 
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
@@ -97,13 +111,15 @@ static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
 static void freeze_clist(capture_file *cf);
 static void thaw_clist(capture_file *cf);
 
-static gint dfilter_progress_cb(gpointer p);
+/* 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) {
   wtap       *wth;
   int         err;
-  FILE       *fh;
+  FILE_T      fh;
+  int         fd;
   struct stat cf_stat;
 
   wth = wtap_open_offline(fname, &err);
@@ -112,7 +128,8 @@ open_cap_file(char *fname, capture_file *cf) {
 
   /* Find the size of the file. */
   fh = wtap_file(wth);
-  if (fstat(fileno(fh), &cf_stat) < 0) {
+  fd = wtap_fd(wth);
+  if (fstat(fd, &cf_stat) < 0) {
     err = errno;
     wtap_close(wth);
     goto fail;
@@ -122,11 +139,17 @@ open_cap_file(char *fname, capture_file *cf) {
      and fill in the information for this file. */
   close_cap_file(cf, info_bar, file_ctx);
 
+  /* 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 */
@@ -139,6 +162,9 @@ open_cap_file(char *fname, capture_file *cf) {
   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;
  
@@ -156,7 +182,7 @@ 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;
   }
   if (cf->wth) {
@@ -196,7 +222,6 @@ read_cap_file(capture_file *cf) {
   gchar  *done_fmt = " File: %s  Drops: %d";
   int     success;
   int     err;
-  gint    timeout;
   size_t  msg_len;
   char   *errmsg;
   char    errmsg_errno[1024+1];
@@ -210,19 +235,26 @@ read_cap_file(capture_file *cf) {
   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);
+
+  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->fh = fopen(cf->filename, "r");
+  cf->filed = open(cf->filename, O_RDONLY);
+  cf->fh = filed_open(cf->filed, "r");
+  cf->unfiltered_count = cf->count;
   thaw_clist(cf);
-  
-  gtk_timeout_remove(timeout);
-  gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
+
+  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);
 
@@ -282,11 +314,17 @@ void
 cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
   
   capture_file *cf = (capture_file *)data;
-  char buffer[256], *p = buffer, *q = buffer;
+  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);
@@ -294,14 +332,117 @@ cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
   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.  Read what remains of the capture file,
-       and stop capture (restore menu items) */
+       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));
 
     /* 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);
 
     wtap_close(cf->wth);
     cf->wth = NULL;
@@ -310,9 +451,7 @@ cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
     set_menu_sensitivity("/File/Save As...", TRUE);
     set_menu_sensitivity("/File/Print...", TRUE);
     set_menu_sensitivity("/File/Reload", TRUE);
-#ifdef HAVE_LIBPCAP
     set_menu_sensitivity("/Capture/Start...", TRUE);
-#endif
     set_menu_sensitivity("/Tools/Summary", TRUE);
     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
     return;
@@ -342,6 +481,8 @@ cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
   /* 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],
@@ -362,9 +503,7 @@ tail_cap_file(char *fname, capture_file *cf) {
 
     set_menu_sensitivity("/File/Open...", FALSE);
     set_menu_sensitivity("/Display/Options...", TRUE);
-#ifdef HAVE_LIBPCAP
     set_menu_sensitivity("/Capture/Start...", FALSE);
-#endif
 
     for (i = 0; i < cf->cinfo.num_cols; i++) {
       if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
@@ -377,7 +516,7 @@ tail_cap_file(char *fname, capture_file *cf) {
       }
     }
 
-    cf->fh = fopen(fname, "r");
+    cf->fh = file_open(fname, "r");
 
     cap_input_id = gtk_input_add_full (sync_pipe[0],
                                       GDK_INPUT_READ,
@@ -393,19 +532,19 @@ tail_cap_file(char *fname, capture_file *cf) {
   }
   return err;
 }
-#endif
+#endif /* HAVE_LIBPCAP */
 
 /* To do: Add check_col checks to the col_add* routines */
 
 static void
-col_add_abs_time(frame_data *fd, gint el)
+col_set_abs_time(frame_data *fd, int col)
 {
   struct tm *tmp;
   time_t then;
 
   then = fd->abs_secs;
   tmp = localtime(&then);
-  col_add_fstr(fd, el, "%02d:%02d:%02d.%04ld",
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
     tmp->tm_hour,
     tmp->tm_min,
     tmp->tm_sec,
@@ -413,33 +552,243 @@ col_add_abs_time(frame_data *fd, gint el)
 }
 
 static void
-col_add_rel_time(frame_data *fd, gint el)
+col_set_rel_time(frame_data *fd, int col)
 {
-  col_add_fstr(fd, el, "%d.%06d", fd->rel_secs, fd->rel_usecs);
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
+    fd->rel_usecs);
 }
 
 static void
-col_add_delta_time(frame_data *fd, gint el)
+col_set_delta_time(frame_data *fd, int col)
 {
-  col_add_fstr(fd, el, "%d.%06d", fd->del_secs, fd->del_usecs);
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
+    fd->del_usecs);
 }
 
 /* Add "command-line-specified" time. */
 static void
-col_add_cls_time(frame_data *fd)
+col_set_cls_time(frame_data *fd, int col)
 {
   switch (timestamp_type) {
     case ABSOLUTE:
-      col_add_abs_time(fd, COL_CLS_TIME);
+      col_set_abs_time(fd, col);
       break;
 
     case RELATIVE:
-      col_add_rel_time(fd, COL_CLS_TIME);
+      col_set_rel_time(fd, col);
       break;
 
     case DELTA:
-      col_add_delta_time(fd, COL_CLS_TIME);
+      col_set_delta_time(fd, col);
+      break;
+  }
+}
+
+static void
+col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
+{
+  u_int ipv4_addr;
+  struct e_in6_addr ipv6_addr;
+  struct atalk_ddp_addr ddp_addr;
+
+  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';
+}
+
+static void
+col_set_port(frame_data *fd, int col, port_type ptype, guint32 port,
+               gboolean is_res)
+{
+  switch (ptype) {
+
+  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;
+  }
+  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;
+    }
   }
 }
 
@@ -451,6 +800,8 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
   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. */
@@ -474,40 +825,27 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
   }
 
   /* Apply the filters */
-  if (DFILTER_CONTAINS_FILTER(cf->dfcode) ||
+  if (cf->dfcode != NULL ||
       CFILTERS_CONTAINS_FILTER(cf)) {
        protocol_tree = proto_tree_create_root();
        dissect_packet(buf, fdata, protocol_tree);
-       if( DFILTER_CONTAINS_FILTER(cf->dfcode) )
+       if (cf->dfcode != NULL)
                fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
        else
                fdata->passed_dfilter = TRUE;
-       /* Apply color filters.  The debuggery can come out real soon! */
-#ifdef DEBUG_COLOR_FILTERS
-       fprintf(stderr, "Processing %d filters...\n",cf->colors->num_of_filters);
-       fflush(stderr);
-#endif
+       /* Apply color filters. */
        color = -1;
         for(crow = 0; cf->colors->num_of_filters && 
              crow < cf->colors->num_of_filters; crow++) {
-#ifdef DEBUG_COLOR_FILTERS
-            fprintf(stderr, "Does it match filter %s (%d)? ",
-              get_color_filter_name(cf,crow),crow);
-            fflush(stderr);
-#endif
+
+            if(color_filter(cf,crow)->c_colorfilter == NULL) {
+               continue;
+           }
             if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
                 cf->pd)){
                 color = crow;
-#ifdef DEBUG_COLOR_FILTERS
-                fprintf(stderr,"yes\n");
-#endif
+               break;
             }
-#ifdef DEBUG_COLOR_FILTERS
-            else {
-                fprintf(stderr,"no\n") ;
-                fflush(stderr);
-           }
-#endif
         }
 
        proto_tree_free(protocol_tree);
@@ -518,9 +856,6 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
        color = -1;
   }
   if (fdata->passed_dfilter) {
-    if (check_col(fdata, COL_NUMBER))
-      col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
-
     /* 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
@@ -546,44 +881,25 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
     prevsec = fdata->abs_secs;
     prevusec = fdata->abs_usecs;
 
-    /* Set any time stamp columns. */
-    if (check_col(fdata, COL_CLS_TIME))
-      col_add_cls_time(fdata);
-    if (check_col(fdata, COL_ABS_TIME))
-      col_add_abs_time(fdata, COL_ABS_TIME);
-    if (check_col(fdata, COL_REL_TIME))
-      col_add_rel_time(fdata, COL_REL_TIME);
-    if (check_col(fdata, COL_DELTA_TIME))
-      col_add_delta_time(fdata, COL_DELTA_TIME);
-
-    if (check_col(fdata, COL_PACKET_LENGTH))
-      col_add_fstr(fdata, COL_PACKET_LENGTH, "%d", fdata->pkt_len);
+    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,
+    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,
+        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);
-
-       }
-
-#ifdef DEBUG_COLOR_FILTERS
-        fprintf(stderr,"Now row %d\n", row+2);
-        fflush(stderr);    
-#endif
+    } 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; "count", however, is 1-origin.) */
-    if (cf->selected_packet == cf->count - 1)
+       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 */
@@ -598,9 +914,28 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
   int           passed;
   proto_tree   *protocol_tree;
   frame_data   *plist_end;
-
-  while (gtk_events_pending())
-    gtk_main_iteration();
+  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));
@@ -617,12 +952,10 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
 
   passed = TRUE;
   if (cf->rfcode) {
-         if (DFILTER_CONTAINS_FILTER(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);
-         }
+    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;
@@ -639,24 +972,56 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
 }
 
 void
-filter_packets(capture_file *cf)
+filter_packets(capture_file *cf, gchar *dftext)
 {
-/*  gint timeout;*/
-  frame_data *fd;
+  dfilter *dfcode;
 
-  if (cf->dfilter == NULL) {
-       dfilter_clear_filter(cf->dfcode);
-  }
-  else {
+  if (dftext == NULL) {
+    /* The new filter is an empty filter (i.e., display all packets). */
+    dfcode = NULL;
+  else {
     /*
-     * Compile the filter.
+     * We have a filter; try to compile it.
      */
-    if (dfilter_compile(cf->dfcode, cf->dfilter) != 0) {
+    if (dfilter_compile(dftext, &dfcode) != 0) {
+      /* The attempt failed; report an error. */
       simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
       return;
     }
+
+    /* Was it empty? */
+    if (dfcode == NULL) {
+      /* Yes - free the filter text, and set it to null. */
+      g_free(dftext);
+      dftext = NULL;
+    }
   }
 
+  /* 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
+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));
@@ -680,20 +1045,39 @@ filter_packets(capture_file *cf)
 
   proto_tree_is_visible = FALSE;
 
-/*  timeout = gtk_timeout_add(250, dfilter_progress_cb, cf);*/
+  /* 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++;
 
-    fseek(cf->fh, fd->file_off, SEEK_SET);
-    fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh);
+    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);
-
-    if (cf->count % 20 == 0) {
-      dfilter_progress_cb(cf);
-    }
   }
-/*  gtk_timeout_remove(timeout);*/
  
   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
 
@@ -709,34 +1093,20 @@ filter_packets(capture_file *cf)
   gtk_clist_thaw(GTK_CLIST(packet_list));
 }
 
-/* Update the progress bar */
-static gint
-dfilter_progress_cb(gpointer p) {
-  capture_file *cf = (capture_file*)p;
-
-  /* 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);
-
-  /* Have GTK+ repaint what is pending */
-  while (gtk_events_pending ()) {
-         gtk_main_iteration();
-  }
-  return TRUE;
-}
-
-
 int
-print_packets(capture_file *cf, int to_file, const char *dest)
+print_packets(capture_file *cf, print_args_t *print_args)
 {
+  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(to_file, dest);
+  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 */
 
@@ -749,31 +1119,127 @@ print_packets(capture_file *cf, int to_file, const char *dest)
   print_preamble(cf->print_fh);
 #endif
 
+  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;
 
-  /* Iterate through the list of packets, printing each of them.  */
-  cf->count = 0;
+  /* 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) {
-    cf->count++;
+    /* 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);
 
-    fseek(cf->fh, fd->file_off, SEEK_SET);
-    fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh);
+        /* Create the logical protocol tree. */
+        protocol_tree = proto_tree_create_root();
+        dissect_packet(cf->pd, fd, protocol_tree);
 
-    /* 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);
 
-    /* Print the packet */
-    proto_tree_print(cf->count, (GNode *)protocol_tree, cf->pd, fd, cf->print_fh);
+        proto_tree_free(protocol_tree);
 
-    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;
+      }
+    }
   }
 
+  if (col_widths != NULL)
+    g_free(col_widths);
+
 #if 0
   print_finale(cf->print_fh);
 #endif
 
-  close_print_dest(to_file, cf->print_fh);
+  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;
 }
@@ -808,14 +1274,12 @@ change_time_formats(capture_file *cf)
       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++) {
-          cf->cinfo.col_data[i][0] = '\0';
-        }
-        col_add_cls_time(fd);
         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]);
          }
@@ -892,14 +1356,16 @@ select_packet(capture_file *cf, int row)
     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. */
-  fseek(cf->fh, cf->fd->file_off, SEEK_SET);
-  fread(cf->pd, sizeof(guint8), cf->fd->cap_len, cf->fh);
+  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)
@@ -916,6 +1382,8 @@ select_packet(capture_file *cf, int row)
 
   /* 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. */
@@ -936,6 +1404,8 @@ unselect_packet(capture_file *cf)
 
   /* 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