[Diameter] Add a couple of command codes from IANA.
[metze/wireshark/wip.git] / wireshark-qt.cpp
index 4268257a312c8eb89fc78d6f60b0860c12fe02da..7e4d597c7a9994d0461da2ba1b0e535e12ea991b 100644 (file)
 #include "wsutil/wsgetopt.h"
 #endif
 
+#ifndef _WIN32
+#include <wsutil/glib-compat.h>
+#endif
+
 #include <wsutil/clopts_common.h>
 #include <wsutil/cmdarg_err.h>
 #include <wsutil/crash_info.h>
@@ -45,7 +49,7 @@
 #ifdef HAVE_PLUGINS
 #include <wsutil/plugins.h>
 #endif
-#include <wsutil/report_err.h>
+#include <wsutil/report_message.h>
 #include <wsutil/unicode-utils.h>
 #include <ws_version_info.h>
 
@@ -63,9 +67,7 @@
 #include <epan/dissectors/packet-kerberos.h>
 #endif
 
-#ifdef HAVE_PLUGINS
 #include <codecs/codecs.h>
-#endif
 
 #ifdef HAVE_EXTCAP
 #include <extcap.h>
@@ -87,7 +89,9 @@
 #include "ui/recent.h"
 #include "ui/simple_dialog.h"
 #include "ui/util.h"
+#include "ui/dissect_opts.h"
 #include "ui/commandline.h"
+#include "ui/capture_ui_utils.h"
 
 #include "ui/qt/conversation_dialog.h"
 #include "ui/qt/color_utils.h"
 #include <QTextCodec>
 #endif
 
-#if defined(HAVE_LIBPCAP) || defined(HAVE_EXTCAP)
-capture_options global_capture_opts;
-#endif
+#define INVALID_OPTION 1
+#define INIT_FAILED 2
+#define INVALID_CAPABILITY 2
+#define INVALID_LINK_TYPE 2
+
+//#define DEBUG_STARTUP_TIME 1
+/*
+# Log level
+# Console log level (for debugging)
+# A bitmask of log levels:
+# ERROR    = 4
+# CRITICAL = 8
+# WARNING  = 16
+# MESSAGE  = 32
+# INFO     = 64
+# DEBUG    = 128
+
+*/
+#define DEBUG_STARTUP_TIME_LOGLEVEL 252
 
 /* update the main window */
 void main_window_update(void)
@@ -220,6 +240,8 @@ get_gui_compiled_info(GString *str)
 #else
     g_string_append(str, "without AirPcap");
 #endif
+
+    codec_get_compiled_version_info(str);
 }
 
 // xxx copied from ../gtk/main.c
@@ -311,26 +333,25 @@ reset_library_path(void)
 #endif
 
 /* And now our feature presentation... [ fade to music ] */
-int main(int argc, char *argv[])
+int main(int argc, char *qt_argv[])
 {
     MainWindow *main_w;
 
 #ifdef _WIN32
     int                  opt;
 #endif
-    int                  ret_val;
-    char               **ws_argv = argv;
+    int                  ret_val = EXIT_SUCCESS;
+    char               **argv = qt_argv;
 
 #ifdef _WIN32
+    int                  result;
     WSADATA              wsaData;
 #endif  /* _WIN32 */
 
     char                *rf_path;
     int                  rf_open_errno;
-    char                *gdp_path, *dp_path;
 #ifdef HAVE_LIBPCAP
     gchar               *err_str;
-    int                  status;
 #else
 #ifdef _WIN32
 #ifdef HAVE_AIRPCAP
@@ -338,12 +359,20 @@ int main(int argc, char *argv[])
 #endif
 #endif
 #endif
+    gchar               *err_msg = NULL;
     GString             *comp_info_str = NULL;
     GString             *runtime_info_str = NULL;
-    commandline_param_info_t commandline_info;
 
     QString              dfilter, read_filter;
-
+    /* Start time in microseconds*/
+    guint64 start_time = g_get_monotonic_time();
+#ifdef DEBUG_STARTUP_TIME
+    /* At least on Windows there is a problem with the loging as the preferences is taken
+     * into account and the preferences are loaded pretty late in the startup process.
+     */
+    prefs.console_log_level = DEBUG_STARTUP_TIME_LOGLEVEL;
+    prefs.gui_console_open = console_open_always;
+#endif /* DEBUG_STARTUP_TIME */
     cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont);
 
     // In Qt 5, C strings are treated always as UTF-8 when converted to
