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