Added the ethereal capture preferences to the preference file.
[obnox/wireshark/wip.git] / gtk / main.c
index f81a3e19af2194414d0a2e118cdc7a885e400671..a18182654a6422fdedba25d46427f1d09b8908bd 100644 (file)
@@ -1,13 +1,15 @@
 /* main.c
  *
- * $Id: main.c,v 1.170 2001/01/02 01:32:21 guy Exp $
+ * $Id: main.c,v 1.192 2001/04/13 14:59:30 jfoster Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
  * Richard Sharpe, 13-Feb-1999, added support for initializing structures
  *                              needed by dissect routines
+ * Jeff Foster,    2001/03/12,  added support tabbed hex display windowss
+ * 
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 
 #include <signal.h>
 
+#ifdef HAVE_LIBPCAP
+#include <pcap.h>
+#endif
+
 #ifdef NEED_SNPRINTF_H
 # include "snprintf.h"
 #endif
 #include "getopt.h"
 #endif
 
+#ifdef WIN32 /* Needed for console I/O */
+#include <fcntl.h>
+#include <conio.h>
+#endif
+
 #include <epan.h>
+#include <epan/filesystem.h>
 
 #include "main.h"
 #include "timestamp.h"
 #include "capture.h"
 #include "summary.h"
 #include "file.h"
+#include "filters.h"
 #include "menu.h"
 #include "../menu.h"
 #include "color.h"
 #include "util.h"
 #include "simple_dialog.h"
 #include "proto_draw.h"
-#include "dfilter.h"
+#include "dfilter/dfilter.h"
 #include "keys.h"
 #include "packet_win.h"
 #include "gtkglobals.h"
 #include "plugins.h"
 #include "colors.h"
 #include "strutil.h"
+#include "register.h"
+#include "prefs.h"
+
+#ifdef WIN32
+#include "capture-wpcap.h"
+#endif
+
 
 packet_info  pi;
 capture_file cfile;
-GtkWidget   *top_level, *packet_list, *tree_view, *byte_view,
+GtkWidget   *top_level, *packet_list, *tree_view, *byte_nb_ptr,
             *info_bar, *tv_scrollw, *pkt_scrollw;
 static GtkWidget       *bv_scrollw;
 GdkFont     *m_r_font, *m_b_font;
+guint          m_font_height, m_font_width;
 guint        main_ctx, file_ctx, help_ctx;
-gchar        comp_info_str[256];
+static GString *comp_info_str;
 gchar       *ethereal_path = NULL;
 gchar       *last_open_dir = NULL;
 
@@ -141,7 +162,15 @@ GtkStyle *item_style;
 /* Specifies the field currently selected in the GUI protocol tree */
 field_info *finfo_selected = NULL;
 
-static char* hfinfo_numeric_format(header_field_info *hfinfo);
+#ifdef WIN32
+static gboolean has_no_console;        /* TRUE if app has no console */
+static gboolean console_was_created; /* TRUE if console was created */
+static void create_console(void);
+static void destroy_console(void);
+static void console_log_handler(const char *log_domain,
+    GLogLevelFlags log_level, const char *message, gpointer user_data);
+#endif
+
 static void create_main_window(gint, gint, gint, e_prefs*);
 
 /* About Ethereal window */
@@ -149,14 +178,27 @@ void
 about_ethereal( GtkWidget *w, gpointer data ) {
   simple_dialog(ESD_TYPE_INFO, NULL,
                "Ethereal - Network Protocol Analyzer\n"
-               "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
-                "Compiled with %s\n\n"
+               "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@ethereal.com>\n"
+                "Compiled %s\n\n"
 
                "Check the man page for complete documentation and\n"
                "for the list of contributors.\n"
 
                "\nSee http://www.ethereal.com/ for more information.",
-                 comp_info_str);
+                 comp_info_str->str);
+}
+
+void
+set_fonts(GdkFont *regular, GdkFont *bold)
+{
+       /* Yes, assert. The code that loads the font should check
+        * for NULL and provide its own error message. */
+       g_assert(m_r_font && m_b_font);
+       m_r_font = regular;
+       m_b_font = bold;
+
+       m_font_height = m_r_font->ascent + m_r_font->descent;
+       m_font_width = gdk_string_width(m_r_font, "0");
 }
 
 