@@ -361,11 +390,11 @@ int main(int argc, char *argv[])
 
 #ifdef _WIN32
     // QCoreApplication clobbers argv. Let's have a local copy.
-    ws_argv = (char **) g_malloc(sizeof(char *) * argc);
+    argv = (char **) g_malloc(sizeof(char *) * argc);
     for (opt = 0; opt < argc; opt++) {
-        ws_argv[opt] = argv[opt];
+        argv[opt] = qt_argv[opt];
     }
-    arg_list_utf_16to8(argc, ws_argv);
+    arg_list_utf_16to8(argc, argv);
     create_app_running_mutex();
 #endif /* _WIN32 */
 
@@ -378,9 +407,10 @@ int main(int argc, char *argv[])
     relinquish_special_privs_perm();
 
     /*
-     * Attempt to get the pathname of the executable file.
+     * Attempt to get the pathname of the directory containing the
+     * executable file.
      */
-    /* init_progfile_dir_error = */ init_progfile_dir(ws_argv[0],
+    /* init_progfile_dir_error = */ init_progfile_dir(argv[0],
         (int (*)(int, char **)) get_gui_compiled_info);
     g_log(NULL, G_LOG_LEVEL_DEBUG, "progfile_dir: %s", get_progfile_dir());
 
@@ -443,6 +473,14 @@ int main(int argc, char *argv[])
     /* Assemble the run-time version information string */
     runtime_info_str = get_runtime_version_info(get_wireshark_runtime_info);
 
+    /* Create the user profiles directory */
+    if (create_profiles_dir(&rf_path) == -1) {
+        simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
+                      "Could not create profiles directory\n\"%s\"",
+                      rf_path);
+        g_free (rf_path);
+    }
+
     profile_store_persconffiles(TRUE);
 
     /* Read the profile independent recent file.  We have to do this here so we can */
@@ -454,14 +492,14 @@ int main(int argc, char *argv[])
         g_free(rf_path);
     }
 
-    commandline_early_options(argc, ws_argv, comp_info_str, runtime_info_str);
+    commandline_early_options(argc, argv, comp_info_str, runtime_info_str);
 
 #ifdef _WIN32
     reset_library_path();
 #endif
 
     /* Create The Wireshark app */
-    WiresharkApplication ws_app(argc, argv);
+    WiresharkApplication ws_app(argc, qt_argv);
 
     /* initialize the funnel mini-api */
     // xxx qtshark
@@ -479,10 +517,17 @@ int main(int argc, char *argv[])
            "\n"
            "%s",
         get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
+    g_string_free(comp_info_str, TRUE);
+    g_string_free(runtime_info_str, TRUE);
 
 #ifdef _WIN32
     /* Start windows sockets */
-    WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
+    result = WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
+    if (result != 0)
+    {
+        ret_val = INIT_FAILED;
+        goto clean_exit;
+    }
 #endif  /* _WIN32 */
 
     /* Read the profile dependent (static part) of the recent file. */
@@ -510,6 +555,8 @@ int main(int argc, char *argv[])
     // to force the issue.
     main_w->connect(&ws_app, SIGNAL(openCaptureFile(QString,QString,unsigned int)),
             main_w, SLOT(openCaptureFile(QString,QString,unsigned int)));
+    main_w->connect(&ws_app, SIGNAL(openCaptureOptions()),
+            main_w, SLOT(on_actionCaptureOptions_triggered()));
 
     /* Init the "Open file" dialog directory */
     /* (do this after the path settings are processed) */
@@ -526,6 +573,9 @@ int main(int argc, char *argv[])
 #endif
 
     set_console_log_handler();
