Provide not only copyright information, but a GPL blurb, in all the
[obnox/wireshark/wip.git] / gtk / main.c
index 6aa20ab69a754052fe57c592630998d98ee3174a..fb786c74b03779d31419fec3dce9cc6d4dafe557 100644 (file)
 #include <unistd.h>
 #endif
 
-#ifdef HAVE_IO_H
-#include <io.h> /* open/close on win32 */
-#endif
-
 #ifdef NEED_STRERROR_H
 #include "strerror.h"
 #endif
@@ -65,6 +61,7 @@
 #include <epan/dfilter/dfilter.h>
 #include <epan/strutil.h>
 #include <epan/addr_resolv.h>
+#include <epan/emem.h>
 
 /* general (not GTK specific) */
 #include "file.h"
 #include "register.h"
 #include <epan/prefs-int.h>
 #include "ringbuffer.h"
-#include "../ui_util.h"     /* beware: ui_util.h exists twice! */
+#include "../ui_util.h"
 #include <epan/tap.h>
-#include <epan/stat.h>
+#include <epan/stat_cmd_args.h>
 #include "util.h"
 #include "clopts_common.h"
+#include "cmdarg_err.h"
 #include "version_info.h"
 #include "merge.h"
 
 #ifdef HAVE_LIBPCAP
 #include <pcap.h>
-#include "pcap-util.h"
+#include "capture-pcap-util.h"
 #include "capture.h"
+#include "capture_loop.h"
+#include "capture_sync.h"
 #endif
 
 #ifdef _WIN32
 #include "dlg_utils.h"
 #include "gtkglobals.h"
 #include "colors.h"
-#include "ui_util.h"        /* beware: ui_util.h exists twice! */
+#include "gui_utils.h"
 #include "compat_macros.h"
 
 #include "main.h"
 #include "decode_as_dlg.h"
 #include "webbrowser.h"
 #include "capture_dlg.h"
-#if 0
+#ifdef SHOW_WELCOME_PAGE
 #include "../image/eicon3d64.xpm"
 #endif
 #include "capture_ui_utils.h"
 #include "log.h"
 #include "../epan/emem.h"
+#include "file_util.h"
 
 
 
@@ -171,6 +172,7 @@ GString *comp_info_str, *runtime_info_str;
 gchar       *ethereal_path = NULL;
 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
 
+gboolean             capture_child; /* True if this is the child for "-S" */
 #ifdef _WIN32
 static gboolean has_console;   /* TRUE if app has console */
 static void destroy_console(void);
@@ -266,9 +268,6 @@ match_selected_cb_do(gpointer data, int action, gchar *text)
 
     /* Free up the new filter text. */
     g_free(new_filter);
-
-    /* Free up the generated text we were handed. */
-    g_free(text);
 }
 
 void
@@ -404,7 +403,7 @@ get_text_from_packet_list(gpointer data)
            strlen(cfile.cinfo.col_expr_val[column]) != 0) {
            len = strlen(cfile.cinfo.col_expr[column]) +
                  strlen(cfile.cinfo.col_expr_val[column]) + 5;
-           buf = g_malloc0(len);
+           buf = ep_alloc0(len);
            g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
                     cfile.cinfo.col_expr_val[column]);
        }