@@ -166,10 +208,6 @@ match_selected_cb(GtkWidget *w, gpointer data)
 {
     char               *buf;
     GtkWidget          *filter_te;
-    char               *ptr, *format, *stringified;
-    int                        i, dfilter_len, abbrev_len;
-    guint8             *c;
-    header_field_info  *hfinfo;
 
     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
 
@@ -181,123 +219,7 @@ match_selected_cb(GtkWidget *w, gpointer data)
        return;
     }
 
-    hfinfo = finfo_selected->hfinfo;
-    g_assert(hfinfo);
-    abbrev_len = strlen(hfinfo->abbrev);
-
-       switch(hfinfo->type) {
-
-               case FT_BOOLEAN:
-                       dfilter_len = abbrev_len + 2;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
-                                       hfinfo->abbrev);
-                       break;
-
-               case FT_UINT8:
-               case FT_UINT16:
-               case FT_UINT24:
-               case FT_UINT32:
-               case FT_INT8:
-               case FT_INT16:
-               case FT_INT24:
-               case FT_INT32:
-                       dfilter_len = abbrev_len + 20;
-                       buf = g_malloc0(dfilter_len);
-                       format = hfinfo_numeric_format(hfinfo);
-                       snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
-                       break;
-
-               case FT_IPv4:
-                       dfilter_len = abbrev_len + 4 + 15 + 1;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
-                                       ipv4_addr_str(&(finfo_selected->value.ipv4)));
-                       break;
-
-               case FT_IPXNET:
-                       dfilter_len = abbrev_len + 15;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
-                                       finfo_selected->value.numeric);
-                       break;
-
-               case FT_IPv6:
-                       stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
-                       dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
-                                       stringified);
-                       break;
-
-               case FT_DOUBLE:
-                       dfilter_len = abbrev_len + 30;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
-                                       finfo_selected->value.floating);
-                       break;
-
-               case FT_ETHER:
-                       dfilter_len = abbrev_len + 22;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == %s",
-                                       hfinfo->abbrev,
-                                       ether_to_str(finfo_selected->value.ether));
-                       break;
-#if 0
-
-               case FT_ABSOLUTE_TIME:
-               case FT_RELATIVE_TIME:
-                       memcpy(&fi->value.time, va_arg(ap, struct timeval*),
-                               sizeof(struct timeval));
-                       break;
-
-               case FT_TEXT_ONLY:
-                       ; /* nothing */
-                       break;
-#endif
-
-               case FT_STRING:
-                       dfilter_len = abbrev_len + 
-                         strlen(finfo_selected->value.string) + 7;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == \"%s\"",
-                                hfinfo->abbrev,
-                                finfo_selected->value.string);
-                       break;
-
-               case FT_BYTES:
-                       dfilter_len = finfo_selected->length*3 - 1;
-                       dfilter_len += abbrev_len + 7;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == %s",
-                                hfinfo->abbrev,
-                                bytes_to_str_punct(finfo_selected->value.bytes, finfo_selected->length,':'));
-                       break;                       
-               default:
-                   c = cfile.pd + finfo_selected->start;
-                   buf = g_malloc0(32 + finfo_selected->length * 3);
-                   ptr = buf;
-
-                   sprintf(ptr, "frame[%d] == ", finfo_selected->start);
-                   ptr = buf+strlen(buf);
-
-                   if (finfo_selected->length == 1) {
-                       sprintf(ptr, "0x%02x", *c++);
-                   }
-                   else {
-                           for (i=0;i<finfo_selected->length; i++) {
-                               if (i == 0 ) {
-                                       sprintf(ptr, "%02x", *c++);
-                               }
-                               else {
-                                       sprintf(ptr, ":%02x", *c++);
-                               }
-                               ptr = buf+strlen(buf);
-                           }
-                   }
-                   break;
-       }
+    buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
 
     /* create a new one and set the display filter entry accordingly */
     gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
@@ -308,60 +230,6 @@ match_selected_cb(GtkWidget *w, gpointer data)
     /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
 }
 