+#ifdef DEBUG_STARTUP_TIME
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "set_console_log_handler, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
+#endif
 
 #ifdef HAVE_LIBPCAP
     /* Set the initial values in the capture options. This might be overwritten
@@ -533,28 +583,32 @@ int main(int argc, char *argv[])
     capture_opts_init(&global_capture_opts);
 #endif
 
-    init_report_err(vfailure_alert_box, open_failure_alert_box,
-                    read_failure_alert_box, write_failure_alert_box);
+    init_report_message(vfailure_alert_box, vwarning_alert_box,
+                        open_failure_alert_box, read_failure_alert_box,
+                        write_failure_alert_box);
 
-    init_open_routines();
+    wtap_init();
 
 #ifdef HAVE_PLUGINS
     /* Register all the plugin types we have. */
     epan_register_plugin_types(); /* Types known to libwireshark */
-    wtap_register_plugin_types(); /* Types known to libwiretap */
     codec_register_plugin_types(); /* Types known to libwscodecs */
 
     /* Scan for plugins.  This does *not* call their registration routines;
        that's done later. */
-    scan_plugins();
+    scan_plugins(REPORT_LOAD_FAILURE);
 
     /* Register all libwiretap plugin modules. */
     register_all_wiretap_modules();
+#endif
 
     /* Register all audio codec plugins. */
     register_all_codecs();
-#endif
 
+    splash_update(RA_DISSECTORS, NULL, NULL);
+#ifdef DEBUG_STARTUP_TIME
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling epan init, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
+#endif
     /* Register all dissectors; we must do this before checking for the
        "-G" flag, as the "-G" flag dumps information registered by the
        dissectors, and we must do it before we read the preferences, in
@@ -562,11 +616,30 @@ int main(int argc, char *argv[])
     if (!epan_init(register_all_protocols,register_all_protocol_handoffs,
                    splash_update, NULL)) {
         SimpleDialog::displayQueuedMessages(main_w);
-        return 2;
+        ret_val = INIT_FAILED;
+        goto clean_exit;
     }
+#ifdef DEBUG_STARTUP_TIME
+    /* epan_init resets the preferences */
+    prefs.console_log_level = DEBUG_STARTUP_TIME_LOGLEVEL;
+    prefs.gui_console_open = console_open_always;
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "epan done, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
+#endif
 
-    splash_update(RA_LISTENERS, NULL, NULL);
+    // Read the dynamic part of the recent file. This determines whether or
+    // not the recent list appears in the main window so the earlier we can
+    // call this the better.
+    if (!recent_read_dynamic(&rf_path, &rf_open_errno)) {
+        simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
+                      "Could not open recent file\n\"%s\": %s.",
+                      rf_path, g_strerror(rf_open_errno));
+        g_free(rf_path);
+    }
 
+    splash_update(RA_LISTENERS, NULL, NULL);
+#ifdef DEBUG_STARTUP_TIME
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Register all tap listeners, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
+#endif
     /* Register all tap listeners; we do this before we parse the arguments,
        as the "-z" argument can specify a registered tap. */
 
@@ -577,10 +650,6 @@ int main(int argc, char *argv[])
     register_all_plugin_tap_listeners();
 #endif
 
-#ifdef HAVE_EXTCAP
-    extcap_register_preferences();
-#endif
-
     register_all_tap_listeners();
     conversation_table_set_gui_info(init_conversation_table);
     hostlist_table_set_gui_info(init_endpoint_table);
@@ -592,45 +661,57 @@ int main(int argc, char *argv[])
         in_file_type = open_info_name_to_type(ex_opt_get_next("read_format"));
     }
 
+#ifdef HAVE_EXTCAP
+#ifdef DEBUG_STARTUP_TIME
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling extcap_register_preferences, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
+#endif
+    splash_update(RA_EXTCAP, NULL, NULL);
+    extcap_register_preferences();
+#endif
     splash_update(RA_PREFERENCES, NULL, NULL);
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling module preferences, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
 
