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