Synchronize the selection of interfaces between the main welcome
[obnox/wireshark/wip.git] / gtk / capture_if_dlg.c
index 340206b02d342d59ae292d310f169ddfcd2ac27f..067f27460d3f474b390d47c2a1f886d538d8f24f 100644 (file)
 # include "config.h"
 #endif
 
-#ifdef HAVE_LIBPCAP
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-
 #include <gtk/gtk.h>
 
-#include "globals.h"
-#include "capture-pcap-util.h"
+#ifdef HAVE_LIBPCAP
 
-#ifdef _WIN32
-#include "capture-wpcap.h"
+#include <string.h>
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <sys/stat.h>
 #endif
 
-#include "compat_macros.h"
-#include "simple_dialog.h"
-#include "capture.h"
-#include "capture_dlg.h"
-#include "capture_if_details_dlg.h"
-#include "capture_errs.h"
-#include "recent.h"
 #include <epan/prefs.h>
 
-#include "gui_utils.h"
-#include "dlg_utils.h"
+#include "../capture_errs.h"
+#include "../capture_ifinfo.h"
+#include "../simple_dialog.h"
+#include "../capture.h"
+#include "../capture-pcap-util.h"
+#include "../capture_ui_utils.h"
+#include "wsutil/file_util.h"
+#include <wiretap/wtap.h>
 
-#include "main.h"
-#include "wtap.h"
-#include "help_dlg.h"
-#include "toolbar.h"
-#include "keys.h"
+#ifdef _WIN32
+#include "../capture-wpcap.h"
+#include "gtk/capture_if_details_dlg_win32.h"
+#endif
 
-#include "webbrowser.h"
+#include "gtk/stock_icons.h"
+#include "gtk/capture_dlg.h"
+#include "gtk/capture_if_dlg.h"
+#include "gtk/recent.h"
+#include "gtk/gui_utils.h"
+#include "gtk/dlg_utils.h"
+#include "gtk/main.h"
+#include "gtk/main_toolbar.h"
+#include "gtk/help_dlg.h"
+#include "gtk/keys.h"
+#include "gtk/webbrowser.h"
+#include "gtk/capture_globals.h"
+#include "gtk/network_icons.h"
+#include "gtk/main_welcome.h"
 
 #ifdef HAVE_AIRPCAP
 #include "../image/toolbar/capture_airpcap_16.xpm"
 #endif
+
+#ifdef _WIN32
 #include "../image/toolbar/capture_ethernet_16.xpm"
+#include "../image/toolbar/modem_16.xpm"
+#endif
+
+#include "../image/toolbar/network_virtual_16.xpm"
 
 /* new buttons to be used instead of labels for 'Capture','Prepare',' */
-#include "../image/toolbar/capture_capture_16.xpm"
-#include "../image/toolbar/capture_prepare_16.xpm"
-#include "../image/toolbar/capture_details_16.xpm"
+/*#include "../image/toolbar/capture_capture_16.xpm"*/
+/*#include "../image/toolbar/capture_prepare_16.xpm"*/
+/*#include "../image/toolbar/capture_details_16.xpm"*/
 
 
 #ifdef HAVE_AIRPCAP
-#include <airpcap.h>
+#include "airpcap.h"
 #include "airpcap_loader.h"
 #include "airpcap_gui_utils.h"
 #include "airpcap_dlg.h"
 #endif
 
+#define CAPTURE_IF_IP_ADDR_LABEL      "capture_if_ip_addr_label"
+#define CAPTURE_IF_SELECTED_IP_ADDR   "capture_if_selected_ip_addr"
+
 /*
  * Keep a static pointer to the current "Capture Interfaces" window, if
  * any, so that if somebody tries to do "Capture:Start" while there's
  * one, rather than creating a new one.
  */
 static GtkWidget *cap_if_w;
-#ifdef HAVE_AIRPCAP
-static GtkWidget *cap_air_w;
-#endif
 
-GList           *if_data = NULL;
+static GList     *if_data_list = NULL;
 
-guint           timer_id;
+static guint      timer_id;
 
-GtkWidget       *stop_bt;
+static GtkWidget *stop_bt, *capture_bt, *options_bt;
 
-GList           *if_list;
+static GList     *if_list;
 
+static guint   currently_selected = 0;
 /*
  * Timeout, in milliseconds, for reads from the stream of captured packets.
  */
@@ -107,46 +120,168 @@ GList           *if_list;
 
 /* the "runtime" data of one interface */
 typedef struct if_dlg_data_s {
-    pcap_t      *pch;
     GtkWidget   *device_lb;
     GtkWidget   *descr_lb;
     GtkWidget   *ip_lb;
     GtkWidget   *curr_lb;
     GtkWidget   *last_lb;
-    GtkWidget   *capture_bt;
-    GtkWidget   *prepare_bt;
+    GtkWidget   *choose_bt;
 #ifdef _WIN32
     GtkWidget   *details_bt;
 #endif
     guint32     last_packets;
     gchar       *device;
+    if_info_t   if_info;
+    gboolean    selected;
 } if_dlg_data_t;
 
-void update_if(if_dlg_data_t *if_dlg_data);
+static gboolean gbl_capture_in_progress = FALSE;
 