-    commandline_info.prefs_p = ws_app.readConfigurationFiles(&gdp_path, &dp_path, false);
+    global_commandline_info.prefs_p = ws_app.readConfigurationFiles(false);
 
     /* Now get our args */
-    commandline_other_options(argc, argv, &commandline_info, TRUE);
+    commandline_other_options(argc, argv, TRUE);
 
     /* Convert some command-line parameters to QStrings */
-    if (commandline_info.cf_name != NULL)
-        cf_name = QString(commandline_info.cf_name);
-    if (commandline_info.rfilter != NULL)
-        read_filter = QString(commandline_info.rfilter);
-    if (commandline_info.dfilter != NULL)
-        dfilter = QString(commandline_info.dfilter);
+    if (global_commandline_info.cf_name != NULL)
+        cf_name = QString(global_commandline_info.cf_name);
+    if (global_commandline_info.rfilter != NULL)
+        read_filter = QString(global_commandline_info.rfilter);
+    if (global_commandline_info.dfilter != NULL)
+        dfilter = QString(global_commandline_info.dfilter);
 
     /* Removed thread code:
      * https://code.wireshark.org/review/gitweb?p=wireshark.git;a=commit;h=9e277ae6154fd04bf6a0a34ec5655a73e5a736a3
      */
 
-    // XXX Is there a better place to set the timestamp format & precision?
     timestamp_set_type(recent.gui_time_format);
     timestamp_set_precision(recent.gui_time_precision);
     timestamp_set_seconds_type (recent.gui_seconds_format);
 
 #ifdef HAVE_LIBPCAP
+#ifdef DEBUG_STARTUP_TIME
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling fill_in_local_interfaces, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
+#endif
+    splash_update(RA_INTERFACES, NULL, NULL);
+
     fill_in_local_interfaces(main_window_update);
 
-    if (commandline_info.start_capture || commandline_info.list_link_layer_types) {
+    if (global_commandline_info.start_capture || global_commandline_info.list_link_layer_types) {
         /* We're supposed to do a live capture or get a list of link-layer
            types for a live capture device; if the user didn't specify an
            interface to use, pick a default. */
-        status = capture_opts_default_iface_if_necessary(&global_capture_opts,
-        ((commandline_info.prefs_p->capture_device) && (*commandline_info.prefs_p->capture_device != '\0')) ? get_if_name(commandline_info.prefs_p->capture_device) : NULL);
-        if (status != 0) {
-            exit(status);
+        ret_val = capture_opts_default_iface_if_necessary(&global_capture_opts,
+        ((global_commandline_info.prefs_p->capture_device) && (*global_commandline_info.prefs_p->capture_device != '\0')) ? get_if_name(global_commandline_info.prefs_p->capture_device) : NULL);
+        if (ret_val != 0) {
+            goto clean_exit;
         }
     }
 
-    if (commandline_info.list_link_layer_types) {
+    if (global_commandline_info.list_link_layer_types) {
         /* Get the list of link-layer types for the capture devices. */
         if_capabilities_t *caps;
         guint i;
@@ -647,11 +728,13 @@ int main(int argc, char *argv[])
                 if (caps == NULL) {
                     cmdarg_err("%s", err_str);
                     g_free(err_str);
-                    exit(2);
+                    ret_val = INVALID_CAPABILITY;
+                    goto clean_exit;
                 }
             if (caps->data_link_types == NULL) {
                 cmdarg_err("The capture device \"%s\" has no data link types.", device.name);
-                exit(2);
+                ret_val = INVALID_LINK_TYPE;
+                goto clean_exit;
             }
 #ifdef _WIN32
             create_console();
@@ -667,16 +750,21 @@ int main(int argc, char *argv[])
             free_if_capabilities(caps);
             }
         }
-        exit(0);
+        ret_val = EXIT_SUCCESS;
+        goto clean_exit;
     }
 
     capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
     capture_opts_trim_ring_num_files(&global_capture_opts);
 #endif /* HAVE_LIBPCAP */
 
+
     /* Notify all registered modules that have had any of their preferences
        changed either from one of the preferences file or from the command
        line that their preferences have changed. */
+#ifdef DEBUG_STARTUP_TIME
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling prefs_apply_all, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
+#endif
     prefs_apply_all();
     wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
 
@@ -698,39 +786,18 @@ int main(int argc, char *argv[])
     }
 #endif
 