@@ -1082,31 +1081,35 @@ print_usage(gboolean print_ver) {
 
   if (print_ver) {
     output = stdout;
-    fprintf(output, "This is "PACKAGE " " VERSION "%s"
-        "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
-       "\n\n%s\n\n%s\n",
-       svnversion, comp_info_str->str, runtime_info_str->str);
+    fprintf(output, "This is "PACKAGE " " VERSION "%s\n"
+        "\n"
+        "%s"
+        "\n"
+       "%s"
+       "\n"
+       "%s",
+       svnversion, get_copyright_info(), comp_info_str->str,
+       runtime_info_str->str);
   } else {
     output = stderr;
   }
 #ifdef HAVE_LIBPCAP
-  fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);       
+  fprintf(output, "\n%s [ -vh ] [ -DklLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);      
   fprintf(output, "\t[ -b <capture ring buffer option> ] ...\n");
-  fprintf(output, "\t[ -B capture buffer size (Win32 only) ]\n"); 
+#ifdef _WIN32
+  fprintf(output, "\t[ -B <capture buffer size> ]\n");
+#endif
   fprintf(output, "\t[ -c <capture packet count> ] [ -f <capture filter> ]\n");
-  fprintf(output, "\t[ -g <packet number> ]\n");
-  fprintf(output, "\t[ -i <capture interface> ] [ -m <font> ] [ -N <name resolving flags> ]\n");
-  fprintf(output, "\t[ -o <preference/recent setting> ] ...\n");
+  fprintf(output, "\t[ -g <packet number> ] [ -i <capture interface> ] [ -m <font> ]\n");
+  fprintf(output, "\t[ -N <name resolving flags> ] [ -o <preference/recent setting> ] ...\n");
   fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
-  fprintf(output, "\t[ -t <time stamp format> ]\n");
-  fprintf(output, "\t[ -w <savefile> ] [ -y <capture link type> ] [ -z <statistics> ]\n");
-  fprintf(output, "\t[ <infile> ]\n");
+  fprintf(output, "\t[ -t <time stamp format> ] [ -w <savefile> ] [ -y <capture link type> ]\n");
+  fprintf(output, "\t[ -z <statistics> ] [ <infile> ]\n");
 #else
   fprintf(output, "\n%s [ -vh ] [ -n ] [ -g <packet number> ] [ -m <font> ]\n", PACKAGE);
   fprintf(output, "\t[ -N <resolving flags> ] [ -o <preference/recent setting> ...\n");
   fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ]\n");
-  fprintf(output, "\t[ -t <time stamp format> ]\n");
-  fprintf(output, "\t[ -z <statistics ] [ <infile> ]\n");
+  fprintf(output, "\t[ -t <time stamp format> ] [ -z <statistics ] [ <infile> ]\n");
 #endif
 
 #ifdef _WIN32
@@ -1121,18 +1124,62 @@ show_version(void)
   create_console();
 #endif
 
-  printf(PACKAGE " " VERSION
-#ifdef SVNVERSION
-      " (" SVNVERSION ")"
-#endif
-      "\n\n%s\n\n%s\n",
-      comp_info_str->str, runtime_info_str->str);
+  printf(PACKAGE " " VERSION "%s\n"
+         "\n"
+         "%s"
+         "\n"
+         "%s"
+         "\n"
+         "%s",
+      svnversion, get_copyright_info(), comp_info_str->str,
+      runtime_info_str->str);
 
 #ifdef _WIN32
   destroy_console();
 #endif
 }
 
+/*
+ * Report an error in command-line arguments.
+ * Creates a console on Windows.
+ * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
+ * terminal isn't the standard error?
+ */
+void
+cmdarg_err(const char *fmt, ...)
+{
+  va_list ap;
+
+#ifdef _WIN32
+  create_console();
+#endif
+  va_start(ap, fmt);
+  fprintf(stderr, "ethereal: ");
+  vfprintf(stderr, fmt, ap);
+  fprintf(stderr, "\n");
+  va_end(ap);
+}
+
+/*
+ * Report additional information for an error in command-line arguments.
+ * Creates a console on Windows.
+ * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
+ * terminal isn't the standard error?
+ */
+void
+cmdarg_err_cont(const char *fmt, ...)
+{
+  va_list ap;
+
+#ifdef _WIN32
+  create_console();
+#endif
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  fprintf(stderr, "\n");
+  va_end(ap);
+}
+
 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
 /* 
    Once every 3 seconds we get a callback here which we use to update
@@ -1219,9 +1266,11 @@ set_display_filename(capture_file *cf)
   }
 
   /* statusbar */
-  status_msg = g_strdup_printf(" File: \"%s\" %s %02u:%02u:%02u", 
+  status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu", 
     (cf->filename) ? cf->filename : "", size_str,
-    cf->esec/3600, cf->esec%3600/60, cf->esec%60);
+    (long)cf->elapsed_time.secs/3600,
+    (long)cf->elapsed_time.secs%3600/60,
+    (long)cf->elapsed_time.secs%60);
   g_free(size_str);
   statusbar_push_file_msg(status_msg);
   g_free(status_msg);
@@ -1232,22 +1281,36 @@ set_display_filename(capture_file *cf)
   g_free(win_name);
 }
 
+GtkWidget           *close_dlg = NULL;
 
 static void