+void
+update_selected_interface(gchar *name, gboolean activate)
+{
+  guint ifs;
+  GList *curr;
+  if_dlg_data_t *temp;
+
+  for (ifs = 0; ifs < g_list_length(if_data_list); ifs++) {
+    curr = g_list_nth(if_data_list, ifs);
+    temp = (if_dlg_data_t *)(curr->data);
+    if (strcmp(name, temp->if_info.name) == 0) {
+      if (activate) {
+        gtk_toggle_button_set_active((GtkToggleButton *)temp->choose_bt, TRUE);
+      } else {
+        gtk_toggle_button_set_active((GtkToggleButton *)temp->choose_bt, FALSE);
+      }
+      break;
+    }
+  }
+}
+
+static void
+store_selected(GtkWidget *choose_bt, gpointer if_data)
+{
+  if_dlg_data_t *if_dlg_data = if_data, *temp;
+  GList *curr;
+  unsigned int ifs, i;
+  gboolean found;
+  cap_settings_t cap_settings;
+  interface_options interface_opts;
+
+  for (ifs = 0; ifs < g_list_length(if_data_list); ifs++) {
+    curr = g_list_nth(if_data_list, ifs);
+    temp = (if_dlg_data_t *)(curr->data);
+    found = FALSE;
+    if (strcmp(if_dlg_data->if_info.name, temp->if_info.name) == 0) {
+      temp->selected ^=1;
+      if_data_list = g_list_remove(if_data_list, curr->data);
+      if_data_list = g_list_insert(if_data_list, temp, ifs);
+      
+      for (i = 0; i < global_capture_opts.ifaces->len; i++) {
+        if (strcmp(g_array_index(global_capture_opts.ifaces, interface_options, i).name, temp->if_info.name) == 0) {
+            found = TRUE;
+          if (!temp->selected) {
+            interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
+            global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i);
+            if (gtk_widget_is_focus(choose_bt) && get_welcome_window()) {
+              change_interface_selection(interface_opts.name, FALSE);
+            }
+            g_free(interface_opts.name);
+            g_free(interface_opts.descr);
+            g_free(interface_opts.cfilter);
+#ifdef HAVE_PCAP_REMOTE
+            g_free(interface_opts.remote_host);
+            g_free(interface_opts.remote_port);
+            g_free(interface_opts.auth_username);
+            g_free(interface_opts.auth_password);
+#endif
+            break;
+          }
+        } 
+      } 
+      if (!found && temp->selected) {
+        interface_opts.name = g_strdup(temp->if_info.name);
+        interface_opts.descr = get_interface_descriptive_name(interface_opts.name);
+        interface_opts.linktype = capture_dev_user_linktype_find(interface_opts.name);
+        interface_opts.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
+        interface_opts.has_snaplen = global_capture_opts.default_options.has_snaplen;
+        interface_opts.snaplen = global_capture_opts.default_options.snaplen;
+        cap_settings = capture_get_cap_settings (interface_opts.name);;
+        interface_opts.promisc_mode = global_capture_opts.default_options.promisc_mode;
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
+        interface_opts.buffer_size =  global_capture_opts.default_options.buffer_size;
+#endif
+        interface_opts.monitor_mode = cap_settings.monitor_mode;
+#ifdef HAVE_PCAP_REMOTE
+        interface_opts.src_type = global_capture_opts.default_options.src_type;
+        interface_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
+        interface_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
+        interface_opts.auth_type = global_capture_opts.default_options.auth_type;
+        interface_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
+        interface_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
+        interface_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
+        interface_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
+        interface_opts.nocap_local = global_capture_opts.default_options.nocap_local;
+#endif
+#ifdef HAVE_PCAP_SETSAMPLING
+        interface_opts.sampling_method = global_capture_opts.default_options.sampling_method;
+        interface_opts.sampling_param  = global_capture_opts.default_options.sampling_param;
+#endif
+        g_array_append_val(global_capture_opts.ifaces, interface_opts);
+        if (gtk_widget_is_focus(choose_bt) && get_welcome_window() != NULL) {
+          change_interface_selection(g_strdup(temp->if_info.name), TRUE);
+        }
+      }
+      
+      if (temp->selected)
+        currently_selected += 1;
+      else
+        currently_selected -= 1;
+      break;
+    }
+  }
+  if (cap_if_w) {
+#ifdef USE_THREADS
+    gtk_widget_set_sensitive(capture_bt, !gbl_capture_in_progress && (currently_selected > 0));
+#else
+    gtk_widget_set_sensitive(capture_bt, !gbl_capture_in_progress && (currently_selected == 1));
+#endif
+    gtk_widget_set_sensitive(options_bt, !gbl_capture_in_progress && (currently_selected <= 1));
+  }
+}
 
 /* start capture button was pressed */
 static void
+#ifdef HAVE_AIRPCAP
 capture_do_cb(GtkWidget *capture_bt _U_, gpointer if_data)
+#else
+capture_do_cb(GtkWidget *capture_bt _U_, gpointer if_data _U_)
+#endif
 {
+  if_dlg_data_t *temp;
+  GList *curr;
+  int ifs;
+#ifdef HAVE_AIRPCAP
   if_dlg_data_t *if_dlg_data = if_data;
 
-#ifdef HAVE_AIRPCAP
-  airpcap_if_active = get_airpcap_if_from_description(airpcap_if_list, GTK_LABEL(if_dlg_data->descr_lb)->label);
+  airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, if_dlg_data->if_info.name);
   airpcap_if_selected = airpcap_if_active;
 #endif
 
-  if (capture_opts->iface)
-    g_free(capture_opts->iface);
-
-  capture_opts->iface = g_strdup(if_dlg_data->device);
+  for (ifs = 0; (curr = g_list_nth(if_data_list, ifs)); ifs++) {
+    temp = (if_dlg_data_t *)(curr->data);
+    gtk_widget_set_sensitive(temp->choose_bt, FALSE);
+  }
 
   /* XXX - remove this? */
-  if (capture_opts->save_file) {
-    g_free(capture_opts->save_file);
-    capture_opts->save_file = NULL;
+  if (global_capture_opts.save_file) {
+    g_free(global_capture_opts.save_file);
+    global_capture_opts.save_file = NULL;
   }
 
+  if (global_capture_opts.ifaces->len > 1) {
+    global_capture_opts.use_pcapng = TRUE;
+  }
   /* stop capturing from all interfaces, we are going to do real work now ... */
   window_destroy(cap_if_w);
 
@@ -156,18 +291,13 @@ capture_do_cb(GtkWidget *capture_bt _U_, gpointer if_data)
 
 /* prepare capture button was pressed */
 static void
-capture_prepare_cb(GtkWidget *prepare_bt _U_, gpointer if_data)
+capture_prepare_cb(GtkWidget *prepare_bt _U_, gpointer if_data _U_)
 {
-  if_dlg_data_t *if_dlg_data = if_data;
-
-  if (capture_opts->iface)
-    g_free(capture_opts->iface);
-
-  capture_opts->iface = g_strdup(if_dlg_data->device);
-
   /* stop capturing from all interfaces, we are going to do real work now ... */
   window_destroy(cap_if_w);
-
+  if (global_capture_opts.ifaces->len > 1) {
+    global_capture_opts.use_pcapng = TRUE;
+  }
   capture_prep_cb(NULL, NULL);
 }
 
@@ -184,73 +314,27 @@ capture_details_cb(GtkWidget *details_bt _U_, gpointer if_data)
 }
 #endif
 