-    /* disabled protocols as per configuration file */
-    if (gdp_path == NULL && dp_path == NULL) {
-        set_disabled_protos_list();
-        set_disabled_heur_dissector_list();
-    }
-
-    if(commandline_info.disable_protocol_slist) {
-        GSList *proto_disable;
-        for (proto_disable = commandline_info.disable_protocol_slist; proto_disable != NULL; proto_disable = g_slist_next(proto_disable))
-        {
-            proto_disable_proto_by_name((char*)proto_disable->data);
-        }
-    }
-
-    if(commandline_info.enable_heur_slist) {
-        GSList *heur_enable;
-        for (heur_enable = commandline_info.enable_heur_slist; heur_enable != NULL; heur_enable = g_slist_next(heur_enable))
-        {
-            proto_enable_heuristic_by_name((char*)heur_enable->data, TRUE);
-        }
-    }
-
-    if(commandline_info.disable_heur_slist) {
-        GSList *heur_disable;
-        for (heur_disable = commandline_info.disable_heur_slist; heur_disable != NULL; heur_disable = g_slist_next(heur_disable))
-        {
-            proto_enable_heuristic_by_name((char*)heur_disable->data, FALSE);
-        }
+    /*
+     * Enabled and disabled protocols and heuristic dissectors as per
+     * command-line options.
+     */
+    if (!setup_enabled_and_disabled_protocols()) {
+        ret_val = INVALID_OPTION;
+        goto clean_exit;
     }
 
-    build_column_format_array(&CaptureFile::globalCapFile()->cinfo, commandline_info.prefs_p->num_cols, TRUE);
+    build_column_format_array(&CaptureFile::globalCapFile()->cinfo, global_commandline_info.prefs_p->num_cols, TRUE);
     wsApp->emitAppSignal(WiresharkApplication::ColumnsChanged); // We read "recent" widths above.
-    wsApp->emitAppSignal(WiresharkApplication::RecentFilesRead); // Must be emitted after PreferencesChanged.
+    wsApp->emitAppSignal(WiresharkApplication::RecentPreferencesRead); // Must be emitted after PreferencesChanged.
 
     wsApp->setMonospaceFont(prefs.gui_qt_font_name);
 
@@ -738,15 +805,6 @@ int main(int argc, char *argv[])
     main_w->setWSWindowTitle();
 ////////
 
-    /* Read the dynamic part of the recent file, as we have the gui now ready for
-       it. */
-    if (!recent_read_dynamic(&rf_path, &rf_open_errno)) {
-        simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
-                      "Could not open recent file\n\"%s\": %s.",
-                      rf_path, g_strerror(rf_open_errno));
-        g_free(rf_path);
-    }
-
     packet_list_enable_color(recent.packet_list_colorize);
 
     g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: fetch recent color settings");
@@ -756,7 +814,6 @@ int main(int argc, char *argv[])
 
 
 ////////