-static char*
-hfinfo_numeric_format(header_field_info *hfinfo)
-{
-       char *format = NULL;
-
-       /* Pick the proper format string */
-       switch(hfinfo->display) {
-               case BASE_DEC:
-               case BASE_NONE:
-               case BASE_OCT: /* I'm lazy */
-               case BASE_BIN: /* I'm lazy */
-                       switch(hfinfo->type) {
-                               case FT_UINT8:
-                               case FT_UINT16:
-                               case FT_UINT24:
-                               case FT_UINT32:
-                                       format = "%s == %u";
-                                       break;
-                               case FT_INT8:
-                               case FT_INT16:
-                               case FT_INT24:
-                               case FT_INT32:
-                                       format = "%s == %d";
-                                       break;
-                               default:
-                                       g_assert_not_reached();
-                                       ;
-                       }
-                       break;
-               case BASE_HEX:
-                       switch(hfinfo->type) {
-                               case FT_UINT8:
-                                       format = "%s == 0x%02x";
-                                       break;
-                               case FT_UINT16:
-                                       format = "%s == 0x%04x";
-                                       break;
-                               case FT_UINT24:
-                                       format = "%s == 0x%06x";
-                                       break;
-                               case FT_UINT32:
-                                       format = "%s == 0x%08x";
-                                       break;
-                               default:
-                                       g_assert_not_reached();
-                                       ;
-                       }
-                       break;
-               default:
-                       g_assert_not_reached();
-                       ;
-       }
-       return format;
-}
 
 
 /* Run the current display filter on the current packet set, and
@@ -556,31 +424,50 @@ static void
 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
 
   blank_packetinfo();
+
+/* Remove the hex display tabbed pages */
+  while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
+    gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
+
   select_packet(&cfile, row);
 }
 
+
 static void
 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
+
   unselect_packet(&cfile);
 }
 
+
 static void
 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
 {
        field_info      *finfo;
        gchar           *help_str = NULL;
        gboolean        has_blurb = FALSE;
-       guint           length = 0;
+       guint           length = 0, byte_len;
+       GtkWidget       *byte_view;
+       guint8          *byte_data;
 
        g_assert(node);
        finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
        if (!finfo) return;
 
+       set_notebook_page(  byte_nb_ptr, find_notebook_page( byte_nb_ptr, finfo->ds_name));
+
+        byte_view = gtk_object_get_data(GTK_OBJECT(byte_nb_ptr), E_BYTE_VIEW_TEXT_INFO_KEY);
+        byte_data = gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_PTR_KEY);
+        byte_len = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_LEN_KEY));
+
+       g_assert(byte_data);
+
        finfo_selected = finfo;
 
        set_menus_for_selected_tree_row(TRUE);
 