-
-/* open a single interface */
-static void
-open_if(gchar *name, if_dlg_data_t *if_dlg_data)
-{
-  gchar       open_err_str[CAPTURE_PCAP_ERRBUF_SIZE];
-
-  /*
-   * XXX - on systems with BPF, the number of BPF devices limits the
-   * number of devices on which you can capture simultaneously.
-   *
-   * This means that
-   *
-   *   1) this might fail if you run out of BPF devices
-   *
-   * and
-   *
-   *   2) opening every interface could leave too few BPF devices
-   *      for *other* programs.
-   *
-   * It also means the system could end up getting a lot of traffic
-   * that it has to pass through the networking stack and capture
-   * mechanism, so opening all the devices and presenting packet
-   * counts might not always be a good idea.
-   */
-  if_dlg_data->pch = pcap_open_live(name,
-                      MIN_PACKET_SIZE,
-                      capture_opts->promisc_mode, CAP_READ_TIMEOUT,
-                      open_err_str);
-
-  if (if_dlg_data->pch != NULL) {
-    update_if(if_dlg_data);
-  } else {
-    printf("open_if: %s\n", open_err_str);
-    gtk_label_set_text(GTK_LABEL(if_dlg_data->curr_lb), "error");
-    gtk_label_set_text(GTK_LABEL(if_dlg_data->last_lb), "error");
-  }
-}
-
 /* update a single interface */