-main_cf_cb_file_closed(capture_file *cf)
+main_cf_cb_file_closing(capture_file *cf)
 {
+
+       /* if we have more than 10000 packets, show a splash screen while closing */
+       /* XXX - don't know a better way to decide wether to show or not,
+        * as most of the time is spend in a single eth_clist_clear function, 
+        * so we can't use a progress bar here! */
+       if(cf->count > 10000) {
+               close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sClosing file!%s\n\nPlease wait ...", 
+                       simple_dialog_primary_start(), simple_dialog_primary_end());
+#if GTK_MAJOR_VERSION >= 2
+               gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
+#else
+               gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER);
+#endif
+       }
+
     /* Destroy all windows, which refer to the
        capture file we're closing. */
-    destroy_cfile_wins();
+    destroy_packet_wins();
+    file_save_as_destroy();
 
     /* Clear any file-related status bar messages.
        XXX - should be "clear *ALL* file-related status bar messages;
        will there ever be more than one on the stack? */
     statusbar_pop_file_msg();
 
-    /* go back to "No packets" */
-    packets_bar_update();
-
     /* Restore the standard title bar message. */
     set_main_window_name("The Ethereal Network Analyzer");
 
@@ -1261,6 +1324,20 @@ main_cf_cb_file_closed(capture_file *cf)
 
     /* Set up main window for no capture file. */
     main_set_for_capture_file(FALSE);
+
+    main_window_update();
+}
+
+static void
+main_cf_cb_file_closed(capture_file *cf _U_)
+{
+  if(close_dlg != NULL) {
+    splash_destroy(close_dlg);
+    close_dlg = NULL;
+  }
+
+  /* go back to "No packets" */
+  packets_bar_update();
 }
 
 static void
@@ -1325,8 +1402,22 @@ static void
 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
 {
     gchar *capture_msg;
+    gchar *title;
 
 
+    /* We've done this in "prepared" above, but it will be cleared while
+       switching to the next multiple file. */
+    if(capture_opts->iface) {
+        title = g_strdup_printf("%s: Capturing - Ethereal",
+                            get_interface_descriptive_name(capture_opts->iface));
+    } else {
+        title = g_strdup_printf("Capturing - Ethereal");
+    }
+    set_main_window_name(title);
+    g_free(title);
+
+    set_menus_for_capture_in_progress(TRUE);
+
     /* Enable menu items that make sense if you have some captured
        packets (yes, I know, we don't have any *yet*). */
     set_menus_for_captured_packets(TRUE);
@@ -1373,9 +1464,16 @@ main_cf_cb_live_capture_update_continue(capture_file *cf)
     statusbar_push_file_msg(capture_msg);
 }
 
+GtkWidget * stop_dlg = NULL;
+
 static void
 main_cf_cb_live_capture_update_finished(capture_file *cf)
 {
+       if(stop_dlg != NULL) {
+               simple_dialog_close(stop_dlg);
+               stop_dlg = NULL;
+       }
+
     /* Pop the "<live capture in progress>" message off the status bar. */
     statusbar_pop_file_msg();
 
@@ -1392,6 +1490,12 @@ main_cf_cb_live_capture_update_finished(capture_file *cf)
 
     /* Set up main window for a capture file. */
     main_set_for_capture_file(TRUE);
+
+    if(capture_opts->quit_after_cap) {
+        /* command line asked us to quit after the capture */
+        /* don't pop up a dialog to ask for unsaved files etc. */
+        main_do_quit();
+    }
 }
 
 static void
@@ -1422,6 +1526,11 @@ main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
 static void
 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
 {
+       if(stop_dlg != NULL) {
+               simple_dialog_close(stop_dlg);
+               stop_dlg = NULL;
+       }
+
     /* Pop the "<live capture in progress>" message off the status bar. */
     statusbar_pop_file_msg();
 
@@ -1434,9 +1543,39 @@ main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
      a capture. */
     set_menus_for_capture_in_progress(FALSE);
 
+    /* Restore the standard title bar message */
+    /* (just in case we have trouble opening the capture file). */
+    set_main_window_name("The Ethereal Network Analyzer");
+
     /* We don't have loaded the capture file, this will be done later.
      * For now we still have simply a blank screen. */
+
+    if(capture_opts->quit_after_cap) {
+        /* command line asked us to quit after the capture */
+        /* don't pop up a dialog to ask for unsaved files etc. */
+        main_do_quit();
+    }
+}
+
+static void
+main_cf_cb_live_capture_stopping(capture_file *cf _U_)
+{
+#if 0
+       /* XXX - the time to stop the capture has been reduced (this was only a 
+        * problem on Win32 because of the capture piping), so showing a splash 
+        * isn't really necessary any longer. Unfortunately, the GTKClist packet 
+        * list seems to have problems updating after the dialog is closed, so 
+        * this was disabled here. */
+    stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...", 
+               simple_dialog_primary_start(), simple_dialog_primary_end());
+#if GTK_MAJOR_VERSION >= 2
+       gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
+#else
+       gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
+#endif
+#endif
 }