-       if (finfo->hfinfo && finfo->hfinfo->type != FT_TEXT_ONLY) {
+       /*if (finfo->hfinfo && finfo->hfinfo->type != FT_TEXT_ONLY) {*/
+       if (finfo->hfinfo) {
          if (finfo->hfinfo->blurb != NULL && 
              finfo->hfinfo->blurb[0] != '\0') {
            has_blurb = TRUE;
@@ -597,18 +484,28 @@ tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user
          g_free(help_str);
        }
 
-       packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame,
-               finfo);
+       packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
+               finfo, byte_len);
 }
 
 static void
 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
 {
+       GtkWidget       *byte_view;
+       guint8  *data;
+       gint    len;    
+       field_info* fi;
+
+       fi = (field_info*)user_data;
+
+       len = get_byte_view_and_data( byte_nb_ptr, &byte_view, &data);
+
+       if ( len < 0) return;
        gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
        finfo_selected = NULL;
        set_menus_for_selected_tree_row(FALSE);
-       packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame,
-               NULL);
+       packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
+               NULL, len);
 }
 
 void collapse_all_cb(GtkWidget *widget, gpointer data) {
@@ -623,11 +520,11 @@ void expand_all_cb(GtkWidget *widget, gpointer data) {
 
 void resolve_name_cb(GtkWidget *widget, gpointer data) {
   if (cfile.protocol_tree) {
-    int tmp = g_resolving_actif;
-    g_resolving_actif = 1;
+    int tmp = prefs.capture_name_resolve;
+    prefs.capture_name_resolve = 1;
     gtk_clist_clear ( GTK_CLIST(tree_view) );
     proto_tree_draw(cfile.protocol_tree, tree_view);
-    g_resolving_actif = tmp;
+    prefs.capture_name_resolve = tmp;
   }
 }
 
@@ -811,8 +708,8 @@ file_quit_cmd_cb (GtkWidget *widget, gpointer data)
 static void 
 print_usage(void) {
 
-  fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
-         comp_info_str);
+  fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
+         comp_info_str->str);
 #ifdef HAVE_LIBPCAP
   fprintf(stderr, "%s [ -vh ] [ -kpQS ] [ -B <byte view height> ] [ -c count ]\n",
          PACKAGE);
@@ -829,6 +726,16 @@ print_usage(void) {
 #endif
 }
 
+static void 
+show_version(void)
+{
+#ifdef WIN32
+  create_console();
+#endif
+
+  printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
+}
+
 /* And now our feature presentation... [ fade to music ] */
 int
 main(int argc, char *argv[])
@@ -844,7 +751,7 @@ main(int argc, char *argv[])
 
 #ifdef HAVE_LIBPCAP
 #ifdef WIN32
-  char pcap_version[] = "0.4a6";
+  char pcap_version[] = WPCAP_STRING;
 #else
   extern char          pcap_version[];
 #endif
@@ -854,26 +761,46 @@ main(int argc, char *argv[])
   WSADATA             wsaData; 
 #endif
 
-  char                *gpf_path, *pf_path;
-  int                  gpf_open_errno, pf_open_errno;
+  char                *gpf_path, *pf_path, *cf_path, *df_path;
+  int                  gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
   int                  err;
 #ifdef HAVE_LIBPCAP
   gboolean             start_capture = FALSE;
   gchar               *save_file = NULL;
   GList               *if_list;
   gchar                err_str[PCAP_ERRBUF_SIZE];
+  gboolean             stats_known;
+  struct pcap_stat     stats;
 #else
   gboolean             capture_option_specified = FALSE;
 #endif
   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
-  dfilter             *rfcode = NULL;
+  dfilter_t           *rfcode = NULL;
   gboolean             rfilter_parse_failed = FALSE;
   e_prefs             *prefs;
   char                *bold_font_name;
 
   ethereal_path = argv[0];
 
+#ifdef WIN32
+  /* Arrange that if we have no console window, and a GLib message logging
+     routine is called to log a message, we pop up a console window.
+
+     We do that by inserting our own handler for all messages logged
+     to the default domain; that handler pops up a console if necessary,
+     and then calls the default handler. */
+  g_log_set_handler(NULL,
+                   G_LOG_LEVEL_ERROR|
+                   G_LOG_LEVEL_CRITICAL|
+                   G_LOG_LEVEL_WARNING|
+                   G_LOG_LEVEL_MESSAGE|
+                   G_LOG_LEVEL_INFO|
+                   G_LOG_LEVEL_DEBUG|
+                   G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
+                   console_log_handler, NULL);
+#endif
+
 #ifdef HAVE_LIBPCAP
   command_name = get_basename(ethereal_path);
   /* Set "capture_child" to indicate whether this is going to be a child
@@ -885,7 +812,7 @@ main(int argc, char *argv[])
      "-G" flag, as the "-G" flag dumps a list of fields registered
      by the dissectors, and we must do it before we read the preferences,
      in case any dissectors register preferences. */
-  epan_init(PLUGIN_DIR);
+  epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
 
   /* Now register the preferences for any non-dissector modules.
      We must do that before we read the preferences as well. */
@@ -924,8 +851,15 @@ main(int argc, char *argv[])
   /* Let GTK get its args */
   gtk_init (&argc, &argv);
   
+  /* Read the preference files. */
   prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
 
+  /* Read the capture filter file. */
+  read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
+
+  /* Read the display filter file. */
+  read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
+
   /* Initialize the capture file struct */
   cfile.plist          = NULL;
   cfile.plist_end      = NULL;
@@ -947,50 +881,65 @@ main(int argc, char *argv[])
   col_init(&cfile.cinfo, prefs->num_cols);
 
   /* Assemble the compile-time options */
-  snprintf(comp_info_str, 256,
+  comp_info_str = g_string_new("");
+
+  g_string_append(comp_info_str, "with ");
+  g_string_sprintfa(comp_info_str,
 #ifdef GTK_MAJOR_VERSION
-    "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
-    GTK_MICRO_VERSION,
+    "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
+    GTK_MICRO_VERSION);
+#else
+    "GTK+ (version unknown)");
+#endif
+
+  g_string_append(comp_info_str, ", with ");
+  g_string_sprintfa(comp_info_str,
+#ifdef GLIB_MAJOR_VERSION
+    "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
+    GLIB_MICRO_VERSION);
 #else
-    "GTK+ (version unknown), %s%s, %s%s, %s%s",
+    "GLib (version unknown)");
 #endif
 
 #ifdef HAVE_LIBPCAP
