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