+
 #endif
 
 static void
@@ -1508,34 +1647,51 @@ main_cf_cb_file_safe_reload_finished(gpointer data _U_)
 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
 {
     switch(event) {
+    case(cf_cb_file_closing):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing");
+        main_cf_cb_file_closing(data);
+        break;
     case(cf_cb_file_closed):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed");
         main_cf_cb_file_closed(data);
         break;
     case(cf_cb_file_read_start):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read start");
         main_cf_cb_file_read_start(data);
         break;
     case(cf_cb_file_read_finished):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished");
         main_cf_cb_file_read_finished(data);
         break;
 #ifdef HAVE_LIBPCAP
     case(cf_cb_live_capture_prepared):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
         main_cf_cb_live_capture_prepared(data);
         break;
     case(cf_cb_live_capture_update_started):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
         main_cf_cb_live_capture_update_started(data);
         break;
     case(cf_cb_live_capture_update_continue):
+               /*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
         main_cf_cb_live_capture_update_continue(data);
         break;
     case(cf_cb_live_capture_fixed_started):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
         main_cf_cb_live_capture_fixed_started(data);
         break;
     case(cf_cb_live_capture_update_finished):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
         main_cf_cb_live_capture_update_finished(data);
         break;
     case(cf_cb_live_capture_fixed_finished):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
         main_cf_cb_live_capture_fixed_finished(data);
         break;
+    case(cf_cb_live_capture_stopping):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
+        main_cf_cb_live_capture_stopping(data);
+        break;
 #endif
     case(cf_cb_packet_selected):
         main_cf_cb_packet_selected(data);
@@ -1547,15 +1703,19 @@ static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
         main_cf_cb_field_unselected(data);
         break;
     case(cf_cb_file_safe_started):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe started");
         main_cf_cb_file_safe_started(data);
         break;
     case(cf_cb_file_safe_finished):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe finished");
         main_cf_cb_file_safe_finished(data);
         break;
     case(cf_cb_file_safe_reload_finished):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: reload finished");
         main_cf_cb_file_safe_reload_finished(data);
         break;
     case(cf_cb_file_safe_failed):
+               g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe failed");
         main_cf_cb_file_safe_failed(data);
         break;
     default:
@@ -1594,12 +1754,6 @@ main(int argc, char *argv[])
   int                  err;
 #ifdef HAVE_LIBPCAP
   gboolean             start_capture = FALSE;
-  GList               *if_list;
-  if_info_t           *if_info;
-  GList               *lt_list, *lt_entry;
-  data_link_info_t    *data_link_info;
-  gchar                err_str[PCAP_ERRBUF_SIZE];
-  gchar               *cant_get_if_list_errstr;
   gboolean             stats_known;
   struct pcap_stat     stats;
 #else
@@ -1612,19 +1766,18 @@ main(int argc, char *argv[])
   e_prefs             *prefs;
   char                 badopt;
   GtkWidget           *splash_win = NULL;
-  gboolean             capture_child; /* True if this is the child for "-S" */
   GLogLevelFlags       log_flags;
   guint                go_to_packet = 0;
   int                  optind_initial;
 
-#define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
+#define OPTSTRING_INIT "a:b:c:Df:g:Hhi:klLm:nN:o:pQr:R:Ss:t:vw:y:z:"
 
 #ifdef HAVE_LIBPCAP
 #ifdef _WIN32
-#define OPTSTRING_CHILD "W:Z:"
+#define OPTSTRING_CHILD "Z:"
 #define OPTSTRING_WIN32 "B:"
 #else
-#define OPTSTRING_CHILD "W:"
+#define OPTSTRING_CHILD ""
 #define OPTSTRING_WIN32 ""
 #endif  /* _WIN32 */
 #else
@@ -1639,7 +1792,6 @@ main(int argc, char *argv[])
   ep_init_chunk();
   se_init_chunk();
 
-  /*** create the compile and runtime version strings ***/
 #ifdef _WIN32
   /* Load wpcap if possible. Do this before collecting the run-time version information */
   load_wpcap();
@@ -1670,8 +1822,18 @@ main(int argc, char *argv[])
   get_runtime_version_info(runtime_info_str);
 
 
-  /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
-  /* (e.g. don't start GTK+, if we only have to show the command line help) */
+  /* "pre-scan" the command line parameters, if we have "console only"
+     parameters.  We do this so we don't start GTK+ if we're only showing
+     command-line help or version information.
+
+     XXX - this pre-scan is doen before we start GTK+, so we haven't
+     run gtk_init() on the arguments.  That means that GTK+ arguments
+     have not been removed from the argument list; those arguments
+     begin with "--", and will be treated as an error by getopt().
+
+     We thus ignore errors - *and* set "opterr" to 0 to suppress the
+     error messages. */
+  opterr = 0;
   optind_initial = optind;
   while ((opt = getopt(argc, argv, optstring)) != -1) {
     switch (opt) {
@@ -1683,42 +1845,46 @@ main(int argc, char *argv[])
         show_version();
         exit(0);
         break;
-      case 'G':        /* dump various field or other infos, see handle_dashG_option() */
-  /* If invoked with the "-G" flag, we dump out information based on
-     the argument to the "-G" flag; if no argument is specified,
-     for backwards compatibility we dump out a glossary of display
-     filter symbols.
-
-     We must do this before calling "gtk_init()", because "gtk_init()"
-     tries to open an X display, and we don't want to have to do any X
-     stuff just to do a build.
-
-     Given that we call "gtk_init()" before doing the regular argument
-     list processing, so that it can handle X and GTK+ arguments and
-     remove them from the list at which we look, this means we must do
-     this before doing the regular argument list processing, as well.
-
-     This means that:
-
-       you must give the "-G" flag as the first flag on the command line;
-
-       you must give it as "-G", nothing more, nothing less;
-
-       the first argument after the "-G" flag, if present, will be used
-       to specify the information to dump;
-
-       arguments after that will not be used. */        
-        handle_dashG_option(argc, argv, "ethereal");
-        /* will never return! */
-        exit(0);
+      case '?':        /* Ignore errors - the "real" scan will catch them. */
         break;
     }
   }
 
-  /* set getopt index back to initial value, so it will start with the first command line parameter again */
-  /* (XXX - this seems to be portable, but time will tell) */
+  /* Set getopt index back to initial value, so it will start with the
+     first command line parameter again.  Also reset opterr to 1, so that
+     error messages are printed by getopt().
+
+     XXX - this seems to work on most platforms, but time will tell.
+     The Single UNIX Specification says "The getopt() function need
+     not be reentrant", so this isn't guaranteed to work.  The Mac
+     OS X 10.4[.x] getopt() man page says
+
+       In order to use getopt() to evaluate multiple sets of arguments, or to
+       evaluate a single set of arguments multiple times, the variable optreset
+       must be set to 1 before the second and each additional set of calls to
+       getopt(), and the variable optind must be reinitialized.
+
+           ...             
+
+       The optreset variable was added to make it possible to call the getopt()
+       function multiple times.  This is an extension to the IEEE Std 1003.2
+       (``POSIX.2'') specification.
+
+     which I think comes from one of the other BSDs.
+
+     XXX - if we want to control all the command-line option errors, so
+     that we can display them where we choose (e.g., in a window), we'd
+     want to leave opterr as 0, and produce our own messages using optopt.
+     We'd have to check the value of optopt to see if it's a valid option
+     letter, in which case *presumably* the error is "this option requires
+     an argument but none was specified", or not a valid option letter,
+     in which case *presumably* the error is "this option isn't valid".
+     Some versions of getopt() let you supply a option string beginning
+     with ':', which means that getopt() will return ':' rather than '?'
+     for "this option requires an argument but none was specified", but
+     not all do. */
   optind = optind_initial;
-
+  opterr = 1;
 
   /* Set the current locale according to the program environment.
    * We haven't localized anything, but some GTK widgets are localized
@@ -1762,6 +1928,9 @@ main(int argc, char *argv[])
   g_log_set_handler(NULL,
                    log_flags,
                    console_log_handler, NULL /* user_data */);
+  g_log_set_handler(LOG_DOMAIN_MAIN,
+                   log_flags,
+                   console_log_handler, NULL /* user_data */);
 
 #ifdef HAVE_LIBPCAP
   g_log_set_handler(LOG_DOMAIN_CAPTURE,
@@ -1794,7 +1963,7 @@ main(int argc, char *argv[])
 #endif
     splash_win = splash_new("Loading Ethereal ...");
 
-  splash_update(splash_win, "Registering dissectors ...");
+  splash_update(splash_win, "Init dissectors ...");
 
   /* Register all dissectors; we must do this before checking for the
      "-G" flag, as the "-G" flag dumps information registered by the
@@ -1803,7 +1972,7 @@ main(int argc, char *argv[])
   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
             failure_alert_box,open_failure_alert_box,read_failure_alert_box);
 
-  splash_update(splash_win, "Registering tap listeners ...");
+  splash_update(splash_win, "Init tap listeners ...");
 
   /* Register all tap listeners; we do this before we parse the arguments,
      as the "-z" argument can specify a registered tap. */
@@ -1982,24 +2151,25 @@ main(int argc, char *argv[])
       case 'Z':        /* Write to pipe FD XXX */
 #endif /* _WIN32 */
 #ifdef HAVE_LIBPCAP
-        capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
+        capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
 #endif
         break;
-#ifdef HAVE_LIBPCAP
-      /* This is a hidden option supporting Sync mode, so we don't set
-       * the error flags for the user in the non-libpcap case.
-       */
-      case 'W':        /* Write to capture file FD xxx */
-        capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
-       break;
-#endif
 
       /*** all non capture option specific ***/
+      case 'D':        /* Print a list of capture devices and exit */
+#ifdef HAVE_LIBPCAP
+        capture_opts_list_interfaces();
+        exit(0);
+#else
+        capture_option_specified = TRUE;
+        arg_error = TRUE;
+#endif
+        break;
       case 'g':        /* Go to packet */
-        go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
+        go_to_packet = get_positive_int(optarg, "go to packet");
         break;
       case 'l':        /* Automatic scrolling in live capture mode */
 #ifdef HAVE_LIBPCAP
@@ -2030,7 +2200,7 @@ main(int argc, char *argv[])
           g_resolv_flags = RESOLV_NONE;
         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
         if (badopt != '\0') {
-          fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
+          cmdarg_err("-N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
                        badopt);
           exit(1);
         }
@@ -2040,7 +2210,7 @@ main(int argc, char *argv[])
         case PREFS_SET_OK:
           break;
         case PREFS_SET_SYNTAX_ERR:
-          fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
+          cmdarg_err("Invalid -o flag \"%s\"", optarg);
           exit(1);
           break;
         case PREFS_SET_NO_SUCH_PREF:
@@ -2050,12 +2220,12 @@ main(int argc, char *argv[])
               break;
             case PREFS_SET_SYNTAX_ERR:
               /* shouldn't happen, checked already above */
-              fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
+              cmdarg_err("Invalid -o flag \"%s\"", optarg);
               exit(1);
               break;
             case PREFS_SET_NO_SUCH_PREF:
             case PREFS_SET_OBSOLETE:
-              fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference/recent value\n",
+              cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
                    optarg);
               exit(1);
               break;
@@ -2064,7 +2234,7 @@ main(int argc, char *argv[])
             }
           break;
         case PREFS_SET_OBSOLETE:
