gQUIC: it is possible to have multiple COPT Tag
[metze/wireshark/wip.git] / wireshark-qt.cpp
1 /* wireshark-qt.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9
10 #include <config.h>
11
12 #include <glib.h>
13
14 #include <locale.h>
15
16 #ifdef HAVE_GETOPT_H
17 #include <getopt.h>
18 #endif
19
20 #ifndef HAVE_GETOPT_LONG
21 #include "wsutil/wsgetopt.h"
22 #endif
23
24 #include <wsutil/clopts_common.h>
25 #include <wsutil/cmdarg_err.h>
26 #include <wsutil/crash_info.h>
27 #include <wsutil/filesystem.h>
28 #include <wsutil/privileges.h>
29 #ifdef HAVE_PLUGINS
30 #include <wsutil/plugins.h>
31 #endif
32 #include <wsutil/report_message.h>
33 #include <wsutil/unicode-utils.h>
34 #include <version_info.h>
35
36 #include <epan/addr_resolv.h>
37 #include <epan/ex-opt.h>
38 #include <epan/tap.h>
39 #include <epan/stat_tap_ui.h>
40 #include <epan/column.h>
41 #include <epan/disabled_protos.h>
42 #include <epan/prefs.h>
43
44 #ifdef HAVE_KERBEROS
45 #include <epan/packet.h>
46 #include <epan/asn1.h>
47 #include <epan/dissectors/packet-kerberos.h>
48 #endif
49
50 #include <codecs/codecs.h>
51
52 #include <extcap.h>
53
54 /* general (not Qt specific) */
55 #include "file.h"
56 #include "epan/color_filters.h"
57 #include "log.h"
58
59 #include "epan/rtd_table.h"
60 #include "epan/srt_table.h"
61
62 #include "ui/alert_box.h"
63 #include "ui/console.h"
64 #include "ui/iface_lists.h"
65 #include "ui/language.h"
66 #include "ui/persfilepath_opt.h"
67 #include "ui/recent.h"
68 #include "ui/simple_dialog.h"
69 #include "ui/util.h"
70 #include "ui/dissect_opts.h"
71 #include "ui/commandline.h"
72 #include "ui/capture_ui_utils.h"
73 #include "ui/preference_utils.h"
74 #include "ui/taps.h"
75
76 #include "ui/qt/conversation_dialog.h"
77 #include "ui/qt/utils/color_utils.h"
78 #include "ui/qt/coloring_rules_dialog.h"
79 #include "ui/qt/endpoint_dialog.h"
80 #include "ui/qt/main_window.h"
81 #include "ui/qt/response_time_delay_dialog.h"
82 #include "ui/qt/service_response_time_dialog.h"
83 #include "ui/qt/simple_dialog.h"
84 #include "ui/qt/simple_statistics_dialog.h"
85 #include "ui/qt/splash_overlay.h"
86 #include "ui/qt/wireshark_application.h"
87
88 #include "caputils/capture-pcap-util.h"
89
90 #include <QMessageBox>
91
92 #ifdef _WIN32
93 #  include "caputils/capture-wpcap.h"
94 #  include "caputils/capture_wpcap_packet.h"
95 #  include <tchar.h> /* Needed for Unicode */
96 #  include <wsutil/file_util.h>
97 #  include <wsutil/os_version_info.h>
98 #endif /* _WIN32 */
99
100 #ifdef HAVE_AIRPCAP
101 #  include <caputils/airpcap.h>
102 #  include <caputils/airpcap_loader.h>
103 //#  include "airpcap_dlg.h"
104 //#  include "airpcap_gui_utils.h"
105 #endif
106
107 #include "epan/crypt/dot11decrypt_ws.h"
108
109 /* Handle the addition of View menu items without request */
110 #if defined(Q_OS_MAC)
111 #include <ui/macosx/cocoa_bridge.h>
112 #endif
113
114 #include <ui/qt/utils/qt_ui_utils.h>
115
116 #define INVALID_OPTION 1
117 #define INIT_FAILED 2
118 #define INVALID_CAPABILITY 2
119 #define INVALID_LINK_TYPE 2
120
121 //#define DEBUG_STARTUP_TIME 1
122 /*
123 # Log level
124 # Console log level (for debugging)
125 # A bitmask of log levels:
126 # ERROR    = 4
127 # CRITICAL = 8
128 # WARNING  = 16
129 # MESSAGE  = 32
130 # INFO     = 64
131 # DEBUG    = 128
132
133 */
134 #define DEBUG_STARTUP_TIME_LOGLEVEL 252
135
136 /* update the main window */
137 void main_window_update(void)
138 {
139     WiresharkApplication::processEvents();
140 }
141
142 #ifdef HAVE_LIBPCAP
143
144 /* quit the main window */
145 void main_window_quit(void)
146 {
147     wsApp->quit();
148 }
149
150 #endif /* HAVE_LIBPCAP */
151
152 void exit_application(int status) {
153     if (wsApp) {
154         wsApp->quit();
155     }
156     exit(status);
157 }
158
159 /*
160  * Report an error in command-line arguments.
161  * Creates a console on Windows.
162  */
163 // xxx copied from ../gtk/main.c
164 static void
165 wireshark_cmdarg_err(const char *fmt, va_list ap)
166 {
167 #ifdef _WIN32
168     create_console();
169 #endif
170     fprintf(stderr, "wireshark: ");
171     vfprintf(stderr, fmt, ap);
172     fprintf(stderr, "\n");
173 }
174
175 /*
176  * Report additional information for an error in command-line arguments.
177  * Creates a console on Windows.
178  * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
179  * terminal isn't the standard error?
180  */
181 // xxx copied from ../gtk/main.c
182 static void
183 wireshark_cmdarg_err_cont(const char *fmt, va_list ap)
184 {
185 #ifdef _WIN32
186     create_console();
187 #endif
188     vfprintf(stderr, fmt, ap);
189     fprintf(stderr, "\n");
190 }
191
192 // xxx based from ../gtk/main.c:get_gtk_compiled_info
193 void
194 get_wireshark_qt_compiled_info(GString *str)
195 {
196     g_string_append(str, "with ");
197     g_string_append_printf(str,
198 #ifdef QT_VERSION
199                     "Qt %s", QT_VERSION_STR);
200 #else
201                     "Qt (version unknown)");
202 #endif
203
204     /* Capture libraries */
205     g_string_append(str, ", ");
206     get_compiled_caplibs_version(str);
207 }
208
209 // xxx copied from ../gtk/main.c
210 void
211 get_gui_compiled_info(GString *str)
212 {
213     epan_get_compiled_version_info(str);
214
215     g_string_append(str, ", ");
216 #ifdef QT_MULTIMEDIA_LIB
217     g_string_append(str, "with QtMultimedia");
218 #else
219     g_string_append(str, "without QtMultimedia");
220 #endif
221
222 #ifdef _WIN32
223     g_string_append(str, ", ");
224 #ifdef HAVE_AIRPCAP
225     get_compiled_airpcap_version(str);
226 #else
227     g_string_append(str, "without AirPcap");
228 #endif
229 #endif /* _WIN32 */
230
231     codec_get_compiled_version_info(str);
232 }
233
234 // xxx copied from ../gtk/main.c
235 void
236 get_wireshark_runtime_info(GString *str)
237 {
238 #ifdef HAVE_LIBPCAP
239     /* Capture libraries */
240     g_string_append(str, ", ");
241     get_runtime_caplibs_version(str);
242 #endif
243
244     /* stuff used by libwireshark */
245     epan_get_runtime_version_info(str);
246
247 #ifdef HAVE_AIRPCAP
248     g_string_append(str, ", ");
249     get_runtime_airpcap_version(str);
250 #endif
251 }
252
253 static void
254 g_log_message_handler(QtMsgType type, const QMessageLogContext &, const QString &msg)
255 {
256     GLogLevelFlags log_level = G_LOG_LEVEL_DEBUG;
257
258     switch (type) {
259     case QtDebugMsg:
260     default:
261         break;
262 #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
263     case QtInfoMsg:
264         log_level = G_LOG_LEVEL_INFO;
265         break;
266 #endif
267     case QtWarningMsg:
268         log_level = G_LOG_LEVEL_WARNING;
269         break;
270     case QtCriticalMsg:
271         log_level = G_LOG_LEVEL_CRITICAL;
272         break;
273     case QtFatalMsg:
274         log_level = G_LOG_FLAG_FATAL;
275         break;
276     }
277     g_log(LOG_DOMAIN_MAIN, log_level, "%s", qUtf8Printable(msg));
278 }
279
280 #ifdef HAVE_LIBPCAP
281 /*  Check if there's something important to tell the user during startup.
282  *  We want to do this *after* showing the main window so that any windows
283  *  we pop up will be above the main window.
284  */
285 static void
286 check_and_warn_user_startup(const QString &cf_name)
287 {
288 #ifndef _WIN32
289     Q_UNUSED(cf_name)
290 #endif
291     gchar               *cur_user, *cur_group;
292
293     /* Tell the user not to run as root. */
294     if (running_with_special_privs() && recent.privs_warn_if_elevated) {
295         cur_user = get_cur_username();
296         cur_group = get_cur_groupname();
297         simple_message_box(ESD_TYPE_WARN, &recent.privs_warn_if_elevated,
298         "Running as user \"%s\" and group \"%s\".\n"
299         "This could be dangerous.\n\n"
300         "If you're running Wireshark this way in order to perform live capture, "
301         "you may want to be aware that there is a better way documented at\n"
302         "https://wiki.wireshark.org/CaptureSetup/CapturePrivileges", cur_user, cur_group);
303         g_free(cur_user);
304         g_free(cur_group);
305     }
306
307 #ifdef _WIN32
308     /* Warn the user if npf.sys isn't loaded. */
309     if (!get_stdin_capture() && cf_name.isEmpty() && !npf_sys_is_running() && recent.privs_warn_if_no_npf && get_windows_major_version() >= 6) {
310         simple_message_box(ESD_TYPE_WARN, &recent.privs_warn_if_no_npf, "%s",
311         "The NPF driver isn't running. You may have trouble\n"
312         "capturing or listing interfaces.");
313     }
314 #endif
315
316 }
317 #endif
318
319 #ifdef _WIN32
320 // Try to avoid library search path collisions. QCoreApplication will
321 // search QT_INSTALL_PREFIX/plugins for platform DLLs before searching
322 // the application directory. If
323 //
324 // - You have Qt version 5.x.y installed in the default location
325 //   (C:\Qt\5.x) on your machine.
326 //
327 // and
328 //
329 // - You install Wireshark that was built on a machine with Qt version
330 //   5.x.z installed in the default location.
331 //
332 // Qt5Core.dll will load qwindows.dll from your local C:\Qt\5.x\...\plugins
333 // directory. This may not be compatible with qwindows.dll from that
334 // same path on the build machine. At any rate, loading DLLs from paths
335 // you don't control is ill-advised. We work around this by removing every
336 // path except our application directory.
337
338 static inline void
339 reset_library_path(void)
340 {
341     QString app_path = QDir(get_progfile_dir()).path();
342     foreach (QString path, QCoreApplication::libraryPaths()) {
343         QCoreApplication::removeLibraryPath(path);
344     }
345     QCoreApplication::addLibraryPath(app_path);
346 }
347 #endif
348
349 /* And now our feature presentation... [ fade to music ] */
350 int main(int argc, char *qt_argv[])
351 {
352     MainWindow *main_w;
353
354 #ifdef _WIN32
355     int                  opt;
356 #endif
357     int                  ret_val = EXIT_SUCCESS;
358     char               **argv = qt_argv;
359
360 #ifdef _WIN32
361     int                  result;
362     WSADATA              wsaData;
363 #endif  /* _WIN32 */
364
365     char                *rf_path;
366     int                  rf_open_errno;
367 #ifdef HAVE_LIBPCAP
368     gchar               *err_str;
369 #else
370 #ifdef _WIN32
371 #ifdef HAVE_AIRPCAP
372     gchar               *err_str;
373 #endif
374 #endif
375 #endif
376     gchar               *err_msg = NULL;
377     GString             *comp_info_str = NULL;
378     GString             *runtime_info_str = NULL;
379
380     QString              dfilter, read_filter;
381 #ifdef HAVE_LIBPCAP
382     int                  caps_queries = 0;
383 #endif
384     /* Start time in microseconds */
385     guint64 start_time = g_get_monotonic_time();
386 #ifdef DEBUG_STARTUP_TIME
387     /* At least on Windows there is a problem with the logging as the preferences is taken
388      * into account and the preferences are loaded pretty late in the startup process.
389      */
390     prefs.console_log_level = DEBUG_STARTUP_TIME_LOGLEVEL;
391     prefs.gui_console_open = console_open_always;
392 #endif /* DEBUG_STARTUP_TIME */
393     cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont);
394
395 #if defined(Q_OS_MAC)
396     /* Disable automatic addition of tab menu entries in view menu */
397     CocoaBridge::cleanOSGeneratedMenuItems();
398 #endif
399
400     /* Set the C-language locale to the native environment. */
401     setlocale(LC_ALL, "");
402
403 #ifdef _WIN32
404     // QCoreApplication clobbers argv. Let's have a local copy.
405     argv = (char **) g_malloc(sizeof(char *) * argc);
406     for (opt = 0; opt < argc; opt++) {
407         argv[opt] = qt_argv[opt];
408     }
409     arg_list_utf_16to8(argc, argv);
410     create_app_running_mutex();
411 #endif /* _WIN32 */
412
413     /*
414      * Get credential information for later use, and drop privileges
415      * before doing anything else.
416      * Let the user know if anything happened.
417      */
418     init_process_policies();
419     relinquish_special_privs_perm();
420
421     /*
422      * Attempt to get the pathname of the directory containing the
423      * executable file.
424      */
425     /* init_progfile_dir_error = */ init_progfile_dir(argv[0]);
426     g_log(NULL, G_LOG_LEVEL_DEBUG, "progfile_dir: %s", get_progfile_dir());
427
428 #ifdef _WIN32
429     ws_init_dll_search_path();
430     /* Load wpcap if possible. Do this before collecting the run-time version information */
431     load_wpcap();
432
433     /* ... and also load the packet.dll from wpcap */
434     wpcap_packet_load();
435
436 #ifdef HAVE_AIRPCAP
437     /* Load the airpcap.dll.  This must also be done before collecting
438      * run-time version information. */
439     load_airpcap();
440 #if 0
441     airpcap_dll_ret_val = load_airpcap();
442
443     switch (airpcap_dll_ret_val) {
444     case AIRPCAP_DLL_OK:
445         /* load the airpcap interfaces */
446         g_airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
447
448         if (g_airpcap_if_list == NULL || g_list_length(g_airpcap_if_list) == 0){
449             if (err == CANT_GET_AIRPCAP_INTERFACE_LIST && err_str != NULL) {
450                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", "Failed to open Airpcap Adapters.");
451                 g_free(err_str);
452             }
453             airpcap_if_active = NULL;
454
455         } else {
456
457             /* select the first ad default (THIS SHOULD BE CHANGED) */
458             airpcap_if_active = airpcap_get_default_if(airpcap_if_list);
459         }
460         break;
461     /*
462      * XXX - Maybe we need to warn the user if one of the following happens???
463      */
464     case AIRPCAP_DLL_OLD:
465         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_OLD\n");
466         break;
467
468     case AIRPCAP_DLL_ERROR:
469         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_ERROR\n");
470         break;
471
472     case AIRPCAP_DLL_NOT_FOUND:
473         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DDL_NOT_FOUND\n");
474         break;
475     }
476 #endif
477 #endif /* HAVE_AIRPCAP */
478 #endif /* _WIN32 */
479
480     /* Get the compile-time version information string */
481     comp_info_str = get_compiled_version_info(get_wireshark_qt_compiled_info,
482                                               get_gui_compiled_info);
483
484     /* Assemble the run-time version information string */
485     runtime_info_str = get_runtime_version_info(get_wireshark_runtime_info);
486
487     /* Create the user profiles directory */
488     if (create_profiles_dir(&rf_path) == -1) {
489         simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
490                       "Could not create profiles directory\n\"%s\"",
491                       rf_path);
492         g_free (rf_path);
493     }
494
495     profile_store_persconffiles(TRUE);
496     recent_init();
497
498     /* Read the profile independent recent file.  We have to do this here so we can */
499     /* set the profile before it can be set from the command line parameter */
500     if (!recent_read_static(&rf_path, &rf_open_errno)) {
501         simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
502                       "Could not open common recent file\n\"%s\": %s.",
503                       rf_path, strerror(rf_open_errno));
504         g_free(rf_path);
505     }
506
507     commandline_early_options(argc, argv, comp_info_str, runtime_info_str);
508
509 #ifdef _WIN32
510     reset_library_path();
511 #endif
512
513     // Handle DPI scaling on Windows. This causes problems in at least
514     // one case on X11 and we don't yet support Android.
515     // We do the equivalent on macOS by setting NSHighResolutionCapable
516     // in Info.plist.
517     // Note that this enables Windows 8.1-style Per-monitor DPI
518     // awareness but not Windows 10-style Per-monitor v2 awareness.
519     // http://doc.qt.io/qt-5/scalability.html
520     // http://doc.qt.io/qt-5/highdpi.html
521     // https://bugreports.qt.io/browse/QTBUG-53022 - The device pixel ratio is pretty much bogus on Windows.
522     // https://bugreports.qt.io/browse/QTBUG-55510 - Windows have wrong size
523 #if defined(Q_OS_WIN) && QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
524     QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
525 #endif
526
527     /* Create The Wireshark app */
528     WiresharkApplication ws_app(argc, qt_argv);
529
530     /* initialize the funnel mini-api */
531     // xxx qtshark
532     //initialize_funnel_ops();
533
534     Dot11DecryptInitContext(&dot11decrypt_ctx);
535
536     QString cf_name;
537     unsigned int in_file_type = WTAP_TYPE_AUTO;
538
539     /* Add it to the information to be reported on a crash. */
540     ws_add_crash_info("Wireshark %s\n"
541            "\n"
542            "%s"
543            "\n"
544            "%s",
545         get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
546     g_string_free(comp_info_str, TRUE);
547     g_string_free(runtime_info_str, TRUE);
548
549 #ifdef _WIN32
550     /* Start windows sockets */
551     result = WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
552     if (result != 0)
553     {
554         ret_val = INIT_FAILED;
555         goto clean_exit;
556     }
557 #endif  /* _WIN32 */
558
559     /* Read the profile dependent (static part) of the recent file. */
560     /* Only the static part of it will be read, as we don't have the gui now to fill the */
561     /* recent lists which is done in the dynamic part. */
562     /* We have to do this already here, so command line parameters can overwrite these values. */
563     if (!recent_read_profile_static(&rf_path, &rf_open_errno)) {
564         simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
565                       "Could not open recent file\n\"%s\": %s.",
566                       rf_path, g_strerror(rf_open_errno));
567         g_free(rf_path);
568     }
569     wsApp->applyCustomColorsFromRecent();
570
571     // Initialize our language
572     read_language_prefs();
573     wsApp->loadLanguage(language);
574
575     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Translator %s", language);
576
577     // Init the main window (and splash)
578     main_w = new(MainWindow);
579     main_w->show();
580     // We may not need a queued connection here but it would seem to make sense
581     // to force the issue.
582     main_w->connect(&ws_app, SIGNAL(openCaptureFile(QString,QString,unsigned int)),
583             main_w, SLOT(openCaptureFile(QString,QString,unsigned int)));
584     main_w->connect(&ws_app, SIGNAL(openCaptureOptions()),
585             main_w, SLOT(on_actionCaptureOptions_triggered()));
586
587     /* Init the "Open file" dialog directory */
588     /* (do this after the path settings are processed) */
589     if (recent.gui_fileopen_remembered_dir &&
590         test_for_directory(recent.gui_fileopen_remembered_dir) == EISDIR) {
591       wsApp->setLastOpenDir(recent.gui_fileopen_remembered_dir);
592     } else {
593       wsApp->setLastOpenDir(get_persdatafile_dir());
594     }
595
596     set_console_log_handler();
597     qInstallMessageHandler(g_log_message_handler);
598 #ifdef DEBUG_STARTUP_TIME
599     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);
600 #endif
601
602 #ifdef HAVE_LIBPCAP
603     /* Set the initial values in the capture options. This might be overwritten
604        by preference settings and then again by the command line parameters. */
605     capture_opts_init(&global_capture_opts);
606 #endif
607
608     init_report_message(vfailure_alert_box, vwarning_alert_box,
609                         open_failure_alert_box, read_failure_alert_box,
610                         write_failure_alert_box);
611
612     wtap_init(TRUE);
613
614     splash_update(RA_DISSECTORS, NULL, NULL);
615 #ifdef DEBUG_STARTUP_TIME
616     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);
617 #endif
618     /* Register all dissectors; we must do this before checking for the
619        "-G" flag, as the "-G" flag dumps information registered by the
620        dissectors, and we must do it before we read the preferences, in
621        case any dissectors register preferences. */
622     if (!epan_init(register_all_protocols,register_all_protocol_handoffs,
623                    splash_update, NULL)) {
624         SimpleDialog::displayQueuedMessages(main_w);
625         ret_val = INIT_FAILED;
626         goto clean_exit;
627     }
628 #ifdef DEBUG_STARTUP_TIME
629     /* epan_init resets the preferences */
630     prefs.console_log_level = DEBUG_STARTUP_TIME_LOGLEVEL;
631     prefs.gui_console_open = console_open_always;
632     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "epan done, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
633 #endif
634
635     /* Register all audio codecs. */
636     codecs_init();
637
638     // Read the dynamic part of the recent file. This determines whether or
639     // not the recent list appears in the main window so the earlier we can
640     // call this the better.
641     if (!recent_read_dynamic(&rf_path, &rf_open_errno)) {
642         simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
643                       "Could not open recent file\n\"%s\": %s.",
644                       rf_path, g_strerror(rf_open_errno));
645         g_free(rf_path);
646     }
647     wsApp->refreshRecentCaptures();
648
649     splash_update(RA_LISTENERS, NULL, NULL);
650 #ifdef DEBUG_STARTUP_TIME
651     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);
652 #endif
653     /* Register all tap listeners; we do this before we parse the arguments,
654        as the "-z" argument can specify a registered tap. */
655
656     /* we register the plugin taps before the other taps because
657             stats_tree taps plugins will be registered as tap listeners
658             by stats_tree_stat.c and need to registered before that */
659 #ifdef HAVE_PLUGINS
660     register_all_plugin_tap_listeners();
661 #endif
662
663     /* Register all tap listeners. */
664     for (tap_reg_t *t = tap_reg_listener; t->cb_func != NULL; t++) {
665         t->cb_func();
666     }
667     conversation_table_set_gui_info(init_conversation_table);
668     hostlist_table_set_gui_info(init_endpoint_table);
669     srt_table_iterate_tables(register_service_response_tables, NULL);
670     rtd_table_iterate_tables(register_response_time_delay_tables, NULL);
671     stat_tap_iterate_tables(register_simple_stat_tables, NULL);
672
673     if (ex_opt_count("read_format") > 0) {
674         in_file_type = open_info_name_to_type(ex_opt_get_next("read_format"));
675     }
676
677 #ifdef DEBUG_STARTUP_TIME
678     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);
679 #endif
680     splash_update(RA_EXTCAP, NULL, NULL);
681     extcap_register_preferences();
682     splash_update(RA_PREFERENCES, NULL, NULL);
683 #ifdef DEBUG_STARTUP_TIME
684     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);
685 #endif
686
687     global_commandline_info.prefs_p = ws_app.readConfigurationFiles(false);
688
689     /* Now get our args */
690     commandline_other_options(argc, argv, TRUE);
691
692     /* Convert some command-line parameters to QStrings */
693     if (global_commandline_info.cf_name != NULL)
694         cf_name = QString(global_commandline_info.cf_name);
695     if (global_commandline_info.rfilter != NULL)
696         read_filter = QString(global_commandline_info.rfilter);
697     if (global_commandline_info.dfilter != NULL)
698         dfilter = QString(global_commandline_info.dfilter);
699
700     timestamp_set_type(recent.gui_time_format);
701     timestamp_set_precision(recent.gui_time_precision);
702     timestamp_set_seconds_type (recent.gui_seconds_format);
703
704 #ifdef HAVE_LIBPCAP
705 #ifdef DEBUG_STARTUP_TIME
706     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);
707 #endif
708     splash_update(RA_INTERFACES, NULL, NULL);
709
710     fill_in_local_interfaces(main_window_update);
711
712     if  (global_commandline_info.list_link_layer_types)
713         caps_queries |= CAPS_QUERY_LINK_TYPES;
714      if (global_commandline_info.list_timestamp_types)
715         caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES;
716
717     if (global_commandline_info.start_capture || caps_queries) {
718         /* We're supposed to do a live capture or get a list of link-layer/timestamp
719            types for a live capture device; if the user didn't specify an
720            interface to use, pick a default. */
721         ret_val = capture_opts_default_iface_if_necessary(&global_capture_opts,
722         ((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);
723         if (ret_val != 0) {
724             goto clean_exit;
725         }
726     }
727
728     if (caps_queries) {
729         /* Get the list of link-layer types for the capture devices. */
730         if_capabilities_t *caps;
731         guint i;
732         interface_t *device;
733         for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
734             int if_caps_queries = caps_queries;
735             device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
736             if (device->selected) {
737 #if defined(HAVE_PCAP_CREATE)
738                 caps = capture_get_if_capabilities(device->name, device->monitor_mode_supported, NULL, &err_str, main_window_update);
739 #else
740                 caps = capture_get_if_capabilities(device->name, FALSE, NULL, &err_str,main_window_update);
741 #endif
742                 if (caps == NULL) {
743                     cmdarg_err("%s", err_str);
744                     g_free(err_str);
745                     ret_val = INVALID_CAPABILITY;
746                     goto clean_exit;
747                 }
748             if (caps->data_link_types == NULL) {
749                 cmdarg_err("The capture device \"%s\" has no data link types.", device->name);
750                 ret_val = INVALID_LINK_TYPE;
751                 goto clean_exit;
752             }
753 #ifdef _WIN32
754             create_console();
755 #endif /* _WIN32 */
756 #if defined(HAVE_PCAP_CREATE)
757             if (device->monitor_mode_supported)
758                 if_caps_queries |= CAPS_MONITOR_MODE;
759 #endif
760             capture_opts_print_if_capabilities(caps, device->name, if_caps_queries);
761 #ifdef _WIN32
762             destroy_console();
763 #endif /* _WIN32 */
764             free_if_capabilities(caps);
765             }
766         }
767         ret_val = EXIT_SUCCESS;
768         goto clean_exit;
769     }
770
771     capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
772     capture_opts_trim_ring_num_files(&global_capture_opts);
773 #endif /* HAVE_LIBPCAP */
774
775     /* Notify all registered modules that have had any of their preferences
776        changed either from one of the preferences file or from the command
777        line that their preferences have changed. */
778 #ifdef DEBUG_STARTUP_TIME
779     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);
780 #endif
781     prefs_apply_all();
782     prefs_to_capture_opts();
783     wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
784
785 #ifdef HAVE_LIBPCAP
786     if ((global_capture_opts.num_selected == 0) &&
787             (prefs.capture_device != NULL)) {
788         guint i;
789         interface_t *device;
790         for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
791             device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
792             if (!device->hidden && strcmp(device->display_name, prefs.capture_device) == 0) {
793                 device->selected = TRUE;
794                 global_capture_opts.num_selected++;
795                 break;
796             }
797         }
798     }
799 #endif
800
801     /*
802      * Enabled and disabled protocols and heuristic dissectors as per
803      * command-line options.
804      */
805     if (!setup_enabled_and_disabled_protocols()) {
806         ret_val = INVALID_OPTION;
807         goto clean_exit;
808     }
809
810     build_column_format_array(&CaptureFile::globalCapFile()->cinfo, global_commandline_info.prefs_p->num_cols, TRUE);
811     wsApp->emitAppSignal(WiresharkApplication::ColumnsChanged); // We read "recent" widths above.
812     wsApp->emitAppSignal(WiresharkApplication::RecentPreferencesRead); // Must be emitted after PreferencesChanged.
813
814     wsApp->setMonospaceFont(prefs.gui_qt_font_name);
815
816     /* For update of WindowTitle (When use gui.window_title preference) */
817     main_w->setWSWindowTitle();
818
819     if (!color_filters_init(&err_msg, color_filter_add_cb)) {
820         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
821         g_free(err_msg);
822     }
823
824     wsApp->allSystemsGo();
825     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go, elapsed time %.3fs\n", (float) (g_get_monotonic_time() - start_time) / 1000000);
826     SimpleDialog::displayQueuedMessages(main_w);
827
828     /* User could specify filename, or display filter, or both */
829     if (!dfilter.isEmpty())
830         main_w->filterPackets(dfilter, false);
831     if (!cf_name.isEmpty()) {
832         if (main_w->openCaptureFile(cf_name, read_filter, in_file_type)) {
833
834             /* Open stat windows; we do so after creating the main window,
835                to avoid Qt warnings, and after successfully opening the
836                capture file, so we know we have something to compute stats
837                on, and after registering all dissectors, so that MATE will
838                have registered its field array and we can have a tap filter
839                with one of MATE's late-registered fields as part of the
840                filter. */
841             start_requested_stats();
842
843             if(global_commandline_info.go_to_packet != 0) {
844                 /* Jump to the specified frame number, kept for backward
845                    compatibility. */
846                 cf_goto_frame(CaptureFile::globalCapFile(), global_commandline_info.go_to_packet);
847             } else if (global_commandline_info.jfilter != NULL) {
848                 dfilter_t *jump_to_filter = NULL;
849                 /* try to compile given filter */
850                 if (!dfilter_compile(global_commandline_info.jfilter, &jump_to_filter, &err_msg)) {
851                     // Similar code in MainWindow::mergeCaptureFile().
852                     QMessageBox::warning(main_w, QObject::tr("Invalid Display Filter"),
853                                          QObject::tr("The filter expression %1 isn't a valid display filter. (%2).")
854                                                  .arg(global_commandline_info.jfilter, err_msg),
855                                          QMessageBox::Ok);
856                     g_free(err_msg);
857                 } else {
858                     /* Filter ok, jump to the first packet matching the filter
859                        conditions. Default search direction is forward, but if
860                        option d was given, search backwards */
861                     cf_find_packet_dfilter(CaptureFile::globalCapFile(), jump_to_filter, global_commandline_info.jump_backwards);
862                 }
863             }
864         }
865     }
866 #ifdef HAVE_LIBPCAP
867     else {
868         if (global_commandline_info.start_capture) {
869             if (global_capture_opts.save_file != NULL) {
870                 /* Save the directory name for future file dialogs. */
871                 /* (get_dirname overwrites filename) */
872                 gchar *s = g_strdup(global_capture_opts.save_file);
873                 set_last_open_dir(get_dirname(s));
874                 g_free(s);
875             }
876             /* "-k" was specified; start a capture. */
877             check_and_warn_user_startup(cf_name);
878
879             /* If no user interfaces were specified on the command line,
880                copy the list of selected interfaces to the set of interfaces
881                to use for this capture. */
882             if (global_capture_opts.ifaces->len == 0)
883                 collect_ifaces(&global_capture_opts);
884             CaptureFile::globalCapFile()->window = main_w;
885             if (capture_start(&global_capture_opts, main_w->captureSession(), main_w->captureInfoData(), main_window_update)) {
886                 /* The capture started.  Open stat windows; we do so after creating
887                    the main window, to avoid GTK warnings, and after successfully
888                    opening the capture file, so we know we have something to compute
889                    stats on, and after registering all dissectors, so that MATE will
890                    have registered its field array and we can have a tap filter with
891                    one of MATE's late-registered fields as part of the filter. */
892                 start_requested_stats();
893             }
894         }
895         /* if the user didn't supply a capture filter, use the one to filter out remote connections like SSH */
896         if (!global_commandline_info.start_capture && !global_capture_opts.default_options.cfilter) {
897             global_capture_opts.default_options.cfilter = g_strdup(get_conn_cfilter());
898         }
899     }
900 #endif /* HAVE_LIBPCAP */
901
902     // UAT files used in configuration profiles which are used in Qt dialogs
903     // are not registered during startup because they only get loaded when
904     // the dialog is shown.  Register them here.
905     g_free(get_persconffile_path("io_graphs", TRUE));
906
907     profile_store_persconffiles(FALSE);
908
909     ret_val = wsApp->exec();
910     wsApp = NULL;
911
912     delete main_w;
913     recent_cleanup();
914     epan_cleanup();
915
916     extcap_cleanup();
917
918     Dot11DecryptDestroyContext(&dot11decrypt_ctx);
919
920 #ifdef _WIN32
921     /* Shutdown windows sockets */
922     WSACleanup();
923
924     /* For some unknown reason, the "atexit()" call in "create_console()"
925        doesn't arrange that "destroy_console()" be called when we exit,
926        so we call it here if a console was created. */
927     destroy_console();
928 #endif /* _WIN32 */
929
930 clean_exit:
931 #ifdef HAVE_LIBPCAP
932     capture_opts_cleanup(&global_capture_opts);
933 #endif
934     col_cleanup(&CaptureFile::globalCapFile()->cinfo);
935     codecs_cleanup();
936     wtap_cleanup();
937     free_progdirs();
938     exit_application(ret_val);
939 }
940
941 /*
942  * Editor modelines
943  *
944  * Local Variables:
945  * c-basic-offset: 4
946  * tab-width: 8
947  * indent-tabs-mode: nil
948  * End:
949  *
950  * ex: set shiftwidth=4 tabstop=8 expandtab:
951  * :indentSize=4:tabSize=8:noTabs=true:
952  */