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 cd5b86d77dd05e418ec902317b1e6cbc17f7d728..d8e920c183eeee1648e01b4852cfde7c896304dd 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.90 1999/09/12 06:11:34 guy 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
 
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
 #include "gtk/main.h"
 #include "column.h"
 #include "gtk/menu.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;
@@ -104,7 +118,8 @@ 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);
@@ -113,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;
@@ -123,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 */
@@ -160,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) {
@@ -226,10 +248,13 @@ read_cap_file(capture_file *cf) {
   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_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);
 
@@ -289,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);
@@ -301,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;
@@ -317,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;
@@ -349,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],
@@ -369,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)
@@ -384,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,
@@ -400,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,
@@ -420,54 +552,244 @@ 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)
 {
-  if (check_col(fd, COL_NUMBER))
-    col_add_fstr(fd, COL_NUMBER, "%u", fd->num);
-
-  /* Set any time stamp columns. */
-  if (check_col(fd, COL_CLS_TIME))
-    col_add_cls_time(fd);
-  if (check_col(fd, COL_ABS_TIME))
-    col_add_abs_time(fd, COL_ABS_TIME);
-  if (check_col(fd, COL_REL_TIME))
-    col_add_rel_time(fd, COL_REL_TIME);
-  if (check_col(fd, COL_DELTA_TIME))
-    col_add_delta_time(fd, COL_DELTA_TIME);
-
-  if (check_col(fd, COL_PACKET_LENGTH))
-    col_add_fstr(fd, COL_PACKET_LENGTH, "%d", fd->pkt_len);
+  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;
+    }
+  }
 }
 
 static void
@@ -503,11 +825,11 @@ 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;
@@ -515,6 +837,10 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
        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;
@@ -588,6 +914,8 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
   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
@@ -599,11 +927,13 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
      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) {
-    gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
-      (gfloat) ftell(cf->fh) / (gfloat) cf->f_len);
-    cf->progbar_nextstep += cf->progbar_quantum;
-    while (gtk_events_pending())
+      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();
   }
 
@@ -622,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;
@@ -644,25 +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)
 {
-  frame_data *fd;
-  guint32 progbar_quantum;
-  guint32 progbar_nextstep;
+  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));
@@ -691,6 +1050,7 @@ filter_packets(capture_file *cf)
   /* 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;
@@ -704,8 +1064,9 @@ filter_packets(capture_file *cf)
        */
       g_assert(cf->unfiltered_count > 0);
 
-      gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
-        (gfloat) cf->count / cf->unfiltered_count);
+       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();
@@ -737,6 +1098,9 @@ 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;
@@ -788,9 +1152,36 @@ print_packets(capture_file *cf, print_args_t *print_args)
   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) {
@@ -822,21 +1213,33 @@ print_packets(capture_file *cf, print_args_t *print_args)
         dissect_packet(cf->pd, fd, protocol_tree);
 
         /* Print the information in that tree. */
-        proto_tree_print(FALSE, (GNode *)protocol_tree, cf->pd, fd, cf->print_fh);
+        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;
       }
     }
   }
 
+  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;
 }
@@ -871,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]);
          }
@@ -955,6 +1356,9 @@ 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. */