-void
-update_if(if_dlg_data_t *if_dlg_data)
+static void
+update_if(if_dlg_data_t *if_dlg_data, if_stat_cache_t *sc)
 {
   struct pcap_stat stats;
   gchar *str;
   guint diff;
 
 
-  /* pcap_stats() stats values differ on libpcap and winpcap!
-   * libpcap: returns the number of packets since pcap_open_live
-   * winpcap: returns the number of packets since the last pcap_stats call
-   * XXX - if that's true, that's a bug, and should be fixed; "pcap_stats()"
-   * is supposed to work the same way on all platforms, including Windows.
-   * Note that the WinPcap 3.0 documentation says "The values represent
-   * packet statistics from the start of the run to the time of the call."
-   * (Note also that some versions of libpcap, on some versions of UN*X,
-   * have the same bug.)
+  /*
+   * Note that some versions of libpcap, on some versions of UN*X,
+   * pcap_stats() returns the number of packets since the last
+   * pcap_stats call.
+   *
+   * That's a bug, and should be fixed; "pcap_stats()" is supposed
+   * to work the same way on all platforms.
    */
-  if (if_dlg_data->pch) {
-    if(pcap_stats(if_dlg_data->pch, &stats) >= 0) {
-#ifdef _WIN32
+  if (sc) {
+    if (capture_stats(sc, if_dlg_data->device, &stats)) {
       diff = stats.ps_recv - if_dlg_data->last_packets;
       if_dlg_data->last_packets = stats.ps_recv;
-#else
-      diff = stats.ps_recv;
-      if_dlg_data->last_packets = stats.ps_recv + if_dlg_data->last_packets;
-#endif
 
       str = g_strdup_printf("%u", if_dlg_data->last_packets);
       gtk_label_set_text(GTK_LABEL(if_dlg_data->curr_lb), str);
@@ -268,160 +352,380 @@ update_if(if_dlg_data_t *if_dlg_data)
   }
 }
 
-
-/* close a single interface */
-static void
-close_if(if_dlg_data_t *if_dlg_data)
-{
-    if(if_dlg_data->pch)
-        pcap_close(if_dlg_data->pch);
-}
-
-
-
 /* update all interfaces */
 static gboolean
 update_all(gpointer data)
 {
     GList *curr;
     int ifs;
+    if_stat_cache_t *sc = data;
 
-
-    if(!cap_if_w) {
+    if (!cap_if_w) {
         return FALSE;
     }
 
-    for(ifs = 0; (curr = g_list_nth(data, ifs)); ifs++) {
-        update_if(curr->data);
+    for (ifs = 0; (curr = g_list_nth(if_data_list, ifs)); ifs++) {
+        update_if(curr->data, sc);
     }
 
     return TRUE;
 }
 
-
 /* a live capture has started or stopped */
 void
 set_capture_if_dialog_for_capture_in_progress(gboolean capture_in_progress)
 {
-    GList *curr;
-    int ifs;
-
-    if(cap_if_w) {
-        gtk_widget_set_sensitive(stop_bt, capture_in_progress);
-
-        for(ifs = 0; (curr = g_list_nth(if_data, ifs)); ifs++) {
-            if_dlg_data_t *if_dlg_data = curr->data;
-
-            gtk_widget_set_sensitive(if_dlg_data->capture_bt, !capture_in_progress);
-            gtk_widget_set_sensitive(if_dlg_data->prepare_bt, !capture_in_progress);
-        }
-    }
+  gbl_capture_in_progress = capture_in_progress;
+  if (cap_if_w) {
+    gtk_widget_set_sensitive(stop_bt, capture_in_progress);
+#ifdef USE_THREADS
+    gtk_widget_set_sensitive(capture_bt, !capture_in_progress && (currently_selected > 0));
+#else
+    gtk_widget_set_sensitive(capture_bt, !capture_in_progress && (currently_selected == 1));
+#endif
+    gtk_widget_set_sensitive(options_bt, !capture_in_progress && (currently_selected <= 1));
+  }
 }
 
 
 /* the window was closed, cleanup things */
 static void
-capture_if_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+capture_if_destroy_cb(GtkWidget *win _U_, gpointer user_data)
 {
     GList *curr;
     int ifs;
+    if_stat_cache_t *sc = user_data;
 
-    gtk_timeout_remove(timer_id);
+    g_source_remove(timer_id);
 
-    for(ifs = 0; (curr = g_list_nth(if_data, ifs)); ifs++) {
-        if_dlg_data_t *if_dlg_data = curr->data;
-
-        close_if(if_dlg_data);
+    for (ifs = 0; (curr = g_list_nth(if_data_list, ifs)); ifs++) {
         g_free(curr->data);
     }
 
-    if_data = NULL;
+    if_data_list = NULL;
 
     free_interface_list(if_list);
 
     /* Note that we no longer have a "Capture Options" dialog box. */
     cap_if_w = NULL;
 
+    capture_stat_stop(sc);
+
 #ifdef HAVE_AIRPCAP
-       airpcap_set_toolbar_stop_capture(airpcap_if_active);
+    airpcap_set_toolbar_stop_capture(airpcap_if_active);
 #endif
 }
 
-GtkWidget*
-combo_channel_new(void)
+
+/*
+ * Sorts the Interface List in alphabetical order
+ */
+gint if_list_comparator_alph (const void *first_arg, const void *second_arg){
+  const if_info_t *first = first_arg, *second = second_arg;
+
+  if (first != NULL && first->description != NULL &&
+      second != NULL && second->description != NULL) {
+    return g_ascii_strcasecmp(first->description, second->description);
+  } else {
+    return 0;
+  }
+}
+
+
+/*
+ * Used to retrieve the interface icon.
+ * This is hideously platform-dependent.
+ */
+GtkWidget * capture_get_if_icon(const if_info_t* if_info)
 {
-         GtkWidget* channel_cb;
-         GList*     popdown;
-
-
-      channel_cb = gtk_combo_new();
-         gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(channel_cb)->entry), "1");
-
-         popdown = NULL;
-
-         popdown = g_list_append(popdown, "1");
-      popdown = g_list_append(popdown, "2");
-      popdown = g_list_append(popdown, "3");
-      popdown = g_list_append(popdown, "4");
-         popdown = g_list_append(popdown, "5");
-         popdown = g_list_append(popdown, "6");
-         popdown = g_list_append(popdown, "7");
-         popdown = g_list_append(popdown, "8");
-         popdown = g_list_append(popdown, "9");
-         popdown = g_list_append(popdown, "10");
-         popdown = g_list_append(popdown, "11");
-         popdown = g_list_append(popdown, "12");
-         popdown = g_list_append(popdown, "13");
-         popdown = g_list_append(popdown, "14");
-
-      gtk_combo_set_popdown_strings( GTK_COMBO(channel_cb), popdown) ;
-
-         #if GTK_MAJOR_VERSION < 2
-         gtk_widget_set_usize( GTK_WIDGET(channel_cb),
-                                  45,
-                                  10 );
-         #else
-         gtk_widget_set_size_request( GTK_WIDGET(channel_cb),
-                                  45,
-                                  10 );
-      #endif
-
-
-         return channel_cb;
+#if defined(_WIN32)
+  /*
+   * Much digging failed to reveal any obvious way to get something such
+   * as the SNMP MIB-II ifType value for an interface:
+   *
+   *   http://www.iana.org/assignments/ianaiftype-mib
+   *
+   * by making some NDIS request.
+   */
+  if ( if_info->description && ( strstr(if_info->description,"generic dialup") != NULL ||
+       strstr(if_info->description,"PPP/SLIP") != NULL ) ) {
+    return xpm_to_widget(modem_16_xpm);
+  }
+
+  if ( if_info->description && ( strstr(if_info->description,"Wireless") != NULL ||
+       strstr(if_info->description,"802.11") != NULL || strstr(if_info->description,"AirPcap") != NULL ) ) {
+    return pixbuf_to_widget(network_wireless_pb_data);
+  }
+
+  if ( strstr(if_info->name,"airpcap") != NULL ) {
+    return pixbuf_to_widget(network_wireless_pb_data);
+  }
+
+  if ( if_info->description && strstr(if_info->description, "Bluetooth") != NULL ) {
+    return pixbuf_to_widget(network_bluetooth_pb_data);
+  }
+#elif defined(__APPLE__)
+  /*
+   * XXX - yes, fetching all the network addresses for an interface
+   * gets you an AF_LINK address, of type "struct sockaddr_dl", and,
+   * yes, that includes an SNMP MIB-II ifType value.
+   *
+   * However, it's IFT_ETHER, i.e. Ethernet, for AirPort interfaces,
+   * not IFT_IEEE80211 (which isn't defined in OS X in any case).
+   *
+   * Perhaps some other BSD-flavored OSes won't make this mistake;
+   * however, FreeBSD 7.0 and OpenBSD 4.2, at least, appear to have
+   * made the same mistake, at least for my Belkin ZyDAS stick.
+   *
+   * On Mac OS X, one might be able to get the information one wants from
+   * IOKit.
+   */
+  if ( strcmp(if_info->name, "en1") == 0) {
+    return pixbuf_to_widget(network_wireless_pb_data);
+  }
+
+  /*
+   * XXX - PPP devices have names beginning with "ppp" and an IFT_ of
+   * IFT_PPP, but they could be dial-up, or PPPoE, or mobile phone modem,
+   * or VPN, or... devices.  One might have to dive into the bowels of
+   * IOKit to find out.
+   */
+
+  /*
+   * XXX - there's currently no support for raw Bluetooth capture,
+   * and IP-over-Bluetooth devices just look like fake Ethernet
+   * devices.  There's also Bluetooth modem support, but that'll
+   * probably just give you a device that looks like a PPP device.
+   */
+#elif defined(__linux__)
+  /*
+   * Look for /sys/class/net/{device}/wireless.
+   */
+  ws_statb64 statb;
+  char *wireless_path;
+
+  wireless_path = g_strdup_printf("/sys/class/net/%s/wireless", if_info->name);
+  if (wireless_path != NULL) {
+    if (ws_stat64(wireless_path, &statb) == 0) {
+      g_free(wireless_path);
+      return pixbuf_to_widget(network_wireless_pb_data);
+    }
+    g_free(wireless_path);
+  }
+
+  /*
+   * Bluetooth devices.
+   *
+   * XXX - this is for raw Bluetooth capture; what about IP-over-Bluetooth
+   * devices?
+   */
+  if ( strstr(if_info->name,"bluetooth") != NULL) {
+    return pixbuf_to_widget(network_bluetooth_pb_data);
+  }
+
+  /*
+   * USB devices.
+   */
+  if ( strstr(if_info->name,"usbmon") != NULL ) {
+    return pixbuf_to_widget(network_usb_pb_data);
+  }
+#endif
+
+  /*
+   * TODO: find a better icon!
+   * Bridge, NAT, or host-only interfaces on VMWare hosts have the name
+   * vmnet[0-9]+ or VMnet[0-9+ on Windows. Guests might use a native
+   * (LANCE or E1000) driver or the vmxnet driver. These devices have an
+   * IFT_ of IFT_ETHER, so we have to check the name.
+   */
+  if ( g_ascii_strncasecmp(if_info->name, "vmnet", 5) == 0) {
+    return xpm_to_widget(network_virtual_16_xpm);
+  }
+
+  if ( g_ascii_strncasecmp(if_info->name, "vmxnet", 6) == 0) {
+    return xpm_to_widget(network_virtual_16_xpm);
+  }
+
+  if ( if_info->description && strstr(if_info->description, "VMware") != NULL ) {
+    return xpm_to_widget(network_virtual_16_xpm);
+  }
+
+  return pixbuf_to_widget(network_wired_pb_data);
 }
 
+
+static int
+get_ip_addr_count(GSList *addr_list)
+{
+  GSList *curr_addr;
+  if_addr_t *addr;
+  int count;
+
+  count = 0;
+  for (curr_addr = addr_list; curr_addr != NULL;
+       curr_addr = g_slist_next(curr_addr)) {
+    addr = (if_addr_t *)curr_addr->data;
+    switch (addr->ifat_type) {
+
+    case IF_AT_IPv4:
+    case IF_AT_IPv6:
+      count++;
+      break;
+
+    default:
+      /* In case we add non-IP addresses */
+      break;
+    }
+  }
+  return count;
+}
+
+static const gchar *
+set_ip_addr_label(GSList *addr_list, GtkWidget *ip_lb, guint selected_ip_addr)
+{
+  GSList *curr_addr;
+  if_addr_t *addr;
+  const gchar *addr_str = NULL;
+
+  curr_addr = g_slist_nth(addr_list, selected_ip_addr);
+  if (curr_addr) {
+    addr = (if_addr_t *)curr_addr->data;
+    switch (addr->ifat_type) {
+
+    case IF_AT_IPv4:
+      addr_str = ip_to_str((guint8 *)&addr->addr.ip4_addr);
+      break;
+
+    case IF_AT_IPv6:
+      addr_str = ip6_to_str((struct e_in6_addr *)&addr->addr.ip6_addr);
+      break;
+
+    default:
+      /* Ignore non-IP addresses, in case we ever support them */
+      break;
+    }
+  }
+
+  if (addr_str) {
+    gtk_label_set_text(GTK_LABEL(ip_lb), addr_str);
+  } else {
+    gtk_label_set_text(GTK_LABEL(ip_lb), "unknown");
+  }
+  g_object_set_data(G_OBJECT(ip_lb), CAPTURE_IF_SELECTED_IP_ADDR, GINT_TO_POINTER(selected_ip_addr));
+
+  return addr_str;
+}
+
+
+static gboolean
+ip_label_enter_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
+{
+    gtk_widget_set_state(eb, GTK_STATE_PRELIGHT);
+
+    return FALSE;
+}
+
+
+static gboolean
+ip_label_leave_cb(GtkWidget *eb, GdkEvent *event _U_, gpointer user_data _U_)
+{
+    gtk_widget_set_state(eb, GTK_STATE_NORMAL);
+
+    return FALSE;
+}
+
+
+static gboolean
+ip_label_press_cb(GtkWidget *widget, GdkEvent *event _U_, gpointer data)
+{
+  GtkWidget *ip_lb = g_object_get_data(G_OBJECT(widget), CAPTURE_IF_IP_ADDR_LABEL);
+  GSList *addr_list = data;
+  GSList *curr_addr, *start_addr;
+  if_addr_t *addr;
+  guint selected_ip_addr = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(ip_lb), CAPTURE_IF_SELECTED_IP_ADDR));
+
+  /* Select next IP address */
+  start_addr = g_slist_nth(addr_list, selected_ip_addr);
+  for (;;) {
+    selected_ip_addr++;
+    if (g_slist_length(addr_list) <= selected_ip_addr) {
+      /* Wrap around */
+      selected_ip_addr = 0;
+    }
+    curr_addr = g_slist_nth(addr_list, selected_ip_addr);
+    if (curr_addr == start_addr) {
+      /* We wrapped all the way around */
+      break;
+    }
+
+    addr = (if_addr_t *)curr_addr->data;
+    switch (addr->ifat_type) {
+
+    case IF_AT_IPv4:
+    case IF_AT_IPv6:
+      goto found;
+
+    default:
+      /* In case we add non-IP addresses */
+      break;
+    }
+  }
+
+found:
+  set_ip_addr_label(addr_list, ip_lb, selected_ip_addr);
+
+  return FALSE;
+}
+
+static void
+capture_if_stop_cb(GtkWidget *w _U_, gpointer d _U_)
+{
+    guint ifs;
+    GList *curr;
+    if_dlg_data_t *if_data;
+
+    for (ifs = 0; ifs < g_list_length(if_data_list); ifs++) {
+        curr = g_list_nth(if_data_list, ifs);
+        if_data = (if_dlg_data_t *)(curr->data);
+        gtk_widget_set_sensitive(if_data->choose_bt, TRUE);
+    }
+    capture_stop_cb(NULL, NULL);
+}
+
+
 /* start getting capture stats from all interfaces */
 void
 capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
 {
-  GtkWidget     *main_vb,
-                               *main_sw,
-                               *bbox,
-                               *close_bt,
-                               *help_bt,
-                               *icon;
-
-  GtkWidget            *decryption_cm;
-
-  GtkWidget     *if_tb;
-  GtkWidget     *if_lb;
-#if GTK_MAJOR_VERSION < 2
-  GtkAccelGroup *accel_group;
+  GtkWidget         *main_vb,
+                    *main_sw,
+                    *bbox,
+                    *close_bt,
+                    *help_bt,
+                    *icon;
+
+#ifdef HAVE_AIRPCAP
+  GtkWidget         *decryption_cb;
 #endif
-  GtkTooltips   *tooltips;
-  int           err;
-  char          err_str[CAPTURE_PCAP_ERRBUF_SIZE];
-  gchar         *cant_get_if_list_errstr;
-  GtkRequisition requisition;
-  int           row, height;
-  if_dlg_data_t *if_dlg_data;
-  int           ifs;
-  GList         *curr;
-  if_info_t     *if_info;
-  GSList        *curr_ip;
-  if_addr_t     *ip_addr;
-  GString       *if_tool_str = g_string_new("");
-  gchar         *tmp_str;
+
+  GtkWidget         *if_tb;
+  GtkWidget         *if_lb;
+  GtkWidget         *eb;
+  int               err;
+  gchar             *err_str;
+  GtkRequisition    requisition;
+  int               row, height;
+  if_dlg_data_t     *if_dlg_data = NULL;
+  int               ifs;
+  GList             *curr;
+  if_info_t         *if_info;
+  GString           *if_tool_str = g_string_new("");
+  const gchar       *addr_str;
+  gchar             *user_descr;
+  if_stat_cache_t   *sc;
+  int               preselected = 0, i;
+  interface_options interface_opts;
+  gboolean      found = FALSE;
 
   if (cap_if_w != NULL) {
     /* There's already a "Capture Interfaces" dialog box; reactivate it. */
@@ -440,70 +744,67 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
     return;
   }
 #endif
-
+  preselected = global_capture_opts.ifaces->len;
   /* LOAD THE INTERFACES */
-  if_list = get_interface_list(&err, err_str);
-  if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
-    cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s",
-                  cant_get_if_list_errstr);
-    g_free(cant_get_if_list_errstr);
+  if_list = capture_interface_list(&err, &err_str);
+  if_list = g_list_sort (if_list, if_list_comparator_alph);
+  if (if_list == NULL) {
+    switch (err) {
+
+    case CANT_GET_INTERFACE_LIST:
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
+      g_free(err_str);
+      break;
+
+    case NO_INTERFACES_FOUND:
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                    "There are no interfaces on which a capture can be done.");
+      break;
+    }
     return;
   }
 
 #ifdef HAVE_AIRPCAP
   /* LOAD AIRPCAP INTERFACES */
-       /* load the airpcap interfaces */
-       airpcap_if_list = get_airpcap_interface_list(&err, err_str);
-       if(airpcap_if_list == NULL) airpcap_if_active = airpcap_if_selected = NULL;
-
-       decryption_cm = OBJECT_GET_DATA(airpcap_tb,AIRPCAP_TOOLBAR_DECRYPTION_KEY);
-       update_decryption_mode_list(decryption_cm);
-
-       if (airpcap_if_list == NULL && err == CANT_GET_AIRPCAP_INTERFACE_LIST) {
-       cant_get_if_list_errstr = cant_get_airpcap_if_list_error_message(err_str);
-       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s",
-                                 cant_get_if_list_errstr);
-       g_free(cant_get_if_list_errstr);
-       }
-
-       /* If no airpcap interface is present, gray everything */
-       if(airpcap_if_active == NULL)
-               {
-               if(airpcap_if_list == NULL)
-                       {
-                       /*No airpcap device found */
-                       airpcap_enable_toolbar_widgets(airpcap_tb,FALSE);
-                       }
-               else
-                       {
-                       /* default adapter is not airpcap... or is airpcap but is not found*/
-                       airpcap_set_toolbar_stop_capture(airpcap_if_active);
-                       airpcap_enable_toolbar_widgets(airpcap_tb,FALSE);
-                       }
-               }
+  airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
+  if (airpcap_if_list == NULL)
+    airpcap_if_active = airpcap_if_selected = NULL;
 