-          fprintf(stderr, "ethereal: -o flag \"%s\" specifies obsolete preference\n",
+          cmdarg_err("-o flag \"%s\" specifies obsolete preference",
                        optarg);
           exit(1);
           break;
@@ -2083,18 +2253,17 @@ main(int argc, char *argv[])
         break;
       case 't':        /* Time stamp type */
         if (strcmp(optarg, "r") == 0)
-          set_timestamp_setting(TS_RELATIVE);
+          timestamp_set_type(TS_RELATIVE);
         else if (strcmp(optarg, "a") == 0)
-          set_timestamp_setting(TS_ABSOLUTE);
+          timestamp_set_type(TS_ABSOLUTE);
         else if (strcmp(optarg, "ad") == 0)
-          set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
+          timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
         else if (strcmp(optarg, "d") == 0)
-          set_timestamp_setting(TS_DELTA);
+          timestamp_set_type(TS_DELTA);
         else {
-          fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
-            optarg);
-          fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
-          fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
+          cmdarg_err("Invalid time stamp type \"%s\"", optarg);
+          cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,");
+          cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta.");
           exit(1);
         }
         break;
@@ -2105,8 +2274,8 @@ main(int argc, char *argv[])
            part of a tap filter.  Instead, we just add the argument
            to a list of stat arguments. */
         if (!process_stat_cmd_arg(optarg)) {
-         fprintf(stderr,"ethereal: invalid -z argument.\n");
-         fprintf(stderr,"  -z argument must be one of :\n");
+         cmdarg_err("Invalid -z argument.");
+         cmdarg_err_cont("  -z argument must be one of :");
          list_stat_cmd_args();
          exit(1);
        }