-   "with libpcap ", pcap_version,
+  g_string_append(comp_info_str, ", with libpcap ");
+  g_string_append(comp_info_str, pcap_version);
 #else
-   "without libpcap", "",
+  g_string_append(comp_info_str, ", without libpcap");
 #endif
 
 #ifdef HAVE_LIBZ
+  g_string_append(comp_info_str, ", with libz ");
 #ifdef ZLIB_VERSION
-   "with libz ", ZLIB_VERSION,
+  g_string_append(comp_info_str, ZLIB_VERSION);
 #else /* ZLIB_VERSION */
-   "with libz ", "(version unknown)",
+  g_string_append(comp_info_str, "(version unknown)");
 #endif /* ZLIB_VERSION */
 #else /* HAVE_LIBZ */
-   "without libz", "",
+  g_string_append(comp_info_str, ", without libz");
 #endif /* HAVE_LIBZ */
 
 /* Oh, this is pretty */
 #if defined(HAVE_UCD_SNMP_SNMP_H)
+  g_string_append(comp_info_str, ", with UCD SNMP ");
 #ifdef HAVE_UCD_SNMP_VERSION_H
-   "with UCD SNMP ", VersionInfo
+  g_string_append(comp_info_str, VersionInfo);
 #else /* HAVE_UCD_SNMP_VERSION_H */
-   "with UCD SNMP ", "(version unknown)"
+  g_string_append(comp_info_str, "(version unknown)");
 #endif /* HAVE_UCD_SNMP_VERSION_H */
 #elif defined(HAVE_SNMP_SNMP_H)
+  g_string_append(comp_info_str, ", with CMU SNMP ");
 #ifdef HAVE_SNMP_VERSION_H
-   "with CMU SNMP ", snmp_Version()
+  g_string_append(comp_info_str, snmp_Version());
 #else /* HAVE_SNMP_VERSION_H */
-   "with CMU SNMP ", "(version unknown)"
+  g_string_append(comp_info_str, "(version unknown)");
 #endif /* HAVE_SNMP_VERSION_H */
 #else /* no SNMP */
-   "without SNMP", ""
+  g_string_append(comp_info_str, ", without SNMP");
 #endif
-   );
 
   /* Now get our args */