-  airpcap_set_toolbar_start_capture(airpcap_if_active);
-#endif
+  decryption_cb = g_object_get_data(G_OBJECT(airpcap_tb),AIRPCAP_TOOLBAR_DECRYPTION_KEY);
+  update_decryption_mode_list(decryption_cb);
 
-  cap_if_w = window_new(GTK_WINDOW_TOPLEVEL, "Wireshark: Capture Interfaces");
+  if (airpcap_if_list == NULL && err == CANT_GET_AIRPCAP_INTERFACE_LIST) {
+#if 0
+    /* XXX - Do we need to show an error here? */
+    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
+#endif
+    g_free(err_str);
+  }
 
-  tooltips = gtk_tooltips_new();
+  /* If no airpcap interface is present, gray everything */
+  if (airpcap_if_active == NULL) {
+    if (airpcap_if_list == NULL) {
+      /*No airpcap device found */
+      airpcap_enable_toolbar_widgets(airpcap_tb,FALSE);
+    } else {
+      /* default adapter is not airpcap... or is airpcap but is not found*/
+      airpcap_set_toolbar_stop_capture(airpcap_if_active);
+      airpcap_enable_toolbar_widgets(airpcap_tb,FALSE);
+    }
+  }
 
-#if GTK_MAJOR_VERSION < 2
-  /* Accelerator group for the accelerators (or, as they're called in
-     Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
-     Ctrl+<key> is an accelerator). */
-  accel_group = gtk_accel_group_new();
-  gtk_window_add_accel_group(GTK_WINDOW(cap_if_w), accel_group);
+  airpcap_set_toolbar_start_capture(airpcap_if_active);
 #endif
 