@@ -2125,6 +2294,7 @@ main(int argc, char *argv[])
        * Input file name specified with "-r" *and* specified as a regular
        * command-line argument.
        */
+      cmdarg_err("File name specified both with -r and regular argument");
       arg_error = TRUE;
     } else {
       /*
@@ -2149,14 +2319,14 @@ main(int argc, char *argv[])
     /*
      * Extra command line arguments were specified; complain.
      */
-    fprintf(stderr, "Invalid argument: %s\n", argv[0]);
+    cmdarg_err("Invalid argument: %s", argv[0]);
     arg_error = TRUE;
   }
 
   if (arg_error) {
 #ifndef HAVE_LIBPCAP
     if (capture_option_specified) {
-      fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
+      cmdarg_err("This version of Ethereal was not built with support for capturing packets.");
     }
 #endif
     print_usage(FALSE);
@@ -2166,7 +2336,7 @@ main(int argc, char *argv[])
 #ifdef HAVE_LIBPCAP
   if (start_capture && list_link_layer_types) {
     /* Specifying *both* is bogus. */
-    fprintf(stderr, "ethereal: You can't specify both -L and a live capture.\n");
+    cmdarg_err("You can't specify both -L and a live capture.");
     exit(1);
   }
 
@@ -2175,12 +2345,12 @@ main(int argc, char *argv[])
        did the user also specify a capture file to be read? */
     if (cf_name) {
       /* Yes - that's bogus. */
-      fprintf(stderr, "ethereal: You can't specify -L and a capture file to be read.\n");
+      cmdarg_err("You can't specify -L and a capture file to be read.");
       exit(1);
     }
     /* No - did they specify a ring buffer option? */
     if (capture_opts->multi_files_on) {
-      fprintf(stderr, "ethereal: Ring buffer requested, but a capture isn't being done.\n");
+      cmdarg_err("Ring buffer requested, but a capture isn't being done.");
       exit(1);
     }
   } else {
@@ -2188,7 +2358,7 @@ main(int argc, char *argv[])
        a capture file to be read? */
     if (start_capture && cf_name) {
       /* Yes - that's bogus. */
-      fprintf(stderr, "ethereal: You can't specify both a live capture and a capture file to be read.\n");
+      cmdarg_err("You can't specify both a live capture and a capture file to be read.");
       exit(1);
     }
 
@@ -2202,15 +2372,15 @@ main(int argc, char *argv[])
         c) it makes no sense to enable the ring buffer if the maximum
            file size is set to "infinite". */
       if (capture_opts->save_file == NULL) {
-       fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
+       cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
        capture_opts->multi_files_on = FALSE;
       }
 /*      if (capture_opts->real_time_mode) {
-       fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
+       cmdarg_err("Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
        capture_opts->multi_files_on = FALSE;
       }*/
       if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