-    gchar* err_msg = NULL;
     if (!color_filters_init(&err_msg, color_filter_add_cb)) {
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
         g_free(err_msg);
@@ -766,7 +823,7 @@ int main(int argc, char *argv[])
 
 #ifdef HAVE_LIBPCAP
     /* if the user didn't supply a capture filter, use the one to filter out remote connections like SSH */
-    if (!commandline_info.start_capture && !global_capture_opts.default_options.cfilter) {
+    if (!global_commandline_info.start_capture && !global_capture_opts.default_options.cfilter) {
         global_capture_opts.default_options.cfilter = g_strdup(get_conn_cfilter());
     }
 #else /* HAVE_LIBPCAP */
@@ -774,7 +831,7 @@ int main(int argc, char *argv[])
 #endif /* HAVE_LIBPCAP */
 
     wsApp->allSystemsGo();
-    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go");
+    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go, elapsed time %" G_GUINT64_FORMAT "us \n", g_get_monotonic_time() - start_time);
     SimpleDialog::displayQueuedMessages(main_w);
 
     /* User could specify filename, or display filter, or both */
@@ -792,32 +849,32 @@ int main(int argc, char *argv[])
                filter. */
             start_requested_stats();
 
-            if(commandline_info.go_to_packet != 0) {
+            if(global_commandline_info.go_to_packet != 0) {
                 /* Jump to the specified frame number, kept for backward
                    compatibility. */
-                cf_goto_frame(CaptureFile::globalCapFile(), commandline_info.go_to_packet);
-            } else if (commandline_info.jfilter != NULL) {
+                cf_goto_frame(CaptureFile::globalCapFile(), global_commandline_info.go_to_packet);
+            } else if (global_commandline_info.jfilter != NULL) {
                 dfilter_t *jump_to_filter = NULL;
                 /* try to compile given filter */
-                if (!dfilter_compile(commandline_info.jfilter, &jump_to_filter, &err_msg)) {
+                if (!dfilter_compile(global_commandline_info.jfilter, &jump_to_filter, &err_msg)) {
                     // Similar code in MainWindow::mergeCaptureFile().
                     QMessageBox::warning(main_w, QObject::tr("Invalid Display Filter"),
                                          QObject::tr("The filter expression %1 isn't a valid display filter. (%2).")
-                                                 .arg(commandline_info.jfilter, err_msg),
+                                                 .arg(global_commandline_info.jfilter, err_msg),
                                          QMessageBox::Ok);
                     g_free(err_msg);
                 } else {
                     /* Filter ok, jump to the first packet matching the filter
                        conditions. Default search direction is forward, but if
                        option d was given, search backwards */
-                    cf_find_packet_dfilter(CaptureFile::globalCapFile(), jump_to_filter, commandline_info.jump_backwards);
+                    cf_find_packet_dfilter(CaptureFile::globalCapFile(), jump_to_filter, global_commandline_info.jump_backwards);
                 }
             }
         }
     }
 #ifdef HAVE_LIBPCAP
     else {
-        if (commandline_info.start_capture) {
+        if (global_commandline_info.start_capture) {
             if (global_capture_opts.save_file != NULL) {
                 /* Save the directory name for future file dialogs. */
                 /* (get_dirname overwrites filename) */
@@ -846,18 +903,27 @@ int main(int argc, char *argv[])
             }
         }
     /* if the user didn't supply a capture filter, use the one to filter out remote connections like SSH */
-        if (!commandline_info.start_capture && !global_capture_opts.default_options.cfilter) {
+        if (!global_commandline_info.start_capture && !global_capture_opts.default_options.cfilter) {
             global_capture_opts.default_options.cfilter = g_strdup(get_conn_cfilter());
         }
     }
 #endif /* HAVE_LIBPCAP */
 
+    // UAT files used in configuration profiles which are used in Qt dialogs
+    // are not registered during startup because they only get loaded when
+    // the dialog is shown.  Register them here.
+    g_free(get_persconffile_path("io_graphs", TRUE));
+
     profile_store_persconffiles(FALSE);
 
     ret_val = wsApp->exec();
 
     epan_cleanup();
 
+#ifdef HAVE_EXTCAP
+    extcap_cleanup();
+#endif
+
     AirPDcapDestroyContext(&airpdcap_ctx);
 
 #ifdef _WIN32
@@ -870,6 +936,16 @@ int main(int argc, char *argv[])
     destroy_console();
 #endif /* _WIN32 */
 
+clean_exit:
+#ifdef HAVE_LIBPCAP
+    capture_opts_cleanup(&global_capture_opts);
+#endif
+    col_cleanup(&CaptureFile::globalCapFile()->cinfo);
+    wtap_cleanup();
+    free_progdirs();
+#ifdef HAVE_PLUGINS
+    plugins_cleanup();
+#endif
     return ret_val;
 }