+  cap_if_w = dlg_window_new("Wireshark: Capture Interfaces");  /* transient_for top_level */
+  gtk_window_set_destroy_with_parent (GTK_WINDOW(cap_if_w), TRUE);
+
   main_sw = gtk_scrolled_window_new(NULL, NULL);
   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(main_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
   gtk_container_add(GTK_CONTAINER(cap_if_w), main_sw);
 
   main_vb = gtk_vbox_new(FALSE, 0);
-  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+  gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(main_sw), main_vb);
 
 
@@ -526,70 +827,104 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
    * bother showing them.
    */
   if_lb = gtk_label_new("Device");
-  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 1, 2, row, row+1);
+  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 1, 4, row, row+1);
 #endif
-
   if_lb = gtk_label_new("Description");
-  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 2, 3, row, row+1);
+  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 4, 5, row, row+1);
 
   if_lb = gtk_label_new(" IP ");
-  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 3, 4, row, row+1);
+  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 5, 6, row, row+1);
 
   if_lb = gtk_label_new("Packets");
-  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 4, 5, row, row+1);
+  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 6, 7, row, row+1);
 
   if_lb = gtk_label_new(" Packets/s ");
-  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 5, 6, row, row+1);
-
-  stop_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_CAPTURE_STOP);
-  gtk_tooltips_set_tip(tooltips, stop_bt,
-          "Stop a running capture.", NULL);
-#ifdef _WIN32
-  gtk_table_attach_defaults(GTK_TABLE(if_tb), stop_bt, 6, 9, row, row+1);
-#else
-  gtk_table_attach_defaults(GTK_TABLE(if_tb), stop_bt, 6, 8, row, row+1);
-#endif
-  SIGNAL_CONNECT(stop_bt, "clicked", capture_stop_cb, NULL);
-
+  gtk_table_attach_defaults(GTK_TABLE(if_tb), if_lb, 7, 8, row, row+1);
   row++;
-  gtk_widget_size_request(stop_bt, &requisition);
-  height += requisition.height + 15;
 