-       fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.\n");
+       cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
 /* XXX - this must be redesigned as the conditions changed */
 /*     capture_opts->multi_files_on = FALSE;*/
       }
@@ -2219,77 +2389,19 @@ main(int argc, char *argv[])
 
   if (start_capture || list_link_layer_types) {
     /* Did the user specify an interface to use? */
-    if (capture_opts->iface == NULL) {
-      /* No - is a default specified in the preferences file? */
-      if (prefs->capture_device != NULL) {
-          /* Yes - use it. */
-          capture_opts->iface = g_strdup(prefs->capture_device);
-      } else {
-        /* No - pick the first one from the list of interfaces. */
-        if_list = get_interface_list(&err, err_str);
-        if (if_list == NULL) {
-          switch (err) {
-
-          case CANT_GET_INTERFACE_LIST:
-              cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
-              fprintf(stderr, "%s\n", cant_get_if_list_errstr);
-              g_free(cant_get_if_list_errstr);
-              break;
-
-          case NO_INTERFACES_FOUND:
-              fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
-              break;
-          }
-          exit(2);
-        }
-        if_info = if_list->data;       /* first interface */
-        capture_opts->iface = g_strdup(if_info->name);
-        free_interface_list(if_list);
-      }
+    if (!capture_opts_trim_iface(capture_opts, 
+        (prefs->capture_device) ? get_if_name(prefs->capture_device) : NULL)) {
+        exit(2);
     }
   }
 
   if (list_link_layer_types) {
-    /* Get the list of link-layer types for the capture device. */
-    lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
-    if (lt_list == NULL) {
-      if (err_str[0] != '\0') {
-       fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
-         "Please check to make sure you have sufficient permissions, and that\n"
-         "you have the proper interface or pipe specified.\n", err_str);
-      } else
-       fprintf(stderr, "ethereal: The capture device has no data link types.\n");
-      exit(2);
-    }
-    fprintf(stderr, "Data link types (use option -y to set):\n");
-    for (lt_entry = lt_list; lt_entry != NULL;
-         lt_entry = g_list_next(lt_entry)) {
-      data_link_info = lt_entry->data;
-      fprintf(stderr, "  %s", data_link_info->name);
-      if (data_link_info->description != NULL)
-       fprintf(stderr, " (%s)", data_link_info->description);
-      else
-       fprintf(stderr, " (not supported)");
-      putchar('\n');
-    }
-    free_pcap_linktype_list(lt_list);
+    capture_opts_list_link_layer_types(capture_opts);
     exit(0);
   }
 