-  while ((opt = getopt(argc, argv, "B:c:Df:hi:km:no:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
+  while ((opt = getopt(argc, argv, "B:c:f:hi:km:no:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
     switch (opt) {
       case 'B':        /* Byte view pane height */
         bv_size = atoi(optarg);
@@ -1039,7 +988,7 @@ main(int argc, char *argv[])
        prefs->gui_font_name = g_strdup(optarg);
        break;
       case 'n':        /* No name resolution */
-       g_resolving_actif = 0;
+       prefs->capture_name_resolve = 0;
        break;
       case 'o':        /* Override preference from command line */
         switch (prefs_set_pref(optarg)) {
@@ -1058,7 +1007,7 @@ main(int argc, char *argv[])
         break;
       case 'p':        /* Don't capture in promiscuous mode */
 #ifdef HAVE_LIBPCAP
-       promisc_mode = 0;
+       prefs->capture_prom_mode = 0;
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -1095,7 +1044,7 @@ main(int argc, char *argv[])
         break;
       case 'S':        /* "Sync" mode: used for following file ala tail -f */
 #ifdef HAVE_LIBPCAP
-        sync_mode = TRUE;
+        prefs->capture_auto_scroll = TRUE;
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -1122,7 +1071,11 @@ main(int argc, char *argv[])
         tv_size = atoi(optarg);
         break;
       case 'v':        /* Show version and exit */
-        printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
+        show_version();
+#ifdef WIN32
+        if (console_was_created)
+          destroy_console();
+#endif
         exit(0);
         break;
       case 'w':        /* Write to capture file xxx */
@@ -1166,6 +1119,9 @@ main(int argc, char *argv[])
   }
 
 #ifdef WIN32
+  /* Load wpcap if possible */
+  load_wpcap();
+
   /* Start windows sockets */
   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
 #endif
@@ -1276,7 +1232,9 @@ main(int argc, char *argv[])
     prefs->gui_font_name = g_strdup("6x13");
   }
 
-  create_main_window(pl_size, tv_size, bv_size, prefs);
+  /* Call this for the side-effects that set_fonts() produces */
+  set_fonts(m_r_font, m_b_font);
+
 
 #ifdef HAVE_LIBPCAP
   /* Is this a "child" ethereal, which is only supposed to pop up a
@@ -1287,7 +1245,7 @@ main(int argc, char *argv[])
     /* No.  Pop up the main window, and read in a capture file if
        we were told to. */
 
-    gtk_widget_show(top_level);
+    create_main_window(pl_size, tv_size, bv_size, prefs);
     set_menus_for_capture_file(FALSE);
 
     cfile.colors = colfilter_new();
@@ -1300,7 +1258,7 @@ main(int argc, char *argv[])
        up on top of us. */
     if (cf_name) {
       if (rfilter != NULL) {
-        if (dfilter_compile(rfilter, &rfcode) != 0) {
+        if (!dfilter_compile(rfilter, &rfcode)) {
           simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
           rfilter_parse_failed = TRUE;
         }
@@ -1330,10 +1288,10 @@ main(int argc, char *argv[])
              good thing, given that "get_dirname()" does write over its
              argument. */
           s = get_dirname(cf_name);
-          if (s != NULL)
-            last_open_dir = s;
+         set_last_open_dir(s);
         } else {
-          dfilter_destroy(rfcode);
+          if (rfcode != NULL)
+            dfilter_free(rfcode);
           cfile.rfcode = NULL;
         }
       }
@@ -1360,6 +1318,26 @@ main(int argc, char *argv[])
         strerror(pf_open_errno));
   }
 
+  /* If the user's capture filter file exists but we failed to open it,
+     pop up an alert box; we defer that until now, so that the alert
+     box is more likely to come up on top of the main window. */
+  if (cf_path != NULL) {
+      simple_dialog(ESD_TYPE_WARN, NULL,
+        "Could not open your capture filter file\n\"%s\": %s.", cf_path,
+        strerror(cf_open_errno));
+      g_free(cf_path);
+  }
+
+  /* If the user's display filter file exists but we failed to open it,
+     pop up an alert box; we defer that until now, so that the alert
+     box is more likely to come up on top of the main window. */
+  if (df_path != NULL) {
+      simple_dialog(ESD_TYPE_WARN, NULL,
+        "Could not open your display filter file\n\"%s\": %s.", df_path,
+        strerror(df_open_errno));
+      g_free(df_path);
+  }
+
 #ifdef HAVE_LIBPCAP
   if (capture_child) {
     /* This is the child process for a sync mode or fork mode capture,
@@ -1367,7 +1345,8 @@ main(int argc, char *argv[])
        a temporary file and fork off *another* child process (so don't
        call "do_capture()"). */
 
-       capture();
+       /* XXX - hand these stats to the parent process */
+       capture(&stats_known, &stats);
 
        /* The capture is done; there's nothing more for us to do. */
        gtk_exit(0);
@@ -1392,6 +1371,12 @@ main(int argc, char *argv[])
 #ifdef WIN32
   /* Shutdown windows sockets */
   WSACleanup();
+
+  /* For some unknown reason, the "atexit()" call in "create_console()"
+     doesn't arrange that "destroy_console()" be called when we exit,
+     so we call it here if a console was created. */
+  if (console_was_created)
+    destroy_console();
 #endif
 
   gtk_exit(0);
@@ -1420,9 +1405,70 @@ WinMain (struct HINSTANCE__ *hInstance,
         char               *lpszCmdLine,
         int                 nCmdShow)
 {
+  has_no_console = TRUE;
   return main (__argc, __argv);
 }
 
+/*
+ * If this application has no console window to which its standard output
+ * would go, create one.
+ */
+static void
+create_console(void)
+{
+  if (has_no_console) {
+    /* We have no console to which to print the version string, so
+       create one and make it the standard input, output, and error. */
+    if (!AllocConsole())
+      return;   /* couldn't create console */
+    freopen("CONIN$", "r", stdin);
+    freopen("CONOUT$", "w", stdout);
+    freopen("CONOUT$", "w", stderr);
+
+    /* Well, we have a console now. */
+    has_no_console = FALSE;
+    console_was_created = TRUE;
+
+    /* Now register "destroy_console()" as a routine to be called just
+       before the application exits, so that we can destroy the console
+       after the user has typed a key (so that the console doesn't just
+       disappear out from under them, giving the user no chance to see
+       the message(s) we put in there). */
+    atexit(destroy_console);
+  }
+}
+
+static void
+destroy_console(void)
+{
+  printf("\n\nPress any key to exit\n");
+  _getch();
+  FreeConsole();
+}
+
+/* This routine should not be necessary, at least as I read the GLib
+   source code, as it looks as if GLib is, on Win32, *supposed* to
+   create a console window into which to display its output.
+
+   That doesn't happen, however.  I suspect there's something completely
+   broken about that code in GLib-for-Win32, and that it may be related
+   to the breakage that forces us to just call "printf()" on the message
+   rather than passing the message on to "g_log_default_handler()"
+   (which is the routine that does the aforementioned non-functional
+   console window creation). */
+static void
+console_log_handler(const char *log_domain, GLogLevelFlags log_level,
+                   const char *message, gpointer user_data)
+{
+  create_console();
+  if (console_was_created) {
+    /* For some unknown reason, the above doesn't appear to actually cause
+       anything to be sent to the standard output, so we'll just splat the
+       message out directly, just to make sure it gets out. */
+    printf("%s\n", message);
+  } else
+    g_log_default_handler(log_domain, log_level, message, user_data);
+}
 #endif
 
 /* Given a font name, construct the name of the next heavier version of
@@ -1479,6 +1525,7 @@ boldify(const char *font_name)
        return bold_font_name;
 }
 
+
 static void
 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
 {
@@ -1489,6 +1536,14 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
   GList               *filter_list = NULL;
   GtkAccelGroup       *accel;
   int                  i;
+  /* Display filter construct dialog has an Apply button, and "OK" not
+     only sets our text widget, it activates it (i.e., it causes us to
+     filter the capture). */
+  static construct_args_t args = {
+       "Ethereal: Display Filter",
+       TRUE,
+       TRUE
+  };
 
   /* Main window */  
   top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -1576,9 +1631,10 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
   gtk_widget_show(tree_view);
 
   /* Byte view. */
-  create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
+  create_byte_view(bv_size, l_pane, &byte_nb_ptr, &bv_scrollw,
                        prefs->gui_scrollbar_on_right);
-  gtk_signal_connect(GTK_OBJECT(byte_view), "button_press_event",
+
+  gtk_signal_connect(GTK_OBJECT(byte_nb_ptr), "button_press_event",
                     GTK_SIGNAL_FUNC(popup_menu_handler),
                     gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
 
@@ -1589,10 +1645,8 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
   gtk_widget_show(stat_hbox);
 
   filter_bt = gtk_button_new_with_label("Filter:");
-  /* A non-null pointer passed to "display_filter_construct_cb()" causes it to
-     give the dialog box it pops up an "Apply" button. */
   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
-    GTK_SIGNAL_FUNC(display_filter_construct_cb), "");
+    GTK_SIGNAL_FUNC(display_filter_construct_cb), &args);
   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
   gtk_widget_show(filter_bt);
   
@@ -1632,4 +1686,28 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
   gtk_widget_show(info_bar);
+
+  gtk_widget_show(top_level);
+}
+
+
+void
+set_last_open_dir(char *dirname)
+{
+       int len;
+
+       if (last_open_dir) {
+               g_free(last_open_dir);
+       }
+
+       if (dirname) {
+               len = strlen(dirname);
+               if (dirname[len-1] != G_DIR_SEPARATOR) {
+                       last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
+                               NULL);
+               }
+       }
+       else {
+               last_open_dir = NULL;
+       }
 }