-  for(ifs = 0; (curr = g_list_nth(if_list, ifs)); ifs++) {
+  height += 30;
+  /* Start gathering statistics (using dumpcap) */
+  sc = capture_stat_start(if_list);
+
+  /* List the interfaces */
+  currently_selected = 0;
+  for (ifs = 0; (curr = g_list_nth(if_list, ifs)); ifs++) {
       g_string_assign(if_tool_str, "");
       if_info = curr->data;
+
+      /* Continue if capture device is hidden */
+      if (prefs_is_capture_device_hidden(if_info->name)) {
+          continue;
+      }
+
       if_dlg_data = g_malloc0(sizeof(if_dlg_data_t));
 
-      /* Kind of adaptor (icon) */
+      if (preselected > 0) {
+        found = FALSE;
+        for (i = 0; i < (gint)global_capture_opts.ifaces->len; i++) {
+          interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
+          if ((interface_opts.name == NULL) ||
+              (strcmp(interface_opts.name, (char*)if_info->name) != 0))
+            continue;
+          else {
+            found = TRUE;
+            currently_selected++;
+            preselected--;
+            break;
+          }
+        }
+        if_dlg_data->selected = found;
+      }
+      else
+        if_dlg_data->selected = FALSE;
+
+      if_dlg_data->if_info = *if_info;
+
+      if_dlg_data->choose_bt = gtk_check_button_new();
+      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->choose_bt, 0, 1, row, row+1);
+      if (gbl_capture_in_progress) {
+          gtk_widget_set_sensitive(if_dlg_data->choose_bt, FALSE);
+      } else {
+          gtk_widget_set_sensitive(if_dlg_data->choose_bt, TRUE);
+      }
+      gtk_toggle_button_set_active((GtkToggleButton *)if_dlg_data->choose_bt, if_dlg_data->selected);
+      g_signal_connect(if_dlg_data->choose_bt, "toggled", G_CALLBACK(store_selected), if_dlg_data);
+     /* Kind of adaptor (icon) */
 #ifdef HAVE_AIRPCAP
-      if(get_airpcap_if_from_description(airpcap_if_list,if_info->description) != NULL)
+      if (get_airpcap_if_from_name(airpcap_if_list,if_info->name) != NULL)
         icon = xpm_to_widget(capture_airpcap_16_xpm);
       else
-        icon = xpm_to_widget(capture_ethernet_16_xpm);
+        icon = capture_get_if_icon(if_info);
 #else
-      icon = xpm_to_widget(capture_ethernet_16_xpm);
+      icon = capture_get_if_icon(if_info);
 #endif
 
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), icon, 0, 1, row, row+1);
+      gtk_table_attach_defaults(GTK_TABLE(if_tb), icon, 1, 2, row, row+1);
 
       /* device name */
       if_dlg_data->device_lb = gtk_label_new(if_info->name);
       if_dlg_data->device = if_info->name;
 #ifndef _WIN32
-      gtk_misc_set_alignment(GTK_MISC(if_dlg_data->device_lb), 0.0, 0.5);
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->device_lb, 1, 2, row, row+1);
+      gtk_misc_set_alignment(GTK_MISC(if_dlg_data->device_lb), 0.0f, 0.5f);
+      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->device_lb, 2, 4, row, row+1);
 #endif
       g_string_append(if_tool_str, "Device: ");
       g_string_append(if_tool_str, if_info->name);
       g_string_append(if_tool_str, "\n");
 
       /* description */
-      if (if_info->description != NULL)
-        if_dlg_data->descr_lb = gtk_label_new(if_info->description);
-      else
-        if_dlg_data->descr_lb = gtk_label_new("");
-      gtk_misc_set_alignment(GTK_MISC(if_dlg_data->descr_lb), 0.0, 0.5);
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->descr_lb, 2, 3, row, row+1);
+      user_descr = capture_dev_user_descr_find(if_info->name);
+      if (user_descr) {
+        if_dlg_data->descr_lb = gtk_label_new(user_descr);
+        g_free (user_descr);
+      } else {
+        if (if_info->description)
+          if_dlg_data->descr_lb = gtk_label_new(if_info->description);
+        else
+          if_dlg_data->descr_lb = gtk_label_new("");
+      }
+      gtk_misc_set_alignment(GTK_MISC(if_dlg_data->descr_lb), 0.0f, 0.5f);
+      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->descr_lb, 4, 5, row, row+1);
 
       if (if_info->description) {
         g_string_append(if_tool_str, "Description: ");
@@ -598,118 +933,105 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
       }
 
       /* IP address */
-      /* only the first IP address will be shown */
+      /* Only one IP address will be shown, start with the first */
       g_string_append(if_tool_str, "IP: ");
-      curr_ip = g_slist_nth(if_info->ip_addr, 0);
-      if(curr_ip) {
-        ip_addr = (if_addr_t *)curr_ip->data;
-        switch (ip_addr->type) {
-
-        case AT_IPv4:
-          tmp_str = ip_to_str((guint8 *)&ip_addr->ip_addr.ip4_addr);
-          break;
-
-        case AT_IPv6:
-          tmp_str = ip6_to_str((struct e_in6_addr *)&ip_addr->ip_addr.ip6_addr);
-          break;
-
-        default:
-          g_assert_not_reached();
-          tmp_str = NULL;
-        }
-        if_dlg_data->ip_lb = gtk_label_new(tmp_str);
+      if_dlg_data->ip_lb = gtk_label_new("");
+      addr_str = set_ip_addr_label (if_info->addrs, if_dlg_data->ip_lb, 0);
+      if (addr_str) {
         gtk_widget_set_sensitive(if_dlg_data->ip_lb, TRUE);
-        g_string_append(if_tool_str, tmp_str);
+        g_string_append(if_tool_str, addr_str);
       } else {
-        if_dlg_data->ip_lb = gtk_label_new("unknown");
         gtk_widget_set_sensitive(if_dlg_data->ip_lb, FALSE);
         g_string_append(if_tool_str, "unknown");
       }
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->ip_lb, 3, 4, row, row+1);
+      eb = gtk_event_box_new ();
+      gtk_container_add(GTK_CONTAINER(eb), if_dlg_data->ip_lb);
+      gtk_table_attach_defaults(GTK_TABLE(if_tb), eb, 5, 6, row, row+1);
+      if (get_ip_addr_count(if_info->addrs) > 1) {
+        /* More than one IP address, make it possible to toggle */
+        g_object_set_data(G_OBJECT(eb), CAPTURE_IF_IP_ADDR_LABEL, if_dlg_data->ip_lb);
+        g_signal_connect(eb, "enter-notify-event", G_CALLBACK(ip_label_enter_cb), NULL);
+        g_signal_connect(eb, "leave-notify-event", G_CALLBACK(ip_label_leave_cb), NULL);
+        g_signal_connect(eb, "button-press-event", G_CALLBACK(ip_label_press_cb), if_info->addrs);
+      }
       g_string_append(if_tool_str, "\n");
 
       /* packets */
       if_dlg_data->curr_lb = gtk_label_new("-");
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->curr_lb, 4, 5, row, row+1);
+      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->curr_lb, 6, 7, row, row+1);
 
       /* packets/s */
       if_dlg_data->last_lb = gtk_label_new("-");
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->last_lb, 5, 6, row, row+1);
-
-      /* capture button */
-      if_dlg_data->capture_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_CAPTURE_START);
-         SIGNAL_CONNECT(if_dlg_data->capture_bt, "clicked", capture_do_cb, if_dlg_data);
-      tmp_str = g_strdup_printf("Immediately start a capture from this interface:\n\n%s", if_tool_str->str);
-      gtk_tooltips_set_tip(tooltips, if_dlg_data->capture_bt,
-          tmp_str, NULL);
-      g_free(tmp_str);
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->capture_bt, 6, 7, row, row+1);
-
-      /* prepare button */
-      if_dlg_data->prepare_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_CAPTURE_OPTIONS);
-      SIGNAL_CONNECT(if_dlg_data->prepare_bt, "clicked", capture_prepare_cb, if_dlg_data);
-      gtk_tooltips_set_tip(tooltips, if_dlg_data->prepare_bt,
-          "Open the capture options dialog with this interface selected.", NULL);
-      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->prepare_bt, 7, 8, row, row+1);
+      gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->last_lb, 7, 8, row, row+1);
 
       /* details button */
 #ifdef _WIN32