-  if (capture_opts->has_snaplen) {
-    if (capture_opts->snaplen < 1)
-      capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
-    else if (capture_opts->snaplen < MIN_PACKET_SIZE)
-      capture_opts->snaplen = MIN_PACKET_SIZE;
-  }
-
-  /* Check the value range of the ringbuffer_num_files parameter */
-  if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
-    capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
-#if RINGBUFFER_MIN_NUM_FILES > 0
-  else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
-    capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
-#endif
+  capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
+  capture_opts_trim_ring_num_files(capture_opts);
 #endif /* HAVE_LIBPCAP */
 
   /* Notify all registered modules that have had any of their preferences
@@ -2489,6 +2601,7 @@ main(int argc, char *argv[])
         if (rfcode != NULL)
           dfilter_free(rfcode);
         cfile.rfcode = NULL;
+    show_main_window(FALSE);
        set_menus_for_capture_in_progress(FALSE);
       }
     }
@@ -2594,9 +2707,9 @@ create_console(void)
        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);
+    eth_freopen("CONIN$", "r", stdin);
+    eth_freopen("CONOUT$", "w", stdout);
+    eth_freopen("CONOUT$", "w", stderr);
 
     /* Well, we have a console now. */
     has_console = TRUE;
@@ -2607,13 +2720,19 @@ create_console(void)
        disappear out from under them, giving the user no chance to see
        the message(s) we put in there). */
     atexit(destroy_console);
+
+       if(capture_child) {
+               SetConsoleTitle("Ethereal Capture Child Debug Console");
+       } else {
+               SetConsoleTitle("Ethereal Debug Console");
+       }
   }
 }
 
 static void
 destroy_console(void)
 {
-  if (has_console) {
+  if (has_console && !capture_child) {
     printf("\n\nPress any key to exit\n");
     _getch();
     FreeConsole();
@@ -2641,9 +2760,8 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
   const char *level;
 
 
-  /* change this, if you want to see more verbose log output */
-  /* XXX - make this a pref value */
-  if( (log_level & G_LOG_LEVEL_MASK) > G_LOG_LEVEL_WARNING) {
+  /* ignore log message, if log_level isn't interesting */
+  if( !(log_level & G_LOG_LEVEL_MASK & prefs.console_log_level)) {
     return;
   }
 
@@ -2895,7 +3013,7 @@ is_widget_visible(GtkWidget *widget, gpointer data)
 }
 
 
-#if 0
+#ifdef SHOW_WELCOME_PAGE
 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
    As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
 GtkWidget *
@@ -3012,14 +3130,14 @@ welcome_new(void)
 
     return welcome_scrollw;
 }
-#endif /* 0 */
-
+#else
 static GtkWidget *
 welcome_new(void)
 {
     /* this is just a dummy to fill up window space, simply showing nothing */
     return scrolled_window_new(NULL, NULL);
 }
+#endif