-      if_dlg_data->details_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_CAPTURE_DETAILS);
-         SIGNAL_CONNECT(if_dlg_data->details_bt, "clicked", capture_details_cb, if_dlg_data);
-      gtk_tooltips_set_tip(tooltips, if_dlg_data->details_bt,
-          "Open the capture details dialog of this interface.", NULL);
+      if_dlg_data->details_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_CAPTURE_DETAILS);
+      gtk_widget_set_tooltip_text(if_dlg_data->details_bt, "Open the capture details dialog of this interface.");
       gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->details_bt, 8, 9, row, row+1);
+      if (capture_if_has_details(if_dlg_data->device)) {
+        g_signal_connect(if_dlg_data->details_bt, "clicked", G_CALLBACK(capture_details_cb), if_dlg_data);
+      } else {
+        gtk_widget_set_sensitive(if_dlg_data->details_bt, FALSE);
+      }
 #endif
 
-      open_if(if_info->name, if_dlg_data);
-
-      if_data = g_list_append(if_data, if_dlg_data);
+      if_data_list = g_list_append(if_data_list, if_dlg_data);
 
       row++;
       if (row <= 10) {
-          /* Lets add up 10 rows of interfaces, otherwise the window may become too high */
-          gtk_widget_size_request(GTK_WIDGET(if_dlg_data->prepare_bt), &requisition);
-          height += requisition.height;
+        /* Lets add up 10 rows of interfaces, otherwise the window may become too high */
+        gtk_widget_size_request(GTK_WIDGET(if_dlg_data->choose_bt), &requisition);
+        height += requisition.height;
       }
   }
 
   g_string_free(if_tool_str, TRUE);
 
-  /* Button row: close button */
-  if(topic_available(HELP_CAPTURE_INTERFACES_DIALOG)) {
-    bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
-  } else {
-    bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
-  }
+  /* Button row: close, help, stop, start, and options button */
+  bbox = dlg_button_row_new(GTK_STOCK_HELP, WIRESHARK_STOCK_CAPTURE_START, WIRESHARK_STOCK_CAPTURE_OPTIONS, WIRESHARK_STOCK_CAPTURE_STOP, GTK_STOCK_CLOSE, NULL);
+
   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
+  help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
+  g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)(HELP_CAPTURE_INTERFACES_DIALOG));
 
-  close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
+  stop_bt = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CAPTURE_STOP);
+  g_signal_connect(stop_bt, "clicked", G_CALLBACK(capture_if_stop_cb), NULL);
+  close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
   window_set_cancel_button(cap_if_w, close_bt, window_cancel_button_cb);
-  gtk_tooltips_set_tip(tooltips, close_bt, "Close this window.", NULL);
-
-  if(topic_available(HELP_CAPTURE_INTERFACES_DIALOG)) {
-    help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
-    SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_CAPTURE_INTERFACES_DIALOG);
-  }
-
+  gtk_widget_set_tooltip_text(close_bt, "Close this window.");
+  options_bt = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CAPTURE_OPTIONS);
+  g_signal_connect(options_bt, "clicked", G_CALLBACK(capture_prepare_cb), if_dlg_data);
+  capture_bt = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CAPTURE_START);
+  g_signal_connect(capture_bt, "clicked", G_CALLBACK(capture_do_cb), if_dlg_data);
   gtk_widget_size_request(GTK_WIDGET(close_bt), &requisition);
-  /* height + static offset + what GTK-Wimp needs in addition per interface */
+  /* height + static offset + what the GTK MS Windows Engine needs in addition per interface */
   height += requisition.height + 20 + ifs;
   gtk_window_set_default_size(GTK_WINDOW(cap_if_w), -1, height);
 
   gtk_widget_grab_default(close_bt);
 
-  SIGNAL_CONNECT(cap_if_w, "delete_event", window_delete_event_cb, NULL);
-  SIGNAL_CONNECT(cap_if_w, "destroy", capture_if_destroy_cb, NULL);
+  g_signal_connect(cap_if_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
+  g_signal_connect(cap_if_w, "destroy", G_CALLBACK(capture_if_destroy_cb), sc);
 
   gtk_widget_show_all(cap_if_w);
   window_present(cap_if_w);
 
-  set_capture_if_dialog_for_capture_in_progress(is_capture_in_progress());
+  set_capture_if_dialog_for_capture_in_progress(gbl_capture_in_progress);
 
     /* update the interface list every 1000ms */
-  timer_id = gtk_timeout_add(1000, update_all, if_data);
+  timer_id = g_timeout_add(1000, update_all, sc);
+}
+
+GtkWidget* get_interfaces_dialog_window(void)
+{
+  return cap_if_w;
 }
+#else /* HAVE_LIBPCAP */
 
+void
+set_capture_if_dialog_for_capture_in_progress(gboolean capture_in_progress _U_)
+{
+}
 
 #endif /* HAVE_LIBPCAP */