From d8008cb89e20aa86200bf37099b26021f98c6931 Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Thu, 10 Feb 2022 15:11:43 -0800 Subject: [PATCH] Qt: Split MainWindow into WiresharkMainWindow and LogwolfMainWindow. Rename the main_window class and UIC files to wireshark_main_window and the MainWindow class to WiresharkMainWindow. Copy wireshark_main_window / WiresharkMainWindow to logwolf_main_window / LogwolfMainWindow. Remove the Wireless menu from Logwolf. --- ui/qt/CMakeLists.txt | 6 +- ui/qt/filter_action.cpp | 1 + ui/qt/main.cpp | 6 +- ui/qt/main_application.cpp | 10 +- ui/qt/main_window.cpp | 3180 +------------ ui/qt/main_window.h | 726 +-- ui/qt/main_window_layout.cpp | 30 +- ui/qt/packet_diagram.cpp | 4 +- ui/qt/show_packet_bytes_dialog.cpp | 1 + ui/qt/widgets/packet_list_header.cpp | 1 + ui/qt/wireshark_main_window.cpp | 3162 +++++++++++++ ui/qt/wireshark_main_window.h | 711 +++ ...ain_window.ui => wireshark_main_window.ui} | 6 +- ...ts.cpp => wireshark_main_window_slots.cpp} | 642 ++- ui/qt_logshark/CMakeLists.txt | 21 +- ui/qt_logshark/logshark_application.cpp | 4 +- ui/qt_logshark/logshark_application.h | 8 +- ui/qt_logshark/logwolf_main_window.cpp | 3160 +++++++++++++ ui/qt_logshark/logwolf_main_window.h | 703 +++ ui/qt_logshark/logwolf_main_window.ui | 3069 ++++++++++++ ui/qt_logshark/logwolf_main_window_slots.cpp | 4197 +++++++++++++++++ ui/qt_logshark/ls_main.cpp | 6 +- 22 files changed, 15435 insertions(+), 4219 deletions(-) create mode 100644 ui/qt/wireshark_main_window.cpp create mode 100644 ui/qt/wireshark_main_window.h rename ui/qt/{main_window.ui => wireshark_main_window.ui} (99%) rename ui/qt/{main_window_slots.cpp => wireshark_main_window_slots.cpp} (85%) create mode 100644 ui/qt_logshark/logwolf_main_window.cpp create mode 100644 ui/qt_logshark/logwolf_main_window.h create mode 100644 ui/qt_logshark/logwolf_main_window.ui create mode 100644 ui/qt_logshark/logwolf_main_window_slots.cpp diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index 9bf01d2b5c..ddd415aebc 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -245,6 +245,7 @@ set(WIRESHARK_QT_HEADERS wireless_frame.h wireshark_application.h wireshark_dialog.h + wireshark_main_window.h wlan_statistics_dialog.h ${WIRESHARK_CUSTOM_QT_HEADERS} ) @@ -425,7 +426,6 @@ set(WIRESHARK_QT_SRC main_status_bar.cpp main_window_layout.cpp main_window_preferences_frame.cpp - main_window_slots.cpp main_window.cpp main.cpp manage_interfaces_dialog.cpp @@ -481,6 +481,8 @@ set(WIRESHARK_QT_SRC wireless_frame.cpp wireshark_application.cpp wireshark_dialog.cpp + wireshark_main_window.cpp + wireshark_main_window_slots.cpp ${WIRESHARK_CUSTOM_QT_SRCS} ) @@ -563,7 +565,6 @@ set(WIRESHARK_QT_UI lbm_stream_dialog.ui lte_rlc_graph_dialog.ui main_window_preferences_frame.ui - main_window.ui manage_interfaces_dialog.ui module_preferences_scroll_area.ui mtp3_summary_dialog.ui @@ -603,6 +604,7 @@ set(WIRESHARK_QT_UI welcome_page.ui widgets/splash_overlay.ui wireless_frame.ui + wireshark_main_window.ui ) if(HAVE_PCAP_REMOTE) diff --git a/ui/qt/filter_action.cpp b/ui/qt/filter_action.cpp index 08e24a1cc6..26c293de50 100644 --- a/ui/qt/filter_action.cpp +++ b/ui/qt/filter_action.cpp @@ -12,6 +12,7 @@ #include #include +#include #include FilterAction::FilterAction(QObject *parent, FilterAction::Action action, FilterAction::ActionType type, FilterAction::ActionDirection direction) : diff --git a/ui/qt/main.cpp b/ui/qt/main.cpp index 912e59762e..cdbc1451a4 100644 --- a/ui/qt/main.cpp +++ b/ui/qt/main.cpp @@ -81,7 +81,7 @@ #include "ui/qt/utils/color_utils.h" #include "ui/qt/coloring_rules_dialog.h" #include "ui/qt/endpoint_dialog.h" -#include "ui/qt/main_window.h" +#include "ui/qt/wireshark_main_window.h" #include "ui/qt/response_time_delay_dialog.h" #include "ui/qt/service_response_time_dialog.h" #include "ui/qt/simple_dialog.h" @@ -418,7 +418,7 @@ macos_enable_layer_backing(void) /* And now our feature presentation... [ fade to music ] */ int main(int argc, char *qt_argv[]) { - MainWindow *main_w; + WiresharkMainWindow *main_w; #ifdef _WIN32 LPWSTR *wc_argv; @@ -697,7 +697,7 @@ int main(int argc, char *qt_argv[]) /* ws_log(LOG_DOMAIN_MAIN, LOG_LEVEL_DEBUG, "Translator %s", language); */ // Init the main window (and splash) - main_w = new(MainWindow); + main_w = new(WiresharkMainWindow); main_w->show(); // We may not need a queued connection here but it would seem to make sense // to force the issue. diff --git a/ui/qt/main_application.cpp b/ui/qt/main_application.cpp index 1c4b37955c..0a42fd5b7c 100644 --- a/ui/qt/main_application.cpp +++ b/ui/qt/main_application.cpp @@ -72,7 +72,7 @@ #include #include -#include +#include #include #include @@ -1301,10 +1301,10 @@ void MainApplication::pushStatus(StatusInfo status, const QString &message, cons return; MainWindow * mw = qobject_cast(mainWindow()); - if (! mw->main_ui_ || ! mw->main_ui_->statusBar) + if (! mw->statusBar()) return; - MainStatusBar * bar = mw->main_ui_->statusBar; + MainStatusBar * bar = mw->statusBar(); switch(status) { @@ -1335,10 +1335,10 @@ void MainApplication::popStatus(StatusInfo status) return; MainWindow * mw = qobject_cast(mainWindow()); - if (! mw->main_ui_ || ! mw->main_ui_->statusBar) + if (! mw->statusBar()) return; - MainStatusBar * bar = mw->main_ui_->statusBar; + MainStatusBar * bar = mw->statusBar(); switch(status) { diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 139005332b..8e6daa7919 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -7,3029 +7,30 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "main_application.h" -#include "main_window.h" +#include "config.h" -/* - * The generated Ui_MainWindow::setupUi() can grow larger than our configured limit, - * so turn off -Wframe-larger-than= for ui_main_window.h. - */ -DIAG_OFF(frame-larger-than=) -#include -DIAG_ON(frame-larger-than=) +#include -#include -#include "epan/conversation_filter.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ui/iface_toolbar.h" - -#ifdef HAVE_LIBPCAP -#include "ui/capture.h" -#include -#endif - -#include "ui/alert_box.h" -#ifdef HAVE_LIBPCAP -#include "ui/capture_ui_utils.h" -#endif -#include "ui/capture_globals.h" -#include "ui/main_statusbar.h" -#include "ui/recent.h" -#include "ui/recent_utils.h" -#include "ui/util.h" #include "ui/preference_utils.h" -#include "byte_view_tab.h" -#ifdef HAVE_LIBPCAP -#include "capture_options_dialog.h" -#endif -#include "conversation_colorize_action.h" -#include "export_dissection_dialog.h" -#include "export_object_action.h" -#include "file_set_dialog.h" -#include "filter_dialog.h" -#include "funnel_statistics.h" -#include "import_text_dialog.h" -#include "interface_toolbar.h" -#include "packet_diagram.h" +#include "main_window.h" + #include "packet_list.h" -#include "proto_tree.h" -#include "simple_dialog.h" -#include "tap_parameter_dialog.h" -#include "wireless_frame.h" -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//menu_recent_file_write_all - -// If we ever add support for multiple windows this will need to be replaced. -static MainWindow *gbl_cur_main_window_ = NULL; - -void pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb) -{ - gbl_cur_main_window_->setPipeInputHandler(source, user_data, child_process, input_cb); -} - -static void plugin_if_mainwindow_apply_filter(GHashTable * data_set) -{ - if (!gbl_cur_main_window_ || !data_set) - return; - - if (g_hash_table_lookup_extended(data_set, "filter_string", NULL, NULL)) { - QString filter((const char *)g_hash_table_lookup(data_set, "filter_string")); - gbl_cur_main_window_->filterPackets(filter); - } -} - -static void plugin_if_mainwindow_preference(GHashTable * data_set) -{ - if (!gbl_cur_main_window_ || !data_set) - return; - - const char * module_name; - const char * pref_name; - const char * pref_value; - -DIAG_OFF_CAST_AWAY_CONST - if (g_hash_table_lookup_extended(data_set, "pref_module", NULL, (gpointer *)&module_name) && - g_hash_table_lookup_extended(data_set, "pref_key", NULL, (gpointer *)&pref_name) && - g_hash_table_lookup_extended(data_set, "pref_value", NULL, (gpointer *)&pref_value)) - { - unsigned int changed_flags = prefs_store_ext(module_name, pref_name, pref_value); - if (changed_flags) { - mainApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged); - mainApp->emitAppSignal(WiresharkApplication::PreferencesChanged); - } - } -DIAG_ON_CAST_AWAY_CONST -} - -static void plugin_if_mainwindow_gotoframe(GHashTable * data_set) -{ - if (!gbl_cur_main_window_ || !data_set) - return; - - gpointer framenr; - - if (g_hash_table_lookup_extended(data_set, "frame_nr", NULL, &framenr)) { - if (GPOINTER_TO_UINT(framenr) != 0) - gbl_cur_main_window_->gotoFrame(GPOINTER_TO_UINT(framenr)); - } -} - -#ifdef HAVE_LIBPCAP - -static void plugin_if_mainwindow_get_ws_info(GHashTable * data_set) -{ - if (!gbl_cur_main_window_ || !data_set) - return; - - ws_info_t *ws_info = NULL; - - if (!g_hash_table_lookup_extended(data_set, "ws_info", NULL, (void**)&ws_info)) - return; - - CaptureFile *cfWrap = gbl_cur_main_window_->captureFile(); - capture_file *cf = cfWrap->capFile(); - - ws_info->ws_info_supported = true; - - /* If we have a filename attached to ws_info clear it */ - if (ws_info->cf_filename != NULL) - { - g_free(ws_info->cf_filename); - ws_info->cf_filename = NULL; - } - - /* Determine the true state of the capture file. We return the true state in - the ws_info structure and DON'T CHANGE the cf->state as we don't want to cause problems - with code that follows this. */ - if (cf) - { - if (cf->filename) - { - /* As we have a cf->filename we'll use the name and the state */ - ws_info->cf_filename = g_strdup(cf->filename); - ws_info->cf_state = cf->state; - } - else - { - /* When we come through here the cf->state can show FILE_READ_DONE even though the - file is actually closed (no filename). A better fix would be to have a - FILE_CLOSE_PENDING state but that involves a lot of code change elsewhere. */ - ws_info->cf_state = FILE_CLOSED; - } - } - - if (!ws_info->cf_filename) - { - /* We may have a filename associated with the main window so let's use it */ - QString fileNameString = gbl_cur_main_window_->getMwFileName(); - if (fileNameString.length()) - { - QByteArray ba = fileNameString.toLatin1(); - const char *c_file_name = ba.data(); - ws_info->cf_filename = g_strdup(c_file_name); - } - } - - if (cf) { - ws_info->cf_count = cf->count; - - QList rows = gbl_cur_main_window_->selectedRows(); - frame_data * fdata = NULL; - if (rows.count() > 0) - fdata = gbl_cur_main_window_->frameDataForRow(rows.at(0)); - - if (cf->state == FILE_READ_DONE && fdata) { - ws_info->cf_framenr = fdata->num; - ws_info->frame_passed_dfilter = (fdata->passed_dfilter == 1); - } - else { - ws_info->cf_framenr = 0; - ws_info->frame_passed_dfilter = FALSE; - } - } - else - { - /* Initialise the other ws_info structure values */ - ws_info->cf_count = 0; - ws_info->cf_framenr = 0; - ws_info->frame_passed_dfilter = FALSE; - } -} - -#endif /* HAVE_LIBPCAP */ - -static void plugin_if_mainwindow_get_frame_data(GHashTable* data_set) -{ - if (!gbl_cur_main_window_ || !data_set) - return; - - plugin_if_frame_data_cb extract_cb; - void* user_data; - void** ret_value_ptr; - - if (g_hash_table_lookup_extended(data_set, "extract_cb", NULL, (void**)&extract_cb) && - g_hash_table_lookup_extended(data_set, "user_data", NULL, (void**)&user_data) && - g_hash_table_lookup_extended(data_set, "ret_value_ptr", NULL, (void**)&ret_value_ptr)) - { - QList rows = gbl_cur_main_window_->selectedRows(); - if (rows.count() > 0) { - frame_data* fdata = gbl_cur_main_window_->frameDataForRow(rows.at(0)); - if (fdata) { - *ret_value_ptr = extract_cb(fdata, user_data); - } - } - } -} - -static void plugin_if_mainwindow_get_capture_file(GHashTable* data_set) -{ - if (!gbl_cur_main_window_ || !data_set) - return; - - plugin_if_capture_file_cb extract_cb; - void* user_data; - void** ret_value_ptr; - - if (g_hash_table_lookup_extended(data_set, "extract_cb", NULL, (void**)&extract_cb) && - g_hash_table_lookup_extended(data_set, "user_data", NULL, (void**)&user_data) && - g_hash_table_lookup_extended(data_set, "ret_value_ptr", NULL, (void**)&ret_value_ptr)) - { - CaptureFile* cfWrap = gbl_cur_main_window_->captureFile(); - capture_file* cf = cfWrap->capFile(); - if (cf) { - *ret_value_ptr = extract_cb(cf, user_data); - } - } -} - -static void plugin_if_mainwindow_update_toolbars(GHashTable * data_set) -{ - if (!gbl_cur_main_window_ || !data_set) - return; - - if (g_hash_table_lookup_extended(data_set, "toolbar_name", NULL, NULL)) { - QString toolbarName((const char *)g_hash_table_lookup(data_set, "toolbar_name")); - gbl_cur_main_window_->removeAdditionalToolbar(toolbarName); - - } -} - -static void mainwindow_add_toolbar(const iface_toolbar *toolbar_entry) -{ - if (gbl_cur_main_window_ && toolbar_entry) - { - gbl_cur_main_window_->addInterfaceToolbar(toolbar_entry); - } -} - -static void mainwindow_remove_toolbar(const gchar *menu_title) -{ - if (gbl_cur_main_window_ && menu_title) - { - gbl_cur_main_window_->removeInterfaceToolbar(menu_title); - } -} - -QMenu* MainWindow::findOrAddMenu(QMenu *parent_menu, QString& menu_text) { - QList actions = parent_menu->actions(); - QList::const_iterator i; - for (i = actions.constBegin(); i != actions.constEnd(); ++i) { - if ((*i)->text()==menu_text) { - return (*i)->menu(); - } - } - // If we get here there menu entry was not found, add a sub menu - return parent_menu->addMenu(menu_text); -} +#include "widgets/display_filter_combo.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - main_ui_(new Ui::MainWindow), + main_stack_(nullptr), + welcome_page_(nullptr), cur_layout_(QVector()), - packet_list_(NULL), - proto_tree_(NULL), - previous_focus_(NULL), - file_set_dialog_(NULL), - show_hide_actions_(NULL), - time_display_actions_(NULL), - time_precision_actions_(NULL), - funnel_statistics_(NULL), - freeze_focus_(NULL), - was_maximized_(false), - capture_stopping_(false), - capture_filter_valid_(false) -#ifdef HAVE_LIBPCAP - , capture_options_dialog_(NULL) - , info_data_() -#endif - , display_filter_dlg_(NULL) - , capture_filter_dlg_(NULL) -#ifdef _WIN32 - , pipe_timer_(NULL) -#else - , pipe_notifier_(NULL) -#endif -#if defined(Q_OS_MAC) - , dock_menu_(NULL) -#endif + packet_list_(nullptr), + proto_tree_(nullptr), + byte_view_tab_(nullptr), + packet_diagram_(nullptr), + df_combo_box_(nullptr), + main_status_bar_(nullptr) { - if (!gbl_cur_main_window_) { - connect(mainApp, SIGNAL(openStatCommandDialog(QString, const char*, void*)), - this, SLOT(openStatCommandDialog(QString, const char*, void*))); - connect(mainApp, SIGNAL(openTapParameterDialog(QString, const QString, void*)), - this, SLOT(openTapParameterDialog(QString, const QString, void*))); - } - gbl_cur_main_window_ = this; -#ifdef HAVE_LIBPCAP - capture_input_init(&cap_session_, CaptureFile::globalCapFile()); -#endif - findTextCodecs(); - // setpUi calls QMetaObject::connectSlotsByName(this). connectSlotsByName - // iterates over *all* of our children, looking for matching "on_" slots. - // The fewer children we have at this point the better. - main_ui_->setupUi(this); -#ifdef HAVE_SOFTWARE_UPDATE - update_action_ = new QAction(tr("Check for Updates…"), main_ui_->menuHelp); -#endif -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) - wireless_frame_ = new WirelessFrame(this); - main_ui_->wirelessToolBar->addWidget(wireless_frame_); -#else - removeToolBar(main_ui_->wirelessToolBar); - main_ui_->menuView->removeAction(main_ui_->actionViewWirelessToolbar); -#endif - - setWindowIcon(mainApp->normalIcon()); - setTitlebarForCaptureFile(); - setMenusForCaptureFile(); - setForCapturedPackets(false); - setMenusForFileSet(false); - interfaceSelectionChanged(); - loadWindowGeometry(); - -#ifndef HAVE_LUA - main_ui_->actionAnalyzeReloadLuaPlugins->setVisible(false); -#endif - - qRegisterMetaType("FilterAction::Action"); - qRegisterMetaType("FilterAction::ActionType"); - connect(this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), - this, SLOT(queuedFilterAction(QString, FilterAction::Action, FilterAction::ActionType)), - Qt::QueuedConnection); - - //To prevent users use features before initialization complete - //Otherwise unexpected problems may occur - setFeaturesEnabled(false); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(setFeaturesEnabled())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(applyGlobalCommandLineOptions())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(zoomText())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initViewColorizeMenu())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addStatsPluginsToMenu())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addDynamicMenus())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addPluginIFStructures())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initConversationMenus())); - connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initExportObjectsMenus())); - - connect(mainApp, SIGNAL(profileChanging()), this, SLOT(saveWindowGeometry())); - connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(layoutPanes())); - connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(layoutToolbars())); - connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(updatePreferenceActions())); - connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(zoomText())); - connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(setTitlebarForCaptureFile())); - - connect(mainApp, SIGNAL(updateRecentCaptureStatus(const QString &, qint64, bool)), this, SLOT(updateRecentCaptures())); - updateRecentCaptures(); - -#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) - connect(mainApp, SIGNAL(softwareUpdateRequested()), this, SLOT(softwareUpdateRequested()), - Qt::BlockingQueuedConnection); - connect(mainApp, SIGNAL(softwareUpdateClose()), this, SLOT(close()), - Qt::BlockingQueuedConnection); -#endif - - df_combo_box_ = new DisplayFilterCombo(this); - - funnel_statistics_ = new FunnelStatistics(this, capture_file_); - connect(df_combo_box_, &QComboBox::editTextChanged, funnel_statistics_, &FunnelStatistics::displayFilterTextChanged); - connect(funnel_statistics_, &FunnelStatistics::setDisplayFilter, this, &MainWindow::setDisplayFilter); - connect(funnel_statistics_, SIGNAL(openCaptureFile(QString, QString)), - this, SLOT(openCaptureFile(QString, QString))); - - file_set_dialog_ = new FileSetDialog(this); - connect(file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString)), - this, SLOT(openCaptureFile(QString))); - - initMainToolbarIcons(); - - main_ui_->displayFilterToolBar->insertWidget(main_ui_->actionNewDisplayFilterExpression, df_combo_box_); - - // Make sure filter expressions overflow into a menu instead of a - // larger toolbar. We do this by adding them to a child toolbar. - // https://bugreports.qt.io/browse/QTBUG-2472 - FilterExpressionToolBar *filter_expression_toolbar_ = new FilterExpressionToolBar(this); - connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterPreferences, this, &MainWindow::onFilterPreferences); - connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterSelected, this, &MainWindow::onFilterSelected); - connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterEdit, this, &MainWindow::onFilterEdit); - - main_ui_->displayFilterToolBar->addWidget(filter_expression_toolbar_); - -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) - connect(wireless_frame_, SIGNAL(showWirelessPreferences(QString)), - this, SLOT(showPreferencesDialog(QString))); -#endif - - main_ui_->goToFrame->hide(); - connect(main_ui_->goToFrame, SIGNAL(visibilityChanged(bool)), - main_ui_->actionGoGoToPacket, SLOT(setChecked(bool))); - - // XXX For some reason the cursor is drawn funny with an input mask set - // https://bugreports.qt-project.org/browse/QTBUG-7174 - - main_ui_->searchFrame->hide(); - connect(main_ui_->searchFrame, SIGNAL(visibilityChanged(bool)), - main_ui_->actionEditFindPacket, SLOT(setChecked(bool))); - - main_ui_->addressEditorFrame->hide(); - main_ui_->columnEditorFrame->hide(); - main_ui_->preferenceEditorFrame->hide(); - main_ui_->filterExpressionFrame->hide(); - -#ifndef HAVE_LIBPCAP - main_ui_->menuCapture->setEnabled(false); -#endif - - // Set OS specific shortcuts for fullscreen mode -#if defined(Q_OS_MAC) - main_ui_->actionViewFullScreen->setShortcut(QKeySequence::FullScreen); -#else - main_ui_->actionViewFullScreen->setShortcut(QKeySequence(Qt::Key_F11)); -#endif - -#if defined(Q_OS_MAC) - - main_ui_->goToPacketLabel->setAttribute(Qt::WA_MacSmallSize, true); - main_ui_->goToLineEdit->setAttribute(Qt::WA_MacSmallSize, true); - main_ui_->goToGo->setAttribute(Qt::WA_MacSmallSize, true); - main_ui_->goToCancel->setAttribute(Qt::WA_MacSmallSize, true); - - main_ui_->actionEditPreferences->setMenuRole(QAction::PreferencesRole); - -#endif // Q_OS_MAC - -// A billion-1 is equivalent to the inputMask 900000000 previously used -// Avoid QValidator::Intermediate values by using a top value of all 9's -#define MAX_GOTO_LINE 999999999 - -QIntValidator *goToLineQiv = new QIntValidator(0,MAX_GOTO_LINE,this); -main_ui_->goToLineEdit->setValidator(goToLineQiv); - -#ifdef HAVE_SOFTWARE_UPDATE - QAction *update_sep = main_ui_->menuHelp->insertSeparator(main_ui_->actionHelpAbout); - main_ui_->menuHelp->insertAction(update_sep, update_action_); - connect(update_action_, SIGNAL(triggered()), this, SLOT(checkForUpdates())); -#endif - master_split_.setObjectName("splitterMaster"); - extra_split_.setObjectName("splitterExtra"); - master_split_.setChildrenCollapsible(false); - extra_split_.setChildrenCollapsible(false); - main_ui_->mainStack->addWidget(&master_split_); - - empty_pane_.setObjectName("emptyPane"); - empty_pane_.setVisible(false); - - packet_list_ = new PacketList(&master_split_); - main_ui_->wirelessTimelineWidget->setPacketList(packet_list_); - connect(packet_list_, SIGNAL(framesSelected(QList)), this, SLOT(setMenusForSelectedPacket())); - connect(packet_list_, SIGNAL(framesSelected(QList)), this, SIGNAL(framesSelected(QList))); - - connect(main_ui_->menuPacketComment, SIGNAL(aboutToShow()), this, SLOT(setEditCommentsMenu())); - - proto_tree_ = new ProtoTree(&master_split_); - proto_tree_->installEventFilter(this); - - packet_list_->setProtoTree(proto_tree_); - packet_list_->installEventFilter(this); - - packet_diagram_ = new PacketDiagram(&master_split_); - - welcome_page_ = main_ui_->welcomePage; - - connect(proto_tree_, &ProtoTree::fieldSelected, - this, &MainWindow::fieldSelected); - connect(packet_list_, &PacketList::fieldSelected, - this, &MainWindow::fieldSelected); - connect(this, &MainWindow::fieldSelected, - this, &MainWindow::setMenusForSelectedTreeRow); - connect(this, &MainWindow::fieldSelected, - main_ui_->statusBar, &MainStatusBar::selectedFieldChanged); - - connect(this, &MainWindow::fieldHighlight, - main_ui_->statusBar, &MainStatusBar::highlightedFieldChanged); - connect(mainApp, &WiresharkApplication::captureActive, - this, &MainWindow::captureActive); - - byte_view_tab_ = new ByteViewTab(&master_split_); - - // Packet list and proto tree must exist before these are called. - setMenusForSelectedPacket(); - setMenusForSelectedTreeRow(); - - initShowHideMainWidgets(); - initTimeDisplayFormatMenu(); - initTimePrecisionFormatMenu(); - initFreezeActions(); - updatePreferenceActions(); - updateRecentActions(); - setForCaptureInProgress(false); - - setTabOrder(df_combo_box_->lineEdit(), packet_list_); - setTabOrder(packet_list_, proto_tree_); - - connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), - this, SLOT(captureEventHandler(CaptureEvent))); - connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), - mainApp, SLOT(captureEventHandler(CaptureEvent))); - connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), - main_ui_->statusBar, SLOT(captureEventHandler(CaptureEvent))); - - connect(mainApp, SIGNAL(columnsChanged()), - packet_list_, SLOT(columnsChanged())); - connect(mainApp, SIGNAL(preferencesChanged()), - packet_list_, SLOT(preferencesChanged())); - connect(mainApp, SIGNAL(recentPreferencesRead()), - this, SLOT(applyRecentPaneGeometry())); - connect(mainApp, SIGNAL(recentPreferencesRead()), - this, SLOT(updateRecentActions())); - connect(mainApp, SIGNAL(packetDissectionChanged()), - this, SLOT(redissectPackets()), Qt::QueuedConnection); - - connect(mainApp, SIGNAL(checkDisplayFilter()), - this, SLOT(checkDisplayFilter())); - connect(mainApp, SIGNAL(fieldsChanged()), - this, SLOT(fieldsChanged())); - connect(mainApp, SIGNAL(reloadLuaPlugins()), - this, SLOT(reloadLuaPlugins())); - - connect(main_ui_->mainStack, SIGNAL(currentChanged(int)), - this, SLOT(mainStackChanged(int))); - - connect(welcome_page_, SIGNAL(startCapture(QStringList)), - this, SLOT(startCapture(QStringList))); - connect(welcome_page_, SIGNAL(recentFileActivated(QString)), - this, SLOT(openCaptureFile(QString))); - - connect(main_ui_->addressEditorFrame, &AddressEditorFrame::redissectPackets, - this, &MainWindow::redissectPackets); - connect(main_ui_->addressEditorFrame, &AddressEditorFrame::showNameResolutionPreferences, - this, &MainWindow::showPreferencesDialog); - connect(main_ui_->preferenceEditorFrame, &PreferenceEditorFrame::showProtocolPreferences, - this, &MainWindow::showPreferencesDialog); - connect(main_ui_->filterExpressionFrame, &FilterExpressionFrame::showPreferencesDialog, - this, &MainWindow::showPreferencesDialog); - connect(main_ui_->filterExpressionFrame, &FilterExpressionFrame::filterExpressionsChanged, - filter_expression_toolbar_, &FilterExpressionToolBar::filterExpressionsChanged); - - /* Connect change of capture file */ - connect(this, &MainWindow::setCaptureFile, - main_ui_->searchFrame, &SearchFrame::setCaptureFile); - connect(this, &MainWindow::setCaptureFile, - main_ui_->statusBar, &MainStatusBar::setCaptureFile); - connect(this, &MainWindow::setCaptureFile, - packet_list_, &PacketList::setCaptureFile); - connect(this, &MainWindow::setCaptureFile, - proto_tree_, &ProtoTree::setCaptureFile); - - connect(mainApp, SIGNAL(zoomMonospaceFont(QFont)), - packet_list_, SLOT(setMonospaceFont(QFont))); - connect(mainApp, SIGNAL(zoomMonospaceFont(QFont)), - proto_tree_, SLOT(setMonospaceFont(QFont))); - - connect(main_ui_->actionGoNextPacket, SIGNAL(triggered()), - packet_list_, SLOT(goNextPacket())); - connect(main_ui_->actionGoPreviousPacket, SIGNAL(triggered()), - packet_list_, SLOT(goPreviousPacket())); - connect(main_ui_->actionGoFirstPacket, SIGNAL(triggered()), - packet_list_, SLOT(goFirstPacket())); - connect(main_ui_->actionGoLastPacket, SIGNAL(triggered()), - packet_list_, SLOT(goLastPacket())); - connect(main_ui_->actionGoNextHistoryPacket, SIGNAL(triggered()), - packet_list_, SLOT(goNextHistoryPacket())); - connect(main_ui_->actionGoPreviousHistoryPacket, SIGNAL(triggered()), - packet_list_, SLOT(goPreviousHistoryPacket())); - - connect(main_ui_->actionViewExpandSubtrees, SIGNAL(triggered()), - proto_tree_, SLOT(expandSubtrees())); - connect(main_ui_->actionViewCollapseSubtrees, SIGNAL(triggered()), - proto_tree_, SLOT(collapseSubtrees())); - connect(main_ui_->actionViewExpandAll, SIGNAL(triggered()), - proto_tree_, SLOT(expandAll())); - connect(main_ui_->actionViewCollapseAll, SIGNAL(triggered()), - proto_tree_, SLOT(collapseAll())); - - connect(packet_list_, SIGNAL(packetDissectionChanged()), - this, SLOT(redissectPackets())); - connect(packet_list_, SIGNAL(showColumnPreferences(QString)), - this, SLOT(showPreferencesDialog(QString))); - connect(packet_list_, SIGNAL(showProtocolPreferences(QString)), - this, SLOT(showPreferencesDialog(QString))); - connect(packet_list_, SIGNAL(editProtocolPreference(preference*, pref_module*)), - main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*))); - connect(packet_list_, SIGNAL(editColumn(int)), this, SLOT(showColumnEditor(int))); - connect(main_ui_->columnEditorFrame, SIGNAL(columnEdited()), - packet_list_, SLOT(columnsChanged())); - connect(packet_list_, SIGNAL(doubleClicked(QModelIndex)), - this, SLOT(openPacketDialog())); - connect(packet_list_, SIGNAL(packetListScrolled(bool)), - main_ui_->actionGoAutoScroll, SLOT(setChecked(bool))); - - connect(proto_tree_, SIGNAL(openPacketInNewWindow(bool)), - this, SLOT(openPacketDialog(bool))); - connect(proto_tree_, SIGNAL(showProtocolPreferences(QString)), - this, SLOT(showPreferencesDialog(QString))); - connect(proto_tree_, SIGNAL(editProtocolPreference(preference*, pref_module*)), - main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*))); - - connect(main_ui_->statusBar, SIGNAL(showExpertInfo()), - this, SLOT(on_actionAnalyzeExpertInfo_triggered())); - - connect(main_ui_->statusBar, SIGNAL(stopLoading()), - &capture_file_, SLOT(stopLoading())); - - connect(main_ui_->statusBar, SIGNAL(editCaptureComment()), - this, SLOT(on_actionStatisticsCaptureFileProperties_triggered())); - - connect(main_ui_->menuApplyAsFilter, &QMenu::aboutToShow, - this, &MainWindow::filterMenuAboutToShow); - connect(main_ui_->menuPrepareAFilter, &QMenu::aboutToShow, - this, &MainWindow::filterMenuAboutToShow); - -#ifdef HAVE_LIBPCAP - QTreeWidget *iface_tree = findChild("interfaceTree"); - if (iface_tree) { - connect(iface_tree, SIGNAL(itemSelectionChanged()), - this, SLOT(interfaceSelectionChanged())); - } - connect(main_ui_->welcomePage, SIGNAL(captureFilterSyntaxChanged(bool)), - this, SLOT(captureFilterSyntaxChanged(bool))); - - connect(this, SIGNAL(showExtcapOptions(QString&, bool)), - this, SLOT(showExtcapOptionsDialog(QString&, bool))); - connect(this->welcome_page_, SIGNAL(showExtcapOptions(QString&, bool)), - this, SLOT(showExtcapOptionsDialog(QString&, bool))); - -#endif // HAVE_LIBPCAP - - /* Create plugin_if hooks */ - plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_APPLY, plugin_if_mainwindow_apply_filter); - plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_PREPARE, plugin_if_mainwindow_apply_filter); - plugin_if_register_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, plugin_if_mainwindow_preference); - plugin_if_register_gui_cb(PLUGIN_IF_GOTO_FRAME, plugin_if_mainwindow_gotoframe); -#ifdef HAVE_LIBPCAP - plugin_if_register_gui_cb(PLUGIN_IF_GET_WS_INFO, plugin_if_mainwindow_get_ws_info); -#endif - plugin_if_register_gui_cb(PLUGIN_IF_GET_FRAME_DATA, plugin_if_mainwindow_get_frame_data); - plugin_if_register_gui_cb(PLUGIN_IF_GET_CAPTURE_FILE, plugin_if_mainwindow_get_capture_file); - plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars); - - /* Register Interface Toolbar callbacks */ - iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar); - - /* Show tooltips on menu items that go to websites */ - main_ui_->actionHelpMPWireshark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_WIRESHARK))); - main_ui_->actionHelpMPWireshark_Filter->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_WIRESHARK_FILTER))); - main_ui_->actionHelpMPCapinfos->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_CAPINFOS))); - main_ui_->actionHelpMPDumpcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_DUMPCAP))); - main_ui_->actionHelpMPEditcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_EDITCAP))); - main_ui_->actionHelpMPMergecap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_MERGECAP))); - main_ui_->actionHelpMPRawshark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_RAWSHARK))); - main_ui_->actionHelpMPReordercap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_REORDERCAP))); - main_ui_->actionHelpMPText2pcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_TEXT2PCAP))); - main_ui_->actionHelpMPTShark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_TSHARK))); - - main_ui_->actionHelpContents->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_USERGUIDE))); - main_ui_->actionHelpWebsite->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_HOME))); - main_ui_->actionHelpFAQ->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_FAQ))); - main_ui_->actionHelpAsk->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_ASK))); - main_ui_->actionHelpDownloads->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_DOWNLOAD))); - main_ui_->actionHelpWiki->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_WIKI))); - main_ui_->actionHelpSampleCaptures->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_SAMPLE_CAPTURES))); - - showWelcome(); -} - -MainWindow::~MainWindow() -{ - disconnect(main_ui_->mainStack, 0, 0, 0); - -#ifndef Q_OS_MAC - // Below dialogs inherit GeometryStateDialog - // For reasons described in geometry_state_dialog.h no parent is set when - // instantiating the dialogs and as a resul objects are not automatically - // freed by its parent. Free then here explicitly to avoid leak and numerous - // Valgrind complaints. - delete file_set_dialog_; - delete capture_filter_dlg_; - delete display_filter_dlg_; -#ifdef HAVE_LIBPCAP - delete capture_options_dialog_; -#endif - -#endif - delete main_ui_; -} - -QString MainWindow::getFilter() -{ - return df_combo_box_->currentText(); -} - -QMenu *MainWindow::createPopupMenu() -{ - QMenu *menu = new QMenu(); - menu->addAction(main_ui_->actionViewMainToolbar); - menu->addAction(main_ui_->actionViewFilterToolbar); -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) - menu->addAction(main_ui_->actionViewWirelessToolbar); -#endif - - if (!main_ui_->menuInterfaceToolbars->actions().isEmpty()) { - QMenu *submenu = menu->addMenu(main_ui_->menuInterfaceToolbars->title()); - foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) { - submenu->addAction(action); - } - } - - if (!main_ui_->menuAdditionalToolbars->actions().isEmpty()) { - QMenu *subMenu = menu->addMenu(main_ui_->menuAdditionalToolbars->title()); - foreach(QAction *action, main_ui_->menuAdditionalToolbars->actions()) { - subMenu->addAction(action); - } - } - - menu->addAction(main_ui_->actionViewStatusBar); - - menu->addSeparator(); - menu->addAction(main_ui_->actionViewPacketList); - menu->addAction(main_ui_->actionViewPacketDetails); - menu->addAction(main_ui_->actionViewPacketBytes); - menu->addAction(main_ui_->actionViewPacketDiagram); - return menu; -} - -void MainWindow::addInterfaceToolbar(const iface_toolbar *toolbar_entry) -{ - QMenu *menu = main_ui_->menuInterfaceToolbars; - bool visible = g_list_find_custom(recent.interface_toolbars, toolbar_entry->menu_title, (GCompareFunc)strcmp) ? true : false; - - QString title = QString().fromUtf8(toolbar_entry->menu_title); - QAction *action = new QAction(title, menu); - action->setEnabled(true); - action->setCheckable(true); - action->setChecked(visible); - action->setToolTip(tr("Show or hide the toolbar")); - - QAction *before = NULL; - foreach(QAction *action, menu->actions()) { - // Ensure we add the menu entries in sorted order - if (action->text().compare(title, Qt::CaseInsensitive) > 0) { - before = action; - break; - } - } - menu->insertAction(before, action); - - InterfaceToolbar *interface_toolbar = new InterfaceToolbar(this, toolbar_entry); - connect(mainApp, SIGNAL(appInitialized()), interface_toolbar, SLOT(interfaceListChanged())); - connect(mainApp, SIGNAL(localInterfaceListChanged()), interface_toolbar, SLOT(interfaceListChanged())); - - QToolBar *toolbar = new QToolBar(this); - toolbar->addWidget(interface_toolbar); - toolbar->setMovable(false); - toolbar->setVisible(visible); - - action->setData(QVariant::fromValue(toolbar)); - - addToolBar(Qt::TopToolBarArea, toolbar); - insertToolBarBreak(toolbar); - - if (show_hide_actions_) { - show_hide_actions_->addAction(action); - } - - menu->menuAction()->setVisible(true); -} - -void MainWindow::removeInterfaceToolbar(const gchar *menu_title) -{ - QMenu *menu = main_ui_->menuInterfaceToolbars; - QAction *action = NULL; - QMap::iterator i; - - QString title = QString().fromUtf8(menu_title); - foreach(action, menu->actions()) { - if (title.compare(action->text()) == 0) { - break; - } - } - - if (action) { - if (show_hide_actions_) { - show_hide_actions_->removeAction(action); - } - menu->removeAction(action); - - QToolBar *toolbar = action->data().value(); - removeToolBar(toolbar); - - delete action; - delete toolbar; - } - - menu->menuAction()->setVisible(!menu->actions().isEmpty()); -} - -void MainWindow::setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb) -{ - pipe_source_ = source; - pipe_child_process_ = child_process; - pipe_user_data_ = user_data; - pipe_input_cb_ = input_cb; - -#ifdef _WIN32 - /* Tricky to use pipes in win9x, as no concept of wait. NT can - do this but that doesn't cover all win32 platforms. GTK can do - this but doesn't seem to work over processes. Attempt to do - something similar here, start a timer and check for data on every - timeout. */ - /*ws_log(NULL, LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/ - - if (pipe_timer_) { - disconnect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout())); - delete pipe_timer_; - } - - pipe_timer_ = new QTimer(this); - connect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout())); - connect(pipe_timer_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed())); - pipe_timer_->start(200); -#else - if (pipe_notifier_) { - disconnect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int))); - delete pipe_notifier_; - } - - pipe_notifier_ = new QSocketNotifier(pipe_source_, QSocketNotifier::Read); - // XXX ui/gtk/gui_utils.c sets the encoding. Do we need to do the same? - connect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int))); - connect(pipe_notifier_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed())); -#endif -} - -bool MainWindow::eventFilter(QObject *obj, QEvent *event) { - - // The user typed some text. Start filling in a filter. - // We may need to be more choosy here. We just need to catch events for the packet list, - // proto tree, and main welcome widgets. - if (event->type() == QEvent::KeyPress) { - QKeyEvent *kevt = static_cast(event); - if (kevt->text().length() > 0 && kevt->text()[0].isPrint() && - !(kevt->modifiers() & Qt::ControlModifier)) { - df_combo_box_->lineEdit()->insert(kevt->text()); - df_combo_box_->lineEdit()->setFocus(); - return true; - } - } - - return QMainWindow::eventFilter(obj, event); -} - -bool MainWindow::event(QEvent *event) -{ - switch (event->type()) { - case QEvent::ApplicationPaletteChange: - initMainToolbarIcons(); - break; - default: - break; - - } - return QMainWindow::event(event); -} - -void MainWindow::keyPressEvent(QKeyEvent *event) { - - // Explicitly focus on the display filter combo. - if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) { - df_combo_box_->setFocus(Qt::ShortcutFocusReason); - return; - } - - if (mainApp->focusWidget() == main_ui_->goToLineEdit) { - if (event->modifiers() == Qt::NoModifier) { - if (event->key() == Qt::Key_Escape) { - on_goToCancel_clicked(); - } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { - on_goToGo_clicked(); - } - } - return; // goToLineEdit didn't want it and we don't either. - } - - // Move up & down the packet list. - if (event->key() == Qt::Key_F7) { - packet_list_->goPreviousPacket(); - } else if (event->key() == Qt::Key_F8) { - packet_list_->goNextPacket(); - } - - // Move along, citizen. - QMainWindow::keyPressEvent(event); -} - -void MainWindow::closeEvent(QCloseEvent *event) { - saveWindowGeometry(); - - /* If we're in the middle of stopping a capture, don't do anything; - the user can try deleting the window after the capture stops. */ - if (capture_stopping_) { - event->ignore(); - return; - } - - QString before_what(tr(" before quitting")); - if (!testCaptureFileClose(before_what, Quit)) { - event->ignore(); - return; - } - -#ifdef HAVE_LIBPCAP - if (capture_options_dialog_) capture_options_dialog_->close(); -#endif - // Make sure we kill any open dumpcap processes. - delete welcome_page_; - - // One of the many places we assume one main window. - if (!mainApp->isInitialized()) { - // If we're still initializing, QCoreApplication::quit() won't - // exit properly because we are not in the event loop. This - // means that the application won't clean up after itself. We - // might want to call mainApp->processEvents() during startup - // instead so that we can do a normal exit here. - exit(0); - } - mainApp->quit(); - // When the main loop is not yet running (i.e. when openCaptureFile is - // executing in main.cpp), the above quit action has no effect. - // Schedule a quit action for the next execution of the main loop. - QMetaObject::invokeMethod(mainApp, "quit", Qt::QueuedConnection); -} - -// XXX On windows the drag description is "Copy". It should be "Open" or -// "Merge" as appropriate. It looks like we need access to IDataObject in -// order to set DROPDESCRIPTION. -void MainWindow::dragEnterEvent(QDragEnterEvent *event) -{ - if (!event->mimeData()->hasUrls()) - { - event->ignore(); - return; - } - - if (!main_ui_->actionFileOpen->isEnabled()) { - // We could alternatively call setAcceptDrops(!capture_in_progress) - // in setMenusForCaptureInProgress but that wouldn't provide feedback. - - mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to drop files during capture.")); - event->setDropAction(Qt::IgnoreAction); - event->ignore(); - return; - } - - bool have_files = false; - foreach(QUrl drag_url, event->mimeData()->urls()) { - if (!drag_url.toLocalFile().isEmpty()) { - have_files = true; - break; - } - } - - if (have_files) { - event->acceptProposedAction(); - } -} - -void MainWindow::dropEvent(QDropEvent *event) -{ - if (!event->mimeData()->hasUrls()) - { - event->ignore(); - return; - } - - QList local_files; - int max_dropped_files = 100; // Arbitrary - - foreach(QUrl drop_url, event->mimeData()->urls()) { - QString drop_file = drop_url.toLocalFile(); - if (!drop_file.isEmpty()) { - local_files << drop_file.toUtf8(); - if (local_files.size() >= max_dropped_files) { - break; - } - } - } - - event->acceptProposedAction(); - - if (local_files.size() < 1) { - event->ignore(); - return; - } - - event->accept(); - - if (local_files.size() == 1) { - openCaptureFile(local_files.at(0)); - return; - } - - const char **in_filenames = g_new(const char *, local_files.size()); - char *tmpname = NULL; - - for (int i = 0; i < local_files.size(); i++) { - in_filenames[i] = local_files.at(i).constData(); - } - - /* merge the files in chronological order */ - if (cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, static_cast(local_files.size()), - in_filenames, - wtap_pcapng_file_type_subtype(), - FALSE) == CF_OK) { - /* Merge succeeded; close the currently-open file and try - to open the merged capture file. */ - openCaptureFile(tmpname, QString(), WTAP_TYPE_AUTO, TRUE); - } - - g_free(tmpname); - g_free(in_filenames); -} - -// Apply recent settings to the main window geometry. -// We haven't loaded the preferences at this point so we assume that the -// position and size preference are enabled. -// Note we might end up with unexpected screen geometries if the user -// unplugs or plugs in a monitor: -// https://bugreports.qt.io/browse/QTBUG-44213 -void MainWindow::loadWindowGeometry() -{ - int min_sensible_dimension = 200; - -#ifndef Q_OS_MAC - if (recent.gui_geometry_main_maximized) { - setWindowState(Qt::WindowMaximized); - } else -#endif - { - QRect recent_geom(recent.gui_geometry_main_x, recent.gui_geometry_main_y, - recent.gui_geometry_main_width, recent.gui_geometry_main_height); - if (!rect_on_screen(recent_geom)) { - // We're not visible on any screens. See if we can move onscreen - // without resizing. - recent_geom.moveTo(50, 50); // recent.c defaults to 20. - } - - if (!rect_on_screen(recent_geom)) { - // Give up and use the default geometry. - return; - } - -// if (prefs.gui_geometry_save_position) { - move(recent_geom.topLeft()); -// } - - if (// prefs.gui_geometry_save_size && - recent_geom.width() > min_sensible_dimension && - recent_geom.height() > min_sensible_dimension) { - resize(recent_geom.size()); - } - } -} - -void MainWindow::saveWindowGeometry() -{ - if (prefs.gui_geometry_save_position) { - recent.gui_geometry_main_x = pos().x(); - recent.gui_geometry_main_y = pos().y(); - } - - if (prefs.gui_geometry_save_size) { - recent.gui_geometry_main_width = size().width(); - recent.gui_geometry_main_height = size().height(); - } - - if (prefs.gui_geometry_save_maximized) { - // On macOS this is false when it shouldn't be - recent.gui_geometry_main_maximized = isMaximized(); - } - - if (master_split_.sizes().length() > 0) { - recent.gui_geometry_main_upper_pane = master_split_.sizes()[0]; - } - - if (master_split_.sizes().length() > 2) { - recent.gui_geometry_main_lower_pane = master_split_.sizes()[1]; - } else if (extra_split_.sizes().length() > 0) { - recent.gui_geometry_main_lower_pane = extra_split_.sizes()[0]; - } -} - -// Our event loop becomes nested whenever we call update_progress_dlg, which -// includes several places in file.c. The GTK+ UI stays out of trouble by -// showing a modal progress dialog. We attempt to do the equivalent below by -// disabling parts of the main window. At a minumum the ProgressFrame in the -// main status bar must remain accessible. -// -// We might want to do this any time the main status bar progress frame is -// shown and hidden. -void MainWindow::freeze() -{ - freeze_focus_ = mainApp->focusWidget(); - - // XXX Alternatively we could just disable and enable the main menu. - for (int i = 0; i < freeze_actions_.size(); i++) { - QAction *action = freeze_actions_[i].first; - freeze_actions_[i].second = action->isEnabled(); - action->setEnabled(false); - } - main_ui_->centralWidget->setEnabled(false); -} - -void MainWindow::thaw() -{ - main_ui_->centralWidget->setEnabled(true); - for (int i = 0; i < freeze_actions_.size(); i++) { - freeze_actions_[i].first->setEnabled(freeze_actions_[i].second); - } - - if (freeze_focus_) freeze_focus_->setFocus(); - freeze_focus_ = NULL; -} - -void MainWindow::mergeCaptureFile() -{ - QString file_name = ""; - QString read_filter = ""; - dfilter_t *rfcode = NULL; - int err; - - if (!capture_file_.capFile()) - return; - - if (prefs.gui_ask_unsaved) { - if (cf_has_unsaved_data(capture_file_.capFile())) { - QMessageBox msg_dialog; - gchar *display_basename; - int response; - - msg_dialog.setIcon(QMessageBox::Question); - /* This file has unsaved data; ask the user whether to save - the capture. */ - if (capture_file_.capFile()->is_tempfile) { - msg_dialog.setText(tr("Save packets before merging?")); - msg_dialog.setInformativeText(tr("A temporary capture file can't be merged.")); - } else { - /* - * Format the message. - */ - display_basename = g_filename_display_basename(capture_file_.capFile()->filename); - msg_dialog.setText(QString(tr("Save changes in \"%1\" before merging?")).arg(display_basename)); - g_free(display_basename); - msg_dialog.setInformativeText(tr("Changes must be saved before the files can be merged.")); - } - - msg_dialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); - msg_dialog.setDefaultButton(QMessageBox::Save); - - response = msg_dialog.exec(); - - switch (response) { - - case QMessageBox::Save: - /* Save the file but don't close it */ - saveCaptureFile(capture_file_.capFile(), false); - break; - - case QMessageBox::Cancel: - default: - /* Don't do the merge. */ - return; - } - } - } - - for (;;) { - CaptureFileDialog merge_dlg(this, capture_file_.capFile(), read_filter); - int file_type; - cf_status_t merge_status; - char *in_filenames[2]; - char *tmpname; - - if (merge_dlg.merge(file_name)) { - gchar *err_msg; - - if (!dfilter_compile(qUtf8Printable(read_filter), &rfcode, &err_msg)) { - /* Not valid. Tell the user, and go back and run the file - selection box again once they dismiss the alert. */ - // Similar to commandline_info.jfilter section in main(). - QMessageBox::warning(this, tr("Invalid Read Filter"), - QString(tr("The filter expression %1 isn't a valid read filter. (%2).").arg(read_filter, err_msg)), - QMessageBox::Ok); - g_free(err_msg); - continue; - } - } else { - return; - } - - file_type = capture_file_.capFile()->cd_t; - - /* Try to merge or append the two files */ - if (merge_dlg.mergeType() == 0) { - /* chronological order */ - in_filenames[0] = g_strdup(capture_file_.capFile()->filename); - in_filenames[1] = qstring_strdup(file_name); - merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, FALSE); - } else if (merge_dlg.mergeType() <= 0) { - /* prepend file */ - in_filenames[0] = qstring_strdup(file_name); - in_filenames[1] = g_strdup(capture_file_.capFile()->filename); - merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, TRUE); - } else { - /* append file */ - in_filenames[0] = g_strdup(capture_file_.capFile()->filename); - in_filenames[1] = qstring_strdup(file_name); - merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, TRUE); - } - - g_free(in_filenames[0]); - g_free(in_filenames[1]); - - if (merge_status != CF_OK) { - dfilter_free(rfcode); - g_free(tmpname); - continue; - } - - cf_close(capture_file_.capFile()); - - /* Try to open the merged capture file. */ - CaptureFile::globalCapFile()->window = this; - if (cf_open(CaptureFile::globalCapFile(), tmpname, WTAP_TYPE_AUTO, TRUE /* temporary file */, &err) != CF_OK) { - /* We couldn't open it; fail. */ - CaptureFile::globalCapFile()->window = NULL; - dfilter_free(rfcode); - g_free(tmpname); - return; - } - - /* Attach the new read filter to "cf" ("cf_open()" succeeded, so - it closed the previous capture file, and thus destroyed any - previous read filter attached to "cf"). */ - cf_set_rfcode(CaptureFile::globalCapFile(), rfcode); - - switch (cf_read(CaptureFile::globalCapFile(), FALSE)) { - - case CF_READ_OK: - case CF_READ_ERROR: - /* Just because we got an error, that doesn't mean we were unable - to read any of the file; we handle what we could get from the - file. */ - break; - - case CF_READ_ABORTED: - /* The user bailed out of re-reading the capture file; the - capture file has been closed - just free the capture file name - string and return (without changing the last containing - directory). */ - g_free(tmpname); - return; - } - - /* Save the name of the containing directory specified in the path name. */ - mainApp->setLastOpenDirFromFilename(tmpname); - g_free(tmpname); - main_ui_->statusBar->showExpert(); - return; - } - -} - -void MainWindow::importCaptureFile() { - ImportTextDialog import_dlg; - - QString before_what(tr(" before importing a capture")); - if (!testCaptureFileClose(before_what)) - return; - - import_dlg.exec(); - - if (import_dlg.result() != QDialog::Accepted) { - showWelcome(); - return; - } - - openCaptureFile(import_dlg.capfileName()); -} - -bool MainWindow::saveCaptureFile(capture_file *cf, bool dont_reopen) { - QString file_name; - gboolean discard_comments; - - if (cf->is_tempfile) { - /* This is a temporary capture file, so saving it means saving - it to a permanent file. Prompt the user for a location - to which to save it. Don't require that the file format - support comments - if it's a temporary capture file, it's - probably pcapng, which supports comments and, if it's - not pcapng, let the user decide what they want to do - if they've added comments. */ - return saveAsCaptureFile(cf, FALSE, dont_reopen); - } else { - if (cf->unsaved_changes) { - cf_write_status_t status; - - /* This is not a temporary capture file, but it has unsaved - changes, so saving it means doing a "safe save" on top - of the existing file, in the same format - no UI needed - unless the file has comments and the file's format doesn't - support them. - - If the file has comments, does the file's format support them? - If not, ask the user whether they want to discard the comments - or choose a different format. */ - switch (CaptureFileDialog::checkSaveAsWithComments(this, cf, cf->cd_t)) { - - case SAVE: - /* The file can be saved in the specified format as is; - just drive on and save in the format they selected. */ - discard_comments = FALSE; - break; - - case SAVE_WITHOUT_COMMENTS: - /* The file can't be saved in the specified format as is, - but it can be saved without the comments, and the user - said "OK, discard the comments", so save it in the - format they specified without the comments. */ - discard_comments = TRUE; - break; - - case SAVE_IN_ANOTHER_FORMAT: - /* There are file formats in which we can save this that - support comments, and the user said not to delete the - comments. Do a "Save As" so the user can select - one of those formats and choose a file name. */ - return saveAsCaptureFile(cf, TRUE, dont_reopen); - - case CANCELLED: - /* The user said "forget it". Just return. */ - return false; - - default: - /* Squelch warnings that discard_comments is being used - uninitialized. */ - ws_assert_not_reached(); - return false; - } - - /* XXX - cf->filename might get freed out from under us, because - the code path through which cf_save_records() goes currently - closes the current file and then opens and reloads the saved file, - so make a copy and free it later. */ - file_name = cf->filename; - status = cf_save_records(cf, qUtf8Printable(file_name), cf->cd_t, cf->compression_type, - discard_comments, dont_reopen); - switch (status) { - - case CF_WRITE_OK: - /* The save succeeded; we're done. - If we discarded comments, redraw the packet list to reflect - any packets that no longer have comments. */ - if (discard_comments) - packet_list_queue_draw(); - - cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes - updateForUnsavedChanges(); // we update the title bar to remove the * - break; - - case CF_WRITE_ERROR: - /* The write failed. - XXX - OK, what do we do now? Let them try a - "Save As", in case they want to try to save to a - different directory or file system? */ - break; - - case CF_WRITE_ABORTED: - /* The write was aborted; just drive on. */ - return false; - } - } - /* Otherwise just do nothing. */ - } - - return true; -} - -bool MainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool dont_reopen) { - QString file_name = ""; - int file_type; - wtap_compression_type compression_type; - cf_write_status_t status; - gchar *dirname; - gboolean discard_comments = FALSE; - - if (!cf) { - return false; - } - - for (;;) { - CaptureFileDialog save_as_dlg(this, cf); - - /* If the file has comments, does the format the user selected - support them? If not, ask the user whether they want to - discard the comments or choose a different format. */ - switch (save_as_dlg.saveAs(file_name, must_support_comments)) { - - case SAVE: - /* The file can be saved in the specified format as is; - just drive on and save in the format they selected. */ - discard_comments = FALSE; - break; - - case SAVE_WITHOUT_COMMENTS: - /* The file can't be saved in the specified format as is, - but it can be saved without the comments, and the user - said "OK, discard the comments", so save it in the - format they specified without the comments. */ - discard_comments = TRUE; - break; - - case SAVE_IN_ANOTHER_FORMAT: - /* There are file formats in which we can save this that - support comments, and the user said not to delete the - comments. The combo box of file formats has had the - formats that don't support comments trimmed from it, - so run the dialog again, to let the user decide - whether to save in one of those formats or give up. */ - must_support_comments = TRUE; - continue; - - case CANCELLED: - /* The user said "forget it". Just get rid of the dialog box - and return. */ - return false; - } - file_type = save_as_dlg.selectedFileType(); - if (file_type == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) { - /* This "should not happen". */ - QMessageBox msg_dialog; - - msg_dialog.setIcon(QMessageBox::Critical); - msg_dialog.setText(tr("Unknown file type returned by merge dialog.")); - msg_dialog.setInformativeText(tr("Please report this as a Wireshark issue at https://gitlab.com/wireshark/wireshark/-/issues.")); - msg_dialog.exec(); - return false; - } - compression_type = save_as_dlg.compressionType(); - -#ifdef Q_OS_WIN - // the Windows dialog does not fixup extensions, do it manually here. - fileAddExtension(file_name, file_type, compression_type); -#endif // Q_OS_WIN - -//#ifndef _WIN32 -// /* If the file exists and it's user-immutable or not writable, -// ask the user whether they want to override that. */ -// if (!file_target_unwritable_ui(top_level, qUtf8Printable(file_name))) { -// /* They don't. Let them try another file name or cancel. */ -// continue; -// } -//#endif - - /* Attempt to save the file */ - status = cf_save_records(cf, qUtf8Printable(file_name), file_type, compression_type, - discard_comments, dont_reopen); - switch (status) { - - case CF_WRITE_OK: - /* The save succeeded; we're done. */ - /* Save the directory name for future file dialogs. */ - dirname = qstring_strdup(file_name); /* Overwrites cf_name */ - set_last_open_dir(get_dirname(dirname)); - g_free(dirname); - /* If we discarded comments, redraw the packet list to reflect - any packets that no longer have comments. */ - if (discard_comments) - packet_list_queue_draw(); - - cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes - updateForUnsavedChanges(); // we update the title bar to remove the * - /* Add this filename to the list of recent files in the "Recent Files" submenu */ - add_menu_recent_capture_file(qUtf8Printable(file_name)); - return true; - - case CF_WRITE_ERROR: - /* The save failed; let the user try again. */ - continue; - - case CF_WRITE_ABORTED: - /* The user aborted the save; just return. */ - return false; - } - } - return true; -} - -void MainWindow::exportSelectedPackets() { - QString file_name = ""; - int file_type; - wtap_compression_type compression_type; - packet_range_t range; - cf_write_status_t status; - gchar *dirname; - bool discard_comments = false; - - if (!capture_file_.capFile()) - return; - - /* Init the packet range */ - packet_range_init(&range, capture_file_.capFile()); - range.process_filtered = TRUE; - range.include_dependents = TRUE; - - QList rows = packet_list_->selectedRows(true); - - QStringList entries; - foreach (int row, rows) - entries << QString::number(row); - QString selRange = entries.join(","); - - for (;;) { - CaptureFileDialog esp_dlg(this, capture_file_.capFile()); - - /* If the file has comments, does the format the user selected - support them? If not, ask the user whether they want to - discard the comments or choose a different format. */ - switch (esp_dlg.exportSelectedPackets(file_name, &range, selRange)) { - - case SAVE: - /* The file can be saved in the specified format as is; - just drive on and save in the format they selected. */ - discard_comments = FALSE; - break; - - case SAVE_WITHOUT_COMMENTS: - /* The file can't be saved in the specified format as is, - but it can be saved without the comments, and the user - said "OK, discard the comments", so save it in the - format they specified without the comments. */ - discard_comments = TRUE; - break; - - case SAVE_IN_ANOTHER_FORMAT: - /* There are file formats in which we can save this that - support comments, and the user said not to delete the - comments. The combo box of file formats has had the - formats that don't support comments trimmed from it, - so run the dialog again, to let the user decide - whether to save in one of those formats or give up. */ - continue; - - case CANCELLED: - /* The user said "forget it". Just get rid of the dialog box - and return. */ - goto cleanup; - } - - /* - * Check that we're not going to save on top of the current - * capture file. - * We do it here so we catch all cases ... - * Unfortunately, the file requester gives us an absolute file - * name and the read file name may be relative (if supplied on - * the command line). From Joerg Mayer. - */ - if (files_identical(capture_file_.capFile()->filename, qUtf8Printable(file_name))) { - QMessageBox msg_box; - gchar *display_basename = g_filename_display_basename(qUtf8Printable(file_name)); - - msg_box.setIcon(QMessageBox::Critical); - msg_box.setText(QString(tr("Unable to export to \"%1\".").arg(display_basename))); - msg_box.setInformativeText(tr("You cannot export packets to the current capture file.")); - msg_box.setStandardButtons(QMessageBox::Ok); - msg_box.setDefaultButton(QMessageBox::Ok); - msg_box.exec(); - g_free(display_basename); - continue; - } - - file_type = esp_dlg.selectedFileType(); - if (file_type == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) { - /* This "should not happen". */ - QMessageBox msg_box; - - msg_box.setIcon(QMessageBox::Critical); - msg_box.setText(tr("Unknown file type returned by export dialog.")); - msg_box.setInformativeText(tr("Please report this as a Wireshark issue at https://gitlab.com/wireshark/wireshark/-/issues.")); - msg_box.exec(); - goto cleanup; - } - compression_type = esp_dlg.compressionType(); -#ifdef Q_OS_WIN - // the Windows dialog does not fixup extensions, do it manually here. - fileAddExtension(file_name, file_type, compression_type); -#endif // Q_OS_WIN - -//#ifndef _WIN32 -// /* If the file exists and it's user-immutable or not writable, -// ask the user whether they want to override that. */ -// if (!file_target_unwritable_ui(top_level, qUtf8Printable(file_name))) { -// /* They don't. Let them try another file name or cancel. */ -// continue; -// } -//#endif - - /* Attempt to save the file */ - status = cf_export_specified_packets(capture_file_.capFile(), qUtf8Printable(file_name), &range, file_type, compression_type); - switch (status) { - - case CF_WRITE_OK: - /* The save succeeded; we're done. */ - /* Save the directory name for future file dialogs. */ - dirname = qstring_strdup(file_name); /* Overwrites cf_name */ - set_last_open_dir(get_dirname(dirname)); - g_free(dirname); - /* If we discarded comments, redraw the packet list to reflect - any packets that no longer have comments. */ - if (discard_comments) - packet_list_queue_draw(); - /* Add this filename to the list of recent files in the "Recent Files" submenu */ - add_menu_recent_capture_file(qUtf8Printable(file_name)); - goto cleanup; - - case CF_WRITE_ERROR: - /* The save failed; let the user try again. */ - continue; - - case CF_WRITE_ABORTED: - /* The user aborted the save; just return. */ - goto cleanup; - } - } - -cleanup: - packet_range_cleanup(&range); -} - -void MainWindow::exportDissections(export_type_e export_type) { - capture_file *cf = capture_file_.capFile(); - g_return_if_fail(cf); - - QList rows = packet_list_->selectedRows(true); - - QStringList entries; - foreach (int row, rows) - entries << QString::number(row); - QString selRange = entries.join(","); - - ExportDissectionDialog *ed_dlg = new ExportDissectionDialog(this, cf, export_type, selRange); - ed_dlg->setWindowModality(Qt::ApplicationModal); - ed_dlg->setAttribute(Qt::WA_DeleteOnClose); - ed_dlg->show(); -} - -#ifdef Q_OS_WIN -/* - * Ensure that: - * - * If the file is to be compressed: - * - * if there is a set of extensions used by the file type to be used, - * the file name has one of those extensions followed by the extension - * for the compression type to be used; - * - * otherwise, the file name has the extension for the compression type - * to be used; - * - * otherwise: - * - * if there is a set of extensions used by the file type to be used, - * the file name has one of those extensions. - */ -void MainWindow::fileAddExtension(QString &file_name, int file_type, wtap_compression_type compression_type) { - QString file_name_lower; - GSList *extensions_list; - const char *compressed_file_extension; - gboolean add_extension_for_file_type; - - /* Lower-case the file name, so the extension matching is case-insensitive. */ - file_name_lower = file_name.toLower(); - - /* Get a list of all extensions used for this file type; don't - include the ones with compression type extensions, as we - only want to check for the extension for the compression - type we'll be using. */ - extensions_list = wtap_get_file_extensions_list(file_type, FALSE); - - /* Get the extension for the compression type we'll be using; - NULL is returned if the type isn't supported or compression - is not being done. */ - compressed_file_extension = wtap_compression_type_extension(compression_type); - - if (extensions_list != NULL) { - GSList *extension; - - /* This file type has one or more extensions. - Start out assuming we need to add the default one. */ - add_extension_for_file_type = TRUE; - - /* OK, see if the file has one of those extensions, followed - by the appropriate compression type extension if it's to be - compressed. */ - for (extension = extensions_list; extension != NULL; - extension = g_slist_next(extension)) { - QString file_suffix = QString(".") + (char *)extension->data; - if (compressed_file_extension != NULL) - file_suffix += QString(".") + compressed_file_extension; - if (file_name_lower.endsWith(file_suffix)) { - /* - * The file name has one of the extensions for this file - * type, followed by a compression type extension if - * appropriate, so we don't need to add an extension for - * the file type or the compression type. - */ - add_extension_for_file_type = FALSE; - break; - } - } - } else { - /* We have no extensions for this file type. Just check - to see if we need to add an extension for the compressed - file type. - - Start out assuming we do. */ - add_extension_for_file_type = TRUE; - if (compressed_file_extension != NULL) { - QString file_suffix = QString(".") + compressed_file_extension; - if (file_name_lower.endsWith(file_suffix)) { - /* - * The file name has the appropriate compressed file extension, - * so we don't need to add an extension for the compression - * type. - */ - add_extension_for_file_type = FALSE; - } - } - } - - /* - * If we need to add an extension for the file type or compressed - * file type, do so. - */ - if (add_extension_for_file_type) { - if (wtap_default_file_extension(file_type) != NULL) { - /* This file type has a default extension; append it. */ - file_name += QString(".") + wtap_default_file_extension(file_type); - } - if (compression_type != WTAP_UNCOMPRESSED) { - /* - * The file is to be compressed, so append the extension for - * its compression type. - */ - file_name += QString(".") + compressed_file_extension; - } - } -} -#endif // Q_OS_WIN - -bool MainWindow::testCaptureFileClose(QString before_what, FileCloseContext context) { - bool capture_in_progress = false; - bool do_close_file = false; - - if (!capture_file_.capFile() || capture_file_.capFile()->state == FILE_CLOSED) - return true; /* Already closed, nothing to do */ - - if (capture_file_.capFile()->read_lock) { - /* - * If the file is being redissected, we cannot stop the capture since - * that would crash and burn "cf_read", so stop early. Ideally all - * callers should be modified to check this condition and act - * accordingly (ignore action or queue it up), so print a warning. - */ - ws_warning("Refusing to close \"%s\" which is being read.", capture_file_.capFile()->filename); - return false; - } - -#ifdef HAVE_LIBPCAP - if (capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { - /* - * This (FILE_READ_IN_PROGRESS) is true if we're reading a capture file - * *or* if we're doing a live capture. From the capture file itself we - * cannot differentiate the cases, so check the current capture session. - */ - capture_in_progress = captureSession()->state != CAPTURE_STOPPED; - } -#endif - - if (prefs.gui_ask_unsaved) { - if (cf_has_unsaved_data(capture_file_.capFile())) { - QMessageBox msg_dialog; - QString question; - QString infotext; - QPushButton *save_button; - QPushButton *discard_button; - - msg_dialog.setIcon(QMessageBox::Question); - msg_dialog.setWindowTitle("Unsaved packets" UTF8_HORIZONTAL_ELLIPSIS); - - /* This file has unsaved data or there's a capture in - progress; ask the user whether to save the data. */ - if (capture_in_progress && context != Restart) { - question = tr("Do you want to stop the capture and save the captured packets%1?").arg(before_what); - infotext = tr("Your captured packets will be lost if you don't save them."); - } else if (capture_file_.capFile()->is_tempfile) { - if (context == Reload) { - // Reloading a tempfile will keep the packets, so this is not unsaved packets - question = tr("Do you want to save the changes you've made%1?").arg(before_what); - infotext = tr("Your changes will be lost if you don't save them."); - } else { - question = tr("Do you want to save the captured packets%1?").arg(before_what); - infotext = tr("Your captured packets will be lost if you don't save them."); - } - } else { - // No capture in progress and not a tempfile, so this is not unsaved packets - gchar *display_basename = g_filename_display_basename(capture_file_.capFile()->filename); - question = tr("Do you want to save the changes you've made to the capture file \"%1\"%2?").arg(display_basename, before_what); - infotext = tr("Your changes will be lost if you don't save them."); - g_free(display_basename); - } - - msg_dialog.setText(question); - msg_dialog.setInformativeText(infotext); - - // XXX Text comes from ui/gtk/stock_icons.[ch] - // Note that the button roles differ from the GTK+ version. - // Cancel = RejectRole - // Save = AcceptRole - // Don't Save = DestructiveRole - msg_dialog.addButton(QMessageBox::Cancel); - - if (capture_in_progress) { - QString save_button_text; - if (context == Restart) { - save_button_text = tr("Save before Continue"); - } else { - save_button_text = tr("Stop and Save"); - } - save_button = msg_dialog.addButton(save_button_text, QMessageBox::AcceptRole); - } else { - save_button = msg_dialog.addButton(QMessageBox::Save); - } - msg_dialog.setDefaultButton(save_button); - - QString discard_button_text; - if (capture_in_progress) { - switch (context) { - case Quit: - discard_button_text = tr("Stop and Quit &without Saving"); - break; - case Restart: - discard_button_text = tr("Continue &without Saving"); - break; - default: - discard_button_text = tr("Stop and Continue &without Saving"); - break; - } - } else { - switch (context) { - case Quit: - discard_button_text = tr("Quit &without Saving"); - break; - case Restart: - default: - discard_button_text = tr("Continue &without Saving"); - break; - } - } - discard_button = msg_dialog.addButton(discard_button_text, QMessageBox::DestructiveRole); - -#if defined(Q_OS_MAC) - /* - * In macOS, the "default button" is not necessarily the - * button that has the input focus; Enter/Return activates - * the default button, and the spacebar activates the button - * that has the input focus, and they might be different - * buttons. - * - * In a "do you want to save" dialog, for example, the - * "save" button is the default button, and the "don't - * save" button has the input focus, so you can press - * Enter/Return to save or space not to save (or Escape - * to dismiss the dialog). - * - * In Qt terms, this means "no auto-default", as auto-default - * makes the button with the input focus the default button, - * so that Enter/Return will activate it. - */ - QList buttons = msg_dialog.buttons(); - for (int i = 0; i < buttons.size(); ++i) { - QPushButton *button = static_cast(buttons.at(i));; - button->setAutoDefault(false); - } - - /* - * It also means that the "don't save" button should be the one - * initially given the focus. - */ - discard_button->setFocus(); -#endif - - msg_dialog.exec(); - /* According to the Qt doc: - * when using QMessageBox with custom buttons, exec() function returns an opaque value. - * - * Therefore we should use clickedButton() to determine which button was clicked. */ - - if (msg_dialog.clickedButton() == save_button) { -#ifdef HAVE_LIBPCAP - /* If there's a capture in progress, we have to stop the capture - and then do the save. */ - if (capture_in_progress) - captureStop(); -#endif - /* Save the file and close it */ - // XXX if no packets were captured, any unsaved comments set by - // the user are silently discarded because capFile() is null. - if (capture_file_.capFile() && saveCaptureFile(capture_file_.capFile(), true) == false) - return false; - do_close_file = true; - } else if (msg_dialog.clickedButton() == discard_button) { - /* Just close the file, discarding changes */ - do_close_file = true; - } else { - // cancelButton or some other unspecified button - return false; - } - } else { - /* Unchanged file or capturing with no packets */ - do_close_file = true; - } - } else { - /* User asked not to be bothered by those prompts, just close it. - XXX - should that apply only to saving temporary files? */ - do_close_file = true; - } - - /* - * Are we done with this file and should we close the file? - */ - if (do_close_file) { -#ifdef HAVE_LIBPCAP - /* If there's a capture in progress, we have to stop the capture - and then do the close. */ - if (capture_in_progress) - captureStop(); - else if (capture_file_.capFile() && capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { - /* - * When an offline capture is being read, mark it as aborted. - * cf_read will be responsible for actually closing the capture. - * - * We cannot just invoke cf_close here since cf_read is up in the - * call chain. (update_progress_dlg can end up processing the Quit - * event from the user which then ends up here.) - * See also the above "read_lock" check. - */ - capture_file_.capFile()->state = FILE_READ_ABORTED; - return true; - } -#endif - /* Clear MainWindow file name details */ - gbl_cur_main_window_->setMwFileName(""); - - /* captureStop() will close the file if not having any packets */ - if (capture_file_.capFile() && context != Restart && context != Reload) - // Don't really close if Restart or Reload - cf_close(capture_file_.capFile()); - } - - return true; /* File closed */ -} - -void MainWindow::captureStop() { - stopCapture(); - - while (capture_file_.capFile() && capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { - WiresharkApplication::processEvents(); - } -} - -void MainWindow::findTextCodecs() { - const QList mibs = QTextCodec::availableMibs(); - QRegularExpression ibmRegExp("^IBM([0-9]+).*$"); - QRegularExpression iso8859RegExp("^ISO-8859-([0-9]+).*$"); - QRegularExpression windowsRegExp("^WINDOWS-([0-9]+).*$"); - QRegularExpressionMatch match; - for (int mib : mibs) { - QTextCodec *codec = QTextCodec::codecForMib(mib); - QString key = codec->name().toUpper(); - char rank; - - if (key.localeAwareCompare("IBM") < 0) { - rank = 1; - } else if ((match = ibmRegExp.match(key)).hasMatch()) { - rank = match.captured(1).size(); // Up to 5 - } else if (key.localeAwareCompare("ISO-8859-") < 0) { - rank = 6; - } else if ((match = iso8859RegExp.match(key)).hasMatch()) { - rank = 6 + match.captured(1).size(); // Up to 6 + 2 - } else if (key.localeAwareCompare("WINDOWS-") < 0) { - rank = 9; - } else if ((match = windowsRegExp.match(key)).hasMatch()) { - rank = 9 + match.captured(1).size(); // Up to 9 + 4 - } else { - rank = 14; - } - // This doesn't perfectly well order the IBM codecs because it's - // annoying to properly place IBM00858 and IBM00924 in the middle of - // code page numbers not zero padded to 5 digits. - // We could manipulate the key further to have more commonly used - // charsets earlier. IANA MIB ordering would be unxpected: - // https://www.iana.org/assignments/character-sets/character-sets.xml - // For data about use in HTTP (other protocols can be quite different): - // https://w3techs.com/technologies/overview/character_encoding - - key.prepend(char('0' + rank)); - // We use a map here because, due to backwards compatibility, - // the same QTextCodec may be returned for multiple MIBs, which - // happens for GBK/GB2312, EUC-KR/windows-949/UHC, and others. - text_codec_map_.insert(key, codec); - } -} - -void MainWindow::initMainToolbarIcons() -{ - // Normally 16 px. Reflects current GTK+ behavior and other Windows apps. - int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); -#if !defined(Q_OS_WIN) - // Force icons to 24x24 for now, otherwise actionFileOpen looks wonky. - // The macOS HIG specifies 32-pixel icons but they're a little too - // large IMHO. - icon_size = icon_size * 3 / 2; -#endif - main_ui_->mainToolBar->setIconSize(QSize(icon_size, icon_size)); - - // Toolbar actions. The GNOME HIG says that we should have a menu icon for each - // toolbar item but that clutters up our menu. Set menu icons sparingly. - - main_ui_->actionCaptureStart->setIcon(StockIcon("x-capture-start")); - main_ui_->actionCaptureStop->setIcon(StockIcon("x-capture-stop")); - main_ui_->actionCaptureRestart->setIcon(StockIcon("x-capture-restart")); - main_ui_->actionCaptureOptions->setIcon(StockIcon("x-capture-options")); - - // Menu icons are disabled in main_window.ui for these items. - main_ui_->actionFileOpen->setIcon(StockIcon("document-open")); - main_ui_->actionFileSave->setIcon(StockIcon("x-capture-file-save")); - main_ui_->actionFileClose->setIcon(StockIcon("x-capture-file-close")); - main_ui_->actionViewReload->setIcon(StockIcon("x-capture-file-reload")); - - main_ui_->actionEditFindPacket->setIcon(StockIcon("edit-find")); - main_ui_->actionGoPreviousPacket->setIcon(StockIcon("go-previous")); - main_ui_->actionGoNextPacket->setIcon(StockIcon("go-next")); - main_ui_->actionGoGoToPacket->setIcon(StockIcon("go-jump")); - main_ui_->actionGoFirstPacket->setIcon(StockIcon("go-first")); - main_ui_->actionGoLastPacket->setIcon(StockIcon("go-last")); - main_ui_->actionGoPreviousConversationPacket->setIcon(StockIcon("go-previous")); - main_ui_->actionGoNextConversationPacket->setIcon(StockIcon("go-next")); -#if defined(Q_OS_MAC) - main_ui_->actionGoPreviousConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Comma)); - main_ui_->actionGoNextConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Period)); -#endif - main_ui_->actionGoPreviousHistoryPacket->setIcon(StockIcon("go-previous")); - main_ui_->actionGoNextHistoryPacket->setIcon(StockIcon("go-next")); - main_ui_->actionGoAutoScroll->setIcon(StockIcon("x-stay-last")); - - main_ui_->actionViewColorizePacketList->setIcon(StockIcon("x-colorize-packets")); - - QList zi_seq = main_ui_->actionViewZoomIn->shortcuts(); - zi_seq << QKeySequence(Qt::CTRL | Qt::Key_Equal); - main_ui_->actionViewZoomIn->setIcon(StockIcon("zoom-in")); - main_ui_->actionViewZoomIn->setShortcuts(zi_seq); - main_ui_->actionViewZoomOut->setIcon(StockIcon("zoom-out")); - main_ui_->actionViewNormalSize->setIcon(StockIcon("zoom-original")); - main_ui_->actionViewResizeColumns->setIcon(StockIcon("x-resize-columns")); - - main_ui_->actionNewDisplayFilterExpression->setIcon(StockIcon("list-add")); -} - -void MainWindow::initShowHideMainWidgets() -{ - if (show_hide_actions_) { - return; - } - - show_hide_actions_ = new QActionGroup(this); - QMap shmw_actions; - - show_hide_actions_->setExclusive(false); - shmw_actions[main_ui_->actionViewMainToolbar] = main_ui_->mainToolBar; - shmw_actions[main_ui_->actionViewFilterToolbar] = main_ui_->displayFilterToolBar; -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) - shmw_actions[main_ui_->actionViewWirelessToolbar] = main_ui_->wirelessToolBar; -#endif - shmw_actions[main_ui_->actionViewStatusBar] = main_ui_->statusBar; - shmw_actions[main_ui_->actionViewPacketList] = packet_list_; - shmw_actions[main_ui_->actionViewPacketDetails] = proto_tree_; - shmw_actions[main_ui_->actionViewPacketBytes] = byte_view_tab_; - shmw_actions[main_ui_->actionViewPacketDiagram] = packet_diagram_; - - foreach(QAction *shmwa, shmw_actions.keys()) { - shmwa->setData(QVariant::fromValue(shmw_actions[shmwa])); - show_hide_actions_->addAction(shmwa); - } - - // Initial hide the Interface Toolbar submenu - main_ui_->menuInterfaceToolbars->menuAction()->setVisible(false); - - /* Initially hide the additional toolbars menus */ - main_ui_->menuAdditionalToolbars->menuAction()->setVisible(false); - - connect(show_hide_actions_, SIGNAL(triggered(QAction*)), this, SLOT(showHideMainWidgets(QAction*))); -} - -void MainWindow::initTimeDisplayFormatMenu() -{ - if (time_display_actions_) { - return; - } - - time_display_actions_ = new QActionGroup(this); - - td_actions[main_ui_->actionViewTimeDisplayFormatDateYMDandTimeOfDay] = TS_ABSOLUTE_WITH_YMD; - td_actions[main_ui_->actionViewTimeDisplayFormatDateYDOYandTimeOfDay] = TS_ABSOLUTE_WITH_YDOY; - td_actions[main_ui_->actionViewTimeDisplayFormatTimeOfDay] = TS_ABSOLUTE; - td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSinceEpoch] = TS_EPOCH; - td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSinceBeginningOfCapture] = TS_RELATIVE; - td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSincePreviousCapturedPacket] = TS_DELTA; - td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSincePreviousDisplayedPacket] = TS_DELTA_DIS; - td_actions[main_ui_->actionViewTimeDisplayFormatUTCDateYMDandTimeOfDay] = TS_UTC_WITH_YMD; - td_actions[main_ui_->actionViewTimeDisplayFormatUTCDateYDOYandTimeOfDay] = TS_UTC_WITH_YDOY; - td_actions[main_ui_->actionViewTimeDisplayFormatUTCTimeOfDay] = TS_UTC; - - foreach(QAction* tda, td_actions.keys()) { - tda->setData(QVariant::fromValue(td_actions[tda])); - time_display_actions_->addAction(tda); - } - - connect(time_display_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setTimestampFormat(QAction*))); -} - -void MainWindow::initTimePrecisionFormatMenu() -{ - if (time_precision_actions_) { - return; - } - - time_precision_actions_ = new QActionGroup(this); - - tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionAutomatic] = TS_PREC_AUTO; - tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionSeconds] = TS_PREC_FIXED_SEC; - tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionDeciseconds] = TS_PREC_FIXED_DSEC; - tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionCentiseconds] = TS_PREC_FIXED_CSEC; - tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionMilliseconds] = TS_PREC_FIXED_MSEC; - tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionMicroseconds] = TS_PREC_FIXED_USEC; - tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionNanoseconds] = TS_PREC_FIXED_NSEC; - - foreach(QAction* tpa, tp_actions.keys()) { - tpa->setData(QVariant::fromValue(tp_actions[tpa])); - time_precision_actions_->addAction(tpa); - } - - connect(time_precision_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setTimestampPrecision(QAction*))); -} - -// Menu items which will be disabled when we freeze() and whose state will -// be restored when we thaw(). Add to the list as needed. -void MainWindow::initFreezeActions() -{ - QList freeze_actions = QList() - << main_ui_->actionFileClose - << main_ui_->actionViewReload - << main_ui_->actionEditMarkPacket - << main_ui_->actionEditMarkAllDisplayed - << main_ui_->actionEditUnmarkAllDisplayed - << main_ui_->actionEditIgnorePacket - << main_ui_->actionEditIgnoreAllDisplayed - << main_ui_->actionEditUnignoreAllDisplayed - << main_ui_->actionEditSetTimeReference - << main_ui_->actionEditUnsetAllTimeReferences; - - foreach(QAction *action, freeze_actions) { - freeze_actions_ << QPair(action, false); - } -} - -void MainWindow::initConversationMenus() -{ - int i; - - QList cc_actions = QList() - << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2 - << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4 - << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6 - << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8 - << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10; - - for (GList *conv_filter_list_entry = conv_filter_list; conv_filter_list_entry; conv_filter_list_entry = gxx_list_next(conv_filter_list_entry)) { - // Main menu items - conversation_filter_t* conv_filter = gxx_list_data(conversation_filter_t *, conv_filter_list_entry); - ConversationAction *conv_action = new ConversationAction(main_ui_->menuConversationFilter, conv_filter); - main_ui_->menuConversationFilter->addAction(conv_action); - - connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); - connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter())); - - // Packet list context menu items - packet_list_->conversationMenu()->addAction(conv_action); - - QMenu *submenu = packet_list_->colorizeMenu()->addMenu(conv_action->text()); - i = 1; - - foreach(QAction *cc_action, cc_actions) { - conv_action = new ConversationAction(submenu, conv_filter); - conv_action->setText(cc_action->text()); - conv_action->setIcon(cc_action->icon()); - conv_action->setColorNumber(i++); - submenu->addAction(conv_action); - connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); - connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); - } - - conv_action = new ConversationAction(submenu, conv_filter); - conv_action->setText(main_ui_->actionViewColorizeNewColoringRule->text()); - submenu->addAction(conv_action); - connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); - connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); - - // Proto tree conversation menu is filled in in ProtoTree::contextMenuEvent. - // We should probably do that here. - } - - // Proto tree colorization items - i = 1; - ColorizeAction *colorize_action; - foreach(QAction *cc_action, cc_actions) { - colorize_action = new ColorizeAction(proto_tree_->colorizeMenu()); - colorize_action->setText(cc_action->text()); - colorize_action->setIcon(cc_action->icon()); - colorize_action->setColorNumber(i++); - proto_tree_->colorizeMenu()->addAction(colorize_action); - connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray))); - connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); - } - - colorize_action = new ColorizeAction(proto_tree_->colorizeMenu()); - colorize_action->setText(main_ui_->actionViewColorizeNewColoringRule->text()); - proto_tree_->colorizeMenu()->addAction(colorize_action); - connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray))); - connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); -} - -gboolean MainWindow::addExportObjectsMenuItem(const void *, void *value, void *userdata) -{ - register_eo_t *eo = (register_eo_t*)value; - MainWindow *window = (MainWindow*)userdata; - - ExportObjectAction *export_action = new ExportObjectAction(window->main_ui_->menuFileExportObjects, eo); - window->main_ui_->menuFileExportObjects->addAction(export_action); - - //initially disable until a file is loaded (then file signals will take over) - export_action->setEnabled(false); - - connect(&window->capture_file_, SIGNAL(captureEvent(CaptureEvent)), export_action, SLOT(captureFileEvent(CaptureEvent))); - connect(export_action, SIGNAL(triggered()), window, SLOT(applyExportObject())); - return FALSE; -} - -void MainWindow::initExportObjectsMenus() -{ - eo_iterate_tables(addExportObjectsMenuItem, this); -} - -// Titlebar -void MainWindow::setTitlebarForCaptureFile() -{ - if (capture_file_.capFile() && capture_file_.capFile()->filename) { - setWSWindowTitle(QString("[*]%1").arg(capture_file_.fileDisplayName())); - // - // XXX - on non-Mac platforms, put in the application - // name? Or do so only for temporary files? - // - if (!capture_file_.capFile()->is_tempfile) { - // - // Set the file path; that way, for macOS, it'll set the - // "proxy icon". - // - setWindowFilePath(capture_file_.filePath()); - } - setWindowModified(cf_has_unsaved_data(capture_file_.capFile())); - } else { - /* We have no capture file. */ - setWSWindowTitle(); - } -} - -QString MainWindow::replaceWindowTitleVariables(QString title) -{ - title.replace("%P", get_profile_name()); - title.replace("%V", get_ws_vcs_version_info()); - - if (title.contains("%F")) { - // %F is file path of the capture file. - if (capture_file_.capFile()) { - // get_dirname() will overwrite the argument so make a copy first - char *filename = g_strdup(capture_file_.capFile()->filename); - QString file(get_dirname(filename)); - g_free(filename); -#ifndef _WIN32 - // Substitute HOME with ~ - QString homedir(g_getenv("HOME")); - if (!homedir.isEmpty()) { - homedir.remove(QRegularExpression("[/]+$")); - file.replace(homedir, "~"); - } -#endif - title.replace("%F", file); - } else { - // No file loaded, no folder name - title.remove("%F"); - } - } - - if (title.contains("%S")) { - // %S is a conditional separator (" - ") that only shows when surrounded by variables - // with values or static text. Remove repeating, leading and trailing separators. - title.replace(QRegularExpression("(%S)+"), "%S"); - title.remove(QRegularExpression("^%S|%S$")); -#ifdef __APPLE__ - // On macOS we separate with a unicode em dash - title.replace("%S", " " UTF8_EM_DASH " "); -#else - title.replace("%S", " - "); -#endif - } - - return title; -} - -void MainWindow::setWSWindowTitle(QString title) -{ - if (title.isEmpty()) { - title = tr("The Wireshark Network Analyzer"); - } - - if (prefs.gui_prepend_window_title && prefs.gui_prepend_window_title[0]) { - QString custom_title = replaceWindowTitleVariables(prefs.gui_prepend_window_title); - if (custom_title.length() > 0) { - title.prepend(QString("[%1] ").arg(custom_title)); - } - } - - if (prefs.gui_window_title && prefs.gui_window_title[0]) { - QString custom_title = replaceWindowTitleVariables(prefs.gui_window_title); - if (custom_title.length() > 0) { -#ifdef __APPLE__ - // On macOS we separate the titles with a unicode em dash - title.append(QString(" %1 %2").arg(UTF8_EM_DASH).arg(custom_title)); -#else - title.append(QString(" [%1]").arg(custom_title)); -#endif - } - } - - setWindowTitle(title); - setWindowFilePath(NULL); -} - -void MainWindow::setTitlebarForCaptureInProgress() -{ - if (capture_file_.capFile()) { - setWSWindowTitle(tr("Capturing from %1").arg(cf_get_tempfile_source(capture_file_.capFile()))); - } else { - /* We have no capture in progress. */ - setWSWindowTitle(); - } -} - -// Menu state - -/* Enable or disable menu items based on whether you have a capture file - you've finished reading and, if you have one, whether it's been saved - and whether it could be saved except by copying the raw packet data. */ -void MainWindow::setMenusForCaptureFile(bool force_disable) -{ - bool enable = true; - bool can_write = false; - bool can_save = false; - bool can_save_as = false; - - if (force_disable || capture_file_.capFile() == NULL || capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { - /* We have no capture file or we're currently reading a file */ - enable = false; - } else { - /* We have a capture file. Can we write or save? */ - can_write = cf_can_write_with_wiretap(capture_file_.capFile()); - can_save = cf_can_save(capture_file_.capFile()); - can_save_as = cf_can_save_as(capture_file_.capFile()); - } - - main_ui_->actionViewReload_as_File_Format_or_Capture->setEnabled(enable); - main_ui_->actionFileMerge->setEnabled(can_write); - main_ui_->actionFileClose->setEnabled(enable); - main_ui_->actionFileSave->setEnabled(can_save); - main_ui_->actionFileSaveAs->setEnabled(can_save_as); - main_ui_->actionStatisticsCaptureFileProperties->setEnabled(enable); - /* - * "Export Specified Packets..." should be available only if - * we can write the file out in at least one format. - */ - main_ui_->actionFileExportPackets->setEnabled(can_write); - - main_ui_->actionFileExportAsCArrays->setEnabled(enable); - main_ui_->actionFileExportAsCSV->setEnabled(enable); - main_ui_->actionFileExportAsPDML->setEnabled(enable); - main_ui_->actionFileExportAsPlainText->setEnabled(enable); - main_ui_->actionFileExportAsPSML->setEnabled(enable); - main_ui_->actionFileExportAsJSON->setEnabled(enable); - - main_ui_->actionFileExportPacketBytes->setEnabled(enable); - main_ui_->actionFileExportPDU->setEnabled(enable); - main_ui_->actionFileStripHeaders->setEnabled(enable); - main_ui_->actionFileExportTLSSessionKeys->setEnabled(enable); - - foreach(QAction *eo_action, main_ui_->menuFileExportObjects->actions()) { - eo_action->setEnabled(enable); - } - - main_ui_->actionViewReload->setEnabled(enable); - -#ifdef HAVE_SOFTWARE_UPDATE - // We might want to enable or disable automatic checks here as well. - update_action_->setEnabled(!can_save); -#endif -} - -void MainWindow::setMenusForCaptureInProgress(bool capture_in_progress) { - /* Either a capture was started or stopped; in either case, it's not - in the process of stopping, so allow quitting. */ - - main_ui_->actionFileOpen->setEnabled(!capture_in_progress); - main_ui_->menuOpenRecentCaptureFile->setEnabled(!capture_in_progress); - - main_ui_->actionFileExportAsCArrays->setEnabled(capture_in_progress); - main_ui_->actionFileExportAsCSV->setEnabled(capture_in_progress); - main_ui_->actionFileExportAsPDML->setEnabled(capture_in_progress); - main_ui_->actionFileExportAsPlainText->setEnabled(capture_in_progress); - main_ui_->actionFileExportAsPSML->setEnabled(capture_in_progress); - main_ui_->actionFileExportAsJSON->setEnabled(capture_in_progress); - - main_ui_->actionFileExportPacketBytes->setEnabled(capture_in_progress); - main_ui_->actionFileExportPDU->setEnabled(!capture_in_progress); - main_ui_->actionFileStripHeaders->setEnabled(!capture_in_progress); - main_ui_->actionFileExportTLSSessionKeys->setEnabled(capture_in_progress); - - foreach(QAction *eo_action, main_ui_->menuFileExportObjects->actions()) { - eo_action->setEnabled(capture_in_progress); - } - - main_ui_->menuFileSet->setEnabled(!capture_in_progress); - main_ui_->actionFileQuit->setEnabled(true); -#ifdef HAVE_SOFTWARE_UPDATE - // We might want to enable or disable automatic checks here as well. - update_action_->setEnabled(!capture_in_progress); -#endif - - main_ui_->actionStatisticsCaptureFileProperties->setEnabled(capture_in_progress); - - // XXX Fix packet list heading menu sensitivity - // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortAscending", - // !capture_in_progress); - // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortDescending", - // !capture_in_progress); - // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/NoSorting", - // !capture_in_progress); - -#ifdef HAVE_LIBPCAP - main_ui_->actionCaptureOptions->setEnabled(!capture_in_progress); - main_ui_->actionCaptureStart->setEnabled(!capture_in_progress); - main_ui_->actionCaptureStart->setChecked(capture_in_progress); - main_ui_->actionCaptureStop->setEnabled(capture_in_progress); - main_ui_->actionCaptureRestart->setEnabled(capture_in_progress); - main_ui_->actionCaptureRefreshInterfaces->setEnabled(!capture_in_progress); -#endif /* HAVE_LIBPCAP */ - -} - -void MainWindow::setMenusForCaptureStopping() { - main_ui_->actionFileQuit->setEnabled(false); -#ifdef HAVE_SOFTWARE_UPDATE - update_action_->setEnabled(false); -#endif - main_ui_->actionStatisticsCaptureFileProperties->setEnabled(false); -#ifdef HAVE_LIBPCAP - main_ui_->actionCaptureStart->setChecked(false); - main_ui_->actionCaptureStop->setEnabled(false); - main_ui_->actionCaptureRestart->setEnabled(false); -#endif /* HAVE_LIBPCAP */ -} - -void MainWindow::setForCapturedPackets(bool have_captured_packets) -{ - main_ui_->actionFilePrint->setEnabled(have_captured_packets); - -// set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/Print", -// have_captured_packets); - - main_ui_->actionEditFindPacket->setEnabled(have_captured_packets); - main_ui_->actionEditFindNext->setEnabled(have_captured_packets); - main_ui_->actionEditFindPrevious->setEnabled(have_captured_packets); - - main_ui_->actionGoGoToPacket->setEnabled(have_captured_packets); - main_ui_->actionGoPreviousPacket->setEnabled(have_captured_packets); - main_ui_->actionGoNextPacket->setEnabled(have_captured_packets); - main_ui_->actionGoFirstPacket->setEnabled(have_captured_packets); - main_ui_->actionGoLastPacket->setEnabled(have_captured_packets); - main_ui_->actionGoNextConversationPacket->setEnabled(have_captured_packets); - main_ui_->actionGoPreviousConversationPacket->setEnabled(have_captured_packets); - - main_ui_->actionViewZoomIn->setEnabled(have_captured_packets); - main_ui_->actionViewZoomOut->setEnabled(have_captured_packets); - main_ui_->actionViewNormalSize->setEnabled(have_captured_packets); - main_ui_->actionViewResizeColumns->setEnabled(have_captured_packets); - - main_ui_->actionStatisticsCaptureFileProperties->setEnabled(have_captured_packets); - main_ui_->actionStatisticsProtocolHierarchy->setEnabled(have_captured_packets); - main_ui_->actionStatisticsIOGraph->setEnabled(have_captured_packets); -} - -void MainWindow::setMenusForFileSet(bool enable_list_files) { - bool enable_next = fileset_get_next() != NULL && enable_list_files; - bool enable_prev = fileset_get_previous() != NULL && enable_list_files; - - main_ui_->actionFileSetListFiles->setEnabled(enable_list_files); - main_ui_->actionFileSetNextFile->setEnabled(enable_next); - main_ui_->actionFileSetPreviousFile->setEnabled(enable_prev); -} - -void MainWindow::setWindowIcon(const QIcon &icon) { - mainApp->setWindowIcon(icon); - QMainWindow::setWindowIcon(icon); -} - -void MainWindow::updateForUnsavedChanges() { - setTitlebarForCaptureFile(); - setMenusForCaptureFile(); -} - -void MainWindow::changeEvent(QEvent* event) -{ - if (0 != event) - { - switch (event->type()) - { - case QEvent::LanguageChange: - main_ui_->retranslateUi(this); - // make sure that the "Clear Menu" item is retranslated - mainApp->emitAppSignal(WiresharkApplication::RecentCapturesChanged); - break; - case QEvent::LocaleChange: { - QString locale = QLocale::system().name(); - locale.truncate(locale.lastIndexOf('_')); - mainApp->loadLanguage(locale); - } - break; - case QEvent::WindowStateChange: - main_ui_->actionViewFullScreen->setChecked(this->isFullScreen()); - break; - default: - break; - } - } - QMainWindow::changeEvent(event); -} - -/* Update main window items based on whether there's a capture in progress. */ -void MainWindow::setForCaptureInProgress(bool capture_in_progress, bool handle_toolbars, GArray *ifaces) -{ - setMenusForCaptureInProgress(capture_in_progress); - -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) - wireless_frame_->setCaptureInProgress(capture_in_progress); -#endif - -#ifdef HAVE_LIBPCAP - packet_list_->setCaptureInProgress(capture_in_progress); - packet_list_->setVerticalAutoScroll(capture_in_progress && main_ui_->actionGoAutoScroll->isChecked()); - -// set_capture_if_dialog_for_capture_in_progress(capture_in_progress); -#endif - - if (handle_toolbars) { - QList toolbars = findChildren(); - foreach(InterfaceToolbar *toolbar, toolbars) { - if (capture_in_progress) { - toolbar->startCapture(ifaces); - } else { - toolbar->stopCapture(); - } - } - } -} - -static QList menu_groups = QList() - << REGISTER_ANALYZE_GROUP_UNSORTED - << REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER - << REGISTER_STAT_GROUP_UNSORTED - << REGISTER_STAT_GROUP_GENERIC - << REGISTER_STAT_GROUP_CONVERSATION_LIST - << REGISTER_STAT_GROUP_ENDPOINT_LIST - << REGISTER_STAT_GROUP_RESPONSE_TIME - << REGISTER_STAT_GROUP_RSERPOOL - << REGISTER_STAT_GROUP_TELEPHONY - << REGISTER_STAT_GROUP_TELEPHONY_ANSI - << REGISTER_STAT_GROUP_TELEPHONY_GSM - << REGISTER_STAT_GROUP_TELEPHONY_LTE - << REGISTER_STAT_GROUP_TELEPHONY_MTP3 - << REGISTER_STAT_GROUP_TELEPHONY_SCTP - << REGISTER_TOOLS_GROUP_UNSORTED; - -void MainWindow::addMenuActions(QList &actions, int menu_group) -{ - foreach(QAction *action, actions) { - switch (menu_group) { - case REGISTER_ANALYZE_GROUP_UNSORTED: - case REGISTER_STAT_GROUP_UNSORTED: - main_ui_->menuStatistics->insertAction( - main_ui_->actionStatistics_REGISTER_STAT_GROUP_UNSORTED, - action); - break; - case REGISTER_STAT_GROUP_RESPONSE_TIME: - main_ui_->menuServiceResponseTime->addAction(action); - break; - case REGISTER_STAT_GROUP_RSERPOOL: - main_ui_->menuRSerPool->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY: - main_ui_->menuTelephony->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_ANSI: - main_ui_->menuANSI->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_GSM: - main_ui_->menuGSM->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_LTE: - main_ui_->menuLTE->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_MTP3: - main_ui_->menuMTP3->addAction(action); - break; - case REGISTER_TOOLS_GROUP_UNSORTED: - { - // Allow the creation of submenus. Mimics the behavor of - // ui/gtk/main_menubar.c:add_menu_item_to_main_menubar - // and GtkUIManager. - // - // For now we limit the insanity to the "Tools" menu. - QStringList menu_path = action->text().split('/'); - QMenu *cur_menu = main_ui_->menuTools; - while (menu_path.length() > 1) { - QString menu_title = menu_path.takeFirst(); - QMenu *submenu = cur_menu->findChild(menu_title.toLower(), Qt::FindDirectChildrenOnly); - if (!submenu) { - submenu = cur_menu->addMenu(menu_title); - submenu->setObjectName(menu_title.toLower()); - } - cur_menu = submenu; - } - action->setText(menu_path.last()); - cur_menu->addAction(action); - break; - } - default: -// qDebug() << "FIX: Add" << action->text() << "to the menu"; - break; - } - - // Connect each action type to its corresponding slot. We to - // distinguish various types of actions. Setting their objectName - // seems to work OK. - if (action->objectName() == TapParameterDialog::actionName()) { - connect(action, SIGNAL(triggered(bool)), this, SLOT(openTapParameterDialog())); - } else if (action->objectName() == FunnelStatistics::actionName()) { - connect(action, SIGNAL(triggered(bool)), funnel_statistics_, SLOT(funnelActionTriggered())); - } - } -} -void MainWindow::removeMenuActions(QList &actions, int menu_group) -{ - foreach(QAction *action, actions) { - switch (menu_group) { - case REGISTER_ANALYZE_GROUP_UNSORTED: - case REGISTER_STAT_GROUP_UNSORTED: - main_ui_->menuStatistics->removeAction(action); - break; - case REGISTER_STAT_GROUP_RESPONSE_TIME: - main_ui_->menuServiceResponseTime->removeAction(action); - break; - case REGISTER_STAT_GROUP_RSERPOOL: - main_ui_->menuRSerPool->removeAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY: - main_ui_->menuTelephony->removeAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_ANSI: - main_ui_->menuANSI->removeAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_GSM: - main_ui_->menuGSM->removeAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_LTE: - main_ui_->menuLTE->removeAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_MTP3: - main_ui_->menuMTP3->removeAction(action); - break; - case REGISTER_TOOLS_GROUP_UNSORTED: - { - // Allow removal of submenus. - // For now we limit the insanity to the "Tools" menu. - QStringList menu_path = action->text().split('/'); - QMenu *cur_menu = main_ui_->menuTools; - while (menu_path.length() > 1) { - QString menu_title = menu_path.takeFirst(); - QMenu *submenu = cur_menu->findChild(menu_title.toLower(), Qt::FindDirectChildrenOnly); - cur_menu = submenu; - } - cur_menu->removeAction(action); - break; - } - default: -// qDebug() << "FIX: Remove" << action->text() << "from the menu"; - break; - } - } -} - -void MainWindow::addDynamicMenus() -{ - // Manual additions - mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_GSM, main_ui_->actionTelephonyGsmMapSummary); - mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteMacStatistics); - mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcStatistics); - mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcGraph); - mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_MTP3, main_ui_->actionTelephonyMtp3Summary); - mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY, main_ui_->actionTelephonySipFlows); - - // Fill in each menu - foreach(register_stat_group_t menu_group, menu_groups) { - QListactions = mainApp->dynamicMenuGroupItems(menu_group); - addMenuActions(actions, menu_group); - } - - // Empty menus don't show up: https://bugreports.qt.io/browse/QTBUG-33728 - // We've added a placeholder in order to make sure some menus are visible. - // Hide them as needed. - if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_ANSI).length() > 0) { - main_ui_->actionTelephonyANSIPlaceholder->setVisible(false); - } - if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_GSM).length() > 0) { - main_ui_->actionTelephonyGSMPlaceholder->setVisible(false); - } - if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_LTE).length() > 0) { - main_ui_->actionTelephonyLTEPlaceholder->setVisible(false); - } - if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_MTP3).length() > 0) { - main_ui_->actionTelephonyMTP3Placeholder->setVisible(false); - } -} - -void MainWindow::reloadDynamicMenus() -{ - foreach(register_stat_group_t menu_group, menu_groups) { - QListactions = mainApp->removedMenuGroupItems(menu_group); - removeMenuActions(actions, menu_group); - - actions = mainApp->addedMenuGroupItems(menu_group); - addMenuActions(actions, menu_group); - } - - mainApp->clearAddedMenuGroupItems(); - mainApp->clearRemovedMenuGroupItems(); -} - -void MainWindow::externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth) -{ - QAction * itemAction = Q_NULLPTR; - ext_menubar_t * item = Q_NULLPTR; - GList * children = Q_NULLPTR; - - /* There must exists an xpath parent */ - Q_ASSERT(subMenu != NULL); - - /* If the depth counter exceeds, something must have gone wrong */ - Q_ASSERT(depth < EXT_MENUBAR_MAX_DEPTH); - - children = menu->children; - /* Iterate the child entries */ - while (children && children->data) { - item = gxx_list_data(ext_menubar_t *, children); - - if (item->type == EXT_MENUBAR_MENU) { - /* Handle Submenu entry */ - this->externalMenuHelper(item, subMenu->addMenu(item->label), depth++); - } else if (item->type == EXT_MENUBAR_SEPARATOR) { - subMenu->addSeparator(); - } else if (item->type == EXT_MENUBAR_ITEM || item->type == EXT_MENUBAR_URL) { - itemAction = subMenu->addAction(item->name); - itemAction->setData(QVariant::fromValue(static_cast(item))); - itemAction->setText(item->label); - connect(itemAction, SIGNAL(triggered()), - this, SLOT(externalMenuItem_triggered())); - } - - /* Iterate Loop */ - children = gxx_list_next(children); - } -} - -QMenu * MainWindow::searchSubMenu(QString objectName) -{ - QList lst; - - if (objectName.length() > 0) { - QString searchName = QString("menu") + objectName; - - lst = main_ui_->menuBar->findChildren(); - foreach(QMenu* m, lst) { - if (QString::compare(m->objectName(), searchName) == 0) - return m; - } - } - - return 0; -} - -void MainWindow::addPluginIFStructures() -{ - GList *user_menu = ext_menubar_get_entries(); - - while (user_menu && user_menu->data) { - QMenu *subMenu = Q_NULLPTR; - ext_menu_t *menu = gxx_list_data(ext_menu_t *, user_menu); - - /* On this level only menu items should exist. Not doing an assert here, - * as it could be an honest mistake */ - if (menu->type != EXT_MENUBAR_MENU) { - user_menu = gxx_list_next(user_menu); - continue; - } - - /* Create main submenu and add it to the menubar */ - if (menu->parent_menu) { - QMenu *sortUnderneath = searchSubMenu(QString(menu->parent_menu)); - if (sortUnderneath) - subMenu = sortUnderneath->addMenu(menu->label); - } - - if (!subMenu) - subMenu = main_ui_->menuBar->addMenu(menu->label); - - /* This will generate the action structure for each menu. It is recursive, - * therefore a sub-routine, and we have a depth counter to prevent endless loops. */ - this->externalMenuHelper(menu, subMenu, 0); - - /* Iterate Loop */ - user_menu = gxx_list_next(user_menu); - } - - int cntToolbars = 0; - - QMenu *tbMenu = main_ui_->menuAdditionalToolbars; - GList *if_toolbars = ext_toolbar_get_entries(); - while (if_toolbars && if_toolbars->data) { - ext_toolbar_t *toolbar = gxx_list_data(ext_toolbar_t*, if_toolbars); - - if (toolbar->type != EXT_TOOLBAR_BAR) { - if_toolbars = gxx_list_next(if_toolbars); - continue; - } - - bool visible = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, reinterpret_cast(strcmp)) ? true : false; - - AdditionalToolBar *ifToolBar = AdditionalToolBar::create(this, toolbar); - - if (ifToolBar) { - ifToolBar->setVisible(visible); - - QAction *iftbAction = new QAction(QString(toolbar->name), this); - iftbAction->setToolTip(toolbar->tooltip); - iftbAction->setEnabled(true); - iftbAction->setCheckable(true); - iftbAction->setChecked(visible); - iftbAction->setToolTip(tr("Show or hide the toolbar")); - iftbAction->setData(VariantPointer::asQVariant(toolbar)); - - QAction *before = Q_NULLPTR; - - foreach(QAction *action, tbMenu->actions()) { - /* Ensure we add the menu entries in sorted order */ - if (action->text().compare(toolbar->name, Qt::CaseInsensitive) > 0) { - before = action; - break; - } - } - - tbMenu->insertAction(before, iftbAction); - - addToolBar(Qt::TopToolBarArea, ifToolBar); - insertToolBarBreak(ifToolBar); - - if (show_hide_actions_) - show_hide_actions_->addAction(iftbAction); - - cntToolbars++; - } - - if_toolbars = gxx_list_next(if_toolbars); - } - - if (cntToolbars) - tbMenu->menuAction()->setVisible(true); -} - -void MainWindow::removeAdditionalToolbar(QString toolbarName) -{ - if (toolbarName.length() == 0) - return; - - QList toolbars = findChildren(); - foreach(QToolBar *tb, toolbars) { - AdditionalToolBar *ifToolBar = dynamic_cast(tb); - - if (ifToolBar && ifToolBar->menuName().compare(toolbarName)) { - GList *entry = g_list_find_custom(recent.gui_additional_toolbars, qUtf8Printable(ifToolBar->menuName()), reinterpret_cast(strcmp)); - if (entry) { - recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data); - } - QList actions = main_ui_->menuAdditionalToolbars->actions(); - foreach(QAction *action, actions) { - ext_toolbar_t *item = VariantPointer::asPtr(action->data()); - if (item && ifToolBar->menuName().compare(item->name)) { - if (show_hide_actions_) - show_hide_actions_->removeAction(action); - main_ui_->menuAdditionalToolbars->removeAction(action); - } - } - break; - } - } - -} - -QString MainWindow::getMwFileName() -{ - return mwFileName_; -} - -void MainWindow::setMwFileName(QString fileName) -{ - mwFileName_ = fileName; - return; } bool MainWindow::hasSelection() @@ -3046,137 +47,38 @@ QList MainWindow::selectedRows(bool useFrameNum) return QList(); } -frame_data * MainWindow::frameDataForRow(int row) const +void MainWindow::insertColumn(QString name, QString abbrev, gint pos) { - if (packet_list_) - return packet_list_->getFDataForRow(row); - - return Q_NULLPTR; + gint colnr = 0; + if (name.length() > 0 && abbrev.length() > 0) + { + colnr = column_prefs_add_custom(COL_CUSTOM, name.toStdString().c_str(), abbrev.toStdString().c_str(), pos); + packet_list_->columnsChanged(); + packet_list_->resizeColumnToContents(colnr); + prefs_main_write(); + } } -// Finds rtp id for selected stream and adds it to stream_ids -// If reverse is set, tries to find reverse stream too -// Return error string if error happens -// -// Note: Caller must free each returned rtpstream_info_t -QString MainWindow::findRtpStreams(QVector *stream_ids, bool reverse) +void MainWindow::gotoFrame(int packet_num) { - rtpstream_tapinfo_t tapinfo; - rtpstream_id_t *fwd_id, *rev_id; - bool fwd_id_used, rev_id_used; - const gchar filter_text[] = "rtp && rtp.version == 2 && rtp.ssrc && (ip || ipv6)"; - dfilter_t *sfcode; - gchar *err_msg; - - /* Try to get the hfid for "rtp.ssrc". */ - int hfid_rtp_ssrc = proto_registrar_get_id_byname("rtp.ssrc"); - if (hfid_rtp_ssrc == -1) { - return tr("There is no \"rtp.ssrc\" field in this version of Wireshark."); + if (packet_num > 0) { + packet_list_->goToPacket(packet_num); } - - /* Try to compile the filter. */ - if (!dfilter_compile(filter_text, &sfcode, &err_msg)) { - QString err = QString(err_msg); - g_free(err_msg); - return err; - } - - if (!capture_file_.capFile() || !capture_file_.capFile()->current_frame) close(); - - if (!cf_read_current_record(capture_file_.capFile())) close(); - - frame_data *fdata = capture_file_.capFile()->current_frame; - - epan_dissect_t edt; - - epan_dissect_init(&edt, capture_file_.capFile()->epan, true, false); - epan_dissect_prime_with_dfilter(&edt, sfcode); - epan_dissect_prime_with_hfid(&edt, hfid_rtp_ssrc); - epan_dissect_run(&edt, capture_file_.capFile()->cd_t, - &capture_file_.capFile()->rec, - frame_tvbuff_new_buffer( - &capture_file_.capFile()->provider, fdata, - &capture_file_.capFile()->buf), - fdata, NULL); - - /* - * Packet must be an RTPv2 packet with an SSRC; we use the filter to - * check. - */ - if (!dfilter_apply_edt(sfcode, &edt)) { - epan_dissect_cleanup(&edt); - dfilter_free(sfcode); - return tr("Please select an RTPv2 packet with an SSRC value"); - } - - dfilter_free(sfcode); - - /* We need the SSRC value of the current frame; try to get it. */ - GPtrArray *gp = proto_get_finfo_ptr_array(edt.tree, hfid_rtp_ssrc); - if (gp == NULL || gp->len == 0) { - /* XXX - should not happen, as the filter includes rtp.ssrc */ - epan_dissect_cleanup(&edt); - return tr("SSRC value not found."); - } - - /* - * OK, we have the SSRC value, so we can proceed. - * Allocate RTP stream ID structures. - */ - fwd_id = g_new0(rtpstream_id_t, 1); - fwd_id_used = false; - rev_id = g_new0(rtpstream_id_t, 1); - rev_id_used = false; - - /* Get the IP and port values for the forward direction. */ - rtpstream_id_copy_pinfo(&(edt.pi), fwd_id, false); - - /* assume the inverse ip/port combination for the reverse direction */ - rtpstream_id_copy_pinfo(&(edt.pi), rev_id, true); - - /* Save the SSRC value for the forward direction. */ - fwd_id->ssrc = fvalue_get_uinteger(&((field_info *)gp->pdata[0])->value); - - epan_dissect_cleanup(&edt); - - /* Register the tap listener */ - memset(&tapinfo, 0, sizeof(rtpstream_tapinfo_t)); - tapinfo.tap_data = this; - tapinfo.mode = TAP_ANALYSE; - - /* Scan for RTP streams (redissect all packets) */ - rtpstream_scan(&tapinfo, capture_file_.capFile(), Q_NULLPTR); - - for (GList *strinfo_list = g_list_first(tapinfo.strinfo_list); strinfo_list; strinfo_list = gxx_list_next(strinfo_list)) { - rtpstream_info_t * strinfo = gxx_list_data(rtpstream_info_t*, strinfo_list); - if (rtpstream_id_equal(&(strinfo->id), fwd_id,RTPSTREAM_ID_EQUAL_NONE)) - { - *stream_ids << fwd_id; - fwd_id_used = true; - } - - if (rtpstream_id_equal(&(strinfo->id), rev_id,RTPSTREAM_ID_EQUAL_NONE)) - { - if (rev_id->ssrc == 0) { - rev_id->ssrc = strinfo->id.ssrc; - } - if (reverse) { - *stream_ids << rev_id; - rev_id_used = true; - } - } - } - - // - // XXX - is it guaranteed that fwd_id and rev_id were both added to - // *stream_ids? If so, this isn't necessary. - // - if (!fwd_id_used) { - rtpstream_id_free(fwd_id); - } - if (!rev_id_used) { - rtpstream_id_free(rev_id); - } - return NULL; } +QString MainWindow::getFilter() +{ + return df_combo_box_->currentText(); +} + +MainStatusBar *MainWindow::statusBar() +{ + return main_status_bar_; +} + +void MainWindow::setDisplayFilter(QString filter, FilterAction::Action action, FilterAction::ActionType filterType) +{ + emit filterAction(filter, action, filterType); +} + + diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index 782d295a28..8e350a8462 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -10,736 +10,70 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -/** @defgroup main_window_group Main window - * The main window has the following submodules: - @dot - digraph main_dependencies { - node [shape=record, fontname=Helvetica, fontsize=10]; - main [ label="main window" URL="\ref main.h"]; - menu [ label="menubar" URL="\ref menus.h"]; - toolbar [ label="toolbar" URL="\ref main_toolbar.h"]; - packet_list [ label="packet list pane" URL="\ref packet_list.h"]; - proto_draw [ label="packet details & bytes panes" URL="\ref main_proto_draw.h"]; - recent [ label="recent user settings" URL="\ref recent.h"]; - main -> menu [ arrowhead="open", style="solid" ]; - main -> toolbar [ arrowhead="open", style="solid" ]; - main -> packet_list [ arrowhead="open", style="solid" ]; - main -> proto_draw [ arrowhead="open", style="solid" ]; - main -> recent [ arrowhead="open", style="solid" ]; - } - @enddot - */ - -/** @file - * The main window - * @ingroup main_window_group - * @ingroup windows_group - */ - -#include - -#include - -#include - -#include "file.h" - -#include "ui/ws_ui_util.h" -#include "ui/iface_toolbar.h" - #include -#include -#include -#ifdef HAVE_LIBPCAP -#include "capture_opts.h" -#endif -#include +#include "filter_action.h" #include -#include #include -#include -#ifdef _WIN32 -# include -#else -# include -#endif - -#include "capture_file.h" -#include "capture_file_dialog.h" -#include "print_dialog.h" -#include "capture_file_properties_dialog.h" -#include -#include -#include "filter_action.h" -#include "follow_stream_dialog.h" -#include -#include "rtp_stream_dialog.h" -#include "voip_calls_dialog.h" -#include "rtp_analysis_dialog.h" - -class AccordionFrame; +class QSplitter; +class QStackedWidget; class ByteViewTab; -class CaptureOptionsDialog; -class PrintDialog; -class FileSetDialog; -class FilterDialog; -class FunnelStatistics; -class WelcomePage; -class PacketCommentDialog; +class DisplayFilterCombo; +class FieldInformation; +class MainStatusBar; class PacketDiagram; class PacketList; class ProtoTree; -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) -class WirelessFrame; -#endif -class FilterExpressionToolBar; -class WiresharkApplication; +class WelcomePage; -class QAction; -class QActionGroup; - -namespace Ui { - class MainWindow; -} - -Q_DECLARE_METATYPE(ts_type) -Q_DECLARE_METATYPE(ts_precision) +typedef struct _capture_file capture_file; class MainWindow : public QMainWindow { Q_OBJECT - public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - void setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb); - - QString getFilter(); -#ifdef HAVE_LIBPCAP - capture_session *captureSession() { return &cap_session_; } - info_data_t *captureInfoData() { return &info_data_; } -#endif - - virtual QMenu *createPopupMenu(); - - void gotoFrame(int packet_num); - CaptureFile *captureFile() { return &capture_file_; } - - void removeAdditionalToolbar(QString toolbarName); - - void addInterfaceToolbar(const iface_toolbar *toolbar_entry); - void removeInterfaceToolbar(const gchar *menu_title); - - QString getMwFileName(); - void setMwFileName(QString fileName); - - void insertColumn(QString name, QString abbrev, gint pos = -1); - + explicit MainWindow(QWidget *parent = nullptr); bool hasSelection(); QList selectedRows(bool useFrameNum = false); - frame_data * frameDataForRow(int row) const; + void insertColumn(QString name, QString abbrev, gint pos = -1); + void gotoFrame(int packet_num); + + QString getFilter(); + MainStatusBar *statusBar(); + +public slots: + void setDisplayFilter(QString filter, FilterAction::Action action, FilterAction::ActionType filterType); + void layoutPanes(); + void applyRecentPaneGeometry(); protected: - virtual bool eventFilter(QObject *obj, QEvent *event); - virtual bool event(QEvent *event); - virtual void keyPressEvent(QKeyEvent *event); - virtual void closeEvent(QCloseEvent *event); - virtual void dragEnterEvent(QDragEnterEvent *event); - virtual void dropEvent(QDropEvent *event); - virtual void changeEvent(QEvent* event); + void showWelcome(); + void showCapture(); -private: - // XXX Move to FilterUtils - enum MatchSelected { - MatchSelectedReplace, - MatchSelectedAnd, - MatchSelectedOr, - MatchSelectedNot, - MatchSelectedAndNot, - MatchSelectedOrNot - }; + QWidget* getLayoutWidget(layout_pane_content_e type); - enum CopySelected { - CopyAllVisibleItems, - CopyAllVisibleSelectedTreeItems, - CopySelectedDescription, - CopySelectedFieldName, - CopySelectedValue, - CopyListAsText, - CopyListAsCSV, - CopyListAsYAML - }; - - enum FileCloseContext { - Default, - Quit, - Restart, - Reload - }; - - Ui::MainWindow *main_ui_; + QStackedWidget *main_stack_; + WelcomePage *welcome_page_; QSplitter master_split_; QSplitter extra_split_; + QWidget empty_pane_; QVector cur_layout_; - WelcomePage *welcome_page_; - DisplayFilterCombo *df_combo_box_; - CaptureFile capture_file_; - QFont mono_font_; - QMap text_codec_map_; -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) - WirelessFrame *wireless_frame_; -#endif - // XXX - packet_list_ and proto_tree_ should - // probably be full-on values instead of pointers. + PacketList *packet_list_; ProtoTree *proto_tree_; ByteViewTab *byte_view_tab_; PacketDiagram *packet_diagram_; - QWidget *previous_focus_; - FileSetDialog *file_set_dialog_; - QWidget empty_pane_; - QActionGroup *show_hide_actions_; - QActionGroup *time_display_actions_; - QActionGroup *time_precision_actions_; - FunnelStatistics *funnel_statistics_; - QList > freeze_actions_; - QPointer freeze_focus_; - QMap td_actions; - QMap tp_actions; - bool was_maximized_; - - /* the following values are maintained so that the capture file name and status - is available when there is no cf structure available */ - QString mwFileName_; - - bool capture_stopping_; - bool capture_filter_valid_; -#ifdef HAVE_LIBPCAP - capture_session cap_session_; - CaptureOptionsDialog *capture_options_dialog_; - info_data_t info_data_; -#endif - FilterDialog *display_filter_dlg_; - FilterDialog *capture_filter_dlg_; - - // Pipe input - gint pipe_source_; - gpointer pipe_user_data_; - ws_process_id *pipe_child_process_; - pipe_input_cb_t pipe_input_cb_; -#ifdef _WIN32 - QTimer *pipe_timer_; -#else - QSocketNotifier *pipe_notifier_; -#endif - -#if defined(Q_OS_MAC) - QMenu *dock_menu_; -#endif - -#ifdef HAVE_SOFTWARE_UPDATE - QAction *update_action_; -#endif - - QPoint dragStartPosition; - - QWidget* getLayoutWidget(layout_pane_content_e type); - - void freeze(); - void thaw(); - - void mergeCaptureFile(); - void importCaptureFile(); - bool saveCaptureFile(capture_file *cf, bool dont_reopen); - bool saveAsCaptureFile(capture_file *cf, bool must_support_comments = false, bool dont_reopen = false); - void exportSelectedPackets(); - void exportDissections(export_type_e export_type); - -#ifdef Q_OS_WIN - void fileAddExtension(QString &file_name, int file_type, wtap_compression_type compression_type); -#endif // Q_OS_WIN - bool testCaptureFileClose(QString before_what, FileCloseContext context = Default); - void captureStop(); - - void findTextCodecs(); - - void initMainToolbarIcons(); - void initShowHideMainWidgets(); - void initTimeDisplayFormatMenu(); - void initTimePrecisionFormatMenu(); - void initFreezeActions(); - - void setTitlebarForCaptureInProgress(); - void setMenusForCaptureFile(bool force_disable = false); - void setMenusForCaptureInProgress(bool capture_in_progress = false); - void setMenusForCaptureStopping(); - void setForCapturedPackets(bool have_captured_packets); - void setMenusForFileSet(bool enable_list_files); - void setWindowIcon(const QIcon &icon); - QString replaceWindowTitleVariables(QString title); - - void externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth); - - void setForCaptureInProgress(bool capture_in_progress = false, bool handle_toolbars = false, GArray *ifaces = NULL); - QMenu* findOrAddMenu(QMenu *parent_menu, QString& menu_text); - - void captureFileReadStarted(const QString &action); - - void addMenuActions(QList &actions, int menu_group); - void removeMenuActions(QList &actions, int menu_group); - void goToConversationFrame(bool go_next); - void colorizeWithFilter(QByteArray filter, int color_number = -1); + DisplayFilterCombo *df_combo_box_; + MainStatusBar *main_status_bar_; signals: void setCaptureFile(capture_file *cf); - void setDissectedCaptureFile(capture_file *cf); - void displayFilterSuccess(bool success); - void closePacketDialogs(); - void reloadFields(); - void packetInfoChanged(struct _packet_info *pinfo); - void fieldFilterChanged(const QByteArray field_filter); + void fieldSelected(FieldInformation *); + void framesSelected(QList); void filterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type); - void fieldSelected(FieldInformation *); - void fieldHighlight(FieldInformation *); - - void framesSelected(QList); - - void captureActive(int); - void selectRtpStream(rtpstream_id_t *id); - void deselectRtpStream(rtpstream_id_t *id); - -#ifdef HAVE_LIBPCAP - void showExtcapOptions(QString &device_name, bool startCaptureOnClose); -#endif - -public slots: - // in main_window_slots.cpp - /** - * Open a capture file. - * @param cf_path Path to the file. - * @param display_filter Display filter to apply. May be empty. - * @param type File type. - * @param is_tempfile TRUE/FALSE. - * @return True on success, false on failure. - */ - // XXX We might want to return a cf_read_status_t or a CaptureFile. - bool openCaptureFile(QString cf_path, QString display_filter, unsigned int type, gboolean is_tempfile = FALSE); - bool openCaptureFile(QString cf_path = QString(), QString display_filter = QString()) { return openCaptureFile(cf_path, display_filter, WTAP_TYPE_AUTO); } - void filterPackets(QString new_filter = QString(), bool force = false); - void setDisplayFilter(QString filter, FilterAction::Action action, FilterAction::ActionType filterType); - void updateForUnsavedChanges(); - void layoutPanes(); - void applyRecentPaneGeometry(); - void layoutToolbars(); - void updatePreferenceActions(); - void updateRecentActions(); - - void showWelcome(); - void showCapture(); - - void setTitlebarForCaptureFile(); - void setWSWindowTitle(QString title = QString()); - -#ifdef HAVE_LIBPCAP - void captureCapturePrepared(capture_session *); - void captureCaptureUpdateStarted(capture_session *); - void captureCaptureUpdateFinished(capture_session *); - void captureCaptureFixedFinished(capture_session *cap_session); - void captureCaptureFailed(capture_session *); -#endif - - void captureFileOpened(); - void captureFileReadFinished(); - void captureFileClosing(); - void captureFileClosed(); - - void launchRLCGraph(bool channelKnown, guint16 ueid, guint8 rlcMode, - guint16 channelType, guint16 channelId, guint8 direction); - - void on_actionViewFullScreen_triggered(bool checked); - - void rtpPlayerDialogReplaceRtpStreams(QVector stream_ids); - void rtpPlayerDialogAddRtpStreams(QVector stream_ids); - void rtpPlayerDialogRemoveRtpStreams(QVector stream_ids); - void rtpAnalysisDialogReplaceRtpStreams(QVector stream_ids); - void rtpAnalysisDialogAddRtpStreams(QVector stream_ids); - void rtpAnalysisDialogRemoveRtpStreams(QVector stream_ids); - void rtpStreamsDialogSelectRtpStreams(QVector stream_ids); - void rtpStreamsDialogDeselectRtpStreams(QVector stream_ids); - -private slots: - - void captureEventHandler(CaptureEvent ev); - - // Manually connected slots (no "on__"). - - void initViewColorizeMenu(); - void initConversationMenus(); - static gboolean addExportObjectsMenuItem(const void *key, void *value, void *userdata); - void initExportObjectsMenus(); - - // in main_window_slots.cpp - /** - * @brief startCapture - * Start capturing from the selected interfaces using the capture filter - * shown in the main welcome screen. - */ - void startCapture(QStringList); - void startCapture(); - void pipeTimeout(); - void pipeActivated(int source); - void pipeNotifierDestroyed(); - void stopCapture(); - - void loadWindowGeometry(); - void saveWindowGeometry(); - void mainStackChanged(int); - void updateRecentCaptures(); - void recentActionTriggered(); - void actionAddPacketComment(); - void actionEditPacketComment(); - void actionDeletePacketComment(); - void actionDeleteCommentsFromPackets(); - QString commentToMenuText(QString text, int max_len = 40); - void setEditCommentsMenu(); - void setMenusForSelectedPacket(); - void setMenusForSelectedTreeRow(FieldInformation *fi = NULL); - void interfaceSelectionChanged(); - void captureFilterSyntaxChanged(bool valid); - void redissectPackets(); - void checkDisplayFilter(); - void fieldsChanged(); - void reloadLuaPlugins(); - void showAccordionFrame(AccordionFrame *show_frame, bool toggle = false); - void showColumnEditor(int column); - void showPreferenceEditor(); // module_t *, pref * - void addStatsPluginsToMenu(); - void addDynamicMenus(); - void reloadDynamicMenus(); - void addPluginIFStructures(); - QMenu * searchSubMenu(QString objectName); - void activatePluginIFToolbar(bool); - - void startInterfaceCapture(bool valid, const QString capture_filter); - - void applyGlobalCommandLineOptions(); - void setFeaturesEnabled(bool enabled = true); - - void on_actionDisplayFilterExpression_triggered(); - void on_actionNewDisplayFilterExpression_triggered(); - void onFilterSelected(QString, bool); - void onFilterPreferences(); - void onFilterEdit(int uatIndex); - - // Handle FilterAction signals - void queuedFilterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type); - - /** Pass stat cmd arguments to a slot. - * @param menu_path slot Partial slot name, e.g. "StatisticsIOGraph". - * @param arg "-z" argument, e.g. "io,stat". - * @param userdata Optional user data. - */ - void openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata); - - /** Pass tap parameter arguments to a slot. - * @param cfg_str slot Partial slot name, e.g. "StatisticsAFPSrt". - * @param arg "-z" argument, e.g. "afp,srt". - * @param userdata Optional user data. - */ - void openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata); - void openTapParameterDialog(); - -#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) - void softwareUpdateRequested(); -#endif - - // Automatically connected slots ("on__"). - // - // The slots below follow the naming conventaion described in - // https://doc.qt.io/archives/qt-4.8/qmetaobject.html#connectSlotsByName - // and are automatically connected at initialization time via - // main_ui_->setupUi, which in turn calls connectSlotsByName. - // - // If you're manually connecting a signal to a slot, don't prefix its name - // with "on_". Otherwise you'll get runtime warnings. - - // We might want move these to main_window_actions.cpp similar to - // gtk/main_menubar.c - - void on_actionFileOpen_triggered(); - void on_actionFileMerge_triggered(); - void on_actionFileImportFromHexDump_triggered(); - void on_actionFileClose_triggered(); - void on_actionFileSave_triggered(); - void on_actionFileSaveAs_triggered(); - void on_actionFileSetListFiles_triggered(); - void on_actionFileSetNextFile_triggered(); - void on_actionFileSetPreviousFile_triggered(); - void on_actionFileExportPackets_triggered(); - void on_actionFileExportAsPlainText_triggered(); - // We're dropping PostScript exports - void on_actionFileExportAsCSV_triggered(); - void on_actionFileExportAsCArrays_triggered(); - void on_actionFileExportAsPSML_triggered(); - void on_actionFileExportAsPDML_triggered(); - void on_actionFileExportAsJSON_triggered(); - void on_actionFileExportPacketBytes_triggered(); - void on_actionFilePrint_triggered(); - - void on_actionFileExportPDU_triggered(); - void on_actionFileStripHeaders_triggered(); - void on_actionFileExportTLSSessionKeys_triggered(); - - void actionEditCopyTriggered(MainWindow::CopySelected selection_type); - void on_actionCopyAllVisibleItems_triggered(); - void on_actionCopyAllVisibleSelectedTreeItems_triggered(); - void on_actionCopyListAsText_triggered(); - void on_actionCopyListAsCSV_triggered(); - void on_actionCopyListAsYAML_triggered(); - void on_actionEditCopyDescription_triggered(); - void on_actionEditCopyFieldName_triggered(); - void on_actionEditCopyValue_triggered(); - void on_actionEditCopyAsFilter_triggered(); - void on_actionEditFindPacket_triggered(); - void on_actionEditFindNext_triggered(); - void on_actionEditFindPrevious_triggered(); - void on_actionEditMarkPacket_triggered(); - void on_actionEditMarkAllDisplayed_triggered(); - void on_actionEditUnmarkAllDisplayed_triggered(); - void on_actionEditNextMark_triggered(); - void on_actionEditPreviousMark_triggered(); - void on_actionEditIgnorePacket_triggered(); - void on_actionEditIgnoreAllDisplayed_triggered(); - void on_actionEditUnignoreAllDisplayed_triggered(); - void on_actionEditSetTimeReference_triggered(); - void on_actionEditUnsetAllTimeReferences_triggered(); - void on_actionEditNextTimeReference_triggered(); - void on_actionEditPreviousTimeReference_triggered(); - void on_actionEditTimeShift_triggered(); - void editTimeShiftFinished(int); - void addPacketCommentFinished(PacketCommentDialog* pc_dialog, int result); - void editPacketCommentFinished(PacketCommentDialog* pc_dialog, int result, guint nComment); - void on_actionDeleteAllPacketComments_triggered(); - void deleteAllPacketCommentsFinished(int result); - void on_actionEditConfigurationProfiles_triggered(); - void showPreferencesDialog(QString module_name); - void on_actionEditPreferences_triggered(); - - void showHideMainWidgets(QAction *action); - void setTimestampFormat(QAction *action); - void setTimestampPrecision(QAction *action); - void on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked); - void on_actionViewEditResolvedName_triggered(); - void setNameResolution(); - void on_actionViewNameResolutionPhysical_triggered(); - void on_actionViewNameResolutionNetwork_triggered(); - void on_actionViewNameResolutionTransport_triggered(); - // XXX We're not porting the concurrency action from GTK+ on purpose. - void zoomText(); - void on_actionViewZoomIn_triggered(); - void on_actionViewZoomOut_triggered(); - void on_actionViewNormalSize_triggered(); - void on_actionViewColorizePacketList_triggered(bool checked); - void on_actionViewColoringRules_triggered(); - void colorizeConversation(bool create_rule = false); - void colorizeActionTriggered(); - void on_actionViewColorizeResetColorization_triggered(); - void on_actionViewColorizeNewColoringRule_triggered(); - void on_actionViewResetLayout_triggered(); - void on_actionViewResizeColumns_triggered(); - - void on_actionViewInternalsConversationHashTables_triggered(); - void on_actionViewInternalsDissectorTables_triggered(); - void on_actionViewInternalsSupportedProtocols_triggered(); - - void openPacketDialog(bool from_reference = false); - void on_actionViewShowPacketInNewWindow_triggered(); - void on_actionContextShowLinkedPacketInNewWindow_triggered(); - void on_actionViewReload_triggered(); - void on_actionViewReload_as_File_Format_or_Capture_triggered(); - - void on_actionGoGoToPacket_triggered(); - void on_actionGoGoToLinkedPacket_triggered(); - void on_actionGoNextConversationPacket_triggered(); - void on_actionGoPreviousConversationPacket_triggered(); - void on_actionGoAutoScroll_toggled(bool checked); - void resetPreviousFocus(); - - void on_actionCaptureOptions_triggered(); -#ifdef HAVE_LIBPCAP - void on_actionCaptureRefreshInterfaces_triggered(); -#endif - void on_actionCaptureCaptureFilters_triggered(); - - void on_actionAnalyzeDisplayFilters_triggered(); - void on_actionAnalyzeDisplayFilterMacros_triggered(); - void matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type); - void on_actionAnalyzeCreateAColumn_triggered(); - - void filterMenuAboutToShow(); - - void applyConversationFilter(); - void applyExportObject(); - - void on_actionAnalyzeEnabledProtocols_triggered(); - void on_actionAnalyzeDecodeAs_triggered(); - void on_actionAnalyzeReloadLuaPlugins_triggered(); - - void openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index = true); - void openFollowStreamDialogForType(follow_type_t type); - void on_actionAnalyzeFollowTCPStream_triggered(); - void on_actionAnalyzeFollowUDPStream_triggered(); - void on_actionAnalyzeFollowDCCPStream_triggered(); - void on_actionAnalyzeFollowTLSStream_triggered(); - void on_actionAnalyzeFollowHTTPStream_triggered(); - void on_actionAnalyzeFollowHTTP2Stream_triggered(); - void on_actionAnalyzeFollowQUICStream_triggered(); - void on_actionAnalyzeFollowSIPCall_triggered(); - - void statCommandExpertInfo(const char *, void *); - void on_actionAnalyzeExpertInfo_triggered(); - - void on_actionHelpContents_triggered(); - void on_actionHelpMPWireshark_triggered(); - void on_actionHelpMPWireshark_Filter_triggered(); - void on_actionHelpMPCapinfos_triggered(); - void on_actionHelpMPDumpcap_triggered(); - void on_actionHelpMPEditcap_triggered(); - void on_actionHelpMPMergecap_triggered(); - void on_actionHelpMPRawshark_triggered(); - void on_actionHelpMPReordercap_triggered(); - void on_actionHelpMPText2pcap_triggered(); - void on_actionHelpMPTShark_triggered(); - void on_actionHelpWebsite_triggered(); - void on_actionHelpFAQ_triggered(); - void on_actionHelpAsk_triggered(); - void on_actionHelpDownloads_triggered(); - void on_actionHelpWiki_triggered(); - void on_actionHelpSampleCaptures_triggered(); - void on_actionHelpAbout_triggered(); - -#ifdef HAVE_SOFTWARE_UPDATE - void checkForUpdates(); -#endif - - void on_goToCancel_clicked(); - void on_goToGo_clicked(); - void on_goToLineEdit_returnPressed(); - void on_actionCaptureStart_triggered(); - void on_actionCaptureStop_triggered(); - void on_actionCaptureRestart_triggered(); - - void on_actionStatisticsCaptureFileProperties_triggered(); - void on_actionStatisticsResolvedAddresses_triggered(); - void on_actionStatisticsProtocolHierarchy_triggered(); - void on_actionStatisticsFlowGraph_triggered(); - void openTcpStreamDialog(int graph_type); - void on_actionStatisticsTcpStreamStevens_triggered(); - void on_actionStatisticsTcpStreamTcptrace_triggered(); - void on_actionStatisticsTcpStreamThroughput_triggered(); - void on_actionStatisticsTcpStreamRoundTripTime_triggered(); - void on_actionStatisticsTcpStreamWindowScaling_triggered(); - void openSCTPAllAssocsDialog(); - void on_actionSCTPShowAllAssociations_triggered(); - void on_actionSCTPAnalyseThisAssociation_triggered(); - void on_actionSCTPFilterThisAssociation_triggered(); - void statCommandMulticastStatistics(const char *arg, void *); - void on_actionStatisticsUdpMulticastStreams_triggered(); - - void statCommandWlanStatistics(const char *arg, void *); - void on_actionWirelessWlanStatistics_triggered(); - - void openStatisticsTreeDialog(const gchar *abbr); - void on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered(); - void on_actionStatistics29WestTopics_Advertisements_by_Source_triggered(); - void on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered(); - void on_actionStatistics29WestTopics_Queries_by_Topic_triggered(); - void on_actionStatistics29WestTopics_Queries_by_Receiver_triggered(); - void on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered(); - void on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered(); - void on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered(); - void on_actionStatistics29WestQueues_Advertisements_by_Source_triggered(); - void on_actionStatistics29WestQueues_Queries_by_Queue_triggered(); - void on_actionStatistics29WestQueues_Queries_by_Receiver_triggered(); - void on_actionStatistics29WestUIM_Streams_triggered(); - void on_actionStatistics29WestLBTRM_triggered(); - void on_actionStatistics29WestLBTRU_triggered(); - void on_actionStatisticsANCP_triggered(); - void on_actionStatisticsBACappInstanceId_triggered(); - void on_actionStatisticsBACappIP_triggered(); - void on_actionStatisticsBACappObjectId_triggered(); - void on_actionStatisticsBACappService_triggered(); - void on_actionStatisticsCollectd_triggered(); - void statCommandConversations(const char *arg = NULL, void *userdata = NULL); - void on_actionStatisticsConversations_triggered(); - void statCommandEndpoints(const char *arg = NULL, void *userdata = NULL); - void on_actionStatisticsEndpoints_triggered(); - void on_actionStatisticsHART_IP_triggered(); - void on_actionStatisticsHTTPPacketCounter_triggered(); - void on_actionStatisticsHTTPRequests_triggered(); - void on_actionStatisticsHTTPLoadDistribution_triggered(); - void on_actionStatisticsHTTPRequestSequences_triggered(); - void on_actionStatisticsPacketLengths_triggered(); - void statCommandIOGraph(const char *, void *); - void on_actionStatisticsIOGraph_triggered(); - void on_actionStatisticsSametime_triggered(); - void on_actionStatisticsDNS_triggered(); - void actionStatisticsPlugin_triggered(); - void on_actionStatisticsHpfeeds_triggered(); - void on_actionStatisticsHTTP2_triggered(); - void on_actionStatisticsSOMEIPmessages_triggered(); - void on_actionStatisticsSOMEIPSDentries_triggered(); - - RtpStreamDialog *openTelephonyRtpStreamsDialog(); - RtpPlayerDialog *openTelephonyRtpPlayerDialog(); - VoipCallsDialog *openTelephonyVoipCallsDialogVoip(); - VoipCallsDialog *openTelephonyVoipCallsDialogSip(); - RtpAnalysisDialog *openTelephonyRtpAnalysisDialog(); - void on_actionTelephonyVoipCalls_triggered(); - void on_actionTelephonyGsmMapSummary_triggered(); - void statCommandLteMacStatistics(const char *arg, void *); - void on_actionTelephonyLteRlcStatistics_triggered(); - void statCommandLteRlcStatistics(const char *arg, void *); - void on_actionTelephonyLteMacStatistics_triggered(); - void on_actionTelephonyLteRlcGraph_triggered(); - void on_actionTelephonyIax2StreamAnalysis_triggered(); - void on_actionTelephonyISUPMessages_triggered(); - void on_actionTelephonyMtp3Summary_triggered(); - void on_actionTelephonyOsmuxPacketCounter_triggered(); - void on_actionTelephonyRtpStreams_triggered(); - void on_actionTelephonyRtpStreamAnalysis_triggered(); - void on_actionTelephonyRtpPlayer_triggered(); - void on_actionTelephonyRTSPPacketCounter_triggered(); - void on_actionTelephonySMPPOperations_triggered(); - void on_actionTelephonyUCPMessages_triggered(); - void on_actionTelephonyF1APMessages_triggered(); - void on_actionTelephonyNGAPMessages_triggered(); - void on_actionTelephonySipFlows_triggered(); - - void on_actionBluetoothATT_Server_Attributes_triggered(); - void on_actionBluetoothDevices_triggered(); - void on_actionBluetoothHCI_Summary_triggered(); - - void on_actionToolsFirewallAclRules_triggered(); - void on_actionToolsCredentials_triggered(); - - void externalMenuItem_triggered(); - - void on_actionAnalyzeShowPacketBytes_triggered(); - - void on_actionContextWikiProtocolPage_triggered(); - void on_actionContextFilterFieldReference_triggered(); - - void extcap_options_finished(int result); - void showExtcapOptionsDialog(QString & device_name, bool startCaptureOnClose); - - QString findRtpStreams(QVector *stream_ids, bool reverse); - - friend class MainApplication; }; #endif // MAINWINDOW_H diff --git a/ui/qt/main_window_layout.cpp b/ui/qt/main_window_layout.cpp index 8b770c0f8c..1d91de778a 100644 --- a/ui/qt/main_window_layout.cpp +++ b/ui/qt/main_window_layout.cpp @@ -22,12 +22,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include @@ -35,18 +37,18 @@ * The generated Ui_MainWindow::setupUi() can grow larger than our configured limit, * so turn off -Wframe-larger-than= for ui_main_window.h. */ -DIAG_OFF(frame-larger-than=) -#include -DIAG_ON(frame-larger-than=) +//DIAG_OFF(frame-larger-than=) +//#include +//DIAG_ON(frame-larger-than=) void MainWindow::showWelcome() { - main_ui_->mainStack->setCurrentWidget(welcome_page_); + main_stack_->setCurrentWidget(welcome_page_); } void MainWindow::showCapture() { - main_ui_->mainStack->setCurrentWidget(&master_split_); + main_stack_->setCurrentWidget(&master_split_); } QWidget* MainWindow::getLayoutWidget(layout_pane_content_e type) { @@ -91,12 +93,12 @@ void MainWindow::layoutPanes() // Reparent all widgets and add them back in the proper order below. // This hides each widget as well. packet_list_->freeze(); // Clears tree, byte view tabs, and diagram. - packet_list_->setParent(main_ui_->mainStack); - proto_tree_->setParent(main_ui_->mainStack); - byte_view_tab_->setParent(main_ui_->mainStack); - packet_diagram_->setParent(main_ui_->mainStack); - empty_pane_.setParent(main_ui_->mainStack); - extra_split_.setParent(main_ui_->mainStack); + packet_list_->setParent(main_stack_); + proto_tree_->setParent(main_stack_); + byte_view_tab_->setParent(main_stack_); + packet_diagram_->setParent(main_stack_); + empty_pane_.setParent(main_stack_); + extra_split_.setParent(main_stack_); // XXX We should try to preserve geometries if we can, e.g. by // checking to see if the layout type is the same. @@ -189,12 +191,12 @@ void MainWindow::applyRecentPaneGeometry() // each. // Force a geometry recalculation - QWidget *cur_w = main_ui_->mainStack->currentWidget(); + QWidget *cur_w = main_stack_->currentWidget(); showCapture(); - QRect geom = main_ui_->mainStack->geometry(); + QRect geom = main_stack_->geometry(); QList master_sizes = master_split_.sizes(); QList extra_sizes = extra_split_.sizes(); - main_ui_->mainStack->setCurrentWidget(cur_w); + main_stack_->setCurrentWidget(cur_w); int master_last_size = master_split_.orientation() == Qt::Vertical ? geom.height() : geom.width(); master_last_size -= master_split_.handleWidth() * (master_sizes.length() - 1); diff --git a/ui/qt/packet_diagram.cpp b/ui/qt/packet_diagram.cpp index 249e6f09e9..22cb7dafac 100644 --- a/ui/qt/packet_diagram.cpp +++ b/ui/qt/packet_diagram.cpp @@ -19,14 +19,16 @@ #include "main_application.h" #include "ui/qt/main_window.h" +#include "ui/qt/capture_file_dialog.h" #include "ui/qt/utils/proto_node.h" #include "ui/qt/utils/variant_pointer.h" #include "ui/recent.h" - +#include #include #include #include +#include #if defined(QT_SVG_LIB) && 0 #include diff --git a/ui/qt/show_packet_bytes_dialog.cpp b/ui/qt/show_packet_bytes_dialog.cpp index fde88c3287..0937c351e0 100644 --- a/ui/qt/show_packet_bytes_dialog.cpp +++ b/ui/qt/show_packet_bytes_dialog.cpp @@ -19,6 +19,7 @@ #include "wsutil/utf8_entities.h" #include +#include #include #include #include diff --git a/ui/qt/widgets/packet_list_header.cpp b/ui/qt/widgets/packet_list_header.cpp index 1dbc6560af..90710638f4 100644 --- a/ui/qt/widgets/packet_list_header.cpp +++ b/ui/qt/widgets/packet_list_header.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include diff --git a/ui/qt/wireshark_main_window.cpp b/ui/qt/wireshark_main_window.cpp new file mode 100644 index 0000000000..c38d80614b --- /dev/null +++ b/ui/qt/wireshark_main_window.cpp @@ -0,0 +1,3162 @@ +/* main_window.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "main_application.h" +#include "wireshark_main_window.h" + +/* + * The generated Ui_WiresharkMainWindow::setupUi() can grow larger than our configured limit, + * so turn off -Wframe-larger-than= for ui_main_window.h. + */ +DIAG_OFF(frame-larger-than=) +#include +DIAG_ON(frame-larger-than=) + +#include +#include "epan/conversation_filter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui/iface_toolbar.h" + +#ifdef HAVE_LIBPCAP +#include "ui/capture.h" +#include +#endif + +#include "ui/alert_box.h" +#ifdef HAVE_LIBPCAP +#include "ui/capture_ui_utils.h" +#endif +#include "ui/capture_globals.h" +#include "ui/main_statusbar.h" +#include "ui/recent.h" +#include "ui/recent_utils.h" +#include "ui/util.h" +#include "ui/preference_utils.h" + +#include "byte_view_tab.h" +#ifdef HAVE_LIBPCAP +#include "capture_options_dialog.h" +#endif +#include "conversation_colorize_action.h" +#include "export_dissection_dialog.h" +#include "export_object_action.h" +#include "file_set_dialog.h" +#include "filter_dialog.h" +#include "funnel_statistics.h" +#include "import_text_dialog.h" +#include "interface_toolbar.h" +#include "packet_diagram.h" +#include "packet_list.h" +#include "proto_tree.h" +#include "simple_dialog.h" +#include "tap_parameter_dialog.h" +#include "wireless_frame.h" +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//menu_recent_file_write_all + +// If we ever add support for multiple windows this will need to be replaced. +static WiresharkMainWindow *gbl_cur_main_window_ = NULL; + +void pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb) +{ + gbl_cur_main_window_->setPipeInputHandler(source, user_data, child_process, input_cb); +} + +static void plugin_if_mainwindow_apply_filter(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + if (g_hash_table_lookup_extended(data_set, "filter_string", NULL, NULL)) { + QString filter((const char *)g_hash_table_lookup(data_set, "filter_string")); + gbl_cur_main_window_->filterPackets(filter); + } +} + +static void plugin_if_mainwindow_preference(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + const char * module_name; + const char * pref_name; + const char * pref_value; + +DIAG_OFF_CAST_AWAY_CONST + if (g_hash_table_lookup_extended(data_set, "pref_module", NULL, (gpointer *)&module_name) && + g_hash_table_lookup_extended(data_set, "pref_key", NULL, (gpointer *)&pref_name) && + g_hash_table_lookup_extended(data_set, "pref_value", NULL, (gpointer *)&pref_value)) + { + unsigned int changed_flags = prefs_store_ext(module_name, pref_name, pref_value); + if (changed_flags) { + mainApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged); + mainApp->emitAppSignal(WiresharkApplication::PreferencesChanged); + } + } +DIAG_ON_CAST_AWAY_CONST +} + +static void plugin_if_mainwindow_gotoframe(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + gpointer framenr; + + if (g_hash_table_lookup_extended(data_set, "frame_nr", NULL, &framenr)) { + if (GPOINTER_TO_UINT(framenr) != 0) + gbl_cur_main_window_->gotoFrame(GPOINTER_TO_UINT(framenr)); + } +} + +#ifdef HAVE_LIBPCAP + +static void plugin_if_mainwindow_get_ws_info(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + ws_info_t *ws_info = NULL; + + if (!g_hash_table_lookup_extended(data_set, "ws_info", NULL, (void**)&ws_info)) + return; + + CaptureFile *cfWrap = gbl_cur_main_window_->captureFile(); + capture_file *cf = cfWrap->capFile(); + + ws_info->ws_info_supported = true; + + /* If we have a filename attached to ws_info clear it */ + if (ws_info->cf_filename != NULL) + { + g_free(ws_info->cf_filename); + ws_info->cf_filename = NULL; + } + + /* Determine the true state of the capture file. We return the true state in + the ws_info structure and DON'T CHANGE the cf->state as we don't want to cause problems + with code that follows this. */ + if (cf) + { + if (cf->filename) + { + /* As we have a cf->filename we'll use the name and the state */ + ws_info->cf_filename = g_strdup(cf->filename); + ws_info->cf_state = cf->state; + } + else + { + /* When we come through here the cf->state can show FILE_READ_DONE even though the + file is actually closed (no filename). A better fix would be to have a + FILE_CLOSE_PENDING state but that involves a lot of code change elsewhere. */ + ws_info->cf_state = FILE_CLOSED; + } + } + + if (!ws_info->cf_filename) + { + /* We may have a filename associated with the main window so let's use it */ + QString fileNameString = gbl_cur_main_window_->getMwFileName(); + if (fileNameString.length()) + { + QByteArray ba = fileNameString.toLatin1(); + const char *c_file_name = ba.data(); + ws_info->cf_filename = g_strdup(c_file_name); + } + } + + if (cf) { + ws_info->cf_count = cf->count; + + QList rows = gbl_cur_main_window_->selectedRows(); + frame_data * fdata = NULL; + if (rows.count() > 0) + fdata = gbl_cur_main_window_->frameDataForRow(rows.at(0)); + + if (cf->state == FILE_READ_DONE && fdata) { + ws_info->cf_framenr = fdata->num; + ws_info->frame_passed_dfilter = (fdata->passed_dfilter == 1); + } + else { + ws_info->cf_framenr = 0; + ws_info->frame_passed_dfilter = FALSE; + } + } + else + { + /* Initialise the other ws_info structure values */ + ws_info->cf_count = 0; + ws_info->cf_framenr = 0; + ws_info->frame_passed_dfilter = FALSE; + } +} + +#endif /* HAVE_LIBPCAP */ + +static void plugin_if_mainwindow_get_frame_data(GHashTable* data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + plugin_if_frame_data_cb extract_cb; + void* user_data; + void** ret_value_ptr; + + if (g_hash_table_lookup_extended(data_set, "extract_cb", NULL, (void**)&extract_cb) && + g_hash_table_lookup_extended(data_set, "user_data", NULL, (void**)&user_data) && + g_hash_table_lookup_extended(data_set, "ret_value_ptr", NULL, (void**)&ret_value_ptr)) + { + QList rows = gbl_cur_main_window_->selectedRows(); + if (rows.count() > 0) { + frame_data* fdata = gbl_cur_main_window_->frameDataForRow(rows.at(0)); + if (fdata) { + *ret_value_ptr = extract_cb(fdata, user_data); + } + } + } +} + +static void plugin_if_mainwindow_get_capture_file(GHashTable* data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + plugin_if_capture_file_cb extract_cb; + void* user_data; + void** ret_value_ptr; + + if (g_hash_table_lookup_extended(data_set, "extract_cb", NULL, (void**)&extract_cb) && + g_hash_table_lookup_extended(data_set, "user_data", NULL, (void**)&user_data) && + g_hash_table_lookup_extended(data_set, "ret_value_ptr", NULL, (void**)&ret_value_ptr)) + { + CaptureFile* cfWrap = gbl_cur_main_window_->captureFile(); + capture_file* cf = cfWrap->capFile(); + if (cf) { + *ret_value_ptr = extract_cb(cf, user_data); + } + } +} + +static void plugin_if_mainwindow_update_toolbars(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + if (g_hash_table_lookup_extended(data_set, "toolbar_name", NULL, NULL)) { + QString toolbarName((const char *)g_hash_table_lookup(data_set, "toolbar_name")); + gbl_cur_main_window_->removeAdditionalToolbar(toolbarName); + + } +} + +static void mainwindow_add_toolbar(const iface_toolbar *toolbar_entry) +{ + if (gbl_cur_main_window_ && toolbar_entry) + { + gbl_cur_main_window_->addInterfaceToolbar(toolbar_entry); + } +} + +static void mainwindow_remove_toolbar(const gchar *menu_title) +{ + if (gbl_cur_main_window_ && menu_title) + { + gbl_cur_main_window_->removeInterfaceToolbar(menu_title); + } +} + +QMenu* WiresharkMainWindow::findOrAddMenu(QMenu *parent_menu, QString& menu_text) { + QList actions = parent_menu->actions(); + QList::const_iterator i; + for (i = actions.constBegin(); i != actions.constEnd(); ++i) { + if ((*i)->text()==menu_text) { + return (*i)->menu(); + } + } + // If we get here there menu entry was not found, add a sub menu + return parent_menu->addMenu(menu_text); +} + +WiresharkMainWindow::WiresharkMainWindow(QWidget *parent) : + MainWindow(parent), + main_ui_(new Ui::WiresharkMainWindow), + previous_focus_(NULL), + file_set_dialog_(NULL), + show_hide_actions_(NULL), + time_display_actions_(NULL), + time_precision_actions_(NULL), + funnel_statistics_(NULL), + freeze_focus_(NULL), + was_maximized_(false), + capture_stopping_(false), + capture_filter_valid_(false) +#ifdef HAVE_LIBPCAP + , capture_options_dialog_(NULL) + , info_data_() +#endif + , display_filter_dlg_(NULL) + , capture_filter_dlg_(NULL) +#ifdef _WIN32 + , pipe_timer_(NULL) +#else + , pipe_notifier_(NULL) +#endif +#if defined(Q_OS_MAC) + , dock_menu_(NULL) +#endif +{ + if (!gbl_cur_main_window_) { + connect(mainApp, SIGNAL(openStatCommandDialog(QString, const char*, void*)), + this, SLOT(openStatCommandDialog(QString, const char*, void*))); + connect(mainApp, SIGNAL(openTapParameterDialog(QString, const QString, void*)), + this, SLOT(openTapParameterDialog(QString, const QString, void*))); + } + gbl_cur_main_window_ = this; +#ifdef HAVE_LIBPCAP + capture_input_init(&cap_session_, CaptureFile::globalCapFile()); +#endif + + findTextCodecs(); + // setpUi calls QMetaObject::connectSlotsByName(this). connectSlotsByName + // iterates over *all* of our children, looking for matching "on_" slots. + // The fewer children we have at this point the better. + main_ui_->setupUi(this); +#ifdef HAVE_SOFTWARE_UPDATE + update_action_ = new QAction(tr("Check for Updates…"), main_ui_->menuHelp); +#endif +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + wireless_frame_ = new WirelessFrame(this); + main_ui_->wirelessToolBar->addWidget(wireless_frame_); +#else + removeToolBar(main_ui_->wirelessToolBar); + main_ui_->menuView->removeAction(main_ui_->actionViewWirelessToolbar); +#endif + + setWindowIcon(mainApp->normalIcon()); + setTitlebarForCaptureFile(); + setMenusForCaptureFile(); + setForCapturedPackets(false); + setMenusForFileSet(false); + interfaceSelectionChanged(); + loadWindowGeometry(); + +#ifndef HAVE_LUA + main_ui_->actionAnalyzeReloadLuaPlugins->setVisible(false); +#endif + + qRegisterMetaType("FilterAction::Action"); + qRegisterMetaType("FilterAction::ActionType"); + connect(this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SLOT(queuedFilterAction(QString, FilterAction::Action, FilterAction::ActionType)), + Qt::QueuedConnection); + + //To prevent users use features before initialization complete + //Otherwise unexpected problems may occur + setFeaturesEnabled(false); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(setFeaturesEnabled())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(applyGlobalCommandLineOptions())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(zoomText())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initViewColorizeMenu())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addStatsPluginsToMenu())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addDynamicMenus())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addPluginIFStructures())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initConversationMenus())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initExportObjectsMenus())); + + connect(mainApp, SIGNAL(profileChanging()), this, SLOT(saveWindowGeometry())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(layoutPanes())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(layoutToolbars())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(updatePreferenceActions())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(zoomText())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(setTitlebarForCaptureFile())); + + connect(mainApp, SIGNAL(updateRecentCaptureStatus(const QString &, qint64, bool)), this, SLOT(updateRecentCaptures())); + updateRecentCaptures(); + +#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) + connect(mainApp, SIGNAL(softwareUpdateRequested()), this, SLOT(softwareUpdateRequested()), + Qt::BlockingQueuedConnection); + connect(mainApp, SIGNAL(softwareUpdateClose()), this, SLOT(close()), + Qt::BlockingQueuedConnection); +#endif + + df_combo_box_ = new DisplayFilterCombo(this); + + funnel_statistics_ = new FunnelStatistics(this, capture_file_); + connect(df_combo_box_, &QComboBox::editTextChanged, funnel_statistics_, &FunnelStatistics::displayFilterTextChanged); + connect(funnel_statistics_, &FunnelStatistics::setDisplayFilter, this, &WiresharkMainWindow::setDisplayFilter); + connect(funnel_statistics_, SIGNAL(openCaptureFile(QString, QString)), + this, SLOT(openCaptureFile(QString, QString))); + + file_set_dialog_ = new FileSetDialog(this); + connect(file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString)), + this, SLOT(openCaptureFile(QString))); + + initMainToolbarIcons(); + + main_ui_->displayFilterToolBar->insertWidget(main_ui_->actionNewDisplayFilterExpression, df_combo_box_); + + // Make sure filter expressions overflow into a menu instead of a + // larger toolbar. We do this by adding them to a child toolbar. + // https://bugreports.qt.io/browse/QTBUG-2472 + FilterExpressionToolBar *filter_expression_toolbar_ = new FilterExpressionToolBar(this); + connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterPreferences, this, &WiresharkMainWindow::onFilterPreferences); + connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterSelected, this, &WiresharkMainWindow::onFilterSelected); + connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterEdit, this, &WiresharkMainWindow::onFilterEdit); + + main_ui_->displayFilterToolBar->addWidget(filter_expression_toolbar_); + +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + connect(wireless_frame_, SIGNAL(showWirelessPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); +#endif + + main_ui_->goToFrame->hide(); + connect(main_ui_->goToFrame, SIGNAL(visibilityChanged(bool)), + main_ui_->actionGoGoToPacket, SLOT(setChecked(bool))); + + // XXX For some reason the cursor is drawn funny with an input mask set + // https://bugreports.qt-project.org/browse/QTBUG-7174 + + main_ui_->searchFrame->hide(); + connect(main_ui_->searchFrame, SIGNAL(visibilityChanged(bool)), + main_ui_->actionEditFindPacket, SLOT(setChecked(bool))); + + main_ui_->addressEditorFrame->hide(); + main_ui_->columnEditorFrame->hide(); + main_ui_->preferenceEditorFrame->hide(); + main_ui_->filterExpressionFrame->hide(); + +#ifndef HAVE_LIBPCAP + main_ui_->menuCapture->setEnabled(false); +#endif + + // Set OS specific shortcuts for fullscreen mode +#if defined(Q_OS_MAC) + main_ui_->actionViewFullScreen->setShortcut(QKeySequence::FullScreen); +#else + main_ui_->actionViewFullScreen->setShortcut(QKeySequence(Qt::Key_F11)); +#endif + +#if defined(Q_OS_MAC) + + main_ui_->goToPacketLabel->setAttribute(Qt::WA_MacSmallSize, true); + main_ui_->goToLineEdit->setAttribute(Qt::WA_MacSmallSize, true); + main_ui_->goToGo->setAttribute(Qt::WA_MacSmallSize, true); + main_ui_->goToCancel->setAttribute(Qt::WA_MacSmallSize, true); + + main_ui_->actionEditPreferences->setMenuRole(QAction::PreferencesRole); + +#endif // Q_OS_MAC + +// A billion-1 is equivalent to the inputMask 900000000 previously used +// Avoid QValidator::Intermediate values by using a top value of all 9's +#define MAX_GOTO_LINE 999999999 + +QIntValidator *goToLineQiv = new QIntValidator(0,MAX_GOTO_LINE,this); +main_ui_->goToLineEdit->setValidator(goToLineQiv); + +#ifdef HAVE_SOFTWARE_UPDATE + QAction *update_sep = main_ui_->menuHelp->insertSeparator(main_ui_->actionHelpAbout); + main_ui_->menuHelp->insertAction(update_sep, update_action_); + connect(update_action_, SIGNAL(triggered()), this, SLOT(checkForUpdates())); +#endif + master_split_.setObjectName("splitterMaster"); + extra_split_.setObjectName("splitterExtra"); + master_split_.setChildrenCollapsible(false); + extra_split_.setChildrenCollapsible(false); + main_ui_->mainStack->addWidget(&master_split_); + + empty_pane_.setObjectName("emptyPane"); + empty_pane_.setVisible(false); + + packet_list_ = new PacketList(&master_split_); + main_ui_->wirelessTimelineWidget->setPacketList(packet_list_); + connect(packet_list_, SIGNAL(framesSelected(QList)), this, SLOT(setMenusForSelectedPacket())); + connect(packet_list_, SIGNAL(framesSelected(QList)), this, SIGNAL(framesSelected(QList))); + + connect(main_ui_->menuPacketComment, SIGNAL(aboutToShow()), this, SLOT(setEditCommentsMenu())); + + proto_tree_ = new ProtoTree(&master_split_); + proto_tree_->installEventFilter(this); + + packet_list_->setProtoTree(proto_tree_); + packet_list_->installEventFilter(this); + + packet_diagram_ = new PacketDiagram(&master_split_); + + main_stack_ = main_ui_->mainStack; + welcome_page_ = main_ui_->welcomePage; + main_status_bar_ = main_ui_->statusBar; + + connect(proto_tree_, &ProtoTree::fieldSelected, + this, &WiresharkMainWindow::fieldSelected); + connect(packet_list_, &PacketList::fieldSelected, + this, &WiresharkMainWindow::fieldSelected); + connect(this, &WiresharkMainWindow::fieldSelected, + this, &WiresharkMainWindow::setMenusForSelectedTreeRow); + connect(this, &WiresharkMainWindow::fieldSelected, + main_ui_->statusBar, &MainStatusBar::selectedFieldChanged); + + connect(this, &WiresharkMainWindow::fieldHighlight, + main_ui_->statusBar, &MainStatusBar::highlightedFieldChanged); + connect(mainApp, &WiresharkApplication::captureActive, + this, &WiresharkMainWindow::captureActive); + + byte_view_tab_ = new ByteViewTab(&master_split_); + + // Packet list and proto tree must exist before these are called. + setMenusForSelectedPacket(); + setMenusForSelectedTreeRow(); + + initShowHideMainWidgets(); + initTimeDisplayFormatMenu(); + initTimePrecisionFormatMenu(); + initFreezeActions(); + updatePreferenceActions(); + updateRecentActions(); + setForCaptureInProgress(false); + + setTabOrder(df_combo_box_->lineEdit(), packet_list_); + setTabOrder(packet_list_, proto_tree_); + + connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), + this, SLOT(captureEventHandler(CaptureEvent))); + connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), + mainApp, SLOT(captureEventHandler(CaptureEvent))); + connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), + main_ui_->statusBar, SLOT(captureEventHandler(CaptureEvent))); + + connect(mainApp, SIGNAL(columnsChanged()), + packet_list_, SLOT(columnsChanged())); + connect(mainApp, SIGNAL(preferencesChanged()), + packet_list_, SLOT(preferencesChanged())); + connect(mainApp, SIGNAL(recentPreferencesRead()), + this, SLOT(applyRecentPaneGeometry())); + connect(mainApp, SIGNAL(recentPreferencesRead()), + this, SLOT(updateRecentActions())); + connect(mainApp, SIGNAL(packetDissectionChanged()), + this, SLOT(redissectPackets()), Qt::QueuedConnection); + + connect(mainApp, SIGNAL(checkDisplayFilter()), + this, SLOT(checkDisplayFilter())); + connect(mainApp, SIGNAL(fieldsChanged()), + this, SLOT(fieldsChanged())); + connect(mainApp, SIGNAL(reloadLuaPlugins()), + this, SLOT(reloadLuaPlugins())); + + connect(main_ui_->mainStack, SIGNAL(currentChanged(int)), + this, SLOT(mainStackChanged(int))); + + connect(welcome_page_, SIGNAL(startCapture(QStringList)), + this, SLOT(startCapture(QStringList))); + connect(welcome_page_, SIGNAL(recentFileActivated(QString)), + this, SLOT(openCaptureFile(QString))); + + connect(main_ui_->addressEditorFrame, &AddressEditorFrame::redissectPackets, + this, &WiresharkMainWindow::redissectPackets); + connect(main_ui_->addressEditorFrame, &AddressEditorFrame::showNameResolutionPreferences, + this, &WiresharkMainWindow::showPreferencesDialog); + connect(main_ui_->preferenceEditorFrame, &PreferenceEditorFrame::showProtocolPreferences, + this, &WiresharkMainWindow::showPreferencesDialog); + connect(main_ui_->filterExpressionFrame, &FilterExpressionFrame::showPreferencesDialog, + this, &WiresharkMainWindow::showPreferencesDialog); + connect(main_ui_->filterExpressionFrame, &FilterExpressionFrame::filterExpressionsChanged, + filter_expression_toolbar_, &FilterExpressionToolBar::filterExpressionsChanged); + + /* Connect change of capture file */ + connect(this, &WiresharkMainWindow::setCaptureFile, + main_ui_->searchFrame, &SearchFrame::setCaptureFile); + connect(this, &WiresharkMainWindow::setCaptureFile, + main_ui_->statusBar, &MainStatusBar::setCaptureFile); + connect(this, &WiresharkMainWindow::setCaptureFile, + packet_list_, &PacketList::setCaptureFile); + connect(this, &WiresharkMainWindow::setCaptureFile, + proto_tree_, &ProtoTree::setCaptureFile); + + connect(mainApp, SIGNAL(zoomMonospaceFont(QFont)), + packet_list_, SLOT(setMonospaceFont(QFont))); + connect(mainApp, SIGNAL(zoomMonospaceFont(QFont)), + proto_tree_, SLOT(setMonospaceFont(QFont))); + + connect(main_ui_->actionGoNextPacket, SIGNAL(triggered()), + packet_list_, SLOT(goNextPacket())); + connect(main_ui_->actionGoPreviousPacket, SIGNAL(triggered()), + packet_list_, SLOT(goPreviousPacket())); + connect(main_ui_->actionGoFirstPacket, SIGNAL(triggered()), + packet_list_, SLOT(goFirstPacket())); + connect(main_ui_->actionGoLastPacket, SIGNAL(triggered()), + packet_list_, SLOT(goLastPacket())); + connect(main_ui_->actionGoNextHistoryPacket, SIGNAL(triggered()), + packet_list_, SLOT(goNextHistoryPacket())); + connect(main_ui_->actionGoPreviousHistoryPacket, SIGNAL(triggered()), + packet_list_, SLOT(goPreviousHistoryPacket())); + + connect(main_ui_->actionViewExpandSubtrees, SIGNAL(triggered()), + proto_tree_, SLOT(expandSubtrees())); + connect(main_ui_->actionViewCollapseSubtrees, SIGNAL(triggered()), + proto_tree_, SLOT(collapseSubtrees())); + connect(main_ui_->actionViewExpandAll, SIGNAL(triggered()), + proto_tree_, SLOT(expandAll())); + connect(main_ui_->actionViewCollapseAll, SIGNAL(triggered()), + proto_tree_, SLOT(collapseAll())); + + connect(packet_list_, SIGNAL(packetDissectionChanged()), + this, SLOT(redissectPackets())); + connect(packet_list_, SIGNAL(showColumnPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); + connect(packet_list_, SIGNAL(showProtocolPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); + connect(packet_list_, SIGNAL(editProtocolPreference(preference*, pref_module*)), + main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*))); + connect(packet_list_, SIGNAL(editColumn(int)), this, SLOT(showColumnEditor(int))); + connect(main_ui_->columnEditorFrame, SIGNAL(columnEdited()), + packet_list_, SLOT(columnsChanged())); + connect(packet_list_, SIGNAL(doubleClicked(QModelIndex)), + this, SLOT(openPacketDialog())); + connect(packet_list_, SIGNAL(packetListScrolled(bool)), + main_ui_->actionGoAutoScroll, SLOT(setChecked(bool))); + + connect(proto_tree_, SIGNAL(openPacketInNewWindow(bool)), + this, SLOT(openPacketDialog(bool))); + connect(proto_tree_, SIGNAL(showProtocolPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); + connect(proto_tree_, SIGNAL(editProtocolPreference(preference*, pref_module*)), + main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*))); + + connect(main_ui_->statusBar, SIGNAL(showExpertInfo()), + this, SLOT(on_actionAnalyzeExpertInfo_triggered())); + + connect(main_ui_->statusBar, SIGNAL(stopLoading()), + &capture_file_, SLOT(stopLoading())); + + connect(main_ui_->statusBar, SIGNAL(editCaptureComment()), + this, SLOT(on_actionStatisticsCaptureFileProperties_triggered())); + + connect(main_ui_->menuApplyAsFilter, &QMenu::aboutToShow, + this, &WiresharkMainWindow::filterMenuAboutToShow); + connect(main_ui_->menuPrepareAFilter, &QMenu::aboutToShow, + this, &WiresharkMainWindow::filterMenuAboutToShow); + +#ifdef HAVE_LIBPCAP + QTreeWidget *iface_tree = findChild("interfaceTree"); + if (iface_tree) { + connect(iface_tree, SIGNAL(itemSelectionChanged()), + this, SLOT(interfaceSelectionChanged())); + } + connect(main_ui_->welcomePage, SIGNAL(captureFilterSyntaxChanged(bool)), + this, SLOT(captureFilterSyntaxChanged(bool))); + + connect(this, SIGNAL(showExtcapOptions(QString&, bool)), + this, SLOT(showExtcapOptionsDialog(QString&, bool))); + connect(this->welcome_page_, SIGNAL(showExtcapOptions(QString&, bool)), + this, SLOT(showExtcapOptionsDialog(QString&, bool))); + +#endif // HAVE_LIBPCAP + + /* Create plugin_if hooks */ + plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_APPLY, plugin_if_mainwindow_apply_filter); + plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_PREPARE, plugin_if_mainwindow_apply_filter); + plugin_if_register_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, plugin_if_mainwindow_preference); + plugin_if_register_gui_cb(PLUGIN_IF_GOTO_FRAME, plugin_if_mainwindow_gotoframe); +#ifdef HAVE_LIBPCAP + plugin_if_register_gui_cb(PLUGIN_IF_GET_WS_INFO, plugin_if_mainwindow_get_ws_info); +#endif + plugin_if_register_gui_cb(PLUGIN_IF_GET_FRAME_DATA, plugin_if_mainwindow_get_frame_data); + plugin_if_register_gui_cb(PLUGIN_IF_GET_CAPTURE_FILE, plugin_if_mainwindow_get_capture_file); + plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars); + + /* Register Interface Toolbar callbacks */ + iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar); + + /* Show tooltips on menu items that go to websites */ + main_ui_->actionHelpMPWireshark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_WIRESHARK))); + main_ui_->actionHelpMPWireshark_Filter->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_WIRESHARK_FILTER))); + main_ui_->actionHelpMPCapinfos->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_CAPINFOS))); + main_ui_->actionHelpMPDumpcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_DUMPCAP))); + main_ui_->actionHelpMPEditcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_EDITCAP))); + main_ui_->actionHelpMPMergecap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_MERGECAP))); + main_ui_->actionHelpMPRawshark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_RAWSHARK))); + main_ui_->actionHelpMPReordercap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_REORDERCAP))); + main_ui_->actionHelpMPText2pcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_TEXT2PCAP))); + main_ui_->actionHelpMPTShark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_TSHARK))); + + main_ui_->actionHelpContents->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_USERGUIDE))); + main_ui_->actionHelpWebsite->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_HOME))); + main_ui_->actionHelpFAQ->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_FAQ))); + main_ui_->actionHelpAsk->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_ASK))); + main_ui_->actionHelpDownloads->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_DOWNLOAD))); + main_ui_->actionHelpWiki->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_WIKI))); + main_ui_->actionHelpSampleCaptures->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_SAMPLE_CAPTURES))); + + showWelcome(); +} + +WiresharkMainWindow::~WiresharkMainWindow() +{ + disconnect(main_ui_->mainStack, 0, 0, 0); + +#ifndef Q_OS_MAC + // Below dialogs inherit GeometryStateDialog + // For reasons described in geometry_state_dialog.h no parent is set when + // instantiating the dialogs and as a resul objects are not automatically + // freed by its parent. Free then here explicitly to avoid leak and numerous + // Valgrind complaints. + delete file_set_dialog_; + delete capture_filter_dlg_; + delete display_filter_dlg_; +#ifdef HAVE_LIBPCAP + delete capture_options_dialog_; +#endif + +#endif + delete main_ui_; +} + +QMenu *WiresharkMainWindow::createPopupMenu() +{ + QMenu *menu = new QMenu(); + menu->addAction(main_ui_->actionViewMainToolbar); + menu->addAction(main_ui_->actionViewFilterToolbar); +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + menu->addAction(main_ui_->actionViewWirelessToolbar); +#endif + + if (!main_ui_->menuInterfaceToolbars->actions().isEmpty()) { + QMenu *submenu = menu->addMenu(main_ui_->menuInterfaceToolbars->title()); + foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + submenu->addAction(action); + } + } + + if (!main_ui_->menuAdditionalToolbars->actions().isEmpty()) { + QMenu *subMenu = menu->addMenu(main_ui_->menuAdditionalToolbars->title()); + foreach(QAction *action, main_ui_->menuAdditionalToolbars->actions()) { + subMenu->addAction(action); + } + } + + menu->addAction(main_ui_->actionViewStatusBar); + + menu->addSeparator(); + menu->addAction(main_ui_->actionViewPacketList); + menu->addAction(main_ui_->actionViewPacketDetails); + menu->addAction(main_ui_->actionViewPacketBytes); + menu->addAction(main_ui_->actionViewPacketDiagram); + return menu; +} + +void WiresharkMainWindow::addInterfaceToolbar(const iface_toolbar *toolbar_entry) +{ + QMenu *menu = main_ui_->menuInterfaceToolbars; + bool visible = g_list_find_custom(recent.interface_toolbars, toolbar_entry->menu_title, (GCompareFunc)strcmp) ? true : false; + + QString title = QString().fromUtf8(toolbar_entry->menu_title); + QAction *action = new QAction(title, menu); + action->setEnabled(true); + action->setCheckable(true); + action->setChecked(visible); + action->setToolTip(tr("Show or hide the toolbar")); + + QAction *before = NULL; + foreach(QAction *action, menu->actions()) { + // Ensure we add the menu entries in sorted order + if (action->text().compare(title, Qt::CaseInsensitive) > 0) { + before = action; + break; + } + } + menu->insertAction(before, action); + + InterfaceToolbar *interface_toolbar = new InterfaceToolbar(this, toolbar_entry); + connect(mainApp, SIGNAL(appInitialized()), interface_toolbar, SLOT(interfaceListChanged())); + connect(mainApp, SIGNAL(localInterfaceListChanged()), interface_toolbar, SLOT(interfaceListChanged())); + + QToolBar *toolbar = new QToolBar(this); + toolbar->addWidget(interface_toolbar); + toolbar->setMovable(false); + toolbar->setVisible(visible); + + action->setData(QVariant::fromValue(toolbar)); + + addToolBar(Qt::TopToolBarArea, toolbar); + insertToolBarBreak(toolbar); + + if (show_hide_actions_) { + show_hide_actions_->addAction(action); + } + + menu->menuAction()->setVisible(true); +} + +void WiresharkMainWindow::removeInterfaceToolbar(const gchar *menu_title) +{ + QMenu *menu = main_ui_->menuInterfaceToolbars; + QAction *action = NULL; + QMap::iterator i; + + QString title = QString().fromUtf8(menu_title); + foreach(action, menu->actions()) { + if (title.compare(action->text()) == 0) { + break; + } + } + + if (action) { + if (show_hide_actions_) { + show_hide_actions_->removeAction(action); + } + menu->removeAction(action); + + QToolBar *toolbar = action->data().value(); + removeToolBar(toolbar); + + delete action; + delete toolbar; + } + + menu->menuAction()->setVisible(!menu->actions().isEmpty()); +} + +void WiresharkMainWindow::setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb) +{ + pipe_source_ = source; + pipe_child_process_ = child_process; + pipe_user_data_ = user_data; + pipe_input_cb_ = input_cb; + +#ifdef _WIN32 + /* Tricky to use pipes in win9x, as no concept of wait. NT can + do this but that doesn't cover all win32 platforms. GTK can do + this but doesn't seem to work over processes. Attempt to do + something similar here, start a timer and check for data on every + timeout. */ + /*ws_log(NULL, LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/ + + if (pipe_timer_) { + disconnect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout())); + delete pipe_timer_; + } + + pipe_timer_ = new QTimer(this); + connect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout())); + connect(pipe_timer_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed())); + pipe_timer_->start(200); +#else + if (pipe_notifier_) { + disconnect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int))); + delete pipe_notifier_; + } + + pipe_notifier_ = new QSocketNotifier(pipe_source_, QSocketNotifier::Read); + // XXX ui/gtk/gui_utils.c sets the encoding. Do we need to do the same? + connect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int))); + connect(pipe_notifier_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed())); +#endif +} + +bool WiresharkMainWindow::eventFilter(QObject *obj, QEvent *event) { + + // The user typed some text. Start filling in a filter. + // We may need to be more choosy here. We just need to catch events for the packet list, + // proto tree, and main welcome widgets. + if (event->type() == QEvent::KeyPress) { + QKeyEvent *kevt = static_cast(event); + if (kevt->text().length() > 0 && kevt->text()[0].isPrint() && + !(kevt->modifiers() & Qt::ControlModifier)) { + df_combo_box_->lineEdit()->insert(kevt->text()); + df_combo_box_->lineEdit()->setFocus(); + return true; + } + } + + return QMainWindow::eventFilter(obj, event); +} + +bool WiresharkMainWindow::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::ApplicationPaletteChange: + initMainToolbarIcons(); + break; + default: + break; + + } + return QMainWindow::event(event); +} + +void WiresharkMainWindow::keyPressEvent(QKeyEvent *event) { + + // Explicitly focus on the display filter combo. + if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) { + df_combo_box_->setFocus(Qt::ShortcutFocusReason); + return; + } + + if (mainApp->focusWidget() == main_ui_->goToLineEdit) { + if (event->modifiers() == Qt::NoModifier) { + if (event->key() == Qt::Key_Escape) { + on_goToCancel_clicked(); + } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { + on_goToGo_clicked(); + } + } + return; // goToLineEdit didn't want it and we don't either. + } + + // Move up & down the packet list. + if (event->key() == Qt::Key_F7) { + packet_list_->goPreviousPacket(); + } else if (event->key() == Qt::Key_F8) { + packet_list_->goNextPacket(); + } + + // Move along, citizen. + QMainWindow::keyPressEvent(event); +} + +void WiresharkMainWindow::closeEvent(QCloseEvent *event) { + saveWindowGeometry(); + + /* If we're in the middle of stopping a capture, don't do anything; + the user can try deleting the window after the capture stops. */ + if (capture_stopping_) { + event->ignore(); + return; + } + + QString before_what(tr(" before quitting")); + if (!testCaptureFileClose(before_what, Quit)) { + event->ignore(); + return; + } + +#ifdef HAVE_LIBPCAP + if (capture_options_dialog_) capture_options_dialog_->close(); +#endif + // Make sure we kill any open dumpcap processes. + delete welcome_page_; + + // One of the many places we assume one main window. + if (!mainApp->isInitialized()) { + // If we're still initializing, QCoreApplication::quit() won't + // exit properly because we are not in the event loop. This + // means that the application won't clean up after itself. We + // might want to call mainApp->processEvents() during startup + // instead so that we can do a normal exit here. + exit(0); + } + mainApp->quit(); + // When the main loop is not yet running (i.e. when openCaptureFile is + // executing in main.cpp), the above quit action has no effect. + // Schedule a quit action for the next execution of the main loop. + QMetaObject::invokeMethod(mainApp, "quit", Qt::QueuedConnection); +} + +// XXX On windows the drag description is "Copy". It should be "Open" or +// "Merge" as appropriate. It looks like we need access to IDataObject in +// order to set DROPDESCRIPTION. +void WiresharkMainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + if (!event->mimeData()->hasUrls()) + { + event->ignore(); + return; + } + + if (!main_ui_->actionFileOpen->isEnabled()) { + // We could alternatively call setAcceptDrops(!capture_in_progress) + // in setMenusForCaptureInProgress but that wouldn't provide feedback. + + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to drop files during capture.")); + event->setDropAction(Qt::IgnoreAction); + event->ignore(); + return; + } + + bool have_files = false; + foreach(QUrl drag_url, event->mimeData()->urls()) { + if (!drag_url.toLocalFile().isEmpty()) { + have_files = true; + break; + } + } + + if (have_files) { + event->acceptProposedAction(); + } +} + +void WiresharkMainWindow::dropEvent(QDropEvent *event) +{ + if (!event->mimeData()->hasUrls()) + { + event->ignore(); + return; + } + + QList local_files; + int max_dropped_files = 100; // Arbitrary + + foreach(QUrl drop_url, event->mimeData()->urls()) { + QString drop_file = drop_url.toLocalFile(); + if (!drop_file.isEmpty()) { + local_files << drop_file.toUtf8(); + if (local_files.size() >= max_dropped_files) { + break; + } + } + } + + event->acceptProposedAction(); + + if (local_files.size() < 1) { + event->ignore(); + return; + } + + event->accept(); + + if (local_files.size() == 1) { + openCaptureFile(local_files.at(0)); + return; + } + + const char **in_filenames = g_new(const char *, local_files.size()); + char *tmpname = NULL; + + for (int i = 0; i < local_files.size(); i++) { + in_filenames[i] = local_files.at(i).constData(); + } + + /* merge the files in chronological order */ + if (cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, static_cast(local_files.size()), + in_filenames, + wtap_pcapng_file_type_subtype(), + FALSE) == CF_OK) { + /* Merge succeeded; close the currently-open file and try + to open the merged capture file. */ + openCaptureFile(tmpname, QString(), WTAP_TYPE_AUTO, TRUE); + } + + g_free(tmpname); + g_free(in_filenames); +} + +// Apply recent settings to the main window geometry. +// We haven't loaded the preferences at this point so we assume that the +// position and size preference are enabled. +// Note we might end up with unexpected screen geometries if the user +// unplugs or plugs in a monitor: +// https://bugreports.qt.io/browse/QTBUG-44213 +void WiresharkMainWindow::loadWindowGeometry() +{ + int min_sensible_dimension = 200; + +#ifndef Q_OS_MAC + if (recent.gui_geometry_main_maximized) { + setWindowState(Qt::WindowMaximized); + } else +#endif + { + QRect recent_geom(recent.gui_geometry_main_x, recent.gui_geometry_main_y, + recent.gui_geometry_main_width, recent.gui_geometry_main_height); + if (!rect_on_screen(recent_geom)) { + // We're not visible on any screens. See if we can move onscreen + // without resizing. + recent_geom.moveTo(50, 50); // recent.c defaults to 20. + } + + if (!rect_on_screen(recent_geom)) { + // Give up and use the default geometry. + return; + } + +// if (prefs.gui_geometry_save_position) { + move(recent_geom.topLeft()); +// } + + if (// prefs.gui_geometry_save_size && + recent_geom.width() > min_sensible_dimension && + recent_geom.height() > min_sensible_dimension) { + resize(recent_geom.size()); + } + } +} + +void WiresharkMainWindow::saveWindowGeometry() +{ + if (prefs.gui_geometry_save_position) { + recent.gui_geometry_main_x = pos().x(); + recent.gui_geometry_main_y = pos().y(); + } + + if (prefs.gui_geometry_save_size) { + recent.gui_geometry_main_width = size().width(); + recent.gui_geometry_main_height = size().height(); + } + + if (prefs.gui_geometry_save_maximized) { + // On macOS this is false when it shouldn't be + recent.gui_geometry_main_maximized = isMaximized(); + } + + if (master_split_.sizes().length() > 0) { + recent.gui_geometry_main_upper_pane = master_split_.sizes()[0]; + } + + if (master_split_.sizes().length() > 2) { + recent.gui_geometry_main_lower_pane = master_split_.sizes()[1]; + } else if (extra_split_.sizes().length() > 0) { + recent.gui_geometry_main_lower_pane = extra_split_.sizes()[0]; + } +} + +// Our event loop becomes nested whenever we call update_progress_dlg, which +// includes several places in file.c. The GTK+ UI stays out of trouble by +// showing a modal progress dialog. We attempt to do the equivalent below by +// disabling parts of the main window. At a minumum the ProgressFrame in the +// main status bar must remain accessible. +// +// We might want to do this any time the main status bar progress frame is +// shown and hidden. +void WiresharkMainWindow::freeze() +{ + freeze_focus_ = mainApp->focusWidget(); + + // XXX Alternatively we could just disable and enable the main menu. + for (int i = 0; i < freeze_actions_.size(); i++) { + QAction *action = freeze_actions_[i].first; + freeze_actions_[i].second = action->isEnabled(); + action->setEnabled(false); + } + main_ui_->centralWidget->setEnabled(false); +} + +void WiresharkMainWindow::thaw() +{ + main_ui_->centralWidget->setEnabled(true); + for (int i = 0; i < freeze_actions_.size(); i++) { + freeze_actions_[i].first->setEnabled(freeze_actions_[i].second); + } + + if (freeze_focus_) freeze_focus_->setFocus(); + freeze_focus_ = NULL; +} + +void WiresharkMainWindow::mergeCaptureFile() +{ + QString file_name = ""; + QString read_filter = ""; + dfilter_t *rfcode = NULL; + int err; + + if (!capture_file_.capFile()) + return; + + if (prefs.gui_ask_unsaved) { + if (cf_has_unsaved_data(capture_file_.capFile())) { + QMessageBox msg_dialog; + gchar *display_basename; + int response; + + msg_dialog.setIcon(QMessageBox::Question); + /* This file has unsaved data; ask the user whether to save + the capture. */ + if (capture_file_.capFile()->is_tempfile) { + msg_dialog.setText(tr("Save packets before merging?")); + msg_dialog.setInformativeText(tr("A temporary capture file can't be merged.")); + } else { + /* + * Format the message. + */ + display_basename = g_filename_display_basename(capture_file_.capFile()->filename); + msg_dialog.setText(QString(tr("Save changes in \"%1\" before merging?")).arg(display_basename)); + g_free(display_basename); + msg_dialog.setInformativeText(tr("Changes must be saved before the files can be merged.")); + } + + msg_dialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); + msg_dialog.setDefaultButton(QMessageBox::Save); + + response = msg_dialog.exec(); + + switch (response) { + + case QMessageBox::Save: + /* Save the file but don't close it */ + saveCaptureFile(capture_file_.capFile(), false); + break; + + case QMessageBox::Cancel: + default: + /* Don't do the merge. */ + return; + } + } + } + + for (;;) { + CaptureFileDialog merge_dlg(this, capture_file_.capFile(), read_filter); + int file_type; + cf_status_t merge_status; + char *in_filenames[2]; + char *tmpname; + + if (merge_dlg.merge(file_name)) { + gchar *err_msg; + + if (!dfilter_compile(qUtf8Printable(read_filter), &rfcode, &err_msg)) { + /* Not valid. Tell the user, and go back and run the file + selection box again once they dismiss the alert. */ + // Similar to commandline_info.jfilter section in main(). + QMessageBox::warning(this, tr("Invalid Read Filter"), + QString(tr("The filter expression %1 isn't a valid read filter. (%2).").arg(read_filter, err_msg)), + QMessageBox::Ok); + g_free(err_msg); + continue; + } + } else { + return; + } + + file_type = capture_file_.capFile()->cd_t; + + /* Try to merge or append the two files */ + if (merge_dlg.mergeType() == 0) { + /* chronological order */ + in_filenames[0] = g_strdup(capture_file_.capFile()->filename); + in_filenames[1] = qstring_strdup(file_name); + merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, FALSE); + } else if (merge_dlg.mergeType() <= 0) { + /* prepend file */ + in_filenames[0] = qstring_strdup(file_name); + in_filenames[1] = g_strdup(capture_file_.capFile()->filename); + merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, TRUE); + } else { + /* append file */ + in_filenames[0] = g_strdup(capture_file_.capFile()->filename); + in_filenames[1] = qstring_strdup(file_name); + merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, TRUE); + } + + g_free(in_filenames[0]); + g_free(in_filenames[1]); + + if (merge_status != CF_OK) { + dfilter_free(rfcode); + g_free(tmpname); + continue; + } + + cf_close(capture_file_.capFile()); + + /* Try to open the merged capture file. */ + CaptureFile::globalCapFile()->window = this; + if (cf_open(CaptureFile::globalCapFile(), tmpname, WTAP_TYPE_AUTO, TRUE /* temporary file */, &err) != CF_OK) { + /* We couldn't open it; fail. */ + CaptureFile::globalCapFile()->window = NULL; + dfilter_free(rfcode); + g_free(tmpname); + return; + } + + /* Attach the new read filter to "cf" ("cf_open()" succeeded, so + it closed the previous capture file, and thus destroyed any + previous read filter attached to "cf"). */ + cf_set_rfcode(CaptureFile::globalCapFile(), rfcode); + + switch (cf_read(CaptureFile::globalCapFile(), FALSE)) { + + case CF_READ_OK: + case CF_READ_ERROR: + /* Just because we got an error, that doesn't mean we were unable + to read any of the file; we handle what we could get from the + file. */ + break; + + case CF_READ_ABORTED: + /* The user bailed out of re-reading the capture file; the + capture file has been closed - just free the capture file name + string and return (without changing the last containing + directory). */ + g_free(tmpname); + return; + } + + /* Save the name of the containing directory specified in the path name. */ + mainApp->setLastOpenDirFromFilename(tmpname); + g_free(tmpname); + main_ui_->statusBar->showExpert(); + return; + } + +} + +void WiresharkMainWindow::importCaptureFile() { + ImportTextDialog import_dlg; + + QString before_what(tr(" before importing a capture")); + if (!testCaptureFileClose(before_what)) + return; + + import_dlg.exec(); + + if (import_dlg.result() != QDialog::Accepted) { + showWelcome(); + return; + } + + openCaptureFile(import_dlg.capfileName()); +} + +bool WiresharkMainWindow::saveCaptureFile(capture_file *cf, bool dont_reopen) { + QString file_name; + gboolean discard_comments; + + if (cf->is_tempfile) { + /* This is a temporary capture file, so saving it means saving + it to a permanent file. Prompt the user for a location + to which to save it. Don't require that the file format + support comments - if it's a temporary capture file, it's + probably pcapng, which supports comments and, if it's + not pcapng, let the user decide what they want to do + if they've added comments. */ + return saveAsCaptureFile(cf, FALSE, dont_reopen); + } else { + if (cf->unsaved_changes) { + cf_write_status_t status; + + /* This is not a temporary capture file, but it has unsaved + changes, so saving it means doing a "safe save" on top + of the existing file, in the same format - no UI needed + unless the file has comments and the file's format doesn't + support them. + + If the file has comments, does the file's format support them? + If not, ask the user whether they want to discard the comments + or choose a different format. */ + switch (CaptureFileDialog::checkSaveAsWithComments(this, cf, cf->cd_t)) { + + case SAVE: + /* The file can be saved in the specified format as is; + just drive on and save in the format they selected. */ + discard_comments = FALSE; + break; + + case SAVE_WITHOUT_COMMENTS: + /* The file can't be saved in the specified format as is, + but it can be saved without the comments, and the user + said "OK, discard the comments", so save it in the + format they specified without the comments. */ + discard_comments = TRUE; + break; + + case SAVE_IN_ANOTHER_FORMAT: + /* There are file formats in which we can save this that + support comments, and the user said not to delete the + comments. Do a "Save As" so the user can select + one of those formats and choose a file name. */ + return saveAsCaptureFile(cf, TRUE, dont_reopen); + + case CANCELLED: + /* The user said "forget it". Just return. */ + return false; + + default: + /* Squelch warnings that discard_comments is being used + uninitialized. */ + ws_assert_not_reached(); + return false; + } + + /* XXX - cf->filename might get freed out from under us, because + the code path through which cf_save_records() goes currently + closes the current file and then opens and reloads the saved file, + so make a copy and free it later. */ + file_name = cf->filename; + status = cf_save_records(cf, qUtf8Printable(file_name), cf->cd_t, cf->compression_type, + discard_comments, dont_reopen); + switch (status) { + + case CF_WRITE_OK: + /* The save succeeded; we're done. + If we discarded comments, redraw the packet list to reflect + any packets that no longer have comments. */ + if (discard_comments) + packet_list_queue_draw(); + + cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes + updateForUnsavedChanges(); // we update the title bar to remove the * + break; + + case CF_WRITE_ERROR: + /* The write failed. + XXX - OK, what do we do now? Let them try a + "Save As", in case they want to try to save to a + different directory or file system? */ + break; + + case CF_WRITE_ABORTED: + /* The write was aborted; just drive on. */ + return false; + } + } + /* Otherwise just do nothing. */ + } + + return true; +} + +bool WiresharkMainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool dont_reopen) { + QString file_name = ""; + int file_type; + wtap_compression_type compression_type; + cf_write_status_t status; + gchar *dirname; + gboolean discard_comments = FALSE; + + if (!cf) { + return false; + } + + for (;;) { + CaptureFileDialog save_as_dlg(this, cf); + + /* If the file has comments, does the format the user selected + support them? If not, ask the user whether they want to + discard the comments or choose a different format. */ + switch (save_as_dlg.saveAs(file_name, must_support_comments)) { + + case SAVE: + /* The file can be saved in the specified format as is; + just drive on and save in the format they selected. */ + discard_comments = FALSE; + break; + + case SAVE_WITHOUT_COMMENTS: + /* The file can't be saved in the specified format as is, + but it can be saved without the comments, and the user + said "OK, discard the comments", so save it in the + format they specified without the comments. */ + discard_comments = TRUE; + break; + + case SAVE_IN_ANOTHER_FORMAT: + /* There are file formats in which we can save this that + support comments, and the user said not to delete the + comments. The combo box of file formats has had the + formats that don't support comments trimmed from it, + so run the dialog again, to let the user decide + whether to save in one of those formats or give up. */ + must_support_comments = TRUE; + continue; + + case CANCELLED: + /* The user said "forget it". Just get rid of the dialog box + and return. */ + return false; + } + file_type = save_as_dlg.selectedFileType(); + if (file_type == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) { + /* This "should not happen". */ + QMessageBox msg_dialog; + + msg_dialog.setIcon(QMessageBox::Critical); + msg_dialog.setText(tr("Unknown file type returned by merge dialog.")); + msg_dialog.setInformativeText(tr("Please report this as a Wireshark issue at https://gitlab.com/wireshark/wireshark/-/issues.")); + msg_dialog.exec(); + return false; + } + compression_type = save_as_dlg.compressionType(); + +#ifdef Q_OS_WIN + // the Windows dialog does not fixup extensions, do it manually here. + fileAddExtension(file_name, file_type, compression_type); +#endif // Q_OS_WIN + +//#ifndef _WIN32 +// /* If the file exists and it's user-immutable or not writable, +// ask the user whether they want to override that. */ +// if (!file_target_unwritable_ui(top_level, qUtf8Printable(file_name))) { +// /* They don't. Let them try another file name or cancel. */ +// continue; +// } +//#endif + + /* Attempt to save the file */ + status = cf_save_records(cf, qUtf8Printable(file_name), file_type, compression_type, + discard_comments, dont_reopen); + switch (status) { + + case CF_WRITE_OK: + /* The save succeeded; we're done. */ + /* Save the directory name for future file dialogs. */ + dirname = qstring_strdup(file_name); /* Overwrites cf_name */ + set_last_open_dir(get_dirname(dirname)); + g_free(dirname); + /* If we discarded comments, redraw the packet list to reflect + any packets that no longer have comments. */ + if (discard_comments) + packet_list_queue_draw(); + + cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes + updateForUnsavedChanges(); // we update the title bar to remove the * + /* Add this filename to the list of recent files in the "Recent Files" submenu */ + add_menu_recent_capture_file(qUtf8Printable(file_name)); + return true; + + case CF_WRITE_ERROR: + /* The save failed; let the user try again. */ + continue; + + case CF_WRITE_ABORTED: + /* The user aborted the save; just return. */ + return false; + } + } + return true; +} + +void WiresharkMainWindow::exportSelectedPackets() { + QString file_name = ""; + int file_type; + wtap_compression_type compression_type; + packet_range_t range; + cf_write_status_t status; + gchar *dirname; + bool discard_comments = false; + + if (!capture_file_.capFile()) + return; + + /* Init the packet range */ + packet_range_init(&range, capture_file_.capFile()); + range.process_filtered = TRUE; + range.include_dependents = TRUE; + + QList rows = packet_list_->selectedRows(true); + + QStringList entries; + foreach (int row, rows) + entries << QString::number(row); + QString selRange = entries.join(","); + + for (;;) { + CaptureFileDialog esp_dlg(this, capture_file_.capFile()); + + /* If the file has comments, does the format the user selected + support them? If not, ask the user whether they want to + discard the comments or choose a different format. */ + switch (esp_dlg.exportSelectedPackets(file_name, &range, selRange)) { + + case SAVE: + /* The file can be saved in the specified format as is; + just drive on and save in the format they selected. */ + discard_comments = FALSE; + break; + + case SAVE_WITHOUT_COMMENTS: + /* The file can't be saved in the specified format as is, + but it can be saved without the comments, and the user + said "OK, discard the comments", so save it in the + format they specified without the comments. */ + discard_comments = TRUE; + break; + + case SAVE_IN_ANOTHER_FORMAT: + /* There are file formats in which we can save this that + support comments, and the user said not to delete the + comments. The combo box of file formats has had the + formats that don't support comments trimmed from it, + so run the dialog again, to let the user decide + whether to save in one of those formats or give up. */ + continue; + + case CANCELLED: + /* The user said "forget it". Just get rid of the dialog box + and return. */ + goto cleanup; + } + + /* + * Check that we're not going to save on top of the current + * capture file. + * We do it here so we catch all cases ... + * Unfortunately, the file requester gives us an absolute file + * name and the read file name may be relative (if supplied on + * the command line). From Joerg Mayer. + */ + if (files_identical(capture_file_.capFile()->filename, qUtf8Printable(file_name))) { + QMessageBox msg_box; + gchar *display_basename = g_filename_display_basename(qUtf8Printable(file_name)); + + msg_box.setIcon(QMessageBox::Critical); + msg_box.setText(QString(tr("Unable to export to \"%1\".").arg(display_basename))); + msg_box.setInformativeText(tr("You cannot export packets to the current capture file.")); + msg_box.setStandardButtons(QMessageBox::Ok); + msg_box.setDefaultButton(QMessageBox::Ok); + msg_box.exec(); + g_free(display_basename); + continue; + } + + file_type = esp_dlg.selectedFileType(); + if (file_type == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) { + /* This "should not happen". */ + QMessageBox msg_box; + + msg_box.setIcon(QMessageBox::Critical); + msg_box.setText(tr("Unknown file type returned by export dialog.")); + msg_box.setInformativeText(tr("Please report this as a Wireshark issue at https://gitlab.com/wireshark/wireshark/-/issues.")); + msg_box.exec(); + goto cleanup; + } + compression_type = esp_dlg.compressionType(); +#ifdef Q_OS_WIN + // the Windows dialog does not fixup extensions, do it manually here. + fileAddExtension(file_name, file_type, compression_type); +#endif // Q_OS_WIN + +//#ifndef _WIN32 +// /* If the file exists and it's user-immutable or not writable, +// ask the user whether they want to override that. */ +// if (!file_target_unwritable_ui(top_level, qUtf8Printable(file_name))) { +// /* They don't. Let them try another file name or cancel. */ +// continue; +// } +//#endif + + /* Attempt to save the file */ + status = cf_export_specified_packets(capture_file_.capFile(), qUtf8Printable(file_name), &range, file_type, compression_type); + switch (status) { + + case CF_WRITE_OK: + /* The save succeeded; we're done. */ + /* Save the directory name for future file dialogs. */ + dirname = qstring_strdup(file_name); /* Overwrites cf_name */ + set_last_open_dir(get_dirname(dirname)); + g_free(dirname); + /* If we discarded comments, redraw the packet list to reflect + any packets that no longer have comments. */ + if (discard_comments) + packet_list_queue_draw(); + /* Add this filename to the list of recent files in the "Recent Files" submenu */ + add_menu_recent_capture_file(qUtf8Printable(file_name)); + goto cleanup; + + case CF_WRITE_ERROR: + /* The save failed; let the user try again. */ + continue; + + case CF_WRITE_ABORTED: + /* The user aborted the save; just return. */ + goto cleanup; + } + } + +cleanup: + packet_range_cleanup(&range); +} + +void WiresharkMainWindow::exportDissections(export_type_e export_type) { + capture_file *cf = capture_file_.capFile(); + g_return_if_fail(cf); + + QList rows = packet_list_->selectedRows(true); + + QStringList entries; + foreach (int row, rows) + entries << QString::number(row); + QString selRange = entries.join(","); + + ExportDissectionDialog *ed_dlg = new ExportDissectionDialog(this, cf, export_type, selRange); + ed_dlg->setWindowModality(Qt::ApplicationModal); + ed_dlg->setAttribute(Qt::WA_DeleteOnClose); + ed_dlg->show(); +} + +#ifdef Q_OS_WIN +/* + * Ensure that: + * + * If the file is to be compressed: + * + * if there is a set of extensions used by the file type to be used, + * the file name has one of those extensions followed by the extension + * for the compression type to be used; + * + * otherwise, the file name has the extension for the compression type + * to be used; + * + * otherwise: + * + * if there is a set of extensions used by the file type to be used, + * the file name has one of those extensions. + */ +void WiresharkMainWindow::fileAddExtension(QString &file_name, int file_type, wtap_compression_type compression_type) { + QString file_name_lower; + GSList *extensions_list; + const char *compressed_file_extension; + gboolean add_extension_for_file_type; + + /* Lower-case the file name, so the extension matching is case-insensitive. */ + file_name_lower = file_name.toLower(); + + /* Get a list of all extensions used for this file type; don't + include the ones with compression type extensions, as we + only want to check for the extension for the compression + type we'll be using. */ + extensions_list = wtap_get_file_extensions_list(file_type, FALSE); + + /* Get the extension for the compression type we'll be using; + NULL is returned if the type isn't supported or compression + is not being done. */ + compressed_file_extension = wtap_compression_type_extension(compression_type); + + if (extensions_list != NULL) { + GSList *extension; + + /* This file type has one or more extensions. + Start out assuming we need to add the default one. */ + add_extension_for_file_type = TRUE; + + /* OK, see if the file has one of those extensions, followed + by the appropriate compression type extension if it's to be + compressed. */ + for (extension = extensions_list; extension != NULL; + extension = g_slist_next(extension)) { + QString file_suffix = QString(".") + (char *)extension->data; + if (compressed_file_extension != NULL) + file_suffix += QString(".") + compressed_file_extension; + if (file_name_lower.endsWith(file_suffix)) { + /* + * The file name has one of the extensions for this file + * type, followed by a compression type extension if + * appropriate, so we don't need to add an extension for + * the file type or the compression type. + */ + add_extension_for_file_type = FALSE; + break; + } + } + } else { + /* We have no extensions for this file type. Just check + to see if we need to add an extension for the compressed + file type. + + Start out assuming we do. */ + add_extension_for_file_type = TRUE; + if (compressed_file_extension != NULL) { + QString file_suffix = QString(".") + compressed_file_extension; + if (file_name_lower.endsWith(file_suffix)) { + /* + * The file name has the appropriate compressed file extension, + * so we don't need to add an extension for the compression + * type. + */ + add_extension_for_file_type = FALSE; + } + } + } + + /* + * If we need to add an extension for the file type or compressed + * file type, do so. + */ + if (add_extension_for_file_type) { + if (wtap_default_file_extension(file_type) != NULL) { + /* This file type has a default extension; append it. */ + file_name += QString(".") + wtap_default_file_extension(file_type); + } + if (compression_type != WTAP_UNCOMPRESSED) { + /* + * The file is to be compressed, so append the extension for + * its compression type. + */ + file_name += QString(".") + compressed_file_extension; + } + } +} +#endif // Q_OS_WIN + +bool WiresharkMainWindow::testCaptureFileClose(QString before_what, FileCloseContext context) { + bool capture_in_progress = false; + bool do_close_file = false; + + if (!capture_file_.capFile() || capture_file_.capFile()->state == FILE_CLOSED) + return true; /* Already closed, nothing to do */ + + if (capture_file_.capFile()->read_lock) { + /* + * If the file is being redissected, we cannot stop the capture since + * that would crash and burn "cf_read", so stop early. Ideally all + * callers should be modified to check this condition and act + * accordingly (ignore action or queue it up), so print a warning. + */ + ws_warning("Refusing to close \"%s\" which is being read.", capture_file_.capFile()->filename); + return false; + } + +#ifdef HAVE_LIBPCAP + if (capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + /* + * This (FILE_READ_IN_PROGRESS) is true if we're reading a capture file + * *or* if we're doing a live capture. From the capture file itself we + * cannot differentiate the cases, so check the current capture session. + */ + capture_in_progress = captureSession()->state != CAPTURE_STOPPED; + } +#endif + + if (prefs.gui_ask_unsaved) { + if (cf_has_unsaved_data(capture_file_.capFile())) { + QMessageBox msg_dialog; + QString question; + QString infotext; + QPushButton *save_button; + QPushButton *discard_button; + + msg_dialog.setIcon(QMessageBox::Question); + msg_dialog.setWindowTitle("Unsaved packets" UTF8_HORIZONTAL_ELLIPSIS); + + /* This file has unsaved data or there's a capture in + progress; ask the user whether to save the data. */ + if (capture_in_progress && context != Restart) { + question = tr("Do you want to stop the capture and save the captured packets%1?").arg(before_what); + infotext = tr("Your captured packets will be lost if you don't save them."); + } else if (capture_file_.capFile()->is_tempfile) { + if (context == Reload) { + // Reloading a tempfile will keep the packets, so this is not unsaved packets + question = tr("Do you want to save the changes you've made%1?").arg(before_what); + infotext = tr("Your changes will be lost if you don't save them."); + } else { + question = tr("Do you want to save the captured packets%1?").arg(before_what); + infotext = tr("Your captured packets will be lost if you don't save them."); + } + } else { + // No capture in progress and not a tempfile, so this is not unsaved packets + gchar *display_basename = g_filename_display_basename(capture_file_.capFile()->filename); + question = tr("Do you want to save the changes you've made to the capture file \"%1\"%2?").arg(display_basename, before_what); + infotext = tr("Your changes will be lost if you don't save them."); + g_free(display_basename); + } + + msg_dialog.setText(question); + msg_dialog.setInformativeText(infotext); + + // XXX Text comes from ui/gtk/stock_icons.[ch] + // Note that the button roles differ from the GTK+ version. + // Cancel = RejectRole + // Save = AcceptRole + // Don't Save = DestructiveRole + msg_dialog.addButton(QMessageBox::Cancel); + + if (capture_in_progress) { + QString save_button_text; + if (context == Restart) { + save_button_text = tr("Save before Continue"); + } else { + save_button_text = tr("Stop and Save"); + } + save_button = msg_dialog.addButton(save_button_text, QMessageBox::AcceptRole); + } else { + save_button = msg_dialog.addButton(QMessageBox::Save); + } + msg_dialog.setDefaultButton(save_button); + + QString discard_button_text; + if (capture_in_progress) { + switch (context) { + case Quit: + discard_button_text = tr("Stop and Quit &without Saving"); + break; + case Restart: + discard_button_text = tr("Continue &without Saving"); + break; + default: + discard_button_text = tr("Stop and Continue &without Saving"); + break; + } + } else { + switch (context) { + case Quit: + discard_button_text = tr("Quit &without Saving"); + break; + case Restart: + default: + discard_button_text = tr("Continue &without Saving"); + break; + } + } + discard_button = msg_dialog.addButton(discard_button_text, QMessageBox::DestructiveRole); + +#if defined(Q_OS_MAC) + /* + * In macOS, the "default button" is not necessarily the + * button that has the input focus; Enter/Return activates + * the default button, and the spacebar activates the button + * that has the input focus, and they might be different + * buttons. + * + * In a "do you want to save" dialog, for example, the + * "save" button is the default button, and the "don't + * save" button has the input focus, so you can press + * Enter/Return to save or space not to save (or Escape + * to dismiss the dialog). + * + * In Qt terms, this means "no auto-default", as auto-default + * makes the button with the input focus the default button, + * so that Enter/Return will activate it. + */ + QList buttons = msg_dialog.buttons(); + for (int i = 0; i < buttons.size(); ++i) { + QPushButton *button = static_cast(buttons.at(i));; + button->setAutoDefault(false); + } + + /* + * It also means that the "don't save" button should be the one + * initially given the focus. + */ + discard_button->setFocus(); +#endif + + msg_dialog.exec(); + /* According to the Qt doc: + * when using QMessageBox with custom buttons, exec() function returns an opaque value. + * + * Therefore we should use clickedButton() to determine which button was clicked. */ + + if (msg_dialog.clickedButton() == save_button) { +#ifdef HAVE_LIBPCAP + /* If there's a capture in progress, we have to stop the capture + and then do the save. */ + if (capture_in_progress) + captureStop(); +#endif + /* Save the file and close it */ + // XXX if no packets were captured, any unsaved comments set by + // the user are silently discarded because capFile() is null. + if (capture_file_.capFile() && saveCaptureFile(capture_file_.capFile(), true) == false) + return false; + do_close_file = true; + } else if (msg_dialog.clickedButton() == discard_button) { + /* Just close the file, discarding changes */ + do_close_file = true; + } else { + // cancelButton or some other unspecified button + return false; + } + } else { + /* Unchanged file or capturing with no packets */ + do_close_file = true; + } + } else { + /* User asked not to be bothered by those prompts, just close it. + XXX - should that apply only to saving temporary files? */ + do_close_file = true; + } + + /* + * Are we done with this file and should we close the file? + */ + if (do_close_file) { +#ifdef HAVE_LIBPCAP + /* If there's a capture in progress, we have to stop the capture + and then do the close. */ + if (capture_in_progress) + captureStop(); + else if (capture_file_.capFile() && capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + /* + * When an offline capture is being read, mark it as aborted. + * cf_read will be responsible for actually closing the capture. + * + * We cannot just invoke cf_close here since cf_read is up in the + * call chain. (update_progress_dlg can end up processing the Quit + * event from the user which then ends up here.) + * See also the above "read_lock" check. + */ + capture_file_.capFile()->state = FILE_READ_ABORTED; + return true; + } +#endif + /* Clear MainWindow file name details */ + gbl_cur_main_window_->setMwFileName(""); + + /* captureStop() will close the file if not having any packets */ + if (capture_file_.capFile() && context != Restart && context != Reload) + // Don't really close if Restart or Reload + cf_close(capture_file_.capFile()); + } + + return true; /* File closed */ +} + +void WiresharkMainWindow::captureStop() { + stopCapture(); + + while (capture_file_.capFile() && capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + WiresharkApplication::processEvents(); + } +} + +void WiresharkMainWindow::findTextCodecs() { + const QList mibs = QTextCodec::availableMibs(); + QRegularExpression ibmRegExp("^IBM([0-9]+).*$"); + QRegularExpression iso8859RegExp("^ISO-8859-([0-9]+).*$"); + QRegularExpression windowsRegExp("^WINDOWS-([0-9]+).*$"); + QRegularExpressionMatch match; + for (int mib : mibs) { + QTextCodec *codec = QTextCodec::codecForMib(mib); + QString key = codec->name().toUpper(); + char rank; + + if (key.localeAwareCompare("IBM") < 0) { + rank = 1; + } else if ((match = ibmRegExp.match(key)).hasMatch()) { + rank = match.captured(1).size(); // Up to 5 + } else if (key.localeAwareCompare("ISO-8859-") < 0) { + rank = 6; + } else if ((match = iso8859RegExp.match(key)).hasMatch()) { + rank = 6 + match.captured(1).size(); // Up to 6 + 2 + } else if (key.localeAwareCompare("WINDOWS-") < 0) { + rank = 9; + } else if ((match = windowsRegExp.match(key)).hasMatch()) { + rank = 9 + match.captured(1).size(); // Up to 9 + 4 + } else { + rank = 14; + } + // This doesn't perfectly well order the IBM codecs because it's + // annoying to properly place IBM00858 and IBM00924 in the middle of + // code page numbers not zero padded to 5 digits. + // We could manipulate the key further to have more commonly used + // charsets earlier. IANA MIB ordering would be unxpected: + // https://www.iana.org/assignments/character-sets/character-sets.xml + // For data about use in HTTP (other protocols can be quite different): + // https://w3techs.com/technologies/overview/character_encoding + + key.prepend(char('0' + rank)); + // We use a map here because, due to backwards compatibility, + // the same QTextCodec may be returned for multiple MIBs, which + // happens for GBK/GB2312, EUC-KR/windows-949/UHC, and others. + text_codec_map_.insert(key, codec); + } +} + +void WiresharkMainWindow::initMainToolbarIcons() +{ + // Normally 16 px. Reflects current GTK+ behavior and other Windows apps. + int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); +#if !defined(Q_OS_WIN) + // Force icons to 24x24 for now, otherwise actionFileOpen looks wonky. + // The macOS HIG specifies 32-pixel icons but they're a little too + // large IMHO. + icon_size = icon_size * 3 / 2; +#endif + main_ui_->mainToolBar->setIconSize(QSize(icon_size, icon_size)); + + // Toolbar actions. The GNOME HIG says that we should have a menu icon for each + // toolbar item but that clutters up our menu. Set menu icons sparingly. + + main_ui_->actionCaptureStart->setIcon(StockIcon("x-capture-start")); + main_ui_->actionCaptureStop->setIcon(StockIcon("x-capture-stop")); + main_ui_->actionCaptureRestart->setIcon(StockIcon("x-capture-restart")); + main_ui_->actionCaptureOptions->setIcon(StockIcon("x-capture-options")); + + // Menu icons are disabled in main_window.ui for these items. + main_ui_->actionFileOpen->setIcon(StockIcon("document-open")); + main_ui_->actionFileSave->setIcon(StockIcon("x-capture-file-save")); + main_ui_->actionFileClose->setIcon(StockIcon("x-capture-file-close")); + main_ui_->actionViewReload->setIcon(StockIcon("x-capture-file-reload")); + + main_ui_->actionEditFindPacket->setIcon(StockIcon("edit-find")); + main_ui_->actionGoPreviousPacket->setIcon(StockIcon("go-previous")); + main_ui_->actionGoNextPacket->setIcon(StockIcon("go-next")); + main_ui_->actionGoGoToPacket->setIcon(StockIcon("go-jump")); + main_ui_->actionGoFirstPacket->setIcon(StockIcon("go-first")); + main_ui_->actionGoLastPacket->setIcon(StockIcon("go-last")); + main_ui_->actionGoPreviousConversationPacket->setIcon(StockIcon("go-previous")); + main_ui_->actionGoNextConversationPacket->setIcon(StockIcon("go-next")); +#if defined(Q_OS_MAC) + main_ui_->actionGoPreviousConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Comma)); + main_ui_->actionGoNextConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Period)); +#endif + main_ui_->actionGoPreviousHistoryPacket->setIcon(StockIcon("go-previous")); + main_ui_->actionGoNextHistoryPacket->setIcon(StockIcon("go-next")); + main_ui_->actionGoAutoScroll->setIcon(StockIcon("x-stay-last")); + + main_ui_->actionViewColorizePacketList->setIcon(StockIcon("x-colorize-packets")); + + QList zi_seq = main_ui_->actionViewZoomIn->shortcuts(); + zi_seq << QKeySequence(Qt::CTRL | Qt::Key_Equal); + main_ui_->actionViewZoomIn->setIcon(StockIcon("zoom-in")); + main_ui_->actionViewZoomIn->setShortcuts(zi_seq); + main_ui_->actionViewZoomOut->setIcon(StockIcon("zoom-out")); + main_ui_->actionViewNormalSize->setIcon(StockIcon("zoom-original")); + main_ui_->actionViewResizeColumns->setIcon(StockIcon("x-resize-columns")); + + main_ui_->actionNewDisplayFilterExpression->setIcon(StockIcon("list-add")); +} + +void WiresharkMainWindow::initShowHideMainWidgets() +{ + if (show_hide_actions_) { + return; + } + + show_hide_actions_ = new QActionGroup(this); + QMap shmw_actions; + + show_hide_actions_->setExclusive(false); + shmw_actions[main_ui_->actionViewMainToolbar] = main_ui_->mainToolBar; + shmw_actions[main_ui_->actionViewFilterToolbar] = main_ui_->displayFilterToolBar; +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + shmw_actions[main_ui_->actionViewWirelessToolbar] = main_ui_->wirelessToolBar; +#endif + shmw_actions[main_ui_->actionViewStatusBar] = main_ui_->statusBar; + shmw_actions[main_ui_->actionViewPacketList] = packet_list_; + shmw_actions[main_ui_->actionViewPacketDetails] = proto_tree_; + shmw_actions[main_ui_->actionViewPacketBytes] = byte_view_tab_; + shmw_actions[main_ui_->actionViewPacketDiagram] = packet_diagram_; + + foreach(QAction *shmwa, shmw_actions.keys()) { + shmwa->setData(QVariant::fromValue(shmw_actions[shmwa])); + show_hide_actions_->addAction(shmwa); + } + + // Initial hide the Interface Toolbar submenu + main_ui_->menuInterfaceToolbars->menuAction()->setVisible(false); + + /* Initially hide the additional toolbars menus */ + main_ui_->menuAdditionalToolbars->menuAction()->setVisible(false); + + connect(show_hide_actions_, SIGNAL(triggered(QAction*)), this, SLOT(showHideMainWidgets(QAction*))); +} + +void WiresharkMainWindow::initTimeDisplayFormatMenu() +{ + if (time_display_actions_) { + return; + } + + time_display_actions_ = new QActionGroup(this); + + td_actions[main_ui_->actionViewTimeDisplayFormatDateYMDandTimeOfDay] = TS_ABSOLUTE_WITH_YMD; + td_actions[main_ui_->actionViewTimeDisplayFormatDateYDOYandTimeOfDay] = TS_ABSOLUTE_WITH_YDOY; + td_actions[main_ui_->actionViewTimeDisplayFormatTimeOfDay] = TS_ABSOLUTE; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSinceEpoch] = TS_EPOCH; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSinceBeginningOfCapture] = TS_RELATIVE; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSincePreviousCapturedPacket] = TS_DELTA; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSincePreviousDisplayedPacket] = TS_DELTA_DIS; + td_actions[main_ui_->actionViewTimeDisplayFormatUTCDateYMDandTimeOfDay] = TS_UTC_WITH_YMD; + td_actions[main_ui_->actionViewTimeDisplayFormatUTCDateYDOYandTimeOfDay] = TS_UTC_WITH_YDOY; + td_actions[main_ui_->actionViewTimeDisplayFormatUTCTimeOfDay] = TS_UTC; + + foreach(QAction* tda, td_actions.keys()) { + tda->setData(QVariant::fromValue(td_actions[tda])); + time_display_actions_->addAction(tda); + } + + connect(time_display_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setTimestampFormat(QAction*))); +} + +void WiresharkMainWindow::initTimePrecisionFormatMenu() +{ + if (time_precision_actions_) { + return; + } + + time_precision_actions_ = new QActionGroup(this); + + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionAutomatic] = TS_PREC_AUTO; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionSeconds] = TS_PREC_FIXED_SEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionDeciseconds] = TS_PREC_FIXED_DSEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionCentiseconds] = TS_PREC_FIXED_CSEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionMilliseconds] = TS_PREC_FIXED_MSEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionMicroseconds] = TS_PREC_FIXED_USEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionNanoseconds] = TS_PREC_FIXED_NSEC; + + foreach(QAction* tpa, tp_actions.keys()) { + tpa->setData(QVariant::fromValue(tp_actions[tpa])); + time_precision_actions_->addAction(tpa); + } + + connect(time_precision_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setTimestampPrecision(QAction*))); +} + +// Menu items which will be disabled when we freeze() and whose state will +// be restored when we thaw(). Add to the list as needed. +void WiresharkMainWindow::initFreezeActions() +{ + QList freeze_actions = QList() + << main_ui_->actionFileClose + << main_ui_->actionViewReload + << main_ui_->actionEditMarkPacket + << main_ui_->actionEditMarkAllDisplayed + << main_ui_->actionEditUnmarkAllDisplayed + << main_ui_->actionEditIgnorePacket + << main_ui_->actionEditIgnoreAllDisplayed + << main_ui_->actionEditUnignoreAllDisplayed + << main_ui_->actionEditSetTimeReference + << main_ui_->actionEditUnsetAllTimeReferences; + + foreach(QAction *action, freeze_actions) { + freeze_actions_ << QPair(action, false); + } +} + +void WiresharkMainWindow::initConversationMenus() +{ + int i; + + QList cc_actions = QList() + << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2 + << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4 + << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6 + << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8 + << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10; + + for (GList *conv_filter_list_entry = conv_filter_list; conv_filter_list_entry; conv_filter_list_entry = gxx_list_next(conv_filter_list_entry)) { + // Main menu items + conversation_filter_t* conv_filter = gxx_list_data(conversation_filter_t *, conv_filter_list_entry); + ConversationAction *conv_action = new ConversationAction(main_ui_->menuConversationFilter, conv_filter); + main_ui_->menuConversationFilter->addAction(conv_action); + + connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); + connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter())); + + // Packet list context menu items + packet_list_->conversationMenu()->addAction(conv_action); + + QMenu *submenu = packet_list_->colorizeMenu()->addMenu(conv_action->text()); + i = 1; + + foreach(QAction *cc_action, cc_actions) { + conv_action = new ConversationAction(submenu, conv_filter); + conv_action->setText(cc_action->text()); + conv_action->setIcon(cc_action->icon()); + conv_action->setColorNumber(i++); + submenu->addAction(conv_action); + connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); + connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); + } + + conv_action = new ConversationAction(submenu, conv_filter); + conv_action->setText(main_ui_->actionViewColorizeNewColoringRule->text()); + submenu->addAction(conv_action); + connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); + connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); + + // Proto tree conversation menu is filled in in ProtoTree::contextMenuEvent. + // We should probably do that here. + } + + // Proto tree colorization items + i = 1; + ColorizeAction *colorize_action; + foreach(QAction *cc_action, cc_actions) { + colorize_action = new ColorizeAction(proto_tree_->colorizeMenu()); + colorize_action->setText(cc_action->text()); + colorize_action->setIcon(cc_action->icon()); + colorize_action->setColorNumber(i++); + proto_tree_->colorizeMenu()->addAction(colorize_action); + connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray))); + connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); + } + + colorize_action = new ColorizeAction(proto_tree_->colorizeMenu()); + colorize_action->setText(main_ui_->actionViewColorizeNewColoringRule->text()); + proto_tree_->colorizeMenu()->addAction(colorize_action); + connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray))); + connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); +} + +gboolean WiresharkMainWindow::addExportObjectsMenuItem(const void *, void *value, void *userdata) +{ + register_eo_t *eo = (register_eo_t*)value; + WiresharkMainWindow *window = (WiresharkMainWindow*)userdata; + + ExportObjectAction *export_action = new ExportObjectAction(window->main_ui_->menuFileExportObjects, eo); + window->main_ui_->menuFileExportObjects->addAction(export_action); + + //initially disable until a file is loaded (then file signals will take over) + export_action->setEnabled(false); + + connect(&window->capture_file_, SIGNAL(captureEvent(CaptureEvent)), export_action, SLOT(captureFileEvent(CaptureEvent))); + connect(export_action, SIGNAL(triggered()), window, SLOT(applyExportObject())); + return FALSE; +} + +void WiresharkMainWindow::initExportObjectsMenus() +{ + eo_iterate_tables(addExportObjectsMenuItem, this); +} + +// Titlebar +void WiresharkMainWindow::setTitlebarForCaptureFile() +{ + if (capture_file_.capFile() && capture_file_.capFile()->filename) { + setWSWindowTitle(QString("[*]%1").arg(capture_file_.fileDisplayName())); + // + // XXX - on non-Mac platforms, put in the application + // name? Or do so only for temporary files? + // + if (!capture_file_.capFile()->is_tempfile) { + // + // Set the file path; that way, for macOS, it'll set the + // "proxy icon". + // + setWindowFilePath(capture_file_.filePath()); + } + setWindowModified(cf_has_unsaved_data(capture_file_.capFile())); + } else { + /* We have no capture file. */ + setWSWindowTitle(); + } +} + +QString WiresharkMainWindow::replaceWindowTitleVariables(QString title) +{ + title.replace("%P", get_profile_name()); + title.replace("%V", get_ws_vcs_version_info()); + + if (title.contains("%F")) { + // %F is file path of the capture file. + if (capture_file_.capFile()) { + // get_dirname() will overwrite the argument so make a copy first + char *filename = g_strdup(capture_file_.capFile()->filename); + QString file(get_dirname(filename)); + g_free(filename); +#ifndef _WIN32 + // Substitute HOME with ~ + QString homedir(g_getenv("HOME")); + if (!homedir.isEmpty()) { + homedir.remove(QRegularExpression("[/]+$")); + file.replace(homedir, "~"); + } +#endif + title.replace("%F", file); + } else { + // No file loaded, no folder name + title.remove("%F"); + } + } + + if (title.contains("%S")) { + // %S is a conditional separator (" - ") that only shows when surrounded by variables + // with values or static text. Remove repeating, leading and trailing separators. + title.replace(QRegularExpression("(%S)+"), "%S"); + title.remove(QRegularExpression("^%S|%S$")); +#ifdef __APPLE__ + // On macOS we separate with a unicode em dash + title.replace("%S", " " UTF8_EM_DASH " "); +#else + title.replace("%S", " - "); +#endif + } + + return title; +} + +void WiresharkMainWindow::setWSWindowTitle(QString title) +{ + if (title.isEmpty()) { + title = tr("The Wireshark Network Analyzer"); + } + + if (prefs.gui_prepend_window_title && prefs.gui_prepend_window_title[0]) { + QString custom_title = replaceWindowTitleVariables(prefs.gui_prepend_window_title); + if (custom_title.length() > 0) { + title.prepend(QString("[%1] ").arg(custom_title)); + } + } + + if (prefs.gui_window_title && prefs.gui_window_title[0]) { + QString custom_title = replaceWindowTitleVariables(prefs.gui_window_title); + if (custom_title.length() > 0) { +#ifdef __APPLE__ + // On macOS we separate the titles with a unicode em dash + title.append(QString(" %1 %2").arg(UTF8_EM_DASH).arg(custom_title)); +#else + title.append(QString(" [%1]").arg(custom_title)); +#endif + } + } + + setWindowTitle(title); + setWindowFilePath(NULL); +} + +void WiresharkMainWindow::setTitlebarForCaptureInProgress() +{ + if (capture_file_.capFile()) { + setWSWindowTitle(tr("Capturing from %1").arg(cf_get_tempfile_source(capture_file_.capFile()))); + } else { + /* We have no capture in progress. */ + setWSWindowTitle(); + } +} + +// Menu state + +/* Enable or disable menu items based on whether you have a capture file + you've finished reading and, if you have one, whether it's been saved + and whether it could be saved except by copying the raw packet data. */ +void WiresharkMainWindow::setMenusForCaptureFile(bool force_disable) +{ + bool enable = true; + bool can_write = false; + bool can_save = false; + bool can_save_as = false; + + if (force_disable || capture_file_.capFile() == NULL || capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + /* We have no capture file or we're currently reading a file */ + enable = false; + } else { + /* We have a capture file. Can we write or save? */ + can_write = cf_can_write_with_wiretap(capture_file_.capFile()); + can_save = cf_can_save(capture_file_.capFile()); + can_save_as = cf_can_save_as(capture_file_.capFile()); + } + + main_ui_->actionViewReload_as_File_Format_or_Capture->setEnabled(enable); + main_ui_->actionFileMerge->setEnabled(can_write); + main_ui_->actionFileClose->setEnabled(enable); + main_ui_->actionFileSave->setEnabled(can_save); + main_ui_->actionFileSaveAs->setEnabled(can_save_as); + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(enable); + /* + * "Export Specified Packets..." should be available only if + * we can write the file out in at least one format. + */ + main_ui_->actionFileExportPackets->setEnabled(can_write); + + main_ui_->actionFileExportAsCArrays->setEnabled(enable); + main_ui_->actionFileExportAsCSV->setEnabled(enable); + main_ui_->actionFileExportAsPDML->setEnabled(enable); + main_ui_->actionFileExportAsPlainText->setEnabled(enable); + main_ui_->actionFileExportAsPSML->setEnabled(enable); + main_ui_->actionFileExportAsJSON->setEnabled(enable); + + main_ui_->actionFileExportPacketBytes->setEnabled(enable); + main_ui_->actionFileExportPDU->setEnabled(enable); + main_ui_->actionFileStripHeaders->setEnabled(enable); + main_ui_->actionFileExportTLSSessionKeys->setEnabled(enable); + + foreach(QAction *eo_action, main_ui_->menuFileExportObjects->actions()) { + eo_action->setEnabled(enable); + } + + main_ui_->actionViewReload->setEnabled(enable); + +#ifdef HAVE_SOFTWARE_UPDATE + // We might want to enable or disable automatic checks here as well. + update_action_->setEnabled(!can_save); +#endif +} + +void WiresharkMainWindow::setMenusForCaptureInProgress(bool capture_in_progress) { + /* Either a capture was started or stopped; in either case, it's not + in the process of stopping, so allow quitting. */ + + main_ui_->actionFileOpen->setEnabled(!capture_in_progress); + main_ui_->menuOpenRecentCaptureFile->setEnabled(!capture_in_progress); + + main_ui_->actionFileExportAsCArrays->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsCSV->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsPDML->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsPlainText->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsPSML->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsJSON->setEnabled(capture_in_progress); + + main_ui_->actionFileExportPacketBytes->setEnabled(capture_in_progress); + main_ui_->actionFileExportPDU->setEnabled(!capture_in_progress); + main_ui_->actionFileStripHeaders->setEnabled(!capture_in_progress); + main_ui_->actionFileExportTLSSessionKeys->setEnabled(capture_in_progress); + + foreach(QAction *eo_action, main_ui_->menuFileExportObjects->actions()) { + eo_action->setEnabled(capture_in_progress); + } + + main_ui_->menuFileSet->setEnabled(!capture_in_progress); + main_ui_->actionFileQuit->setEnabled(true); +#ifdef HAVE_SOFTWARE_UPDATE + // We might want to enable or disable automatic checks here as well. + update_action_->setEnabled(!capture_in_progress); +#endif + + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(capture_in_progress); + + // XXX Fix packet list heading menu sensitivity + // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortAscending", + // !capture_in_progress); + // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortDescending", + // !capture_in_progress); + // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/NoSorting", + // !capture_in_progress); + +#ifdef HAVE_LIBPCAP + main_ui_->actionCaptureOptions->setEnabled(!capture_in_progress); + main_ui_->actionCaptureStart->setEnabled(!capture_in_progress); + main_ui_->actionCaptureStart->setChecked(capture_in_progress); + main_ui_->actionCaptureStop->setEnabled(capture_in_progress); + main_ui_->actionCaptureRestart->setEnabled(capture_in_progress); + main_ui_->actionCaptureRefreshInterfaces->setEnabled(!capture_in_progress); +#endif /* HAVE_LIBPCAP */ + +} + +void WiresharkMainWindow::setMenusForCaptureStopping() { + main_ui_->actionFileQuit->setEnabled(false); +#ifdef HAVE_SOFTWARE_UPDATE + update_action_->setEnabled(false); +#endif + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(false); +#ifdef HAVE_LIBPCAP + main_ui_->actionCaptureStart->setChecked(false); + main_ui_->actionCaptureStop->setEnabled(false); + main_ui_->actionCaptureRestart->setEnabled(false); +#endif /* HAVE_LIBPCAP */ +} + +void WiresharkMainWindow::setForCapturedPackets(bool have_captured_packets) +{ + main_ui_->actionFilePrint->setEnabled(have_captured_packets); + +// set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/Print", +// have_captured_packets); + + main_ui_->actionEditFindPacket->setEnabled(have_captured_packets); + main_ui_->actionEditFindNext->setEnabled(have_captured_packets); + main_ui_->actionEditFindPrevious->setEnabled(have_captured_packets); + + main_ui_->actionGoGoToPacket->setEnabled(have_captured_packets); + main_ui_->actionGoPreviousPacket->setEnabled(have_captured_packets); + main_ui_->actionGoNextPacket->setEnabled(have_captured_packets); + main_ui_->actionGoFirstPacket->setEnabled(have_captured_packets); + main_ui_->actionGoLastPacket->setEnabled(have_captured_packets); + main_ui_->actionGoNextConversationPacket->setEnabled(have_captured_packets); + main_ui_->actionGoPreviousConversationPacket->setEnabled(have_captured_packets); + + main_ui_->actionViewZoomIn->setEnabled(have_captured_packets); + main_ui_->actionViewZoomOut->setEnabled(have_captured_packets); + main_ui_->actionViewNormalSize->setEnabled(have_captured_packets); + main_ui_->actionViewResizeColumns->setEnabled(have_captured_packets); + + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(have_captured_packets); + main_ui_->actionStatisticsProtocolHierarchy->setEnabled(have_captured_packets); + main_ui_->actionStatisticsIOGraph->setEnabled(have_captured_packets); +} + +void WiresharkMainWindow::setMenusForFileSet(bool enable_list_files) { + bool enable_next = fileset_get_next() != NULL && enable_list_files; + bool enable_prev = fileset_get_previous() != NULL && enable_list_files; + + main_ui_->actionFileSetListFiles->setEnabled(enable_list_files); + main_ui_->actionFileSetNextFile->setEnabled(enable_next); + main_ui_->actionFileSetPreviousFile->setEnabled(enable_prev); +} + +void WiresharkMainWindow::setWindowIcon(const QIcon &icon) { + mainApp->setWindowIcon(icon); + QMainWindow::setWindowIcon(icon); +} + +void WiresharkMainWindow::updateForUnsavedChanges() { + setTitlebarForCaptureFile(); + setMenusForCaptureFile(); +} + +void WiresharkMainWindow::changeEvent(QEvent* event) +{ + if (0 != event) + { + switch (event->type()) + { + case QEvent::LanguageChange: + main_ui_->retranslateUi(this); + // make sure that the "Clear Menu" item is retranslated + mainApp->emitAppSignal(WiresharkApplication::RecentCapturesChanged); + break; + case QEvent::LocaleChange: { + QString locale = QLocale::system().name(); + locale.truncate(locale.lastIndexOf('_')); + mainApp->loadLanguage(locale); + } + break; + case QEvent::WindowStateChange: + main_ui_->actionViewFullScreen->setChecked(this->isFullScreen()); + break; + default: + break; + } + } + QMainWindow::changeEvent(event); +} + +/* Update main window items based on whether there's a capture in progress. */ +void WiresharkMainWindow::setForCaptureInProgress(bool capture_in_progress, bool handle_toolbars, GArray *ifaces) +{ + setMenusForCaptureInProgress(capture_in_progress); + +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + wireless_frame_->setCaptureInProgress(capture_in_progress); +#endif + +#ifdef HAVE_LIBPCAP + packet_list_->setCaptureInProgress(capture_in_progress); + packet_list_->setVerticalAutoScroll(capture_in_progress && main_ui_->actionGoAutoScroll->isChecked()); + +// set_capture_if_dialog_for_capture_in_progress(capture_in_progress); +#endif + + if (handle_toolbars) { + QList toolbars = findChildren(); + foreach(InterfaceToolbar *toolbar, toolbars) { + if (capture_in_progress) { + toolbar->startCapture(ifaces); + } else { + toolbar->stopCapture(); + } + } + } +} + +static QList menu_groups = QList() + << REGISTER_ANALYZE_GROUP_UNSORTED + << REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER + << REGISTER_STAT_GROUP_UNSORTED + << REGISTER_STAT_GROUP_GENERIC + << REGISTER_STAT_GROUP_CONVERSATION_LIST + << REGISTER_STAT_GROUP_ENDPOINT_LIST + << REGISTER_STAT_GROUP_RESPONSE_TIME + << REGISTER_STAT_GROUP_RSERPOOL + << REGISTER_STAT_GROUP_TELEPHONY + << REGISTER_STAT_GROUP_TELEPHONY_ANSI + << REGISTER_STAT_GROUP_TELEPHONY_GSM + << REGISTER_STAT_GROUP_TELEPHONY_LTE + << REGISTER_STAT_GROUP_TELEPHONY_MTP3 + << REGISTER_STAT_GROUP_TELEPHONY_SCTP + << REGISTER_TOOLS_GROUP_UNSORTED; + +void WiresharkMainWindow::addMenuActions(QList &actions, int menu_group) +{ + foreach(QAction *action, actions) { + switch (menu_group) { + case REGISTER_ANALYZE_GROUP_UNSORTED: + case REGISTER_STAT_GROUP_UNSORTED: + main_ui_->menuStatistics->insertAction( + main_ui_->actionStatistics_REGISTER_STAT_GROUP_UNSORTED, + action); + break; + case REGISTER_STAT_GROUP_RESPONSE_TIME: + main_ui_->menuServiceResponseTime->addAction(action); + break; + case REGISTER_STAT_GROUP_RSERPOOL: + main_ui_->menuRSerPool->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY: + main_ui_->menuTelephony->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_ANSI: + main_ui_->menuANSI->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_GSM: + main_ui_->menuGSM->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_LTE: + main_ui_->menuLTE->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_MTP3: + main_ui_->menuMTP3->addAction(action); + break; + case REGISTER_TOOLS_GROUP_UNSORTED: + { + // Allow the creation of submenus. Mimics the behavor of + // ui/gtk/main_menubar.c:add_menu_item_to_main_menubar + // and GtkUIManager. + // + // For now we limit the insanity to the "Tools" menu. + QStringList menu_path = action->text().split('/'); + QMenu *cur_menu = main_ui_->menuTools; + while (menu_path.length() > 1) { + QString menu_title = menu_path.takeFirst(); + QMenu *submenu = cur_menu->findChild(menu_title.toLower(), Qt::FindDirectChildrenOnly); + if (!submenu) { + submenu = cur_menu->addMenu(menu_title); + submenu->setObjectName(menu_title.toLower()); + } + cur_menu = submenu; + } + action->setText(menu_path.last()); + cur_menu->addAction(action); + break; + } + default: +// qDebug() << "FIX: Add" << action->text() << "to the menu"; + break; + } + + // Connect each action type to its corresponding slot. We to + // distinguish various types of actions. Setting their objectName + // seems to work OK. + if (action->objectName() == TapParameterDialog::actionName()) { + connect(action, SIGNAL(triggered(bool)), this, SLOT(openTapParameterDialog())); + } else if (action->objectName() == FunnelStatistics::actionName()) { + connect(action, SIGNAL(triggered(bool)), funnel_statistics_, SLOT(funnelActionTriggered())); + } + } +} +void WiresharkMainWindow::removeMenuActions(QList &actions, int menu_group) +{ + foreach(QAction *action, actions) { + switch (menu_group) { + case REGISTER_ANALYZE_GROUP_UNSORTED: + case REGISTER_STAT_GROUP_UNSORTED: + main_ui_->menuStatistics->removeAction(action); + break; + case REGISTER_STAT_GROUP_RESPONSE_TIME: + main_ui_->menuServiceResponseTime->removeAction(action); + break; + case REGISTER_STAT_GROUP_RSERPOOL: + main_ui_->menuRSerPool->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY: + main_ui_->menuTelephony->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_ANSI: + main_ui_->menuANSI->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_GSM: + main_ui_->menuGSM->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_LTE: + main_ui_->menuLTE->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_MTP3: + main_ui_->menuMTP3->removeAction(action); + break; + case REGISTER_TOOLS_GROUP_UNSORTED: + { + // Allow removal of submenus. + // For now we limit the insanity to the "Tools" menu. + QStringList menu_path = action->text().split('/'); + QMenu *cur_menu = main_ui_->menuTools; + while (menu_path.length() > 1) { + QString menu_title = menu_path.takeFirst(); + QMenu *submenu = cur_menu->findChild(menu_title.toLower(), Qt::FindDirectChildrenOnly); + cur_menu = submenu; + } + cur_menu->removeAction(action); + break; + } + default: +// qDebug() << "FIX: Remove" << action->text() << "from the menu"; + break; + } + } +} + +void WiresharkMainWindow::addDynamicMenus() +{ + // Manual additions + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_GSM, main_ui_->actionTelephonyGsmMapSummary); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteMacStatistics); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcStatistics); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcGraph); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_MTP3, main_ui_->actionTelephonyMtp3Summary); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY, main_ui_->actionTelephonySipFlows); + + // Fill in each menu + foreach(register_stat_group_t menu_group, menu_groups) { + QListactions = mainApp->dynamicMenuGroupItems(menu_group); + addMenuActions(actions, menu_group); + } + + // Empty menus don't show up: https://bugreports.qt.io/browse/QTBUG-33728 + // We've added a placeholder in order to make sure some menus are visible. + // Hide them as needed. + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_ANSI).length() > 0) { + main_ui_->actionTelephonyANSIPlaceholder->setVisible(false); + } + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_GSM).length() > 0) { + main_ui_->actionTelephonyGSMPlaceholder->setVisible(false); + } + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_LTE).length() > 0) { + main_ui_->actionTelephonyLTEPlaceholder->setVisible(false); + } + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_MTP3).length() > 0) { + main_ui_->actionTelephonyMTP3Placeholder->setVisible(false); + } +} + +void WiresharkMainWindow::reloadDynamicMenus() +{ + foreach(register_stat_group_t menu_group, menu_groups) { + QListactions = mainApp->removedMenuGroupItems(menu_group); + removeMenuActions(actions, menu_group); + + actions = mainApp->addedMenuGroupItems(menu_group); + addMenuActions(actions, menu_group); + } + + mainApp->clearAddedMenuGroupItems(); + mainApp->clearRemovedMenuGroupItems(); +} + +void WiresharkMainWindow::externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth) +{ + QAction * itemAction = Q_NULLPTR; + ext_menubar_t * item = Q_NULLPTR; + GList * children = Q_NULLPTR; + + /* There must exists an xpath parent */ + Q_ASSERT(subMenu != NULL); + + /* If the depth counter exceeds, something must have gone wrong */ + Q_ASSERT(depth < EXT_MENUBAR_MAX_DEPTH); + + children = menu->children; + /* Iterate the child entries */ + while (children && children->data) { + item = gxx_list_data(ext_menubar_t *, children); + + if (item->type == EXT_MENUBAR_MENU) { + /* Handle Submenu entry */ + this->externalMenuHelper(item, subMenu->addMenu(item->label), depth++); + } else if (item->type == EXT_MENUBAR_SEPARATOR) { + subMenu->addSeparator(); + } else if (item->type == EXT_MENUBAR_ITEM || item->type == EXT_MENUBAR_URL) { + itemAction = subMenu->addAction(item->name); + itemAction->setData(QVariant::fromValue(static_cast(item))); + itemAction->setText(item->label); + connect(itemAction, SIGNAL(triggered()), + this, SLOT(externalMenuItem_triggered())); + } + + /* Iterate Loop */ + children = gxx_list_next(children); + } +} + +QMenu * WiresharkMainWindow::searchSubMenu(QString objectName) +{ + QList lst; + + if (objectName.length() > 0) { + QString searchName = QString("menu") + objectName; + + lst = main_ui_->menuBar->findChildren(); + foreach(QMenu* m, lst) { + if (QString::compare(m->objectName(), searchName) == 0) + return m; + } + } + + return 0; +} + +void WiresharkMainWindow::addPluginIFStructures() +{ + GList *user_menu = ext_menubar_get_entries(); + + while (user_menu && user_menu->data) { + QMenu *subMenu = Q_NULLPTR; + ext_menu_t *menu = gxx_list_data(ext_menu_t *, user_menu); + + /* On this level only menu items should exist. Not doing an assert here, + * as it could be an honest mistake */ + if (menu->type != EXT_MENUBAR_MENU) { + user_menu = gxx_list_next(user_menu); + continue; + } + + /* Create main submenu and add it to the menubar */ + if (menu->parent_menu) { + QMenu *sortUnderneath = searchSubMenu(QString(menu->parent_menu)); + if (sortUnderneath) + subMenu = sortUnderneath->addMenu(menu->label); + } + + if (!subMenu) + subMenu = main_ui_->menuBar->addMenu(menu->label); + + /* This will generate the action structure for each menu. It is recursive, + * therefore a sub-routine, and we have a depth counter to prevent endless loops. */ + this->externalMenuHelper(menu, subMenu, 0); + + /* Iterate Loop */ + user_menu = gxx_list_next(user_menu); + } + + int cntToolbars = 0; + + QMenu *tbMenu = main_ui_->menuAdditionalToolbars; + GList *if_toolbars = ext_toolbar_get_entries(); + while (if_toolbars && if_toolbars->data) { + ext_toolbar_t *toolbar = gxx_list_data(ext_toolbar_t*, if_toolbars); + + if (toolbar->type != EXT_TOOLBAR_BAR) { + if_toolbars = gxx_list_next(if_toolbars); + continue; + } + + bool visible = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, reinterpret_cast(strcmp)) ? true : false; + + AdditionalToolBar *ifToolBar = AdditionalToolBar::create(this, toolbar); + + if (ifToolBar) { + ifToolBar->setVisible(visible); + + QAction *iftbAction = new QAction(QString(toolbar->name), this); + iftbAction->setToolTip(toolbar->tooltip); + iftbAction->setEnabled(true); + iftbAction->setCheckable(true); + iftbAction->setChecked(visible); + iftbAction->setToolTip(tr("Show or hide the toolbar")); + iftbAction->setData(VariantPointer::asQVariant(toolbar)); + + QAction *before = Q_NULLPTR; + + foreach(QAction *action, tbMenu->actions()) { + /* Ensure we add the menu entries in sorted order */ + if (action->text().compare(toolbar->name, Qt::CaseInsensitive) > 0) { + before = action; + break; + } + } + + tbMenu->insertAction(before, iftbAction); + + addToolBar(Qt::TopToolBarArea, ifToolBar); + insertToolBarBreak(ifToolBar); + + if (show_hide_actions_) + show_hide_actions_->addAction(iftbAction); + + cntToolbars++; + } + + if_toolbars = gxx_list_next(if_toolbars); + } + + if (cntToolbars) + tbMenu->menuAction()->setVisible(true); +} + +void WiresharkMainWindow::removeAdditionalToolbar(QString toolbarName) +{ + if (toolbarName.length() == 0) + return; + + QList toolbars = findChildren(); + foreach(QToolBar *tb, toolbars) { + AdditionalToolBar *ifToolBar = dynamic_cast(tb); + + if (ifToolBar && ifToolBar->menuName().compare(toolbarName)) { + GList *entry = g_list_find_custom(recent.gui_additional_toolbars, qUtf8Printable(ifToolBar->menuName()), reinterpret_cast(strcmp)); + if (entry) { + recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data); + } + QList actions = main_ui_->menuAdditionalToolbars->actions(); + foreach(QAction *action, actions) { + ext_toolbar_t *item = VariantPointer::asPtr(action->data()); + if (item && ifToolBar->menuName().compare(item->name)) { + if (show_hide_actions_) + show_hide_actions_->removeAction(action); + main_ui_->menuAdditionalToolbars->removeAction(action); + } + } + break; + } + } + +} + +QString WiresharkMainWindow::getMwFileName() +{ + return mwFileName_; +} + +void WiresharkMainWindow::setMwFileName(QString fileName) +{ + mwFileName_ = fileName; + return; +} + +frame_data * WiresharkMainWindow::frameDataForRow(int row) const +{ + if (packet_list_) + return packet_list_->getFDataForRow(row); + + return Q_NULLPTR; +} + +// Finds rtp id for selected stream and adds it to stream_ids +// If reverse is set, tries to find reverse stream too +// Return error string if error happens +// +// Note: Caller must free each returned rtpstream_info_t +QString WiresharkMainWindow::findRtpStreams(QVector *stream_ids, bool reverse) +{ + rtpstream_tapinfo_t tapinfo; + rtpstream_id_t *fwd_id, *rev_id; + bool fwd_id_used, rev_id_used; + const gchar filter_text[] = "rtp && rtp.version == 2 && rtp.ssrc && (ip || ipv6)"; + dfilter_t *sfcode; + gchar *err_msg; + + /* Try to get the hfid for "rtp.ssrc". */ + int hfid_rtp_ssrc = proto_registrar_get_id_byname("rtp.ssrc"); + if (hfid_rtp_ssrc == -1) { + return tr("There is no \"rtp.ssrc\" field in this version of Wireshark."); + } + + /* Try to compile the filter. */ + if (!dfilter_compile(filter_text, &sfcode, &err_msg)) { + QString err = QString(err_msg); + g_free(err_msg); + return err; + } + + if (!capture_file_.capFile() || !capture_file_.capFile()->current_frame) close(); + + if (!cf_read_current_record(capture_file_.capFile())) close(); + + frame_data *fdata = capture_file_.capFile()->current_frame; + + epan_dissect_t edt; + + epan_dissect_init(&edt, capture_file_.capFile()->epan, true, false); + epan_dissect_prime_with_dfilter(&edt, sfcode); + epan_dissect_prime_with_hfid(&edt, hfid_rtp_ssrc); + epan_dissect_run(&edt, capture_file_.capFile()->cd_t, + &capture_file_.capFile()->rec, + frame_tvbuff_new_buffer( + &capture_file_.capFile()->provider, fdata, + &capture_file_.capFile()->buf), + fdata, NULL); + + /* + * Packet must be an RTPv2 packet with an SSRC; we use the filter to + * check. + */ + if (!dfilter_apply_edt(sfcode, &edt)) { + epan_dissect_cleanup(&edt); + dfilter_free(sfcode); + return tr("Please select an RTPv2 packet with an SSRC value"); + } + + dfilter_free(sfcode); + + /* We need the SSRC value of the current frame; try to get it. */ + GPtrArray *gp = proto_get_finfo_ptr_array(edt.tree, hfid_rtp_ssrc); + if (gp == NULL || gp->len == 0) { + /* XXX - should not happen, as the filter includes rtp.ssrc */ + epan_dissect_cleanup(&edt); + return tr("SSRC value not found."); + } + + /* + * OK, we have the SSRC value, so we can proceed. + * Allocate RTP stream ID structures. + */ + fwd_id = g_new0(rtpstream_id_t, 1); + fwd_id_used = false; + rev_id = g_new0(rtpstream_id_t, 1); + rev_id_used = false; + + /* Get the IP and port values for the forward direction. */ + rtpstream_id_copy_pinfo(&(edt.pi), fwd_id, false); + + /* assume the inverse ip/port combination for the reverse direction */ + rtpstream_id_copy_pinfo(&(edt.pi), rev_id, true); + + /* Save the SSRC value for the forward direction. */ + fwd_id->ssrc = fvalue_get_uinteger(&((field_info *)gp->pdata[0])->value); + + epan_dissect_cleanup(&edt); + + /* Register the tap listener */ + memset(&tapinfo, 0, sizeof(rtpstream_tapinfo_t)); + tapinfo.tap_data = this; + tapinfo.mode = TAP_ANALYSE; + + /* Scan for RTP streams (redissect all packets) */ + rtpstream_scan(&tapinfo, capture_file_.capFile(), Q_NULLPTR); + + for (GList *strinfo_list = g_list_first(tapinfo.strinfo_list); strinfo_list; strinfo_list = gxx_list_next(strinfo_list)) { + rtpstream_info_t * strinfo = gxx_list_data(rtpstream_info_t*, strinfo_list); + if (rtpstream_id_equal(&(strinfo->id), fwd_id,RTPSTREAM_ID_EQUAL_NONE)) + { + *stream_ids << fwd_id; + fwd_id_used = true; + } + + if (rtpstream_id_equal(&(strinfo->id), rev_id,RTPSTREAM_ID_EQUAL_NONE)) + { + if (rev_id->ssrc == 0) { + rev_id->ssrc = strinfo->id.ssrc; + } + if (reverse) { + *stream_ids << rev_id; + rev_id_used = true; + } + } + } + + // + // XXX - is it guaranteed that fwd_id and rev_id were both added to + // *stream_ids? If so, this isn't necessary. + // + if (!fwd_id_used) { + rtpstream_id_free(fwd_id); + } + if (!rev_id_used) { + rtpstream_id_free(rev_id); + } + return NULL; +} + diff --git a/ui/qt/wireshark_main_window.h b/ui/qt/wireshark_main_window.h new file mode 100644 index 0000000000..61210ff44f --- /dev/null +++ b/ui/qt/wireshark_main_window.h @@ -0,0 +1,711 @@ +/** @file + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef WIRESHARK_MAIN_WINDOW_H +#define WIRESHARK_MAIN_WINDOW_H + +/** @defgroup main_window_group Main window + * The main window has the following submodules: + @dot + digraph main_dependencies { + node [shape=record, fontname=Helvetica, fontsize=10]; + main [ label="main window" URL="\ref main.h"]; + menu [ label="menubar" URL="\ref menus.h"]; + toolbar [ label="toolbar" URL="\ref main_toolbar.h"]; + packet_list [ label="packet list pane" URL="\ref packet_list.h"]; + proto_draw [ label="packet details & bytes panes" URL="\ref main_proto_draw.h"]; + recent [ label="recent user settings" URL="\ref recent.h"]; + main -> menu [ arrowhead="open", style="solid" ]; + main -> toolbar [ arrowhead="open", style="solid" ]; + main -> packet_list [ arrowhead="open", style="solid" ]; + main -> proto_draw [ arrowhead="open", style="solid" ]; + main -> recent [ arrowhead="open", style="solid" ]; + } + @enddot + */ + +/** @file + * The Wireshark main window + * @ingroup main_window_group + * @ingroup windows_group + */ + +#include + +#include + +#include + +#include "file.h" + +#include "ui/ws_ui_util.h" +#include "ui/iface_toolbar.h" + +#include +#include + +#ifdef HAVE_LIBPCAP +#include "capture_opts.h" +#endif +#include + +#include +#include +#include + +#ifdef _WIN32 +# include +#else +# include +#endif + +#include "capture_file.h" +#include "capture_file_dialog.h" +#include "print_dialog.h" +#include "capture_file_properties_dialog.h" +#include +#include +#include "follow_stream_dialog.h" +#include "main_window.h" +#include "rtp_stream_dialog.h" +#include "voip_calls_dialog.h" +#include "rtp_analysis_dialog.h" + +class AccordionFrame; +class ByteViewTab; +class CaptureOptionsDialog; +class PrintDialog; +class FileSetDialog; +class FilterDialog; +class FunnelStatistics; +class WelcomePage; +class PacketCommentDialog; +class PacketDiagram; +class PacketList; +class ProtoTree; +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) +class WirelessFrame; +#endif +class FilterExpressionToolBar; +class WiresharkApplication; + +class QAction; +class QActionGroup; + +namespace Ui { + class WiresharkMainWindow; +} + +Q_DECLARE_METATYPE(ts_type) +Q_DECLARE_METATYPE(ts_precision) + +class WiresharkMainWindow : public MainWindow +{ + Q_OBJECT + +public: + explicit WiresharkMainWindow(QWidget *parent = nullptr); + ~WiresharkMainWindow(); + void setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb); + +#ifdef HAVE_LIBPCAP + capture_session *captureSession() { return &cap_session_; } + info_data_t *captureInfoData() { return &info_data_; } +#endif + + virtual QMenu *createPopupMenu(); + + CaptureFile *captureFile() { return &capture_file_; } + + void removeAdditionalToolbar(QString toolbarName); + + void addInterfaceToolbar(const iface_toolbar *toolbar_entry); + void removeInterfaceToolbar(const gchar *menu_title); + + QString getMwFileName(); + void setMwFileName(QString fileName); + + frame_data * frameDataForRow(int row) const; + +protected: + virtual bool eventFilter(QObject *obj, QEvent *event); + virtual bool event(QEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void closeEvent(QCloseEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); + virtual void changeEvent(QEvent* event); + +private: + // XXX Move to FilterUtils + enum MatchSelected { + MatchSelectedReplace, + MatchSelectedAnd, + MatchSelectedOr, + MatchSelectedNot, + MatchSelectedAndNot, + MatchSelectedOrNot + }; + + enum CopySelected { + CopyAllVisibleItems, + CopyAllVisibleSelectedTreeItems, + CopySelectedDescription, + CopySelectedFieldName, + CopySelectedValue, + CopyListAsText, + CopyListAsCSV, + CopyListAsYAML + }; + + enum FileCloseContext { + Default, + Quit, + Restart, + Reload + }; + + Ui::WiresharkMainWindow *main_ui_; + CaptureFile capture_file_; + QFont mono_font_; + QMap text_codec_map_; +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + WirelessFrame *wireless_frame_; +#endif + QWidget *previous_focus_; + FileSetDialog *file_set_dialog_; + QActionGroup *show_hide_actions_; + QActionGroup *time_display_actions_; + QActionGroup *time_precision_actions_; + FunnelStatistics *funnel_statistics_; + QList > freeze_actions_; + QPointer freeze_focus_; + QMap td_actions; + QMap tp_actions; + bool was_maximized_; + + /* the following values are maintained so that the capture file name and status + is available when there is no cf structure available */ + QString mwFileName_; + + bool capture_stopping_; + bool capture_filter_valid_; +#ifdef HAVE_LIBPCAP + capture_session cap_session_; + CaptureOptionsDialog *capture_options_dialog_; + info_data_t info_data_; +#endif + FilterDialog *display_filter_dlg_; + FilterDialog *capture_filter_dlg_; + + // Pipe input + gint pipe_source_; + gpointer pipe_user_data_; + ws_process_id *pipe_child_process_; + pipe_input_cb_t pipe_input_cb_; +#ifdef _WIN32 + QTimer *pipe_timer_; +#else + QSocketNotifier *pipe_notifier_; +#endif + +#if defined(Q_OS_MAC) + QMenu *dock_menu_; +#endif + +#ifdef HAVE_SOFTWARE_UPDATE + QAction *update_action_; +#endif + + QPoint dragStartPosition; + + void freeze(); + void thaw(); + + void mergeCaptureFile(); + void importCaptureFile(); + bool saveCaptureFile(capture_file *cf, bool dont_reopen); + bool saveAsCaptureFile(capture_file *cf, bool must_support_comments = false, bool dont_reopen = false); + void exportSelectedPackets(); + void exportDissections(export_type_e export_type); + +#ifdef Q_OS_WIN + void fileAddExtension(QString &file_name, int file_type, wtap_compression_type compression_type); +#endif // Q_OS_WIN + bool testCaptureFileClose(QString before_what, FileCloseContext context = Default); + void captureStop(); + + void findTextCodecs(); + + void initMainToolbarIcons(); + void initShowHideMainWidgets(); + void initTimeDisplayFormatMenu(); + void initTimePrecisionFormatMenu(); + void initFreezeActions(); + + void setTitlebarForCaptureInProgress(); + void setMenusForCaptureFile(bool force_disable = false); + void setMenusForCaptureInProgress(bool capture_in_progress = false); + void setMenusForCaptureStopping(); + void setForCapturedPackets(bool have_captured_packets); + void setMenusForFileSet(bool enable_list_files); + void setWindowIcon(const QIcon &icon); + QString replaceWindowTitleVariables(QString title); + + void externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth); + + void setForCaptureInProgress(bool capture_in_progress = false, bool handle_toolbars = false, GArray *ifaces = NULL); + QMenu* findOrAddMenu(QMenu *parent_menu, QString& menu_text); + + void captureFileReadStarted(const QString &action); + + void addMenuActions(QList &actions, int menu_group); + void removeMenuActions(QList &actions, int menu_group); + void goToConversationFrame(bool go_next); + void colorizeWithFilter(QByteArray filter, int color_number = -1); + +signals: + void setDissectedCaptureFile(capture_file *cf); + void displayFilterSuccess(bool success); + void closePacketDialogs(); + void reloadFields(); + void packetInfoChanged(struct _packet_info *pinfo); + void fieldFilterChanged(const QByteArray field_filter); + + void fieldHighlight(FieldInformation *); + + void captureActive(int); + void selectRtpStream(rtpstream_id_t *id); + void deselectRtpStream(rtpstream_id_t *id); + +#ifdef HAVE_LIBPCAP + void showExtcapOptions(QString &device_name, bool startCaptureOnClose); +#endif + +public slots: + // in main_window_slots.cpp + /** + * Open a capture file. + * @param cf_path Path to the file. + * @param display_filter Display filter to apply. May be empty. + * @param type File type. + * @param is_tempfile TRUE/FALSE. + * @return True on success, false on failure. + */ + // XXX We might want to return a cf_read_status_t or a CaptureFile. + bool openCaptureFile(QString cf_path, QString display_filter, unsigned int type, gboolean is_tempfile = FALSE); + bool openCaptureFile(QString cf_path = QString(), QString display_filter = QString()) { return openCaptureFile(cf_path, display_filter, WTAP_TYPE_AUTO); } + void filterPackets(QString new_filter = QString(), bool force = false); + void updateForUnsavedChanges(); + void layoutToolbars(); + void updatePreferenceActions(); + void updateRecentActions(); + + void setTitlebarForCaptureFile(); + void setWSWindowTitle(QString title = QString()); + +#ifdef HAVE_LIBPCAP + void captureCapturePrepared(capture_session *); + void captureCaptureUpdateStarted(capture_session *); + void captureCaptureUpdateFinished(capture_session *); + void captureCaptureFixedFinished(capture_session *cap_session); + void captureCaptureFailed(capture_session *); +#endif + + void captureFileOpened(); + void captureFileReadFinished(); + void captureFileClosing(); + void captureFileClosed(); + + void launchRLCGraph(bool channelKnown, guint16 ueid, guint8 rlcMode, + guint16 channelType, guint16 channelId, guint8 direction); + + void on_actionViewFullScreen_triggered(bool checked); + + void rtpPlayerDialogReplaceRtpStreams(QVector stream_ids); + void rtpPlayerDialogAddRtpStreams(QVector stream_ids); + void rtpPlayerDialogRemoveRtpStreams(QVector stream_ids); + void rtpAnalysisDialogReplaceRtpStreams(QVector stream_ids); + void rtpAnalysisDialogAddRtpStreams(QVector stream_ids); + void rtpAnalysisDialogRemoveRtpStreams(QVector stream_ids); + void rtpStreamsDialogSelectRtpStreams(QVector stream_ids); + void rtpStreamsDialogDeselectRtpStreams(QVector stream_ids); + +private slots: + + void captureEventHandler(CaptureEvent ev); + + // Manually connected slots (no "on__"). + + void initViewColorizeMenu(); + void initConversationMenus(); + static gboolean addExportObjectsMenuItem(const void *key, void *value, void *userdata); + void initExportObjectsMenus(); + + // in main_window_slots.cpp + /** + * @brief startCapture + * Start capturing from the selected interfaces using the capture filter + * shown in the main welcome screen. + */ + void startCapture(QStringList); + void startCapture(); + void pipeTimeout(); + void pipeActivated(int source); + void pipeNotifierDestroyed(); + void stopCapture(); + + void loadWindowGeometry(); + void saveWindowGeometry(); + void mainStackChanged(int); + void updateRecentCaptures(); + void recentActionTriggered(); + void actionAddPacketComment(); + void actionEditPacketComment(); + void actionDeletePacketComment(); + void actionDeleteCommentsFromPackets(); + QString commentToMenuText(QString text, int max_len = 40); + void setEditCommentsMenu(); + void setMenusForSelectedPacket(); + void setMenusForSelectedTreeRow(FieldInformation *fi = NULL); + void interfaceSelectionChanged(); + void captureFilterSyntaxChanged(bool valid); + void redissectPackets(); + void checkDisplayFilter(); + void fieldsChanged(); + void reloadLuaPlugins(); + void showAccordionFrame(AccordionFrame *show_frame, bool toggle = false); + void showColumnEditor(int column); + void showPreferenceEditor(); // module_t *, pref * + void addStatsPluginsToMenu(); + void addDynamicMenus(); + void reloadDynamicMenus(); + void addPluginIFStructures(); + QMenu * searchSubMenu(QString objectName); + void activatePluginIFToolbar(bool); + + void startInterfaceCapture(bool valid, const QString capture_filter); + + void applyGlobalCommandLineOptions(); + void setFeaturesEnabled(bool enabled = true); + + void on_actionDisplayFilterExpression_triggered(); + void on_actionNewDisplayFilterExpression_triggered(); + void onFilterSelected(QString, bool); + void onFilterPreferences(); + void onFilterEdit(int uatIndex); + + // Handle FilterAction signals + void queuedFilterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type); + + /** Pass stat cmd arguments to a slot. + * @param menu_path slot Partial slot name, e.g. "StatisticsIOGraph". + * @param arg "-z" argument, e.g. "io,stat". + * @param userdata Optional user data. + */ + void openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata); + + /** Pass tap parameter arguments to a slot. + * @param cfg_str slot Partial slot name, e.g. "StatisticsAFPSrt". + * @param arg "-z" argument, e.g. "afp,srt". + * @param userdata Optional user data. + */ + void openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata); + void openTapParameterDialog(); + +#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) + void softwareUpdateRequested(); +#endif + + // Automatically connected slots ("on__"). + // + // The slots below follow the naming conventaion described in + // https://doc.qt.io/archives/qt-4.8/qmetaobject.html#connectSlotsByName + // and are automatically connected at initialization time via + // main_ui_->setupUi, which in turn calls connectSlotsByName. + // + // If you're manually connecting a signal to a slot, don't prefix its name + // with "on_". Otherwise you'll get runtime warnings. + + // We might want move these to main_window_actions.cpp similar to + // gtk/main_menubar.c + + void on_actionFileOpen_triggered(); + void on_actionFileMerge_triggered(); + void on_actionFileImportFromHexDump_triggered(); + void on_actionFileClose_triggered(); + void on_actionFileSave_triggered(); + void on_actionFileSaveAs_triggered(); + void on_actionFileSetListFiles_triggered(); + void on_actionFileSetNextFile_triggered(); + void on_actionFileSetPreviousFile_triggered(); + void on_actionFileExportPackets_triggered(); + void on_actionFileExportAsPlainText_triggered(); + // We're dropping PostScript exports + void on_actionFileExportAsCSV_triggered(); + void on_actionFileExportAsCArrays_triggered(); + void on_actionFileExportAsPSML_triggered(); + void on_actionFileExportAsPDML_triggered(); + void on_actionFileExportAsJSON_triggered(); + void on_actionFileExportPacketBytes_triggered(); + void on_actionFilePrint_triggered(); + + void on_actionFileExportPDU_triggered(); + void on_actionFileStripHeaders_triggered(); + void on_actionFileExportTLSSessionKeys_triggered(); + + void actionEditCopyTriggered(WiresharkMainWindow::CopySelected selection_type); + void on_actionCopyAllVisibleItems_triggered(); + void on_actionCopyAllVisibleSelectedTreeItems_triggered(); + void on_actionCopyListAsText_triggered(); + void on_actionCopyListAsCSV_triggered(); + void on_actionCopyListAsYAML_triggered(); + void on_actionEditCopyDescription_triggered(); + void on_actionEditCopyFieldName_triggered(); + void on_actionEditCopyValue_triggered(); + void on_actionEditCopyAsFilter_triggered(); + void on_actionEditFindPacket_triggered(); + void on_actionEditFindNext_triggered(); + void on_actionEditFindPrevious_triggered(); + void on_actionEditMarkPacket_triggered(); + void on_actionEditMarkAllDisplayed_triggered(); + void on_actionEditUnmarkAllDisplayed_triggered(); + void on_actionEditNextMark_triggered(); + void on_actionEditPreviousMark_triggered(); + void on_actionEditIgnorePacket_triggered(); + void on_actionEditIgnoreAllDisplayed_triggered(); + void on_actionEditUnignoreAllDisplayed_triggered(); + void on_actionEditSetTimeReference_triggered(); + void on_actionEditUnsetAllTimeReferences_triggered(); + void on_actionEditNextTimeReference_triggered(); + void on_actionEditPreviousTimeReference_triggered(); + void on_actionEditTimeShift_triggered(); + void editTimeShiftFinished(int); + void addPacketCommentFinished(PacketCommentDialog* pc_dialog, int result); + void editPacketCommentFinished(PacketCommentDialog* pc_dialog, int result, guint nComment); + void on_actionDeleteAllPacketComments_triggered(); + void deleteAllPacketCommentsFinished(int result); + void on_actionEditConfigurationProfiles_triggered(); + void showPreferencesDialog(QString module_name); + void on_actionEditPreferences_triggered(); + + void showHideMainWidgets(QAction *action); + void setTimestampFormat(QAction *action); + void setTimestampPrecision(QAction *action); + void on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked); + void on_actionViewEditResolvedName_triggered(); + void setNameResolution(); + void on_actionViewNameResolutionPhysical_triggered(); + void on_actionViewNameResolutionNetwork_triggered(); + void on_actionViewNameResolutionTransport_triggered(); + // XXX We're not porting the concurrency action from GTK+ on purpose. + void zoomText(); + void on_actionViewZoomIn_triggered(); + void on_actionViewZoomOut_triggered(); + void on_actionViewNormalSize_triggered(); + void on_actionViewColorizePacketList_triggered(bool checked); + void on_actionViewColoringRules_triggered(); + void colorizeConversation(bool create_rule = false); + void colorizeActionTriggered(); + void on_actionViewColorizeResetColorization_triggered(); + void on_actionViewColorizeNewColoringRule_triggered(); + void on_actionViewResetLayout_triggered(); + void on_actionViewResizeColumns_triggered(); + + void on_actionViewInternalsConversationHashTables_triggered(); + void on_actionViewInternalsDissectorTables_triggered(); + void on_actionViewInternalsSupportedProtocols_triggered(); + + void openPacketDialog(bool from_reference = false); + void on_actionViewShowPacketInNewWindow_triggered(); + void on_actionContextShowLinkedPacketInNewWindow_triggered(); + void on_actionViewReload_triggered(); + void on_actionViewReload_as_File_Format_or_Capture_triggered(); + + void on_actionGoGoToPacket_triggered(); + void on_actionGoGoToLinkedPacket_triggered(); + void on_actionGoNextConversationPacket_triggered(); + void on_actionGoPreviousConversationPacket_triggered(); + void on_actionGoAutoScroll_toggled(bool checked); + void resetPreviousFocus(); + + void on_actionCaptureOptions_triggered(); +#ifdef HAVE_LIBPCAP + void on_actionCaptureRefreshInterfaces_triggered(); +#endif + void on_actionCaptureCaptureFilters_triggered(); + + void on_actionAnalyzeDisplayFilters_triggered(); + void on_actionAnalyzeDisplayFilterMacros_triggered(); + void matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type); + void on_actionAnalyzeCreateAColumn_triggered(); + + void filterMenuAboutToShow(); + + void applyConversationFilter(); + void applyExportObject(); + + void on_actionAnalyzeEnabledProtocols_triggered(); + void on_actionAnalyzeDecodeAs_triggered(); + void on_actionAnalyzeReloadLuaPlugins_triggered(); + + void openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index = true); + void openFollowStreamDialogForType(follow_type_t type); + void on_actionAnalyzeFollowTCPStream_triggered(); + void on_actionAnalyzeFollowUDPStream_triggered(); + void on_actionAnalyzeFollowDCCPStream_triggered(); + void on_actionAnalyzeFollowTLSStream_triggered(); + void on_actionAnalyzeFollowHTTPStream_triggered(); + void on_actionAnalyzeFollowHTTP2Stream_triggered(); + void on_actionAnalyzeFollowQUICStream_triggered(); + void on_actionAnalyzeFollowSIPCall_triggered(); + + void statCommandExpertInfo(const char *, void *); + void on_actionAnalyzeExpertInfo_triggered(); + + void on_actionHelpContents_triggered(); + void on_actionHelpMPWireshark_triggered(); + void on_actionHelpMPWireshark_Filter_triggered(); + void on_actionHelpMPCapinfos_triggered(); + void on_actionHelpMPDumpcap_triggered(); + void on_actionHelpMPEditcap_triggered(); + void on_actionHelpMPMergecap_triggered(); + void on_actionHelpMPRawshark_triggered(); + void on_actionHelpMPReordercap_triggered(); + void on_actionHelpMPText2pcap_triggered(); + void on_actionHelpMPTShark_triggered(); + void on_actionHelpWebsite_triggered(); + void on_actionHelpFAQ_triggered(); + void on_actionHelpAsk_triggered(); + void on_actionHelpDownloads_triggered(); + void on_actionHelpWiki_triggered(); + void on_actionHelpSampleCaptures_triggered(); + void on_actionHelpAbout_triggered(); + +#ifdef HAVE_SOFTWARE_UPDATE + void checkForUpdates(); +#endif + + void on_goToCancel_clicked(); + void on_goToGo_clicked(); + void on_goToLineEdit_returnPressed(); + void on_actionCaptureStart_triggered(); + void on_actionCaptureStop_triggered(); + void on_actionCaptureRestart_triggered(); + + void on_actionStatisticsCaptureFileProperties_triggered(); + void on_actionStatisticsResolvedAddresses_triggered(); + void on_actionStatisticsProtocolHierarchy_triggered(); + void on_actionStatisticsFlowGraph_triggered(); + void openTcpStreamDialog(int graph_type); + void on_actionStatisticsTcpStreamStevens_triggered(); + void on_actionStatisticsTcpStreamTcptrace_triggered(); + void on_actionStatisticsTcpStreamThroughput_triggered(); + void on_actionStatisticsTcpStreamRoundTripTime_triggered(); + void on_actionStatisticsTcpStreamWindowScaling_triggered(); + void openSCTPAllAssocsDialog(); + void on_actionSCTPShowAllAssociations_triggered(); + void on_actionSCTPAnalyseThisAssociation_triggered(); + void on_actionSCTPFilterThisAssociation_triggered(); + void statCommandMulticastStatistics(const char *arg, void *); + void on_actionStatisticsUdpMulticastStreams_triggered(); + + void statCommandWlanStatistics(const char *arg, void *); + void on_actionWirelessWlanStatistics_triggered(); + + void openStatisticsTreeDialog(const gchar *abbr); + void on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered(); + void on_actionStatistics29WestTopics_Advertisements_by_Source_triggered(); + void on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered(); + void on_actionStatistics29WestTopics_Queries_by_Topic_triggered(); + void on_actionStatistics29WestTopics_Queries_by_Receiver_triggered(); + void on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered(); + void on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered(); + void on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered(); + void on_actionStatistics29WestQueues_Advertisements_by_Source_triggered(); + void on_actionStatistics29WestQueues_Queries_by_Queue_triggered(); + void on_actionStatistics29WestQueues_Queries_by_Receiver_triggered(); + void on_actionStatistics29WestUIM_Streams_triggered(); + void on_actionStatistics29WestLBTRM_triggered(); + void on_actionStatistics29WestLBTRU_triggered(); + void on_actionStatisticsANCP_triggered(); + void on_actionStatisticsBACappInstanceId_triggered(); + void on_actionStatisticsBACappIP_triggered(); + void on_actionStatisticsBACappObjectId_triggered(); + void on_actionStatisticsBACappService_triggered(); + void on_actionStatisticsCollectd_triggered(); + void statCommandConversations(const char *arg = NULL, void *userdata = NULL); + void on_actionStatisticsConversations_triggered(); + void statCommandEndpoints(const char *arg = NULL, void *userdata = NULL); + void on_actionStatisticsEndpoints_triggered(); + void on_actionStatisticsHART_IP_triggered(); + void on_actionStatisticsHTTPPacketCounter_triggered(); + void on_actionStatisticsHTTPRequests_triggered(); + void on_actionStatisticsHTTPLoadDistribution_triggered(); + void on_actionStatisticsHTTPRequestSequences_triggered(); + void on_actionStatisticsPacketLengths_triggered(); + void statCommandIOGraph(const char *, void *); + void on_actionStatisticsIOGraph_triggered(); + void on_actionStatisticsSametime_triggered(); + void on_actionStatisticsDNS_triggered(); + void actionStatisticsPlugin_triggered(); + void on_actionStatisticsHpfeeds_triggered(); + void on_actionStatisticsHTTP2_triggered(); + void on_actionStatisticsSOMEIPmessages_triggered(); + void on_actionStatisticsSOMEIPSDentries_triggered(); + + RtpStreamDialog *openTelephonyRtpStreamsDialog(); + RtpPlayerDialog *openTelephonyRtpPlayerDialog(); + VoipCallsDialog *openTelephonyVoipCallsDialogVoip(); + VoipCallsDialog *openTelephonyVoipCallsDialogSip(); + RtpAnalysisDialog *openTelephonyRtpAnalysisDialog(); + void on_actionTelephonyVoipCalls_triggered(); + void on_actionTelephonyGsmMapSummary_triggered(); + void statCommandLteMacStatistics(const char *arg, void *); + void on_actionTelephonyLteRlcStatistics_triggered(); + void statCommandLteRlcStatistics(const char *arg, void *); + void on_actionTelephonyLteMacStatistics_triggered(); + void on_actionTelephonyLteRlcGraph_triggered(); + void on_actionTelephonyIax2StreamAnalysis_triggered(); + void on_actionTelephonyISUPMessages_triggered(); + void on_actionTelephonyMtp3Summary_triggered(); + void on_actionTelephonyOsmuxPacketCounter_triggered(); + void on_actionTelephonyRtpStreams_triggered(); + void on_actionTelephonyRtpStreamAnalysis_triggered(); + void on_actionTelephonyRtpPlayer_triggered(); + void on_actionTelephonyRTSPPacketCounter_triggered(); + void on_actionTelephonySMPPOperations_triggered(); + void on_actionTelephonyUCPMessages_triggered(); + void on_actionTelephonyF1APMessages_triggered(); + void on_actionTelephonyNGAPMessages_triggered(); + void on_actionTelephonySipFlows_triggered(); + + void on_actionBluetoothATT_Server_Attributes_triggered(); + void on_actionBluetoothDevices_triggered(); + void on_actionBluetoothHCI_Summary_triggered(); + + void on_actionToolsFirewallAclRules_triggered(); + void on_actionToolsCredentials_triggered(); + + void externalMenuItem_triggered(); + + void on_actionAnalyzeShowPacketBytes_triggered(); + + void on_actionContextWikiProtocolPage_triggered(); + void on_actionContextFilterFieldReference_triggered(); + + void extcap_options_finished(int result); + void showExtcapOptionsDialog(QString & device_name, bool startCaptureOnClose); + + QString findRtpStreams(QVector *stream_ids, bool reverse); + + friend class MainApplication; +}; + +#endif // WIRESHARK_MAIN_WINDOW_H diff --git a/ui/qt/main_window.ui b/ui/qt/wireshark_main_window.ui similarity index 99% rename from ui/qt/main_window.ui rename to ui/qt/wireshark_main_window.ui index f7adc4d61b..488c007748 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/wireshark_main_window.ui @@ -1,7 +1,7 @@ - MainWindow - + WiresharkMainWindow + 0 @@ -3094,7 +3094,7 @@ actionFileQuit triggered() - MainWindow + WiresharkMainWindow close() diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/wireshark_main_window_slots.cpp similarity index 85% rename from ui/qt/main_window_slots.cpp rename to ui/qt/wireshark_main_window_slots.cpp index 67a477a25d..ed631817ec 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/wireshark_main_window_slots.cpp @@ -15,14 +15,14 @@ #pragma warning(disable:4996) #endif -#include "main_window.h" +#include "wireshark_main_window.h" /* - * The generated Ui_MainWindow::setupUi() can grow larger than our configured limit, + * The generated Ui_WiresharkMainWindow::setupUi() can grow larger than our configured limit, * so turn off -Wframe-larger-than= for ui_main_window.h. */ DIAG_OFF(frame-larger-than=) -#include +#include DIAG_ON(frame-larger-than=) #ifdef _WIN32 @@ -184,7 +184,7 @@ DIAG_ON(frame-larger-than=) // Public slots // -bool MainWindow::openCaptureFile(QString cf_path, QString read_filter, unsigned int type, gboolean is_tempfile) +bool WiresharkMainWindow::openCaptureFile(QString cf_path, QString read_filter, unsigned int type, gboolean is_tempfile) { QString file_name = ""; dfilter_t *rfcode = NULL; @@ -290,7 +290,7 @@ finish: return ret; } -void MainWindow::filterPackets(QString new_filter, bool force) +void WiresharkMainWindow::filterPackets(QString new_filter, bool force) { cf_status_t cf_status; @@ -319,7 +319,7 @@ void MainWindow::filterPackets(QString new_filter, bool force) } } -void MainWindow::layoutToolbars() +void WiresharkMainWindow::layoutToolbars() { Qt::ToolButtonStyle tbstyle = Qt::ToolButtonIconOnly; switch (prefs.gui_toolbar_main_style) { @@ -363,7 +363,7 @@ void MainWindow::layoutToolbars() } } -void MainWindow::updatePreferenceActions() +void WiresharkMainWindow::updatePreferenceActions() { main_ui_->actionViewPacketList->setEnabled(prefs_has_layout_pane_content(layout_pane_content_plist)); main_ui_->actionViewPacketDetails->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdetails)); @@ -378,7 +378,7 @@ void MainWindow::updatePreferenceActions() main_ui_->actionGoAutoScroll->setChecked(prefs.capture_auto_scroll); } -void MainWindow::updateRecentActions() +void WiresharkMainWindow::updateRecentActions() { main_ui_->actionViewMainToolbar->setChecked(recent.main_toolbar_show); main_ui_->actionViewFilterToolbar->setChecked(recent.filter_toolbar_show); @@ -423,7 +423,7 @@ void MainWindow::updateRecentActions() } // Don't connect to this directly. Connect to or emit fiterAction(...) instead. -void MainWindow::queuedFilterAction(QString action_filter, FilterAction::Action action, FilterAction::ActionType type) +void WiresharkMainWindow::queuedFilterAction(QString action_filter, FilterAction::Action action, FilterAction::ActionType type) { QString cur_filter, new_filter; @@ -504,7 +504,7 @@ void MainWindow::queuedFilterAction(QString action_filter, FilterAction::Action // Capture callbacks #ifdef HAVE_LIBPCAP -void MainWindow::captureCapturePrepared(capture_session *session) { +void WiresharkMainWindow::captureCapturePrepared(capture_session *session) { setTitlebarForCaptureInProgress(); setWindowIcon(mainApp->captureIcon()); @@ -520,7 +520,7 @@ void MainWindow::captureCapturePrepared(capture_session *session) { showCapture(); } -void MainWindow::captureCaptureUpdateStarted(capture_session *session) { +void WiresharkMainWindow::captureCaptureUpdateStarted(capture_session *session) { /* We've done this in "prepared" above, but it will be cleared while switching to the next multiple file. */ @@ -532,7 +532,7 @@ void MainWindow::captureCaptureUpdateStarted(capture_session *session) { setForCapturedPackets(true); } -void MainWindow::captureCaptureUpdateFinished(capture_session *session) { +void WiresharkMainWindow::captureCaptureUpdateFinished(capture_session *session) { /* The capture isn't stopping any more - it's stopped. */ capture_stopping_ = false; @@ -555,7 +555,7 @@ void MainWindow::captureCaptureUpdateFinished(capture_session *session) { } } -void MainWindow::captureCaptureFixedFinished(capture_session *) { +void WiresharkMainWindow::captureCaptureFixedFinished(capture_session *) { /* The capture isn't stopping any more - it's stopped. */ capture_stopping_ = false; @@ -577,7 +577,7 @@ void MainWindow::captureCaptureFixedFinished(capture_session *) { } } -void MainWindow::captureCaptureFailed(capture_session *) { +void WiresharkMainWindow::captureCaptureFailed(capture_session *) { /* Capture isn't stopping any more. */ capture_stopping_ = false; @@ -600,7 +600,7 @@ void MainWindow::captureCaptureFailed(capture_session *) { // Callbacks from cfile.c and file.c via CaptureFile::captureFileCallback -void MainWindow::captureEventHandler(CaptureEvent ev) +void WiresharkMainWindow::captureEventHandler(CaptureEvent ev) { switch (ev.captureContext()) { @@ -740,7 +740,7 @@ void MainWindow::captureEventHandler(CaptureEvent ev) } } -void MainWindow::captureFileOpened() { +void WiresharkMainWindow::captureFileOpened() { if (capture_file_.window() != this) return; file_set_dialog_->fileOpened(capture_file_.capFile()); @@ -748,7 +748,7 @@ void MainWindow::captureFileOpened() { emit setCaptureFile(capture_file_.capFile()); } -void MainWindow::captureFileReadStarted(const QString &action) { +void WiresharkMainWindow::captureFileReadStarted(const QString &action) { // tap_param_dlg_update(); /* Set up main window for a capture file. */ @@ -763,7 +763,7 @@ void MainWindow::captureFileReadStarted(const QString &action) { main_ui_->wirelessTimelineWidget->captureFileReadStarted(capture_file_.capFile()); } -void MainWindow::captureFileReadFinished() { +void WiresharkMainWindow::captureFileReadFinished() { if (!capture_file_.capFile()->is_tempfile && capture_file_.capFile()->filename) { /* Add this filename to the list of recent files in the "Recent Files" submenu */ add_menu_recent_capture_file(capture_file_.capFile()->filename); @@ -789,7 +789,7 @@ void MainWindow::captureFileReadFinished() { emit setDissectedCaptureFile(capture_file_.capFile()); } -void MainWindow::captureFileClosing() { +void WiresharkMainWindow::captureFileClosing() { setMenusForCaptureFile(true); setForCapturedPackets(false); setForCaptureInProgress(false); @@ -803,7 +803,7 @@ void MainWindow::captureFileClosing() { emit setDissectedCaptureFile(NULL); } -void MainWindow::captureFileClosed() { +void WiresharkMainWindow::captureFileClosed() { packets_bar_update(); file_set_dialog_->fileClosed(); @@ -831,11 +831,11 @@ void MainWindow::captureFileClosed() { // ui/gtk/capture_dlg.c:start_capture_confirmed -void MainWindow::startCapture() { +void WiresharkMainWindow::startCapture() { startCapture(QStringList()); } -void MainWindow::startCapture(QStringList interfaces _U_) { +void WiresharkMainWindow::startCapture(QStringList interfaces _U_) { #ifdef HAVE_LIBPCAP interface_options *interface_opts; guint i; @@ -968,7 +968,7 @@ void MainWindow::startCapture(QStringList interfaces _U_) { } // Copied from ui/gtk/gui_utils.c -void MainWindow::pipeTimeout() { +void WiresharkMainWindow::pipeTimeout() { #ifdef _WIN32 HANDLE handle; DWORD avail = 0; @@ -1010,7 +1010,7 @@ void MainWindow::pipeTimeout() { #endif // _WIN32 } -void MainWindow::pipeActivated(int source) { +void WiresharkMainWindow::pipeActivated(int source) { Q_UNUSED(source) #ifndef _WIN32 @@ -1026,7 +1026,7 @@ void MainWindow::pipeActivated(int source) { #endif // _WIN32 } -void MainWindow::pipeNotifierDestroyed() +void WiresharkMainWindow::pipeNotifierDestroyed() { /* Pop the "" message off the status bar. */ main_ui_->statusBar->setFileName(capture_file_); @@ -1038,7 +1038,7 @@ void MainWindow::pipeNotifierDestroyed() #endif // _WIN32 } -void MainWindow::stopCapture() { +void WiresharkMainWindow::stopCapture() { //#ifdef HAVE_AIRPCAP // if (airpcap_if_active) // airpcap_set_toolbar_stop_capture(airpcap_if_active); @@ -1052,7 +1052,7 @@ void MainWindow::stopCapture() { // Keep focus rects from showing through the welcome screen. Primarily for // macOS. -void MainWindow::mainStackChanged(int) +void WiresharkMainWindow::mainStackChanged(int) { for (int i = 0; i < main_ui_->mainStack->count(); i++) { main_ui_->mainStack->widget(i)->setEnabled(i == main_ui_->mainStack->currentIndex()); @@ -1065,7 +1065,7 @@ void MainWindow::mainStackChanged(int) * Add the capture filename (with an absolute path) to the "Recent Files" menu. */ // XXX - We should probably create a RecentFile class. -void MainWindow::updateRecentCaptures() { +void WiresharkMainWindow::updateRecentCaptures() { QAction *ra; QMenu *recentMenu = main_ui_->menuOpenRecentCaptureFile; QString action_cf_name; @@ -1155,7 +1155,7 @@ void MainWindow::updateRecentCaptures() { } } -void MainWindow::recentActionTriggered() { +void WiresharkMainWindow::recentActionTriggered() { QAction *ra = qobject_cast(sender()); if (ra) { @@ -1164,7 +1164,7 @@ void MainWindow::recentActionTriggered() { } } -QString MainWindow::commentToMenuText(QString text, int max_len) +QString WiresharkMainWindow::commentToMenuText(QString text, int max_len) { text = text.trimmed().replace(QRegularExpression("(\\r?\\n|\\r\\n?)+"), " "); if (text.size() > 0) { @@ -1179,7 +1179,7 @@ QString MainWindow::commentToMenuText(QString text, int max_len) return text; } -void MainWindow::setEditCommentsMenu() +void WiresharkMainWindow::setEditCommentsMenu() { main_ui_->menuPacketComment->clear(); main_ui_->menuPacketComment->addAction(tr("Add New Comment…"), this, SLOT(actionAddPacketComment()), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_C)); @@ -1218,7 +1218,7 @@ void MainWindow::setEditCommentsMenu() } } -void MainWindow::setMenusForSelectedPacket() +void WiresharkMainWindow::setMenusForSelectedPacket() { gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_dccp = FALSE, is_sctp = FALSE, is_tls = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE, is_http = FALSE, is_http2 = FALSE, is_quic = FALSE, is_sip = FALSE, is_exported_pdu = FALSE; @@ -1384,7 +1384,7 @@ void MainWindow::setMenusForSelectedPacket() main_ui_->actionTelephonyLteRlcGraph->setEnabled(is_lte_rlc); } -void MainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) { +void WiresharkMainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) { bool can_match_selected = false; bool is_framenum = false; @@ -1487,7 +1487,7 @@ void MainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) { } -void MainWindow::interfaceSelectionChanged() +void WiresharkMainWindow::interfaceSelectionChanged() { #ifdef HAVE_LIBPCAP // XXX This doesn't disable the toolbar button when using @@ -1500,13 +1500,13 @@ void MainWindow::interfaceSelectionChanged() #endif // HAVE_LIBPCAP } -void MainWindow::captureFilterSyntaxChanged(bool valid) +void WiresharkMainWindow::captureFilterSyntaxChanged(bool valid) { capture_filter_valid_ = valid; interfaceSelectionChanged(); } -void MainWindow::startInterfaceCapture(bool valid, const QString capture_filter) +void WiresharkMainWindow::startInterfaceCapture(bool valid, const QString capture_filter) { capture_filter_valid_ = valid; welcome_page_->setCaptureFilter(capture_filter); @@ -1518,7 +1518,7 @@ void MainWindow::startInterfaceCapture(bool valid, const QString capture_filter) } } -void MainWindow::applyGlobalCommandLineOptions() +void WiresharkMainWindow::applyGlobalCommandLineOptions() { if (global_dissect_options.time_format != TS_NOT_SET) { foreach(QAction* tda, td_actions.keys()) { @@ -1535,7 +1535,7 @@ void MainWindow::applyGlobalCommandLineOptions() } } -void MainWindow::redissectPackets() +void WiresharkMainWindow::redissectPackets() { if (capture_file_.capFile()) { cf_redissect_packets(capture_file_.capFile()); @@ -1545,7 +1545,7 @@ void MainWindow::redissectPackets() proto_free_deregistered_fields(); } -void MainWindow::checkDisplayFilter() +void WiresharkMainWindow::checkDisplayFilter() { if (!df_combo_box_->checkDisplayFilter()) { g_free(CaptureFile::globalCapFile()->dfilter); @@ -1553,7 +1553,7 @@ void MainWindow::checkDisplayFilter() } } -void MainWindow::fieldsChanged() +void WiresharkMainWindow::fieldsChanged() { gchar *err_msg = NULL; if (!color_filters_reload(&err_msg, color_filter_add_cb)) { @@ -1572,7 +1572,7 @@ void MainWindow::fieldsChanged() emit reloadFields(); } -void MainWindow::reloadLuaPlugins() +void WiresharkMainWindow::reloadLuaPlugins() { #ifdef HAVE_LUA if (mainApp->isReloadingLua()) @@ -1625,7 +1625,7 @@ void MainWindow::reloadLuaPlugins() #endif } -void MainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle) +void WiresharkMainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle) { QListframe_list = QList() << main_ui_->goToFrame << main_ui_->searchFrame @@ -1644,7 +1644,7 @@ void MainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle) show_frame->animatedShow(); } -void MainWindow::showColumnEditor(int column) +void WiresharkMainWindow::showColumnEditor(int column) { previous_focus_ = mainApp->focusWidget(); connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus())); @@ -1652,12 +1652,12 @@ void MainWindow::showColumnEditor(int column) showAccordionFrame(main_ui_->columnEditorFrame); } -void MainWindow::showPreferenceEditor() +void WiresharkMainWindow::showPreferenceEditor() { showAccordionFrame(main_ui_->preferenceEditorFrame); } -void MainWindow::initViewColorizeMenu() +void WiresharkMainWindow::initViewColorizeMenu() { QList cc_actions = QList() << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2 @@ -1687,7 +1687,7 @@ void MainWindow::initViewColorizeMenu() #endif } -void MainWindow::addStatsPluginsToMenu() { +void WiresharkMainWindow::addStatsPluginsToMenu() { GList *cfg_list = stats_tree_get_cfg_list(); GList *iter = g_list_first(cfg_list); QAction *stats_tree_action; @@ -1727,7 +1727,7 @@ void MainWindow::addStatsPluginsToMenu() { g_list_free(cfg_list); } -void MainWindow::setFeaturesEnabled(bool enabled) +void WiresharkMainWindow::setFeaturesEnabled(bool enabled) { main_ui_->menuBar->setEnabled(enabled); main_ui_->mainToolBar->setEnabled(enabled); @@ -1747,7 +1747,7 @@ void MainWindow::setFeaturesEnabled(bool enabled) // Display Filter Toolbar -void MainWindow::on_actionDisplayFilterExpression_triggered() +void WiresharkMainWindow::on_actionDisplayFilterExpression_triggered() { DisplayFilterExpressionDialog *dfe_dialog = new DisplayFilterExpressionDialog(this); @@ -1757,12 +1757,12 @@ void MainWindow::on_actionDisplayFilterExpression_triggered() dfe_dialog->show(); } -void MainWindow::on_actionNewDisplayFilterExpression_triggered() +void WiresharkMainWindow::on_actionNewDisplayFilterExpression_triggered() { main_ui_->filterExpressionFrame->addExpression(df_combo_box_->lineEdit()->text()); } -void MainWindow::onFilterSelected(QString filterText, bool prepare) +void WiresharkMainWindow::onFilterSelected(QString filterText, bool prepare) { if (filterText.length() <= 0) return; @@ -1773,23 +1773,23 @@ void MainWindow::onFilterSelected(QString filterText, bool prepare) df_combo_box_->applyDisplayFilter(); } -void MainWindow::onFilterPreferences() +void WiresharkMainWindow::onFilterPreferences() { emit showPreferencesDialog(PrefsModel::typeToString(PrefsModel::FilterButtons)); } -void MainWindow::onFilterEdit(int uatIndex) +void WiresharkMainWindow::onFilterEdit(int uatIndex) { main_ui_->filterExpressionFrame->editExpression(uatIndex); } -void MainWindow::openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata) +void WiresharkMainWindow::openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata) { QString slot = QString("statCommand%1").arg(menu_path); QMetaObject::invokeMethod(this, slot.toLatin1().constData(), Q_ARG(const char *, arg), Q_ARG(void *, userdata)); } -void MainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata) +void WiresharkMainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata) { TapParameterDialog *tp_dialog = TapParameterDialog::showTapParameterStatistics(*this, capture_file_, cfg_str, arg, userdata); if (!tp_dialog) return; @@ -1801,7 +1801,7 @@ void MainWindow::openTapParameterDialog(const QString cfg_str, const QString arg tp_dialog->show(); } -void MainWindow::openTapParameterDialog() +void WiresharkMainWindow::openTapParameterDialog() { QAction *tpa = qobject_cast(QObject::sender()); if (!tpa) return; @@ -1811,7 +1811,7 @@ void MainWindow::openTapParameterDialog() } #if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) -void MainWindow::softwareUpdateRequested() { +void WiresharkMainWindow::softwareUpdateRequested() { // We could call testCaptureFileClose here, but that would give us yet // another dialog. Just try again later. if (capture_file_.capFile() && capture_file_.capFile()->state != FILE_CLOSED) { @@ -1822,43 +1822,43 @@ void MainWindow::softwareUpdateRequested() { // File Menu -void MainWindow::on_actionFileOpen_triggered() +void WiresharkMainWindow::on_actionFileOpen_triggered() { openCaptureFile(); } -void MainWindow::on_actionFileMerge_triggered() +void WiresharkMainWindow::on_actionFileMerge_triggered() { mergeCaptureFile(); } -void MainWindow::on_actionFileImportFromHexDump_triggered() +void WiresharkMainWindow::on_actionFileImportFromHexDump_triggered() { importCaptureFile(); } -void MainWindow::on_actionFileClose_triggered() { +void WiresharkMainWindow::on_actionFileClose_triggered() { QString before_what(tr(" before closing the file")); if (testCaptureFileClose(before_what)) showWelcome(); } -void MainWindow::on_actionFileSave_triggered() +void WiresharkMainWindow::on_actionFileSave_triggered() { saveCaptureFile(capture_file_.capFile(), false); } -void MainWindow::on_actionFileSaveAs_triggered() +void WiresharkMainWindow::on_actionFileSaveAs_triggered() { saveAsCaptureFile(capture_file_.capFile()); } -void MainWindow::on_actionFileSetListFiles_triggered() +void WiresharkMainWindow::on_actionFileSetListFiles_triggered() { file_set_dialog_->show(); } -void MainWindow::on_actionFileSetNextFile_triggered() +void WiresharkMainWindow::on_actionFileSetNextFile_triggered() { fileset_entry *entry = fileset_get_next(); @@ -1868,7 +1868,7 @@ void MainWindow::on_actionFileSetNextFile_triggered() } } -void MainWindow::on_actionFileSetPreviousFile_triggered() +void WiresharkMainWindow::on_actionFileSetPreviousFile_triggered() { fileset_entry *entry = fileset_get_previous(); @@ -1878,42 +1878,42 @@ void MainWindow::on_actionFileSetPreviousFile_triggered() } } -void MainWindow::on_actionFileExportPackets_triggered() +void WiresharkMainWindow::on_actionFileExportPackets_triggered() { exportSelectedPackets(); } -void MainWindow::on_actionFileExportAsPlainText_triggered() +void WiresharkMainWindow::on_actionFileExportAsPlainText_triggered() { exportDissections(export_type_text); } -void MainWindow::on_actionFileExportAsCSV_triggered() +void WiresharkMainWindow::on_actionFileExportAsCSV_triggered() { exportDissections(export_type_csv); } -void MainWindow::on_actionFileExportAsCArrays_triggered() +void WiresharkMainWindow::on_actionFileExportAsCArrays_triggered() { exportDissections(export_type_carrays); } -void MainWindow::on_actionFileExportAsPSML_triggered() +void WiresharkMainWindow::on_actionFileExportAsPSML_triggered() { exportDissections(export_type_psml); } -void MainWindow::on_actionFileExportAsPDML_triggered() +void WiresharkMainWindow::on_actionFileExportAsPDML_triggered() { exportDissections(export_type_pdml); } -void MainWindow::on_actionFileExportAsJSON_triggered() +void WiresharkMainWindow::on_actionFileExportAsJSON_triggered() { exportDissections(export_type_json); } -void MainWindow::on_actionFileExportPacketBytes_triggered() +void WiresharkMainWindow::on_actionFileExportPacketBytes_triggered() { QString file_name; @@ -1937,14 +1937,14 @@ void MainWindow::on_actionFileExportPacketBytes_triggered() } } -void MainWindow::on_actionAnalyzeShowPacketBytes_triggered() +void WiresharkMainWindow::on_actionAnalyzeShowPacketBytes_triggered() { ShowPacketBytesDialog *spbd = new ShowPacketBytesDialog(*this, capture_file_); spbd->addCodecs(text_codec_map_); spbd->show(); } -void MainWindow::on_actionFileExportPDU_triggered() +void WiresharkMainWindow::on_actionFileExportPDU_triggered() { ExportPDUDialog *exportpdu_dialog = new ExportPDUDialog(this); @@ -1961,7 +1961,7 @@ void MainWindow::on_actionFileExportPDU_triggered() exportpdu_dialog->activateWindow(); } -void MainWindow::on_actionFileStripHeaders_triggered() +void WiresharkMainWindow::on_actionFileStripHeaders_triggered() { StripHeadersDialog *stripheaders_dialog = new StripHeadersDialog(this); @@ -1979,7 +1979,7 @@ void MainWindow::on_actionFileStripHeaders_triggered() } -void MainWindow::on_actionFileExportTLSSessionKeys_triggered() +void WiresharkMainWindow::on_actionFileExportTLSSessionKeys_triggered() { QString file_name; QString save_title; @@ -2015,12 +2015,12 @@ void MainWindow::on_actionFileExportTLSSessionKeys_triggered() } } -void MainWindow::on_actionStatisticsHpfeeds_triggered() +void WiresharkMainWindow::on_actionStatisticsHpfeeds_triggered() { openStatisticsTreeDialog("hpfeeds"); } -void MainWindow::on_actionFilePrint_triggered() +void WiresharkMainWindow::on_actionFilePrint_triggered() { capture_file *cf = capture_file_.capFile(); g_return_if_fail(cf); @@ -2040,7 +2040,7 @@ void MainWindow::on_actionFilePrint_triggered() // Edit Menu // XXX This should probably be somewhere else. -void MainWindow::actionEditCopyTriggered(MainWindow::CopySelected selection_type) +void WiresharkMainWindow::actionEditCopyTriggered(WiresharkMainWindow::CopySelected selection_type) { char label_str[ITEM_LABEL_LENGTH]; QString clip; @@ -2137,52 +2137,52 @@ void MainWindow::actionEditCopyTriggered(MainWindow::CopySelected selection_type } } -void MainWindow::on_actionCopyAllVisibleItems_triggered() +void WiresharkMainWindow::on_actionCopyAllVisibleItems_triggered() { actionEditCopyTriggered(CopyAllVisibleItems); } -void MainWindow::on_actionCopyListAsText_triggered() +void WiresharkMainWindow::on_actionCopyListAsText_triggered() { actionEditCopyTriggered(CopyListAsText); } -void MainWindow::on_actionCopyListAsCSV_triggered() +void WiresharkMainWindow::on_actionCopyListAsCSV_triggered() { actionEditCopyTriggered(CopyListAsCSV); } -void MainWindow::on_actionCopyListAsYAML_triggered() +void WiresharkMainWindow::on_actionCopyListAsYAML_triggered() { actionEditCopyTriggered(CopyListAsYAML); } -void MainWindow::on_actionCopyAllVisibleSelectedTreeItems_triggered() +void WiresharkMainWindow::on_actionCopyAllVisibleSelectedTreeItems_triggered() { actionEditCopyTriggered(CopyAllVisibleSelectedTreeItems); } -void MainWindow::on_actionEditCopyDescription_triggered() +void WiresharkMainWindow::on_actionEditCopyDescription_triggered() { actionEditCopyTriggered(CopySelectedDescription); } -void MainWindow::on_actionEditCopyFieldName_triggered() +void WiresharkMainWindow::on_actionEditCopyFieldName_triggered() { actionEditCopyTriggered(CopySelectedFieldName); } -void MainWindow::on_actionEditCopyValue_triggered() +void WiresharkMainWindow::on_actionEditCopyValue_triggered() { actionEditCopyTriggered(CopySelectedValue); } -void MainWindow::on_actionEditCopyAsFilter_triggered() +void WiresharkMainWindow::on_actionEditCopyAsFilter_triggered() { matchFieldFilter(FilterAction::ActionCopy, FilterAction::ActionTypePlain); } -void MainWindow::on_actionEditFindPacket_triggered() +void WiresharkMainWindow::on_actionEditFindPacket_triggered() { if (! packet_list_->model() || packet_list_->model()->rowCount() < 1) { return; @@ -2197,17 +2197,17 @@ void MainWindow::on_actionEditFindPacket_triggered() main_ui_->searchFrame->setFocus(); } -void MainWindow::on_actionEditFindNext_triggered() +void WiresharkMainWindow::on_actionEditFindNext_triggered() { main_ui_->searchFrame->findNext(); } -void MainWindow::on_actionEditFindPrevious_triggered() +void WiresharkMainWindow::on_actionEditFindPrevious_triggered() { main_ui_->searchFrame->findPrevious(); } -void MainWindow::on_actionEditMarkPacket_triggered() +void WiresharkMainWindow::on_actionEditMarkPacket_triggered() { freeze(); packet_list_->markFrame(); @@ -2215,7 +2215,7 @@ void MainWindow::on_actionEditMarkPacket_triggered() setMenusForSelectedPacket(); } -void MainWindow::on_actionEditMarkAllDisplayed_triggered() +void WiresharkMainWindow::on_actionEditMarkAllDisplayed_triggered() { freeze(); packet_list_->markAllDisplayedFrames(true); @@ -2223,7 +2223,7 @@ void MainWindow::on_actionEditMarkAllDisplayed_triggered() setMenusForSelectedPacket(); } -void MainWindow::on_actionEditUnmarkAllDisplayed_triggered() +void WiresharkMainWindow::on_actionEditUnmarkAllDisplayed_triggered() { freeze(); packet_list_->markAllDisplayedFrames(false); @@ -2231,19 +2231,19 @@ void MainWindow::on_actionEditUnmarkAllDisplayed_triggered() setMenusForSelectedPacket(); } -void MainWindow::on_actionEditNextMark_triggered() +void WiresharkMainWindow::on_actionEditNextMark_triggered() { if (capture_file_.capFile()) cf_find_packet_marked(capture_file_.capFile(), SD_FORWARD); } -void MainWindow::on_actionEditPreviousMark_triggered() +void WiresharkMainWindow::on_actionEditPreviousMark_triggered() { if (capture_file_.capFile()) cf_find_packet_marked(capture_file_.capFile(), SD_BACKWARD); } -void MainWindow::on_actionEditIgnorePacket_triggered() +void WiresharkMainWindow::on_actionEditIgnorePacket_triggered() { freeze(); packet_list_->ignoreFrame(); @@ -2251,7 +2251,7 @@ void MainWindow::on_actionEditIgnorePacket_triggered() setMenusForSelectedPacket(); } -void MainWindow::on_actionEditIgnoreAllDisplayed_triggered() +void WiresharkMainWindow::on_actionEditIgnoreAllDisplayed_triggered() { freeze(); packet_list_->ignoreAllDisplayedFrames(true); @@ -2259,7 +2259,7 @@ void MainWindow::on_actionEditIgnoreAllDisplayed_triggered() setMenusForSelectedPacket(); } -void MainWindow::on_actionEditUnignoreAllDisplayed_triggered() +void WiresharkMainWindow::on_actionEditUnignoreAllDisplayed_triggered() { freeze(); packet_list_->ignoreAllDisplayedFrames(false); @@ -2267,31 +2267,31 @@ void MainWindow::on_actionEditUnignoreAllDisplayed_triggered() setMenusForSelectedPacket(); } -void MainWindow::on_actionEditSetTimeReference_triggered() +void WiresharkMainWindow::on_actionEditSetTimeReference_triggered() { packet_list_->setTimeReference(); setMenusForSelectedPacket(); } -void MainWindow::on_actionEditUnsetAllTimeReferences_triggered() +void WiresharkMainWindow::on_actionEditUnsetAllTimeReferences_triggered() { packet_list_->unsetAllTimeReferences(); setMenusForSelectedPacket(); } -void MainWindow::on_actionEditNextTimeReference_triggered() +void WiresharkMainWindow::on_actionEditNextTimeReference_triggered() { if (!capture_file_.capFile()) return; cf_find_packet_time_reference(capture_file_.capFile(), SD_FORWARD); } -void MainWindow::on_actionEditPreviousTimeReference_triggered() +void WiresharkMainWindow::on_actionEditPreviousTimeReference_triggered() { if (!capture_file_.capFile()) return; cf_find_packet_time_reference(capture_file_.capFile(), SD_BACKWARD); } -void MainWindow::on_actionEditTimeShift_triggered() +void WiresharkMainWindow::on_actionEditTimeShift_triggered() { TimeShiftDialog *ts_dialog = new TimeShiftDialog(this, capture_file_.capFile()); connect(ts_dialog, SIGNAL(finished(int)), this, SLOT(editTimeShiftFinished(int))); @@ -2305,14 +2305,14 @@ void MainWindow::on_actionEditTimeShift_triggered() ts_dialog->show(); } -void MainWindow::editTimeShiftFinished(int) +void WiresharkMainWindow::editTimeShiftFinished(int) { if (capture_file_.capFile()->unsaved_changes) { updateForUnsavedChanges(); } } -void MainWindow::actionAddPacketComment() +void WiresharkMainWindow::actionAddPacketComment() { QList rows = selectedRows(); if (rows.count() == 0) @@ -2324,13 +2324,13 @@ void MainWindow::actionAddPacketComment() PacketCommentDialog* pc_dialog; pc_dialog = new PacketCommentDialog(false, this, NULL); - connect(pc_dialog, &QDialog::finished, std::bind(&MainWindow::addPacketCommentFinished, this, pc_dialog, std::placeholders::_1)); + connect(pc_dialog, &QDialog::finished, std::bind(&WiresharkMainWindow::addPacketCommentFinished, this, pc_dialog, std::placeholders::_1)); pc_dialog->setWindowModality(Qt::ApplicationModal); pc_dialog->setAttribute(Qt::WA_DeleteOnClose); pc_dialog->show(); } -void MainWindow::addPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_) +void WiresharkMainWindow::addPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_) { if (result == QDialog::Accepted) { packet_list_->addPacketComment(pc_dialog->text()); @@ -2338,7 +2338,7 @@ void MainWindow::addPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, in } } -void MainWindow::actionEditPacketComment() +void WiresharkMainWindow::actionEditPacketComment() { QList rows = selectedRows(); if (rows.count() != 1) @@ -2348,13 +2348,13 @@ void MainWindow::actionEditPacketComment() guint nComment = ra->data().toUInt(); PacketCommentDialog* pc_dialog; pc_dialog = new PacketCommentDialog(true, this, packet_list_->getPacketComment(nComment)); - connect(pc_dialog, &QDialog::finished, std::bind(&MainWindow::editPacketCommentFinished, this, pc_dialog, std::placeholders::_1, nComment)); + connect(pc_dialog, &QDialog::finished, std::bind(&WiresharkMainWindow::editPacketCommentFinished, this, pc_dialog, std::placeholders::_1, nComment)); pc_dialog->setWindowModality(Qt::ApplicationModal); pc_dialog->setAttribute(Qt::WA_DeleteOnClose); pc_dialog->show(); } -void MainWindow::editPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_, guint nComment) +void WiresharkMainWindow::editPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_, guint nComment) { if (result == QDialog::Accepted) { packet_list_->setPacketComment(nComment, pc_dialog->text()); @@ -2362,7 +2362,7 @@ void MainWindow::editPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, i } } -void MainWindow::actionDeletePacketComment() +void WiresharkMainWindow::actionDeletePacketComment() { QAction *ra = qobject_cast(sender()); guint nComment = ra->data().toUInt(); @@ -2370,13 +2370,13 @@ void MainWindow::actionDeletePacketComment() updateForUnsavedChanges(); } -void MainWindow::actionDeleteCommentsFromPackets() +void WiresharkMainWindow::actionDeleteCommentsFromPackets() { packet_list_->deleteCommentsFromPackets(); updateForUnsavedChanges(); } -void MainWindow::on_actionDeleteAllPacketComments_triggered() +void WiresharkMainWindow::on_actionDeleteAllPacketComments_triggered() { QMessageBox *msg_dialog = new QMessageBox(); connect(msg_dialog, SIGNAL(finished(int)), this, SLOT(deleteAllPacketCommentsFinished(int))); @@ -2392,7 +2392,7 @@ void MainWindow::on_actionDeleteAllPacketComments_triggered() msg_dialog->show(); } -void MainWindow::deleteAllPacketCommentsFinished(int result) +void WiresharkMainWindow::deleteAllPacketCommentsFinished(int result) { if (result == QMessageBox::Ok) { /* XXX Do we need a wait/hourglass for large files? */ @@ -2401,7 +2401,7 @@ void MainWindow::deleteAllPacketCommentsFinished(int result) } } -void MainWindow::on_actionEditConfigurationProfiles_triggered() +void WiresharkMainWindow::on_actionEditConfigurationProfiles_triggered() { ProfileDialog *cp_dialog = new ProfileDialog(); cp_dialog->setWindowModality(Qt::ApplicationModal); @@ -2409,7 +2409,7 @@ void MainWindow::on_actionEditConfigurationProfiles_triggered() cp_dialog->show(); } -void MainWindow::showPreferencesDialog(QString module_name) +void WiresharkMainWindow::showPreferencesDialog(QString module_name) { PreferencesDialog *pref_dialog = new PreferencesDialog(this); connect(pref_dialog, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals())); @@ -2421,14 +2421,14 @@ void MainWindow::showPreferencesDialog(QString module_name) pref_dialog->show(); } -void MainWindow::on_actionEditPreferences_triggered() +void WiresharkMainWindow::on_actionEditPreferences_triggered() { showPreferencesDialog(PrefsModel::typeToString(PrefsModel::Appearance)); } // View Menu -void MainWindow::showHideMainWidgets(QAction *action) +void WiresharkMainWindow::showHideMainWidgets(QAction *action) { if (!action) { return; @@ -2503,7 +2503,7 @@ void MainWindow::showHideMainWidgets(QAction *action) } } -void MainWindow::setTimestampFormat(QAction *action) +void WiresharkMainWindow::setTimestampFormat(QAction *action) { if (!action) { return; @@ -2523,7 +2523,7 @@ void MainWindow::setTimestampFormat(QAction *action) } } -void MainWindow::setTimestampPrecision(QAction *action) +void WiresharkMainWindow::setTimestampPrecision(QAction *action) { if (!action) { return; @@ -2544,7 +2544,7 @@ void MainWindow::setTimestampPrecision(QAction *action) } } -void MainWindow::on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked) +void WiresharkMainWindow::on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked) { if (checked) { recent.gui_seconds_format = TS_SECONDS_HOUR_MIN_SEC; @@ -2562,7 +2562,7 @@ void MainWindow::on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bo } } -void MainWindow::on_actionViewEditResolvedName_triggered() +void WiresharkMainWindow::on_actionViewEditResolvedName_triggered() { //int column = packet_list_->selectedColumn(); int column = -1; @@ -2575,7 +2575,7 @@ void MainWindow::on_actionViewEditResolvedName_triggered() showAccordionFrame(main_ui_->addressEditorFrame); } -void MainWindow::setNameResolution() +void WiresharkMainWindow::setNameResolution() { gbl_resolv_flags.mac_name = main_ui_->actionViewNameResolutionPhysical->isChecked() ? TRUE : FALSE; gbl_resolv_flags.network_name = main_ui_->actionViewNameResolutionNetwork->isChecked() ? TRUE : FALSE; @@ -2587,51 +2587,51 @@ void MainWindow::setNameResolution() mainApp->emitAppSignal(WiresharkApplication::NameResolutionChanged); } -void MainWindow::on_actionViewNameResolutionPhysical_triggered() +void WiresharkMainWindow::on_actionViewNameResolutionPhysical_triggered() { setNameResolution(); } -void MainWindow::on_actionViewNameResolutionNetwork_triggered() +void WiresharkMainWindow::on_actionViewNameResolutionNetwork_triggered() { setNameResolution(); } -void MainWindow::on_actionViewNameResolutionTransport_triggered() +void WiresharkMainWindow::on_actionViewNameResolutionTransport_triggered() { setNameResolution(); } -void MainWindow::zoomText() +void WiresharkMainWindow::zoomText() { mainApp->zoomTextFont(recent.gui_zoom_level); } -void MainWindow::on_actionViewZoomIn_triggered() +void WiresharkMainWindow::on_actionViewZoomIn_triggered() { recent.gui_zoom_level++; zoomText(); } -void MainWindow::on_actionViewZoomOut_triggered() +void WiresharkMainWindow::on_actionViewZoomOut_triggered() { recent.gui_zoom_level--; zoomText(); } -void MainWindow::on_actionViewNormalSize_triggered() +void WiresharkMainWindow::on_actionViewNormalSize_triggered() { recent.gui_zoom_level = 0; zoomText(); } -void MainWindow::on_actionViewColorizePacketList_triggered(bool checked) { +void WiresharkMainWindow::on_actionViewColorizePacketList_triggered(bool checked) { recent.packet_list_colorize = checked; packet_list_recolor_packets(); packet_list_->resetColorized(); } -void MainWindow::on_actionViewColoringRules_triggered() +void WiresharkMainWindow::on_actionViewColoringRules_triggered() { ColoringRulesDialog *coloring_rules_dialog = new ColoringRulesDialog(this); connect(coloring_rules_dialog, SIGNAL(accepted()), @@ -2645,7 +2645,7 @@ void MainWindow::on_actionViewColoringRules_triggered() } // actionViewColorizeConversation1 - 10 -void MainWindow::colorizeConversation(bool create_rule) +void WiresharkMainWindow::colorizeConversation(bool create_rule) { QAction *colorize_action = qobject_cast(sender()); if (!colorize_action) return; @@ -2678,7 +2678,7 @@ void MainWindow::colorizeConversation(bool create_rule) setMenusForSelectedPacket(); } -void MainWindow::colorizeActionTriggered() +void WiresharkMainWindow::colorizeActionTriggered() { QByteArray filter; int color_number = -1; @@ -2698,7 +2698,7 @@ void MainWindow::colorizeActionTriggered() colorizeWithFilter(filter, color_number); } -void MainWindow::colorizeWithFilter(QByteArray filter, int color_number) +void WiresharkMainWindow::colorizeWithFilter(QByteArray filter, int color_number) { if (filter.isEmpty()) return; @@ -2722,7 +2722,7 @@ void MainWindow::colorizeWithFilter(QByteArray filter, int color_number) main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used()); } -void MainWindow::on_actionViewColorizeResetColorization_triggered() +void WiresharkMainWindow::on_actionViewColorizeResetColorization_triggered() { gchar *err_msg = NULL; if (!color_filters_reset_tmp(&err_msg)) { @@ -2733,12 +2733,12 @@ void MainWindow::on_actionViewColorizeResetColorization_triggered() setMenusForSelectedPacket(); } -void MainWindow::on_actionViewColorizeNewColoringRule_triggered() +void WiresharkMainWindow::on_actionViewColorizeNewColoringRule_triggered() { colorizeConversation(true); } -void MainWindow::on_actionViewResetLayout_triggered() +void WiresharkMainWindow::on_actionViewResetLayout_triggered() { recent.gui_geometry_main_upper_pane = 0; recent.gui_geometry_main_lower_pane = 0; @@ -2746,7 +2746,7 @@ void MainWindow::on_actionViewResetLayout_triggered() applyRecentPaneGeometry(); } -void MainWindow::on_actionViewResizeColumns_triggered() +void WiresharkMainWindow::on_actionViewResizeColumns_triggered() { if (! packet_list_->model()) return; @@ -2756,7 +2756,7 @@ void MainWindow::on_actionViewResizeColumns_triggered() } } -void MainWindow::openPacketDialog(bool from_reference) +void WiresharkMainWindow::openPacketDialog(bool from_reference) { frame_data * fdata = Q_NULLPTR; @@ -2789,36 +2789,36 @@ void MainWindow::openPacketDialog(bool from_reference) } } -void MainWindow::on_actionViewInternalsConversationHashTables_triggered() +void WiresharkMainWindow::on_actionViewInternalsConversationHashTables_triggered() { ConversationHashTablesDialog *conversation_hash_tables_dlg = new ConversationHashTablesDialog(this); conversation_hash_tables_dlg->show(); } -void MainWindow::on_actionViewInternalsDissectorTables_triggered() +void WiresharkMainWindow::on_actionViewInternalsDissectorTables_triggered() { DissectorTablesDialog *dissector_tables_dlg = new DissectorTablesDialog(this); dissector_tables_dlg->show(); } -void MainWindow::on_actionViewInternalsSupportedProtocols_triggered() +void WiresharkMainWindow::on_actionViewInternalsSupportedProtocols_triggered() { SupportedProtocolsDialog *supported_protocols_dlg = new SupportedProtocolsDialog(this); supported_protocols_dlg->show(); } -void MainWindow::on_actionViewShowPacketInNewWindow_triggered() +void WiresharkMainWindow::on_actionViewShowPacketInNewWindow_triggered() { openPacketDialog(); } // This is only used in ProtoTree. Defining it here makes more sense. -void MainWindow::on_actionContextShowLinkedPacketInNewWindow_triggered() +void WiresharkMainWindow::on_actionContextShowLinkedPacketInNewWindow_triggered() { openPacketDialog(true); } -void MainWindow::on_actionViewReload_triggered() +void WiresharkMainWindow::on_actionViewReload_triggered() { capture_file *cf = CaptureFile::globalCapFile(); @@ -2831,7 +2831,7 @@ void MainWindow::on_actionViewReload_triggered() cf_reload(cf); } -void MainWindow::on_actionViewReload_as_File_Format_or_Capture_triggered() +void WiresharkMainWindow::on_actionViewReload_as_File_Format_or_Capture_triggered() { capture_file *cf = CaptureFile::globalCapFile(); @@ -2856,7 +2856,7 @@ void MainWindow::on_actionViewReload_as_File_Format_or_Capture_triggered() // Analyze Menu -void MainWindow::filterMenuAboutToShow() +void WiresharkMainWindow::filterMenuAboutToShow() { QMenu * menu = qobject_cast(sender()); QString field_filter; @@ -2875,7 +2875,7 @@ void MainWindow::filterMenuAboutToShow() menu->addActions(group->actions()); } -void MainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type) +void WiresharkMainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type) { QString field_filter; @@ -2897,12 +2897,7 @@ void MainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::Act setDisplayFilter(field_filter, action, filter_type); } -void MainWindow::setDisplayFilter(QString filter, FilterAction::Action action, FilterAction::ActionType filterType) -{ - emit filterAction(filter, action, filterType); -} - -void MainWindow::on_actionAnalyzeDisplayFilters_triggered() +void WiresharkMainWindow::on_actionAnalyzeDisplayFilters_triggered() { if (!display_filter_dlg_) { display_filter_dlg_ = new FilterDialog(this, FilterDialog::DisplayFilter); @@ -2913,7 +2908,7 @@ void MainWindow::on_actionAnalyzeDisplayFilters_triggered() } struct epan_uat; -void MainWindow::on_actionAnalyzeDisplayFilterMacros_triggered() +void WiresharkMainWindow::on_actionAnalyzeDisplayFilterMacros_triggered() { struct epan_uat* dfm_uat; dfilter_macro_get_uat(&dfm_uat); @@ -2925,7 +2920,7 @@ void MainWindow::on_actionAnalyzeDisplayFilterMacros_triggered() uat_dlg->show(); } -void MainWindow::on_actionAnalyzeCreateAColumn_triggered() +void WiresharkMainWindow::on_actionAnalyzeCreateAColumn_triggered() { if (capture_file_.capFile() != 0 && capture_file_.capFile()->finfo_selected != 0) { header_field_info *hfinfo = capture_file_.capFile()->finfo_selected->hfinfo; @@ -2950,7 +2945,7 @@ void MainWindow::on_actionAnalyzeCreateAColumn_triggered() } } -void MainWindow::applyConversationFilter() +void WiresharkMainWindow::applyConversationFilter() { ConversationAction *conv_action = qobject_cast(sender()); if (!conv_action) return; @@ -2968,7 +2963,7 @@ void MainWindow::applyConversationFilter() } } -void MainWindow::applyExportObject() +void WiresharkMainWindow::applyExportObject() { ExportObjectAction *export_action = qobject_cast(sender()); if (!export_action) @@ -2980,7 +2975,7 @@ void MainWindow::applyExportObject() export_dialog->show(); } -void MainWindow::on_actionAnalyzeEnabledProtocols_triggered() +void WiresharkMainWindow::on_actionAnalyzeEnabledProtocols_triggered() { EnabledProtocolsDialog *enable_proto_dialog = new EnabledProtocolsDialog(this); connect(enable_proto_dialog, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals())); @@ -2990,7 +2985,7 @@ void MainWindow::on_actionAnalyzeEnabledProtocols_triggered() enable_proto_dialog->show(); } -void MainWindow::on_actionAnalyzeDecodeAs_triggered() +void WiresharkMainWindow::on_actionAnalyzeDecodeAs_triggered() { QAction *da_action = qobject_cast(sender()); bool create_new = da_action && da_action->property("create_new").toBool(); @@ -3003,12 +2998,12 @@ void MainWindow::on_actionAnalyzeDecodeAs_triggered() da_dialog->show(); } -void MainWindow::on_actionAnalyzeReloadLuaPlugins_triggered() +void WiresharkMainWindow::on_actionAnalyzeReloadLuaPlugins_triggered() { reloadLuaPlugins(); } -void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index) { +void WiresharkMainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index) { FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type); connect(fsd, SIGNAL(updateFilter(QString, bool)), this, SLOT(filterPackets(QString, bool))); connect(fsd, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int))); @@ -3023,51 +3018,51 @@ void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, gu } } -void MainWindow::openFollowStreamDialogForType(follow_type_t type) { +void WiresharkMainWindow::openFollowStreamDialogForType(follow_type_t type) { openFollowStreamDialog(type, 0, 0, false); } -void MainWindow::on_actionAnalyzeFollowTCPStream_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowTCPStream_triggered() { openFollowStreamDialogForType(FOLLOW_TCP); } -void MainWindow::on_actionAnalyzeFollowUDPStream_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowUDPStream_triggered() { openFollowStreamDialogForType(FOLLOW_UDP); } -void MainWindow::on_actionAnalyzeFollowDCCPStream_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowDCCPStream_triggered() { openFollowStreamDialogForType(FOLLOW_DCCP); } -void MainWindow::on_actionAnalyzeFollowTLSStream_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowTLSStream_triggered() { openFollowStreamDialogForType(FOLLOW_TLS); } -void MainWindow::on_actionAnalyzeFollowHTTPStream_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowHTTPStream_triggered() { openFollowStreamDialogForType(FOLLOW_HTTP); } -void MainWindow::on_actionAnalyzeFollowHTTP2Stream_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowHTTP2Stream_triggered() { openFollowStreamDialogForType(FOLLOW_HTTP2); } -void MainWindow::on_actionAnalyzeFollowQUICStream_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowQUICStream_triggered() { openFollowStreamDialogForType(FOLLOW_QUIC); } -void MainWindow::on_actionAnalyzeFollowSIPCall_triggered() +void WiresharkMainWindow::on_actionAnalyzeFollowSIPCall_triggered() { openFollowStreamDialogForType(FOLLOW_SIP); } -void MainWindow::openSCTPAllAssocsDialog() +void WiresharkMainWindow::openSCTPAllAssocsDialog() { SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile()); connect(sctp_dialog, SIGNAL(filterPackets(QString, bool)), @@ -3089,12 +3084,12 @@ void MainWindow::openSCTPAllAssocsDialog() sctp_dialog->activateWindow(); } -void MainWindow::on_actionSCTPShowAllAssociations_triggered() +void WiresharkMainWindow::on_actionSCTPShowAllAssociations_triggered() { openSCTPAllAssocsDialog(); } -void MainWindow::on_actionSCTPAnalyseThisAssociation_triggered() +void WiresharkMainWindow::on_actionSCTPAnalyseThisAssociation_triggered() { const sctp_assoc_info_t* assoc = SCTPAssocAnalyseDialog::findAssocForPacket(capture_file_.capFile()); if (!assoc) { @@ -3117,7 +3112,7 @@ void MainWindow::on_actionSCTPAnalyseThisAssociation_triggered() sctp_analyse->activateWindow(); } -void MainWindow::on_actionSCTPFilterThisAssociation_triggered() +void WiresharkMainWindow::on_actionSCTPFilterThisAssociation_triggered() { const sctp_assoc_info_t* assoc = SCTPAssocAnalyseDialog::findAssocForPacket(capture_file_.capFile()); if (assoc) { @@ -3128,7 +3123,7 @@ void MainWindow::on_actionSCTPFilterThisAssociation_triggered() } // -z wlan,stat -void MainWindow::statCommandWlanStatistics(const char *arg, void *) +void WiresharkMainWindow::statCommandWlanStatistics(const char *arg, void *) { WlanStatisticsDialog *wlan_stats_dlg = new WlanStatisticsDialog(*this, capture_file_, arg); connect(wlan_stats_dlg, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), @@ -3136,13 +3131,13 @@ void MainWindow::statCommandWlanStatistics(const char *arg, void *) wlan_stats_dlg->show(); } -void MainWindow::on_actionWirelessWlanStatistics_triggered() +void WiresharkMainWindow::on_actionWirelessWlanStatistics_triggered() { statCommandWlanStatistics(NULL, NULL); } // -z expert -void MainWindow::statCommandExpertInfo(const char *, void *) +void WiresharkMainWindow::statCommandExpertInfo(const char *, void *) { ExpertInfoDialog *expert_dialog = new ExpertInfoDialog(*this, capture_file_); const DisplayFilterEdit *df_edit = dynamic_cast(df_combo_box_->lineEdit()); @@ -3157,7 +3152,7 @@ void MainWindow::statCommandExpertInfo(const char *, void *) expert_dialog->show(); } -void MainWindow::on_actionAnalyzeExpertInfo_triggered() +void WiresharkMainWindow::on_actionAnalyzeExpertInfo_triggered() { statCommandExpertInfo(NULL, NULL); } @@ -3167,13 +3162,13 @@ void MainWindow::on_actionAnalyzeExpertInfo_triggered() // Statistics Menu -void MainWindow::on_actionStatisticsFlowGraph_triggered() +void WiresharkMainWindow::on_actionStatisticsFlowGraph_triggered() { SequenceDialog *sequence_dialog = new SequenceDialog(*this, capture_file_); sequence_dialog->show(); } -void MainWindow::openTcpStreamDialog(int graph_type) +void WiresharkMainWindow::openTcpStreamDialog(int graph_type) { TCPStreamDialog *stream_dialog = new TCPStreamDialog(this, capture_file_.capFile(), (tcp_graph_type)graph_type); connect(stream_dialog, SIGNAL(goToPacket(int)), @@ -3185,33 +3180,33 @@ void MainWindow::openTcpStreamDialog(int graph_type) } } -void MainWindow::on_actionStatisticsTcpStreamStevens_triggered() +void WiresharkMainWindow::on_actionStatisticsTcpStreamStevens_triggered() { openTcpStreamDialog(GRAPH_TSEQ_STEVENS); } -void MainWindow::on_actionStatisticsTcpStreamTcptrace_triggered() +void WiresharkMainWindow::on_actionStatisticsTcpStreamTcptrace_triggered() { openTcpStreamDialog(GRAPH_TSEQ_TCPTRACE); } -void MainWindow::on_actionStatisticsTcpStreamThroughput_triggered() +void WiresharkMainWindow::on_actionStatisticsTcpStreamThroughput_triggered() { openTcpStreamDialog(GRAPH_THROUGHPUT); } -void MainWindow::on_actionStatisticsTcpStreamRoundTripTime_triggered() +void WiresharkMainWindow::on_actionStatisticsTcpStreamRoundTripTime_triggered() { openTcpStreamDialog(GRAPH_RTT); } -void MainWindow::on_actionStatisticsTcpStreamWindowScaling_triggered() +void WiresharkMainWindow::on_actionStatisticsTcpStreamWindowScaling_triggered() { openTcpStreamDialog(GRAPH_WSCALE); } // -z mcast,stat -void MainWindow::statCommandMulticastStatistics(const char *arg, void *) +void WiresharkMainWindow::statCommandMulticastStatistics(const char *arg, void *) { MulticastStatisticsDialog *mcast_stats_dlg = new MulticastStatisticsDialog(*this, capture_file_, arg); connect(mcast_stats_dlg, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), @@ -3219,12 +3214,12 @@ void MainWindow::statCommandMulticastStatistics(const char *arg, void *) mcast_stats_dlg->show(); } -void MainWindow::on_actionStatisticsUdpMulticastStreams_triggered() +void WiresharkMainWindow::on_actionStatisticsUdpMulticastStreams_triggered() { statCommandMulticastStatistics(NULL, NULL); } -void MainWindow::openStatisticsTreeDialog(const gchar *abbr) +void WiresharkMainWindow::openStatisticsTreeDialog(const gchar *abbr) { StatsTreeDialog *st_dialog = new StatsTreeDialog(*this, capture_file_, abbr); // connect(st_dialog, SIGNAL(goToPacket(int)), @@ -3232,62 +3227,62 @@ void MainWindow::openStatisticsTreeDialog(const gchar *abbr) st_dialog->show(); } -void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered() +void WiresharkMainWindow::on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered() { openStatisticsTreeDialog("lbmr_topic_ads_topic"); } -void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Source_triggered() +void WiresharkMainWindow::on_actionStatistics29WestTopics_Advertisements_by_Source_triggered() { openStatisticsTreeDialog("lbmr_topic_ads_source"); } -void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered() +void WiresharkMainWindow::on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered() { openStatisticsTreeDialog("lbmr_topic_ads_transport"); } -void MainWindow::on_actionStatistics29WestTopics_Queries_by_Topic_triggered() +void WiresharkMainWindow::on_actionStatistics29WestTopics_Queries_by_Topic_triggered() { openStatisticsTreeDialog("lbmr_topic_queries_topic"); } -void MainWindow::on_actionStatistics29WestTopics_Queries_by_Receiver_triggered() +void WiresharkMainWindow::on_actionStatistics29WestTopics_Queries_by_Receiver_triggered() { openStatisticsTreeDialog("lbmr_topic_queries_receiver"); } -void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered() +void WiresharkMainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered() { openStatisticsTreeDialog("lbmr_topic_queries_pattern"); } -void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered() +void WiresharkMainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered() { openStatisticsTreeDialog("lbmr_topic_queries_pattern_receiver"); } -void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered() +void WiresharkMainWindow::on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered() { openStatisticsTreeDialog("lbmr_queue_ads_queue"); } -void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Source_triggered() +void WiresharkMainWindow::on_actionStatistics29WestQueues_Advertisements_by_Source_triggered() { openStatisticsTreeDialog("lbmr_queue_ads_source"); } -void MainWindow::on_actionStatistics29WestQueues_Queries_by_Queue_triggered() +void WiresharkMainWindow::on_actionStatistics29WestQueues_Queries_by_Queue_triggered() { openStatisticsTreeDialog("lbmr_queue_queries_queue"); } -void MainWindow::on_actionStatistics29WestQueues_Queries_by_Receiver_triggered() +void WiresharkMainWindow::on_actionStatistics29WestQueues_Queries_by_Receiver_triggered() { openStatisticsTreeDialog("lbmr_queue_queries_receiver"); } -void MainWindow::on_actionStatistics29WestUIM_Streams_triggered() +void WiresharkMainWindow::on_actionStatistics29WestUIM_Streams_triggered() { LBMStreamDialog *stream_dialog = new LBMStreamDialog(this, capture_file_.capFile()); // connect(stream_dialog, SIGNAL(goToPacket(int)), @@ -3297,7 +3292,7 @@ void MainWindow::on_actionStatistics29WestUIM_Streams_triggered() stream_dialog->show(); } -void MainWindow::on_actionStatistics29WestLBTRM_triggered() +void WiresharkMainWindow::on_actionStatistics29WestLBTRM_triggered() { LBMLBTRMTransportDialog * lbtrm_dialog = new LBMLBTRMTransportDialog(this, capture_file_.capFile()); connect(lbtrm_dialog, SIGNAL(goToPacket(int)), @@ -3306,7 +3301,7 @@ void MainWindow::on_actionStatistics29WestLBTRM_triggered() lbtrm_dialog, SLOT(setCaptureFile(capture_file*))); lbtrm_dialog->show(); } -void MainWindow::on_actionStatistics29WestLBTRU_triggered() +void WiresharkMainWindow::on_actionStatistics29WestLBTRU_triggered() { LBMLBTRUTransportDialog * lbtru_dialog = new LBMLBTRUTransportDialog(this, capture_file_.capFile()); connect(lbtru_dialog, SIGNAL(goToPacket(int)), @@ -3316,39 +3311,39 @@ void MainWindow::on_actionStatistics29WestLBTRU_triggered() lbtru_dialog->show(); } -void MainWindow::on_actionStatisticsANCP_triggered() +void WiresharkMainWindow::on_actionStatisticsANCP_triggered() { openStatisticsTreeDialog("ancp"); } -void MainWindow::on_actionStatisticsBACappInstanceId_triggered() +void WiresharkMainWindow::on_actionStatisticsBACappInstanceId_triggered() { openStatisticsTreeDialog("bacapp_instanceid"); } -void MainWindow::on_actionStatisticsBACappIP_triggered() +void WiresharkMainWindow::on_actionStatisticsBACappIP_triggered() { openStatisticsTreeDialog("bacapp_ip"); } -void MainWindow::on_actionStatisticsBACappObjectId_triggered() +void WiresharkMainWindow::on_actionStatisticsBACappObjectId_triggered() { openStatisticsTreeDialog("bacapp_objectid"); } -void MainWindow::on_actionStatisticsBACappService_triggered() +void WiresharkMainWindow::on_actionStatisticsBACappService_triggered() { openStatisticsTreeDialog("bacapp_service"); } -void MainWindow::on_actionStatisticsCollectd_triggered() +void WiresharkMainWindow::on_actionStatisticsCollectd_triggered() { openStatisticsTreeDialog("collectd"); } // -z conv,... -void MainWindow::statCommandConversations(const char *arg, void *userdata) +void WiresharkMainWindow::statCommandConversations(const char *arg, void *userdata) { ConversationDialog *conv_dialog = new ConversationDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg); connect(conv_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), @@ -3360,13 +3355,13 @@ void MainWindow::statCommandConversations(const char *arg, void *userdata) conv_dialog->show(); } -void MainWindow::on_actionStatisticsConversations_triggered() +void WiresharkMainWindow::on_actionStatisticsConversations_triggered() { statCommandConversations(NULL, NULL); } // -z endpoints,... -void MainWindow::statCommandEndpoints(const char *arg, void *userdata) +void WiresharkMainWindow::statCommandEndpoints(const char *arg, void *userdata) { EndpointDialog *endp_dialog = new EndpointDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg); connect(endp_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), @@ -3378,43 +3373,43 @@ void MainWindow::statCommandEndpoints(const char *arg, void *userdata) endp_dialog->show(); } -void MainWindow::on_actionStatisticsEndpoints_triggered() +void WiresharkMainWindow::on_actionStatisticsEndpoints_triggered() { statCommandEndpoints(NULL, NULL); } -void MainWindow::on_actionStatisticsHART_IP_triggered() +void WiresharkMainWindow::on_actionStatisticsHART_IP_triggered() { openStatisticsTreeDialog("hart_ip"); } -void MainWindow::on_actionStatisticsHTTPPacketCounter_triggered() +void WiresharkMainWindow::on_actionStatisticsHTTPPacketCounter_triggered() { openStatisticsTreeDialog("http"); } -void MainWindow::on_actionStatisticsHTTPRequests_triggered() +void WiresharkMainWindow::on_actionStatisticsHTTPRequests_triggered() { openStatisticsTreeDialog("http_req"); } -void MainWindow::on_actionStatisticsHTTPLoadDistribution_triggered() +void WiresharkMainWindow::on_actionStatisticsHTTPLoadDistribution_triggered() { openStatisticsTreeDialog("http_srv"); } -void MainWindow::on_actionStatisticsHTTPRequestSequences_triggered() +void WiresharkMainWindow::on_actionStatisticsHTTPRequestSequences_triggered() { openStatisticsTreeDialog("http_seq"); } -void MainWindow::on_actionStatisticsPacketLengths_triggered() +void WiresharkMainWindow::on_actionStatisticsPacketLengths_triggered() { openStatisticsTreeDialog("plen"); } // -z io,stat -void MainWindow::statCommandIOGraph(const char *, void *) +void WiresharkMainWindow::statCommandIOGraph(const char *, void *) { const DisplayFilterEdit *df_edit = qobject_cast(df_combo_box_->lineEdit()); QString displayFilter; @@ -3427,22 +3422,22 @@ void MainWindow::statCommandIOGraph(const char *, void *) iog_dialog->show(); } -void MainWindow::on_actionStatisticsIOGraph_triggered() +void WiresharkMainWindow::on_actionStatisticsIOGraph_triggered() { statCommandIOGraph(NULL, NULL); } -void MainWindow::on_actionStatisticsSametime_triggered() +void WiresharkMainWindow::on_actionStatisticsSametime_triggered() { openStatisticsTreeDialog("sametime"); } -void MainWindow::on_actionStatisticsDNS_triggered() +void WiresharkMainWindow::on_actionStatisticsDNS_triggered() { openStatisticsTreeDialog("dns"); } -void MainWindow::actionStatisticsPlugin_triggered() +void WiresharkMainWindow::actionStatisticsPlugin_triggered() { QAction* action = qobject_cast(sender()); if (action) { @@ -3450,25 +3445,25 @@ void MainWindow::actionStatisticsPlugin_triggered() } } -void MainWindow::on_actionStatisticsHTTP2_triggered() +void WiresharkMainWindow::on_actionStatisticsHTTP2_triggered() { openStatisticsTreeDialog("http2"); } -void MainWindow::on_actionStatisticsSOMEIPmessages_triggered() +void WiresharkMainWindow::on_actionStatisticsSOMEIPmessages_triggered() { openStatisticsTreeDialog("someip_messages"); } -void MainWindow::on_actionStatisticsSOMEIPSDentries_triggered() +void WiresharkMainWindow::on_actionStatisticsSOMEIPSDentries_triggered() { openStatisticsTreeDialog("someipsd_entries"); } // Telephony Menu -RtpPlayerDialog *MainWindow::openTelephonyRtpPlayerDialog() +RtpPlayerDialog *WiresharkMainWindow::openTelephonyRtpPlayerDialog() { RtpPlayerDialog *dialog; @@ -3483,7 +3478,7 @@ RtpPlayerDialog *MainWindow::openTelephonyRtpPlayerDialog() return dialog; } -VoipCallsDialog *MainWindow::openTelephonyVoipCallsDialogVoip() +VoipCallsDialog *WiresharkMainWindow::openTelephonyVoipCallsDialogVoip() { VoipCallsDialog *dialog; @@ -3493,7 +3488,7 @@ VoipCallsDialog *MainWindow::openTelephonyVoipCallsDialogVoip() return dialog; } -VoipCallsDialog *MainWindow::openTelephonyVoipCallsDialogSip() +VoipCallsDialog *WiresharkMainWindow::openTelephonyVoipCallsDialogSip() { VoipCallsDialog *dialog; @@ -3503,7 +3498,7 @@ VoipCallsDialog *MainWindow::openTelephonyVoipCallsDialogSip() return dialog; } -RtpAnalysisDialog *MainWindow::openTelephonyRtpAnalysisDialog() +RtpAnalysisDialog *WiresharkMainWindow::openTelephonyRtpAnalysisDialog() { RtpAnalysisDialog *dialog; @@ -3513,18 +3508,18 @@ RtpAnalysisDialog *MainWindow::openTelephonyRtpAnalysisDialog() return dialog; } -void MainWindow::on_actionTelephonyVoipCalls_triggered() +void WiresharkMainWindow::on_actionTelephonyVoipCalls_triggered() { openTelephonyVoipCallsDialogVoip(); } -void MainWindow::on_actionTelephonyGsmMapSummary_triggered() +void WiresharkMainWindow::on_actionTelephonyGsmMapSummary_triggered() { GsmMapSummaryDialog *gms_dialog = new GsmMapSummaryDialog(*this, capture_file_); gms_dialog->show(); } -void MainWindow::on_actionTelephonyIax2StreamAnalysis_triggered() +void WiresharkMainWindow::on_actionTelephonyIax2StreamAnalysis_triggered() { Iax2AnalysisDialog *iax2_analysis_dialog = new Iax2AnalysisDialog(*this, capture_file_); connect(iax2_analysis_dialog, SIGNAL(goToPacket(int)), @@ -3532,13 +3527,13 @@ void MainWindow::on_actionTelephonyIax2StreamAnalysis_triggered() iax2_analysis_dialog->show(); } -void MainWindow::on_actionTelephonyISUPMessages_triggered() +void WiresharkMainWindow::on_actionTelephonyISUPMessages_triggered() { openStatisticsTreeDialog("isup_msg"); } // -z mac-lte,stat -void MainWindow::statCommandLteMacStatistics(const char *arg, void *) +void WiresharkMainWindow::statCommandLteMacStatistics(const char *arg, void *) { LteMacStatisticsDialog *lte_mac_stats_dlg = new LteMacStatisticsDialog(*this, capture_file_, arg); connect(lte_mac_stats_dlg, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), @@ -3546,12 +3541,12 @@ void MainWindow::statCommandLteMacStatistics(const char *arg, void *) lte_mac_stats_dlg->show(); } -void MainWindow::on_actionTelephonyLteMacStatistics_triggered() +void WiresharkMainWindow::on_actionTelephonyLteMacStatistics_triggered() { statCommandLteMacStatistics(NULL, NULL); } -void MainWindow::statCommandLteRlcStatistics(const char *arg, void *) +void WiresharkMainWindow::statCommandLteRlcStatistics(const char *arg, void *) { LteRlcStatisticsDialog *lte_rlc_stats_dlg = new LteRlcStatisticsDialog(*this, capture_file_, arg); connect(lte_rlc_stats_dlg, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), @@ -3564,12 +3559,12 @@ void MainWindow::statCommandLteRlcStatistics(const char *arg, void *) lte_rlc_stats_dlg->show(); } -void MainWindow::on_actionTelephonyLteRlcStatistics_triggered() +void WiresharkMainWindow::on_actionTelephonyLteRlcStatistics_triggered() { statCommandLteRlcStatistics(NULL, NULL); } -void MainWindow::launchRLCGraph(bool channelKnown, +void WiresharkMainWindow::launchRLCGraph(bool channelKnown, guint16 ueid, guint8 rlcMode, guint16 channelType, guint16 channelId, guint8 direction) { @@ -3583,24 +3578,24 @@ void MainWindow::launchRLCGraph(bool channelKnown, lrg_dialog->show(); } -void MainWindow::on_actionTelephonyLteRlcGraph_triggered() +void WiresharkMainWindow::on_actionTelephonyLteRlcGraph_triggered() { // We don't yet know the channel. launchRLCGraph(false, 0, 0, 0, 0, 0); } -void MainWindow::on_actionTelephonyMtp3Summary_triggered() +void WiresharkMainWindow::on_actionTelephonyMtp3Summary_triggered() { Mtp3SummaryDialog *mtp3s_dialog = new Mtp3SummaryDialog(*this, capture_file_); mtp3s_dialog->show(); } -void MainWindow::on_actionTelephonyOsmuxPacketCounter_triggered() +void WiresharkMainWindow::on_actionTelephonyOsmuxPacketCounter_triggered() { openStatisticsTreeDialog("osmux"); } -RtpStreamDialog *MainWindow::openTelephonyRtpStreamsDialog() +RtpStreamDialog *WiresharkMainWindow::openTelephonyRtpStreamsDialog() { RtpStreamDialog *dialog; @@ -3610,12 +3605,12 @@ RtpStreamDialog *MainWindow::openTelephonyRtpStreamsDialog() return dialog; } -void MainWindow::on_actionTelephonyRtpStreams_triggered() +void WiresharkMainWindow::on_actionTelephonyRtpStreams_triggered() { openTelephonyRtpStreamsDialog(); } -void MainWindow::on_actionTelephonyRtpStreamAnalysis_triggered() +void WiresharkMainWindow::on_actionTelephonyRtpStreamAnalysis_triggered() { QVector stream_ids; QString err; @@ -3637,7 +3632,7 @@ void MainWindow::on_actionTelephonyRtpStreamAnalysis_triggered() } } -void MainWindow::on_actionTelephonyRtpPlayer_triggered() +void WiresharkMainWindow::on_actionTelephonyRtpPlayer_triggered() { QVector stream_ids; QString err; @@ -3661,39 +3656,39 @@ void MainWindow::on_actionTelephonyRtpPlayer_triggered() } } -void MainWindow::on_actionTelephonyRTSPPacketCounter_triggered() +void WiresharkMainWindow::on_actionTelephonyRTSPPacketCounter_triggered() { openStatisticsTreeDialog("rtsp"); } -void MainWindow::on_actionTelephonySMPPOperations_triggered() +void WiresharkMainWindow::on_actionTelephonySMPPOperations_triggered() { openStatisticsTreeDialog("smpp_commands"); } -void MainWindow::on_actionTelephonyUCPMessages_triggered() +void WiresharkMainWindow::on_actionTelephonyUCPMessages_triggered() { openStatisticsTreeDialog("ucp_messages"); } -void MainWindow::on_actionTelephonyF1APMessages_triggered() +void WiresharkMainWindow::on_actionTelephonyF1APMessages_triggered() { openStatisticsTreeDialog("f1ap"); } -void MainWindow::on_actionTelephonyNGAPMessages_triggered() +void WiresharkMainWindow::on_actionTelephonyNGAPMessages_triggered() { openStatisticsTreeDialog("ngap"); } -void MainWindow::on_actionTelephonySipFlows_triggered() +void WiresharkMainWindow::on_actionTelephonySipFlows_triggered() { openTelephonyVoipCallsDialogSip(); } // Wireless Menu -void MainWindow::on_actionBluetoothATT_Server_Attributes_triggered() +void WiresharkMainWindow::on_actionBluetoothATT_Server_Attributes_triggered() { BluetoothAttServerAttributesDialog *bluetooth_att_sever_attributes_dialog = new BluetoothAttServerAttributesDialog(*this, capture_file_); connect(bluetooth_att_sever_attributes_dialog, SIGNAL(goToPacket(int)), @@ -3703,7 +3698,7 @@ void MainWindow::on_actionBluetoothATT_Server_Attributes_triggered() bluetooth_att_sever_attributes_dialog->show(); } -void MainWindow::on_actionBluetoothDevices_triggered() +void WiresharkMainWindow::on_actionBluetoothDevices_triggered() { BluetoothDevicesDialog *bluetooth_devices_dialog = new BluetoothDevicesDialog(*this, capture_file_, packet_list_); connect(bluetooth_devices_dialog, SIGNAL(goToPacket(int)), @@ -3713,7 +3708,7 @@ void MainWindow::on_actionBluetoothDevices_triggered() bluetooth_devices_dialog->show(); } -void MainWindow::on_actionBluetoothHCI_Summary_triggered() +void WiresharkMainWindow::on_actionBluetoothHCI_Summary_triggered() { BluetoothHciSummaryDialog *bluetooth_hci_summary_dialog = new BluetoothHciSummaryDialog(*this, capture_file_); connect(bluetooth_hci_summary_dialog, SIGNAL(goToPacket(int)), @@ -3725,103 +3720,103 @@ void MainWindow::on_actionBluetoothHCI_Summary_triggered() // Tools Menu -void MainWindow::on_actionToolsFirewallAclRules_triggered() +void WiresharkMainWindow::on_actionToolsFirewallAclRules_triggered() { FirewallRulesDialog *firewall_rules_dialog = new FirewallRulesDialog(*this, capture_file_); firewall_rules_dialog->show(); } -void MainWindow::on_actionToolsCredentials_triggered() +void WiresharkMainWindow::on_actionToolsCredentials_triggered() { CredentialsDialog *credentials_dialog = new CredentialsDialog(*this, capture_file_, packet_list_); credentials_dialog->show(); } // Help Menu -void MainWindow::on_actionHelpContents_triggered() { +void WiresharkMainWindow::on_actionHelpContents_triggered() { mainApp->helpTopicAction(HELP_CONTENT); } -void MainWindow::on_actionHelpMPWireshark_triggered() { +void WiresharkMainWindow::on_actionHelpMPWireshark_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK); } -void MainWindow::on_actionHelpMPWireshark_Filter_triggered() { +void WiresharkMainWindow::on_actionHelpMPWireshark_Filter_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK_FILTER); } -void MainWindow::on_actionHelpMPCapinfos_triggered() { +void WiresharkMainWindow::on_actionHelpMPCapinfos_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_CAPINFOS); } -void MainWindow::on_actionHelpMPDumpcap_triggered() { +void WiresharkMainWindow::on_actionHelpMPDumpcap_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_DUMPCAP); } -void MainWindow::on_actionHelpMPEditcap_triggered() { +void WiresharkMainWindow::on_actionHelpMPEditcap_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_EDITCAP); } -void MainWindow::on_actionHelpMPMergecap_triggered() { +void WiresharkMainWindow::on_actionHelpMPMergecap_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_MERGECAP); } -void MainWindow::on_actionHelpMPRawshark_triggered() { +void WiresharkMainWindow::on_actionHelpMPRawshark_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_RAWSHARK); } -void MainWindow::on_actionHelpMPReordercap_triggered() { +void WiresharkMainWindow::on_actionHelpMPReordercap_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_REORDERCAP); } -void MainWindow::on_actionHelpMPText2pcap_triggered() { +void WiresharkMainWindow::on_actionHelpMPText2pcap_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_TEXT2PCAP); } -void MainWindow::on_actionHelpMPTShark_triggered() { +void WiresharkMainWindow::on_actionHelpMPTShark_triggered() { mainApp->helpTopicAction(LOCALPAGE_MAN_TSHARK); } -void MainWindow::on_actionHelpWebsite_triggered() { +void WiresharkMainWindow::on_actionHelpWebsite_triggered() { mainApp->helpTopicAction(ONLINEPAGE_HOME); } -void MainWindow::on_actionHelpFAQ_triggered() { +void WiresharkMainWindow::on_actionHelpFAQ_triggered() { mainApp->helpTopicAction(ONLINEPAGE_FAQ); } -void MainWindow::on_actionHelpAsk_triggered() { +void WiresharkMainWindow::on_actionHelpAsk_triggered() { mainApp->helpTopicAction(ONLINEPAGE_ASK); } -void MainWindow::on_actionHelpDownloads_triggered() { +void WiresharkMainWindow::on_actionHelpDownloads_triggered() { mainApp->helpTopicAction(ONLINEPAGE_DOWNLOAD); } -void MainWindow::on_actionHelpWiki_triggered() { +void WiresharkMainWindow::on_actionHelpWiki_triggered() { mainApp->helpTopicAction(ONLINEPAGE_WIKI); } -void MainWindow::on_actionHelpSampleCaptures_triggered() { +void WiresharkMainWindow::on_actionHelpSampleCaptures_triggered() { mainApp->helpTopicAction(ONLINEPAGE_SAMPLE_FILES); } #ifdef HAVE_SOFTWARE_UPDATE -void MainWindow::checkForUpdates() +void WiresharkMainWindow::checkForUpdates() { software_update_check(); } #endif -void MainWindow::on_actionHelpAbout_triggered() +void WiresharkMainWindow::on_actionHelpAbout_triggered() { AboutDialog *about_dialog = new AboutDialog(this); @@ -3838,7 +3833,7 @@ void MainWindow::on_actionHelpAbout_triggered() about_dialog->activateWindow(); } -void MainWindow::on_actionGoGoToPacket_triggered() { +void WiresharkMainWindow::on_actionGoGoToPacket_triggered() { if (! packet_list_->model() || packet_list_->model()->rowCount() < 1) { return; } @@ -3852,7 +3847,7 @@ void MainWindow::on_actionGoGoToPacket_triggered() { } } -void MainWindow::on_actionGoGoToLinkedPacket_triggered() +void WiresharkMainWindow::on_actionGoGoToLinkedPacket_triggered() { QAction *gta = qobject_cast(sender()); if (!gta) return; @@ -3865,7 +3860,7 @@ void MainWindow::on_actionGoGoToLinkedPacket_triggered() } // gtk/main_menubar.c:goto_conversation_frame -void MainWindow::goToConversationFrame(bool go_next) { +void WiresharkMainWindow::goToConversationFrame(bool go_next) { gchar *filter = NULL; dfilter_t *dfcode = NULL; gboolean found_packet = FALSE; @@ -3904,26 +3899,26 @@ void MainWindow::goToConversationFrame(bool go_next) { g_free(filter); } -void MainWindow::on_actionGoNextConversationPacket_triggered() +void WiresharkMainWindow::on_actionGoNextConversationPacket_triggered() { goToConversationFrame(true); } -void MainWindow::on_actionGoPreviousConversationPacket_triggered() +void WiresharkMainWindow::on_actionGoPreviousConversationPacket_triggered() { goToConversationFrame(false); } -void MainWindow::on_actionGoAutoScroll_toggled(bool checked) +void WiresharkMainWindow::on_actionGoAutoScroll_toggled(bool checked) { packet_list_->setVerticalAutoScroll(checked); } -void MainWindow::resetPreviousFocus() { +void WiresharkMainWindow::resetPreviousFocus() { previous_focus_ = NULL; } -void MainWindow::on_goToCancel_clicked() +void WiresharkMainWindow::on_goToCancel_clicked() { main_ui_->goToFrame->animatedHide(); if (previous_focus_) { @@ -3933,19 +3928,19 @@ void MainWindow::on_goToCancel_clicked() } } -void MainWindow::on_goToGo_clicked() +void WiresharkMainWindow::on_goToGo_clicked() { gotoFrame(main_ui_->goToLineEdit->text().toInt()); on_goToCancel_clicked(); } -void MainWindow::on_goToLineEdit_returnPressed() +void WiresharkMainWindow::on_goToLineEdit_returnPressed() { on_goToGo_clicked(); } -void MainWindow::on_actionCaptureStart_triggered() +void WiresharkMainWindow::on_actionCaptureStart_triggered() { //#ifdef HAVE_AIRPCAP // airpcap_if_active = airpcap_if_selected; @@ -3992,12 +3987,12 @@ void MainWindow::on_actionCaptureStart_triggered() #endif // HAVE_LIBPCAP } -void MainWindow::on_actionCaptureStop_triggered() +void WiresharkMainWindow::on_actionCaptureStop_triggered() { stopCapture(); } -void MainWindow::on_actionCaptureRestart_triggered() +void WiresharkMainWindow::on_actionCaptureRestart_triggered() { #ifdef HAVE_LIBPCAP QString before_what(tr(" before restarting the capture")); @@ -4009,7 +4004,7 @@ void MainWindow::on_actionCaptureRestart_triggered() #endif // HAVE_LIBPCAP } -void MainWindow::on_actionCaptureCaptureFilters_triggered() +void WiresharkMainWindow::on_actionCaptureCaptureFilters_triggered() { if (!capture_filter_dlg_) { capture_filter_dlg_ = new FilterDialog(this, FilterDialog::CaptureFilter); @@ -4019,7 +4014,7 @@ void MainWindow::on_actionCaptureCaptureFilters_triggered() capture_filter_dlg_->activateWindow(); } -void MainWindow::on_actionStatisticsCaptureFileProperties_triggered() +void WiresharkMainWindow::on_actionStatisticsCaptureFileProperties_triggered() { CaptureFilePropertiesDialog *capture_file_properties_dialog = new CaptureFilePropertiesDialog(*this, capture_file_); connect(capture_file_properties_dialog, SIGNAL(captureCommentChanged()), @@ -4027,7 +4022,7 @@ void MainWindow::on_actionStatisticsCaptureFileProperties_triggered() capture_file_properties_dialog->show(); } -void MainWindow::on_actionStatisticsResolvedAddresses_triggered() +void WiresharkMainWindow::on_actionStatisticsResolvedAddresses_triggered() { QString capFileName; wtap* wth = Q_NULLPTR; @@ -4041,7 +4036,7 @@ void MainWindow::on_actionStatisticsResolvedAddresses_triggered() resolved_addresses_dialog->show(); } -void MainWindow::on_actionStatisticsProtocolHierarchy_triggered() +void WiresharkMainWindow::on_actionStatisticsProtocolHierarchy_triggered() { ProtocolHierarchyDialog *phd = new ProtocolHierarchyDialog(*this, capture_file_); connect(phd, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), @@ -4049,7 +4044,7 @@ void MainWindow::on_actionStatisticsProtocolHierarchy_triggered() phd->show(); } -void MainWindow::on_actionCaptureOptions_triggered() +void WiresharkMainWindow::on_actionCaptureOptions_triggered() { #ifdef HAVE_LIBPCAP if (!capture_options_dialog_) { @@ -4093,7 +4088,7 @@ void MainWindow::on_actionCaptureOptions_triggered() } #ifdef HAVE_LIBPCAP -void MainWindow::on_actionCaptureRefreshInterfaces_triggered() +void WiresharkMainWindow::on_actionCaptureRefreshInterfaces_triggered() { main_ui_->actionCaptureRefreshInterfaces->setEnabled(false); mainApp->refreshLocalInterfaces(); @@ -4101,7 +4096,7 @@ void MainWindow::on_actionCaptureRefreshInterfaces_triggered() } #endif -void MainWindow::externalMenuItem_triggered() +void WiresharkMainWindow::externalMenuItem_triggered() { QAction * triggerAction = NULL; QVariant v; @@ -4123,14 +4118,7 @@ void MainWindow::externalMenuItem_triggered() } } -void MainWindow::gotoFrame(int packet_num) -{ - if (packet_num > 0) { - packet_list_->goToPacket(packet_num); - } -} - -void MainWindow::extcap_options_finished(int result) +void WiresharkMainWindow::extcap_options_finished(int result) { if (result == QDialog::Accepted) { QString before_what(tr(" before starting a new capture")); @@ -4141,7 +4129,7 @@ void MainWindow::extcap_options_finished(int result) this->welcome_page_->getInterfaceFrame()->interfaceListChanged(); } -void MainWindow::showExtcapOptionsDialog(QString &device_name, bool startCaptureOnClose) +void WiresharkMainWindow::showExtcapOptionsDialog(QString &device_name, bool startCaptureOnClose) { ExtcapOptionsDialog * extcap_options_dialog = ExtcapOptionsDialog::createForDevice(device_name, startCaptureOnClose, this); /* The dialog returns null, if the given device name is not a valid extcap device */ @@ -4163,19 +4151,7 @@ void MainWindow::showExtcapOptionsDialog(QString &device_name, bool startCapture } } -void MainWindow::insertColumn(QString name, QString abbrev, gint pos) -{ - gint colnr = 0; - if (name.length() > 0 && abbrev.length() > 0) - { - colnr = column_prefs_add_custom(COL_CUSTOM, name.toStdString().c_str(), abbrev.toStdString().c_str(), pos); - packet_list_->columnsChanged(); - packet_list_->resizeColumnToContents(colnr); - prefs_main_write(); - } -} - -void MainWindow::on_actionContextWikiProtocolPage_triggered() +void WiresharkMainWindow::on_actionContextWikiProtocolPage_triggered() { QAction *wa = qobject_cast(sender()); if (!wa) return; @@ -4199,7 +4175,7 @@ void MainWindow::on_actionContextWikiProtocolPage_triggered() QDesktopServices::openUrl(wiki_url); } -void MainWindow::on_actionContextFilterFieldReference_triggered() +void WiresharkMainWindow::on_actionContextFilterFieldReference_triggered() { QAction *wa = qobject_cast(sender()); if (!wa) return; @@ -4216,7 +4192,7 @@ void MainWindow::on_actionContextFilterFieldReference_triggered() QDesktopServices::openUrl(dfref_url); } -void MainWindow::on_actionViewFullScreen_triggered(bool checked) +void WiresharkMainWindow::on_actionViewFullScreen_triggered(bool checked) { if (checked) { // Save the state for future restore @@ -4231,7 +4207,7 @@ void MainWindow::on_actionViewFullScreen_triggered(bool checked) } } -void MainWindow::activatePluginIFToolbar(bool) +void WiresharkMainWindow::activatePluginIFToolbar(bool) { QAction *sendingAction = dynamic_cast(sender()); if (!sendingAction || !sendingAction->data().isValid()) @@ -4254,48 +4230,48 @@ void MainWindow::activatePluginIFToolbar(bool) } } -void MainWindow::rtpPlayerDialogReplaceRtpStreams(QVector stream_ids _U_) +void WiresharkMainWindow::rtpPlayerDialogReplaceRtpStreams(QVector stream_ids _U_) { #ifdef QT_MULTIMEDIA_LIB openTelephonyRtpPlayerDialog()->replaceRtpStreams(stream_ids); #endif } -void MainWindow::rtpPlayerDialogAddRtpStreams(QVector stream_ids _U_) +void WiresharkMainWindow::rtpPlayerDialogAddRtpStreams(QVector stream_ids _U_) { #ifdef QT_MULTIMEDIA_LIB openTelephonyRtpPlayerDialog()->addRtpStreams(stream_ids); #endif } -void MainWindow::rtpPlayerDialogRemoveRtpStreams(QVector stream_ids _U_) +void WiresharkMainWindow::rtpPlayerDialogRemoveRtpStreams(QVector stream_ids _U_) { #ifdef QT_MULTIMEDIA_LIB openTelephonyRtpPlayerDialog()->removeRtpStreams(stream_ids); #endif } -void MainWindow::rtpAnalysisDialogReplaceRtpStreams(QVector stream_ids) +void WiresharkMainWindow::rtpAnalysisDialogReplaceRtpStreams(QVector stream_ids) { openTelephonyRtpAnalysisDialog()->replaceRtpStreams(stream_ids); } -void MainWindow::rtpAnalysisDialogAddRtpStreams(QVector stream_ids) +void WiresharkMainWindow::rtpAnalysisDialogAddRtpStreams(QVector stream_ids) { openTelephonyRtpAnalysisDialog()->addRtpStreams(stream_ids); } -void MainWindow::rtpAnalysisDialogRemoveRtpStreams(QVector stream_ids) +void WiresharkMainWindow::rtpAnalysisDialogRemoveRtpStreams(QVector stream_ids) { openTelephonyRtpAnalysisDialog()->removeRtpStreams(stream_ids); } -void MainWindow::rtpStreamsDialogSelectRtpStreams(QVector stream_ids) +void WiresharkMainWindow::rtpStreamsDialogSelectRtpStreams(QVector stream_ids) { openTelephonyRtpStreamsDialog()->selectRtpStream(stream_ids); } -void MainWindow::rtpStreamsDialogDeselectRtpStreams(QVector stream_ids) +void WiresharkMainWindow::rtpStreamsDialogDeselectRtpStreams(QVector stream_ids) { openTelephonyRtpStreamsDialog()->deselectRtpStream(stream_ids); } diff --git a/ui/qt_logshark/CMakeLists.txt b/ui/qt_logshark/CMakeLists.txt index 4006fe9595..6fe995b393 100644 --- a/ui/qt_logshark/CMakeLists.txt +++ b/ui/qt_logshark/CMakeLists.txt @@ -137,10 +137,6 @@ set(WIRESHARK_QT_HEADERS ../qt/about_dialog.h ../qt/accordion_frame.h ../qt/address_editor_frame.h - ../qt/bluetooth_att_server_attributes_dialog.h - ../qt/bluetooth_device_dialog.h - ../qt/bluetooth_devices_dialog.h - ../qt/bluetooth_hci_summary_dialog.h ../qt/byte_view_tab.h ../qt/capture_file_dialog.h ../qt/capture_file_properties_dialog.h @@ -253,7 +249,6 @@ set(WIRESHARK_QT_HEADERS ../qt/welcome_page.h ../qt/wireless_frame.h ../qt/wireshark_dialog.h - ../qt/wlan_statistics_dialog.h ../qt/${WIRESHARK_CUSTOM_QT_HEADERS} ) @@ -271,6 +266,7 @@ endif() set (LOGSHARK_QT_HEADERS logshark_application.h + logwolf_main_window.h ${WIRESHARK_QT_HEADERS} ) @@ -390,10 +386,6 @@ set(WIRESHARK_QT_SRC ../qt/about_dialog.cpp ../qt/accordion_frame.cpp ../qt/address_editor_frame.cpp - ../qt/bluetooth_att_server_attributes_dialog.cpp - ../qt/bluetooth_device_dialog.cpp - ../qt/bluetooth_devices_dialog.cpp - ../qt/bluetooth_hci_summary_dialog.cpp ../qt/byte_view_tab.cpp ../qt/capture_file_dialog.cpp ../qt/capture_file_properties_dialog.cpp @@ -448,9 +440,7 @@ set(WIRESHARK_QT_SRC ../qt/main_status_bar.cpp ../qt/main_window_layout.cpp ../qt/main_window_preferences_frame.cpp - ../qt/main_window_slots.cpp ../qt/main_window.cpp - # ../qt/main.cpp ../qt/manage_interfaces_dialog.cpp ../qt/module_preferences_scroll_area.cpp ../qt/packet_comment_dialog.cpp @@ -519,6 +509,8 @@ endif() set (LOGSHARK_QT_SRC ls_main.cpp + logwolf_main_window.cpp + logwolf_main_window_slots.cpp logshark_application.cpp ${WIRESHARK_QT_SRC}) @@ -535,7 +527,6 @@ set(WIRESHARK_QT_TAP_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../qt/sctp_all_assocs_dialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../qt/sctp_assoc_analyse_dialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../qt/stats_tree_dialog.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../qt/wlan_statistics_dialog.cpp ${WIRESHARK_CUSTOM_TAP_SRC} ) @@ -593,7 +584,6 @@ set(WIRESHARK_QT_UI ../qt/lbm_stream_dialog.ui ../qt/lte_rlc_graph_dialog.ui ../qt/main_window_preferences_frame.ui - ../qt/main_window.ui ../qt/manage_interfaces_dialog.ui ../qt/module_preferences_scroll_area.ui ../qt/mtp3_summary_dialog.ui @@ -641,7 +631,10 @@ if(HAVE_PCAP_REMOTE) ) endif() -set (LOGSHARK_QT_UI ${WIRESHARK_QT_UI}) +set (LOGSHARK_QT_UI + logwolf_main_window.ui + ${WIRESHARK_QT_UI} +) set(WIRESHARK_QT_TS ../qt/wireshark_de.ts diff --git a/ui/qt_logshark/logshark_application.cpp b/ui/qt_logshark/logshark_application.cpp index d07f138a47..b2a44a96bd 100644 --- a/ui/qt_logshark/logshark_application.cpp +++ b/ui/qt_logshark/logshark_application.cpp @@ -15,8 +15,8 @@ LogsharkApplication::LogsharkApplication(int &argc, char **argv) : MainApplication(argc, argv) { lsApp = this; - setApplicationName("Logshark"); - setDesktopFileName(QStringLiteral("org.wireshark.Logshark")); + setApplicationName("Logwolf"); + setDesktopFileName(QStringLiteral("org.wireshark.Logwolf")); } LogsharkApplication::~LogsharkApplication() diff --git a/ui/qt_logshark/logshark_application.h b/ui/qt_logshark/logshark_application.h index c44dd187a6..b28bb21f9d 100644 --- a/ui/qt_logshark/logshark_application.h +++ b/ui/qt_logshark/logshark_application.h @@ -1,14 +1,14 @@ /** @file * - * Logshark - Event log analyzer + * Logwolf - Event log analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef LOGSHARK_APPLICATION_H -#define LOGSHARK_APPLICATION_H +#ifndef LOGWOLF_APPLICATION_H +#define LOGWOLF_APPLICATION_H #include @@ -21,4 +21,4 @@ public: extern LogsharkApplication *lsApp; -#endif // LOGSHARK_APPLICATION_H +#endif // LOGWOLF_APPLICATION_H diff --git a/ui/qt_logshark/logwolf_main_window.cpp b/ui/qt_logshark/logwolf_main_window.cpp new file mode 100644 index 0000000000..d482b98f00 --- /dev/null +++ b/ui/qt_logshark/logwolf_main_window.cpp @@ -0,0 +1,3160 @@ +/* logwolf_main_window.cpp + * + * Logwolf - Event log analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "main_application.h" +#include "logwolf_main_window.h" + +/* + * The generated Ui_LogwolfMainWindow::setupUi() can grow larger than our configured limit, + * so turn off -Wframe-larger-than= for ui_main_window.h. + */ +DIAG_OFF(frame-larger-than=) +#include +DIAG_ON(frame-larger-than=) + +#include +#include "epan/conversation_filter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui/iface_toolbar.h" + +#ifdef HAVE_LIBPCAP +#include "ui/capture.h" +#include +#endif + +#include "ui/alert_box.h" +#ifdef HAVE_LIBPCAP +#include "ui/capture_ui_utils.h" +#endif +#include "ui/capture_globals.h" +#include "ui/main_statusbar.h" +#include "ui/recent.h" +#include "ui/recent_utils.h" +#include "ui/util.h" +#include "ui/preference_utils.h" + +#include "byte_view_tab.h" +#ifdef HAVE_LIBPCAP +#include "capture_options_dialog.h" +#endif +#include "conversation_colorize_action.h" +#include "export_dissection_dialog.h" +#include "export_object_action.h" +#include "file_set_dialog.h" +#include "filter_dialog.h" +#include "funnel_statistics.h" +#include "import_text_dialog.h" +#include "interface_toolbar.h" +#include "packet_diagram.h" +#include "packet_list.h" +#include "proto_tree.h" +#include "simple_dialog.h" +#include "tap_parameter_dialog.h" +#include "wireless_frame.h" +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//menu_recent_file_write_all + +// If we ever add support for multiple windows this will need to be replaced. +static LogwolfMainWindow *gbl_cur_main_window_ = NULL; + +void pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb) +{ + gbl_cur_main_window_->setPipeInputHandler(source, user_data, child_process, input_cb); +} + +static void plugin_if_mainwindow_apply_filter(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + if (g_hash_table_lookup_extended(data_set, "filter_string", NULL, NULL)) { + QString filter((const char *)g_hash_table_lookup(data_set, "filter_string")); + gbl_cur_main_window_->filterPackets(filter); + } +} + +static void plugin_if_mainwindow_preference(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + const char * module_name; + const char * pref_name; + const char * pref_value; + +DIAG_OFF_CAST_AWAY_CONST + if (g_hash_table_lookup_extended(data_set, "pref_module", NULL, (gpointer *)&module_name) && + g_hash_table_lookup_extended(data_set, "pref_key", NULL, (gpointer *)&pref_name) && + g_hash_table_lookup_extended(data_set, "pref_value", NULL, (gpointer *)&pref_value)) + { + unsigned int changed_flags = prefs_store_ext(module_name, pref_name, pref_value); + if (changed_flags) { + mainApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged); + mainApp->emitAppSignal(WiresharkApplication::PreferencesChanged); + } + } +DIAG_ON_CAST_AWAY_CONST +} + +static void plugin_if_mainwindow_gotoframe(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + gpointer framenr; + + if (g_hash_table_lookup_extended(data_set, "frame_nr", NULL, &framenr)) { + if (GPOINTER_TO_UINT(framenr) != 0) + gbl_cur_main_window_->gotoFrame(GPOINTER_TO_UINT(framenr)); + } +} + +#ifdef HAVE_LIBPCAP + +static void plugin_if_mainwindow_get_ws_info(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + ws_info_t *ws_info = NULL; + + if (!g_hash_table_lookup_extended(data_set, "ws_info", NULL, (void**)&ws_info)) + return; + + CaptureFile *cfWrap = gbl_cur_main_window_->captureFile(); + capture_file *cf = cfWrap->capFile(); + + ws_info->ws_info_supported = true; + + /* If we have a filename attached to ws_info clear it */ + if (ws_info->cf_filename != NULL) + { + g_free(ws_info->cf_filename); + ws_info->cf_filename = NULL; + } + + /* Determine the true state of the capture file. We return the true state in + the ws_info structure and DON'T CHANGE the cf->state as we don't want to cause problems + with code that follows this. */ + if (cf) + { + if (cf->filename) + { + /* As we have a cf->filename we'll use the name and the state */ + ws_info->cf_filename = g_strdup(cf->filename); + ws_info->cf_state = cf->state; + } + else + { + /* When we come through here the cf->state can show FILE_READ_DONE even though the + file is actually closed (no filename). A better fix would be to have a + FILE_CLOSE_PENDING state but that involves a lot of code change elsewhere. */ + ws_info->cf_state = FILE_CLOSED; + } + } + + if (!ws_info->cf_filename) + { + /* We may have a filename associated with the main window so let's use it */ + QString fileNameString = gbl_cur_main_window_->getMwFileName(); + if (fileNameString.length()) + { + QByteArray ba = fileNameString.toLatin1(); + const char *c_file_name = ba.data(); + ws_info->cf_filename = g_strdup(c_file_name); + } + } + + if (cf) { + ws_info->cf_count = cf->count; + + QList rows = gbl_cur_main_window_->selectedRows(); + frame_data * fdata = NULL; + if (rows.count() > 0) + fdata = gbl_cur_main_window_->frameDataForRow(rows.at(0)); + + if (cf->state == FILE_READ_DONE && fdata) { + ws_info->cf_framenr = fdata->num; + ws_info->frame_passed_dfilter = (fdata->passed_dfilter == 1); + } + else { + ws_info->cf_framenr = 0; + ws_info->frame_passed_dfilter = FALSE; + } + } + else + { + /* Initialise the other ws_info structure values */ + ws_info->cf_count = 0; + ws_info->cf_framenr = 0; + ws_info->frame_passed_dfilter = FALSE; + } +} + +#endif /* HAVE_LIBPCAP */ + +static void plugin_if_mainwindow_get_frame_data(GHashTable* data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + plugin_if_frame_data_cb extract_cb; + void* user_data; + void** ret_value_ptr; + + if (g_hash_table_lookup_extended(data_set, "extract_cb", NULL, (void**)&extract_cb) && + g_hash_table_lookup_extended(data_set, "user_data", NULL, (void**)&user_data) && + g_hash_table_lookup_extended(data_set, "ret_value_ptr", NULL, (void**)&ret_value_ptr)) + { + QList rows = gbl_cur_main_window_->selectedRows(); + if (rows.count() > 0) { + frame_data* fdata = gbl_cur_main_window_->frameDataForRow(rows.at(0)); + if (fdata) { + *ret_value_ptr = extract_cb(fdata, user_data); + } + } + } +} + +static void plugin_if_mainwindow_get_capture_file(GHashTable* data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + plugin_if_capture_file_cb extract_cb; + void* user_data; + void** ret_value_ptr; + + if (g_hash_table_lookup_extended(data_set, "extract_cb", NULL, (void**)&extract_cb) && + g_hash_table_lookup_extended(data_set, "user_data", NULL, (void**)&user_data) && + g_hash_table_lookup_extended(data_set, "ret_value_ptr", NULL, (void**)&ret_value_ptr)) + { + CaptureFile* cfWrap = gbl_cur_main_window_->captureFile(); + capture_file* cf = cfWrap->capFile(); + if (cf) { + *ret_value_ptr = extract_cb(cf, user_data); + } + } +} + +static void plugin_if_mainwindow_update_toolbars(GHashTable * data_set) +{ + if (!gbl_cur_main_window_ || !data_set) + return; + + if (g_hash_table_lookup_extended(data_set, "toolbar_name", NULL, NULL)) { + QString toolbarName((const char *)g_hash_table_lookup(data_set, "toolbar_name")); + gbl_cur_main_window_->removeAdditionalToolbar(toolbarName); + + } +} + +static void mainwindow_add_toolbar(const iface_toolbar *toolbar_entry) +{ + if (gbl_cur_main_window_ && toolbar_entry) + { + gbl_cur_main_window_->addInterfaceToolbar(toolbar_entry); + } +} + +static void mainwindow_remove_toolbar(const gchar *menu_title) +{ + if (gbl_cur_main_window_ && menu_title) + { + gbl_cur_main_window_->removeInterfaceToolbar(menu_title); + } +} + +QMenu* LogwolfMainWindow::findOrAddMenu(QMenu *parent_menu, QString& menu_text) { + QList actions = parent_menu->actions(); + QList::const_iterator i; + for (i = actions.constBegin(); i != actions.constEnd(); ++i) { + if ((*i)->text()==menu_text) { + return (*i)->menu(); + } + } + // If we get here there menu entry was not found, add a sub menu + return parent_menu->addMenu(menu_text); +} + +LogwolfMainWindow::LogwolfMainWindow(QWidget *parent) : + MainWindow(parent), + main_ui_(new Ui::LogwolfMainWindow), + previous_focus_(NULL), + file_set_dialog_(NULL), + show_hide_actions_(NULL), + time_display_actions_(NULL), + time_precision_actions_(NULL), + funnel_statistics_(NULL), + freeze_focus_(NULL), + was_maximized_(false), + capture_stopping_(false), + capture_filter_valid_(false) +#ifdef HAVE_LIBPCAP + , capture_options_dialog_(NULL) + , info_data_() +#endif + , display_filter_dlg_(NULL) + , capture_filter_dlg_(NULL) +#ifdef _WIN32 + , pipe_timer_(NULL) +#else + , pipe_notifier_(NULL) +#endif +#if defined(Q_OS_MAC) + , dock_menu_(NULL) +#endif +{ + if (!gbl_cur_main_window_) { + connect(mainApp, SIGNAL(openStatCommandDialog(QString, const char*, void*)), + this, SLOT(openStatCommandDialog(QString, const char*, void*))); + connect(mainApp, SIGNAL(openTapParameterDialog(QString, const QString, void*)), + this, SLOT(openTapParameterDialog(QString, const QString, void*))); + } + gbl_cur_main_window_ = this; +#ifdef HAVE_LIBPCAP + capture_input_init(&cap_session_, CaptureFile::globalCapFile()); +#endif + + findTextCodecs(); + // setpUi calls QMetaObject::connectSlotsByName(this). connectSlotsByName + // iterates over *all* of our children, looking for matching "on_" slots. + // The fewer children we have at this point the better. + main_ui_->setupUi(this); +#ifdef HAVE_SOFTWARE_UPDATE + update_action_ = new QAction(tr("Check for Updates…"), main_ui_->menuHelp); +#endif +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + wireless_frame_ = new WirelessFrame(this); + main_ui_->wirelessToolBar->addWidget(wireless_frame_); +#else + removeToolBar(main_ui_->wirelessToolBar); + main_ui_->menuView->removeAction(main_ui_->actionViewWirelessToolbar); +#endif + + setWindowIcon(mainApp->normalIcon()); + setTitlebarForCaptureFile(); + setMenusForCaptureFile(); + setForCapturedPackets(false); + setMenusForFileSet(false); + interfaceSelectionChanged(); + loadWindowGeometry(); + +#ifndef HAVE_LUA + main_ui_->actionAnalyzeReloadLuaPlugins->setVisible(false); +#endif + + qRegisterMetaType("FilterAction::Action"); + qRegisterMetaType("FilterAction::ActionType"); + connect(this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SLOT(queuedFilterAction(QString, FilterAction::Action, FilterAction::ActionType)), + Qt::QueuedConnection); + + //To prevent users use features before initialization complete + //Otherwise unexpected problems may occur + setFeaturesEnabled(false); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(setFeaturesEnabled())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(applyGlobalCommandLineOptions())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(zoomText())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initViewColorizeMenu())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addStatsPluginsToMenu())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addDynamicMenus())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(addPluginIFStructures())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initConversationMenus())); + connect(mainApp, SIGNAL(appInitialized()), this, SLOT(initExportObjectsMenus())); + + connect(mainApp, SIGNAL(profileChanging()), this, SLOT(saveWindowGeometry())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(layoutPanes())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(layoutToolbars())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(updatePreferenceActions())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(zoomText())); + connect(mainApp, SIGNAL(preferencesChanged()), this, SLOT(setTitlebarForCaptureFile())); + + connect(mainApp, SIGNAL(updateRecentCaptureStatus(const QString &, qint64, bool)), this, SLOT(updateRecentCaptures())); + updateRecentCaptures(); + +#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) + connect(mainApp, SIGNAL(softwareUpdateRequested()), this, SLOT(softwareUpdateRequested()), + Qt::BlockingQueuedConnection); + connect(mainApp, SIGNAL(softwareUpdateClose()), this, SLOT(close()), + Qt::BlockingQueuedConnection); +#endif + + df_combo_box_ = new DisplayFilterCombo(this); + + funnel_statistics_ = new FunnelStatistics(this, capture_file_); + connect(df_combo_box_, &QComboBox::editTextChanged, funnel_statistics_, &FunnelStatistics::displayFilterTextChanged); + connect(funnel_statistics_, &FunnelStatistics::setDisplayFilter, this, &LogwolfMainWindow::setDisplayFilter); + connect(funnel_statistics_, SIGNAL(openCaptureFile(QString, QString)), + this, SLOT(openCaptureFile(QString, QString))); + + file_set_dialog_ = new FileSetDialog(this); + connect(file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString)), + this, SLOT(openCaptureFile(QString))); + + initMainToolbarIcons(); + + main_ui_->displayFilterToolBar->insertWidget(main_ui_->actionNewDisplayFilterExpression, df_combo_box_); + + // Make sure filter expressions overflow into a menu instead of a + // larger toolbar. We do this by adding them to a child toolbar. + // https://bugreports.qt.io/browse/QTBUG-2472 + FilterExpressionToolBar *filter_expression_toolbar_ = new FilterExpressionToolBar(this); + connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterPreferences, this, &LogwolfMainWindow::onFilterPreferences); + connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterSelected, this, &LogwolfMainWindow::onFilterSelected); + connect(filter_expression_toolbar_, &FilterExpressionToolBar::filterEdit, this, &LogwolfMainWindow::onFilterEdit); + + main_ui_->displayFilterToolBar->addWidget(filter_expression_toolbar_); + +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + connect(wireless_frame_, SIGNAL(showWirelessPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); +#endif + + main_ui_->goToFrame->hide(); + connect(main_ui_->goToFrame, SIGNAL(visibilityChanged(bool)), + main_ui_->actionGoGoToPacket, SLOT(setChecked(bool))); + + // XXX For some reason the cursor is drawn funny with an input mask set + // https://bugreports.qt-project.org/browse/QTBUG-7174 + + main_ui_->searchFrame->hide(); + connect(main_ui_->searchFrame, SIGNAL(visibilityChanged(bool)), + main_ui_->actionEditFindPacket, SLOT(setChecked(bool))); + + main_ui_->addressEditorFrame->hide(); + main_ui_->columnEditorFrame->hide(); + main_ui_->preferenceEditorFrame->hide(); + main_ui_->filterExpressionFrame->hide(); + +#ifndef HAVE_LIBPCAP + main_ui_->menuCapture->setEnabled(false); +#endif + + // Set OS specific shortcuts for fullscreen mode +#if defined(Q_OS_MAC) + main_ui_->actionViewFullScreen->setShortcut(QKeySequence::FullScreen); +#else + main_ui_->actionViewFullScreen->setShortcut(QKeySequence(Qt::Key_F11)); +#endif + +#if defined(Q_OS_MAC) + + main_ui_->goToPacketLabel->setAttribute(Qt::WA_MacSmallSize, true); + main_ui_->goToLineEdit->setAttribute(Qt::WA_MacSmallSize, true); + main_ui_->goToGo->setAttribute(Qt::WA_MacSmallSize, true); + main_ui_->goToCancel->setAttribute(Qt::WA_MacSmallSize, true); + + main_ui_->actionEditPreferences->setMenuRole(QAction::PreferencesRole); + +#endif // Q_OS_MAC + +// A billion-1 is equivalent to the inputMask 900000000 previously used +// Avoid QValidator::Intermediate values by using a top value of all 9's +#define MAX_GOTO_LINE 999999999 + +QIntValidator *goToLineQiv = new QIntValidator(0,MAX_GOTO_LINE,this); +main_ui_->goToLineEdit->setValidator(goToLineQiv); + +#ifdef HAVE_SOFTWARE_UPDATE + QAction *update_sep = main_ui_->menuHelp->insertSeparator(main_ui_->actionHelpAbout); + main_ui_->menuHelp->insertAction(update_sep, update_action_); + connect(update_action_, SIGNAL(triggered()), this, SLOT(checkForUpdates())); +#endif + master_split_.setObjectName("splitterMaster"); + extra_split_.setObjectName("splitterExtra"); + master_split_.setChildrenCollapsible(false); + extra_split_.setChildrenCollapsible(false); + main_ui_->mainStack->addWidget(&master_split_); + + empty_pane_.setObjectName("emptyPane"); + empty_pane_.setVisible(false); + + packet_list_ = new PacketList(&master_split_); + main_ui_->wirelessTimelineWidget->setPacketList(packet_list_); + connect(packet_list_, SIGNAL(framesSelected(QList)), this, SLOT(setMenusForSelectedPacket())); + connect(packet_list_, SIGNAL(framesSelected(QList)), this, SIGNAL(framesSelected(QList))); + + connect(main_ui_->menuPacketComment, SIGNAL(aboutToShow()), this, SLOT(setEditCommentsMenu())); + + proto_tree_ = new ProtoTree(&master_split_); + proto_tree_->installEventFilter(this); + + packet_list_->setProtoTree(proto_tree_); + packet_list_->installEventFilter(this); + + packet_diagram_ = new PacketDiagram(&master_split_); + + main_stack_ = main_ui_->mainStack; + welcome_page_ = main_ui_->welcomePage; + main_status_bar_ = main_ui_->statusBar; + + connect(proto_tree_, &ProtoTree::fieldSelected, + this, &LogwolfMainWindow::fieldSelected); + connect(packet_list_, &PacketList::fieldSelected, + this, &LogwolfMainWindow::fieldSelected); + connect(this, &LogwolfMainWindow::fieldSelected, + this, &LogwolfMainWindow::setMenusForSelectedTreeRow); + connect(this, &LogwolfMainWindow::fieldSelected, + main_ui_->statusBar, &MainStatusBar::selectedFieldChanged); + + connect(this, &LogwolfMainWindow::fieldHighlight, + main_ui_->statusBar, &MainStatusBar::highlightedFieldChanged); + connect(mainApp, &WiresharkApplication::captureActive, + this, &LogwolfMainWindow::captureActive); + + byte_view_tab_ = new ByteViewTab(&master_split_); + + // Packet list and proto tree must exist before these are called. + setMenusForSelectedPacket(); + setMenusForSelectedTreeRow(); + + initShowHideMainWidgets(); + initTimeDisplayFormatMenu(); + initTimePrecisionFormatMenu(); + initFreezeActions(); + updatePreferenceActions(); + updateRecentActions(); + setForCaptureInProgress(false); + + setTabOrder(df_combo_box_->lineEdit(), packet_list_); + setTabOrder(packet_list_, proto_tree_); + + connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), + this, SLOT(captureEventHandler(CaptureEvent))); + connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), + mainApp, SLOT(captureEventHandler(CaptureEvent))); + connect(&capture_file_, SIGNAL(captureEvent(CaptureEvent)), + main_ui_->statusBar, SLOT(captureEventHandler(CaptureEvent))); + + connect(mainApp, SIGNAL(columnsChanged()), + packet_list_, SLOT(columnsChanged())); + connect(mainApp, SIGNAL(preferencesChanged()), + packet_list_, SLOT(preferencesChanged())); + connect(mainApp, SIGNAL(recentPreferencesRead()), + this, SLOT(applyRecentPaneGeometry())); + connect(mainApp, SIGNAL(recentPreferencesRead()), + this, SLOT(updateRecentActions())); + connect(mainApp, SIGNAL(packetDissectionChanged()), + this, SLOT(redissectPackets()), Qt::QueuedConnection); + + connect(mainApp, SIGNAL(checkDisplayFilter()), + this, SLOT(checkDisplayFilter())); + connect(mainApp, SIGNAL(fieldsChanged()), + this, SLOT(fieldsChanged())); + connect(mainApp, SIGNAL(reloadLuaPlugins()), + this, SLOT(reloadLuaPlugins())); + + connect(main_ui_->mainStack, SIGNAL(currentChanged(int)), + this, SLOT(mainStackChanged(int))); + + connect(welcome_page_, SIGNAL(startCapture(QStringList)), + this, SLOT(startCapture(QStringList))); + connect(welcome_page_, SIGNAL(recentFileActivated(QString)), + this, SLOT(openCaptureFile(QString))); + + connect(main_ui_->addressEditorFrame, &AddressEditorFrame::redissectPackets, + this, &LogwolfMainWindow::redissectPackets); + connect(main_ui_->addressEditorFrame, &AddressEditorFrame::showNameResolutionPreferences, + this, &LogwolfMainWindow::showPreferencesDialog); + connect(main_ui_->preferenceEditorFrame, &PreferenceEditorFrame::showProtocolPreferences, + this, &LogwolfMainWindow::showPreferencesDialog); + connect(main_ui_->filterExpressionFrame, &FilterExpressionFrame::showPreferencesDialog, + this, &LogwolfMainWindow::showPreferencesDialog); + connect(main_ui_->filterExpressionFrame, &FilterExpressionFrame::filterExpressionsChanged, + filter_expression_toolbar_, &FilterExpressionToolBar::filterExpressionsChanged); + + /* Connect change of capture file */ + connect(this, &LogwolfMainWindow::setCaptureFile, + main_ui_->searchFrame, &SearchFrame::setCaptureFile); + connect(this, &LogwolfMainWindow::setCaptureFile, + main_ui_->statusBar, &MainStatusBar::setCaptureFile); + connect(this, &LogwolfMainWindow::setCaptureFile, + packet_list_, &PacketList::setCaptureFile); + connect(this, &LogwolfMainWindow::setCaptureFile, + proto_tree_, &ProtoTree::setCaptureFile); + + connect(mainApp, SIGNAL(zoomMonospaceFont(QFont)), + packet_list_, SLOT(setMonospaceFont(QFont))); + connect(mainApp, SIGNAL(zoomMonospaceFont(QFont)), + proto_tree_, SLOT(setMonospaceFont(QFont))); + + connect(main_ui_->actionGoNextPacket, SIGNAL(triggered()), + packet_list_, SLOT(goNextPacket())); + connect(main_ui_->actionGoPreviousPacket, SIGNAL(triggered()), + packet_list_, SLOT(goPreviousPacket())); + connect(main_ui_->actionGoFirstPacket, SIGNAL(triggered()), + packet_list_, SLOT(goFirstPacket())); + connect(main_ui_->actionGoLastPacket, SIGNAL(triggered()), + packet_list_, SLOT(goLastPacket())); + connect(main_ui_->actionGoNextHistoryPacket, SIGNAL(triggered()), + packet_list_, SLOT(goNextHistoryPacket())); + connect(main_ui_->actionGoPreviousHistoryPacket, SIGNAL(triggered()), + packet_list_, SLOT(goPreviousHistoryPacket())); + + connect(main_ui_->actionViewExpandSubtrees, SIGNAL(triggered()), + proto_tree_, SLOT(expandSubtrees())); + connect(main_ui_->actionViewCollapseSubtrees, SIGNAL(triggered()), + proto_tree_, SLOT(collapseSubtrees())); + connect(main_ui_->actionViewExpandAll, SIGNAL(triggered()), + proto_tree_, SLOT(expandAll())); + connect(main_ui_->actionViewCollapseAll, SIGNAL(triggered()), + proto_tree_, SLOT(collapseAll())); + + connect(packet_list_, SIGNAL(packetDissectionChanged()), + this, SLOT(redissectPackets())); + connect(packet_list_, SIGNAL(showColumnPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); + connect(packet_list_, SIGNAL(showProtocolPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); + connect(packet_list_, SIGNAL(editProtocolPreference(preference*, pref_module*)), + main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*))); + connect(packet_list_, SIGNAL(editColumn(int)), this, SLOT(showColumnEditor(int))); + connect(main_ui_->columnEditorFrame, SIGNAL(columnEdited()), + packet_list_, SLOT(columnsChanged())); + connect(packet_list_, SIGNAL(doubleClicked(QModelIndex)), + this, SLOT(openPacketDialog())); + connect(packet_list_, SIGNAL(packetListScrolled(bool)), + main_ui_->actionGoAutoScroll, SLOT(setChecked(bool))); + + connect(proto_tree_, SIGNAL(openPacketInNewWindow(bool)), + this, SLOT(openPacketDialog(bool))); + connect(proto_tree_, SIGNAL(showProtocolPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); + connect(proto_tree_, SIGNAL(editProtocolPreference(preference*, pref_module*)), + main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*))); + + connect(main_ui_->statusBar, SIGNAL(showExpertInfo()), + this, SLOT(on_actionAnalyzeExpertInfo_triggered())); + + connect(main_ui_->statusBar, SIGNAL(stopLoading()), + &capture_file_, SLOT(stopLoading())); + + connect(main_ui_->statusBar, SIGNAL(editCaptureComment()), + this, SLOT(on_actionStatisticsCaptureFileProperties_triggered())); + + connect(main_ui_->menuApplyAsFilter, &QMenu::aboutToShow, + this, &LogwolfMainWindow::filterMenuAboutToShow); + connect(main_ui_->menuPrepareAFilter, &QMenu::aboutToShow, + this, &LogwolfMainWindow::filterMenuAboutToShow); + +#ifdef HAVE_LIBPCAP + QTreeWidget *iface_tree = findChild("interfaceTree"); + if (iface_tree) { + connect(iface_tree, SIGNAL(itemSelectionChanged()), + this, SLOT(interfaceSelectionChanged())); + } + connect(main_ui_->welcomePage, SIGNAL(captureFilterSyntaxChanged(bool)), + this, SLOT(captureFilterSyntaxChanged(bool))); + + connect(this, SIGNAL(showExtcapOptions(QString&, bool)), + this, SLOT(showExtcapOptionsDialog(QString&, bool))); + connect(this->welcome_page_, SIGNAL(showExtcapOptions(QString&, bool)), + this, SLOT(showExtcapOptionsDialog(QString&, bool))); + +#endif // HAVE_LIBPCAP + + /* Create plugin_if hooks */ + plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_APPLY, plugin_if_mainwindow_apply_filter); + plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_PREPARE, plugin_if_mainwindow_apply_filter); + plugin_if_register_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, plugin_if_mainwindow_preference); + plugin_if_register_gui_cb(PLUGIN_IF_GOTO_FRAME, plugin_if_mainwindow_gotoframe); +#ifdef HAVE_LIBPCAP + plugin_if_register_gui_cb(PLUGIN_IF_GET_WS_INFO, plugin_if_mainwindow_get_ws_info); +#endif + plugin_if_register_gui_cb(PLUGIN_IF_GET_FRAME_DATA, plugin_if_mainwindow_get_frame_data); + plugin_if_register_gui_cb(PLUGIN_IF_GET_CAPTURE_FILE, plugin_if_mainwindow_get_capture_file); + plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars); + + /* Register Interface Toolbar callbacks */ + iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar); + + /* Show tooltips on menu items that go to websites */ + main_ui_->actionHelpMPWireshark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_WIRESHARK))); + main_ui_->actionHelpMPWireshark_Filter->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_WIRESHARK_FILTER))); + main_ui_->actionHelpMPCapinfos->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_CAPINFOS))); + main_ui_->actionHelpMPDumpcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_DUMPCAP))); + main_ui_->actionHelpMPEditcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_EDITCAP))); + main_ui_->actionHelpMPMergecap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_MERGECAP))); + main_ui_->actionHelpMPRawshark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_RAWSHARK))); + main_ui_->actionHelpMPReordercap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_REORDERCAP))); + main_ui_->actionHelpMPText2pcap->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_TEXT2PCAP))); + main_ui_->actionHelpMPTShark->setToolTip(gchar_free_to_qstring(topic_action_url(LOCALPAGE_MAN_TSHARK))); + + main_ui_->actionHelpContents->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_USERGUIDE))); + main_ui_->actionHelpWebsite->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_HOME))); + main_ui_->actionHelpFAQ->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_FAQ))); + main_ui_->actionHelpAsk->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_ASK))); + main_ui_->actionHelpDownloads->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_DOWNLOAD))); + main_ui_->actionHelpWiki->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_WIKI))); + main_ui_->actionHelpSampleCaptures->setToolTip(gchar_free_to_qstring(topic_action_url(ONLINEPAGE_SAMPLE_CAPTURES))); + + showWelcome(); +} + +LogwolfMainWindow::~LogwolfMainWindow() +{ + disconnect(main_ui_->mainStack, 0, 0, 0); + +#ifndef Q_OS_MAC + // Below dialogs inherit GeometryStateDialog + // For reasons described in geometry_state_dialog.h no parent is set when + // instantiating the dialogs and as a resul objects are not automatically + // freed by its parent. Free then here explicitly to avoid leak and numerous + // Valgrind complaints. + delete file_set_dialog_; + delete capture_filter_dlg_; + delete display_filter_dlg_; +#ifdef HAVE_LIBPCAP + delete capture_options_dialog_; +#endif + +#endif + delete main_ui_; +} + +QMenu *LogwolfMainWindow::createPopupMenu() +{ + QMenu *menu = new QMenu(); + menu->addAction(main_ui_->actionViewMainToolbar); + menu->addAction(main_ui_->actionViewFilterToolbar); +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + menu->addAction(main_ui_->actionViewWirelessToolbar); +#endif + + if (!main_ui_->menuInterfaceToolbars->actions().isEmpty()) { + QMenu *submenu = menu->addMenu(main_ui_->menuInterfaceToolbars->title()); + foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + submenu->addAction(action); + } + } + + if (!main_ui_->menuAdditionalToolbars->actions().isEmpty()) { + QMenu *subMenu = menu->addMenu(main_ui_->menuAdditionalToolbars->title()); + foreach(QAction *action, main_ui_->menuAdditionalToolbars->actions()) { + subMenu->addAction(action); + } + } + + menu->addAction(main_ui_->actionViewStatusBar); + + menu->addSeparator(); + menu->addAction(main_ui_->actionViewPacketList); + menu->addAction(main_ui_->actionViewPacketDetails); + menu->addAction(main_ui_->actionViewPacketBytes); + menu->addAction(main_ui_->actionViewPacketDiagram); + return menu; +} + +void LogwolfMainWindow::addInterfaceToolbar(const iface_toolbar *toolbar_entry) +{ + QMenu *menu = main_ui_->menuInterfaceToolbars; + bool visible = g_list_find_custom(recent.interface_toolbars, toolbar_entry->menu_title, (GCompareFunc)strcmp) ? true : false; + + QString title = QString().fromUtf8(toolbar_entry->menu_title); + QAction *action = new QAction(title, menu); + action->setEnabled(true); + action->setCheckable(true); + action->setChecked(visible); + action->setToolTip(tr("Show or hide the toolbar")); + + QAction *before = NULL; + foreach(QAction *action, menu->actions()) { + // Ensure we add the menu entries in sorted order + if (action->text().compare(title, Qt::CaseInsensitive) > 0) { + before = action; + break; + } + } + menu->insertAction(before, action); + + InterfaceToolbar *interface_toolbar = new InterfaceToolbar(this, toolbar_entry); + connect(mainApp, SIGNAL(appInitialized()), interface_toolbar, SLOT(interfaceListChanged())); + connect(mainApp, SIGNAL(localInterfaceListChanged()), interface_toolbar, SLOT(interfaceListChanged())); + + QToolBar *toolbar = new QToolBar(this); + toolbar->addWidget(interface_toolbar); + toolbar->setMovable(false); + toolbar->setVisible(visible); + + action->setData(QVariant::fromValue(toolbar)); + + addToolBar(Qt::TopToolBarArea, toolbar); + insertToolBarBreak(toolbar); + + if (show_hide_actions_) { + show_hide_actions_->addAction(action); + } + + menu->menuAction()->setVisible(true); +} + +void LogwolfMainWindow::removeInterfaceToolbar(const gchar *menu_title) +{ + QMenu *menu = main_ui_->menuInterfaceToolbars; + QAction *action = NULL; + QMap::iterator i; + + QString title = QString().fromUtf8(menu_title); + foreach(action, menu->actions()) { + if (title.compare(action->text()) == 0) { + break; + } + } + + if (action) { + if (show_hide_actions_) { + show_hide_actions_->removeAction(action); + } + menu->removeAction(action); + + QToolBar *toolbar = action->data().value(); + removeToolBar(toolbar); + + delete action; + delete toolbar; + } + + menu->menuAction()->setVisible(!menu->actions().isEmpty()); +} + +void LogwolfMainWindow::setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb) +{ + pipe_source_ = source; + pipe_child_process_ = child_process; + pipe_user_data_ = user_data; + pipe_input_cb_ = input_cb; + +#ifdef _WIN32 + /* Tricky to use pipes in win9x, as no concept of wait. NT can + do this but that doesn't cover all win32 platforms. GTK can do + this but doesn't seem to work over processes. Attempt to do + something similar here, start a timer and check for data on every + timeout. */ + /*ws_log(NULL, LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/ + + if (pipe_timer_) { + disconnect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout())); + delete pipe_timer_; + } + + pipe_timer_ = new QTimer(this); + connect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout())); + connect(pipe_timer_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed())); + pipe_timer_->start(200); +#else + if (pipe_notifier_) { + disconnect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int))); + delete pipe_notifier_; + } + + pipe_notifier_ = new QSocketNotifier(pipe_source_, QSocketNotifier::Read); + // XXX ui/gtk/gui_utils.c sets the encoding. Do we need to do the same? + connect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int))); + connect(pipe_notifier_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed())); +#endif +} + +bool LogwolfMainWindow::eventFilter(QObject *obj, QEvent *event) { + + // The user typed some text. Start filling in a filter. + // We may need to be more choosy here. We just need to catch events for the packet list, + // proto tree, and main welcome widgets. + if (event->type() == QEvent::KeyPress) { + QKeyEvent *kevt = static_cast(event); + if (kevt->text().length() > 0 && kevt->text()[0].isPrint() && + !(kevt->modifiers() & Qt::ControlModifier)) { + df_combo_box_->lineEdit()->insert(kevt->text()); + df_combo_box_->lineEdit()->setFocus(); + return true; + } + } + + return QMainWindow::eventFilter(obj, event); +} + +bool LogwolfMainWindow::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::ApplicationPaletteChange: + initMainToolbarIcons(); + break; + default: + break; + + } + return QMainWindow::event(event); +} + +void LogwolfMainWindow::keyPressEvent(QKeyEvent *event) { + + // Explicitly focus on the display filter combo. + if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) { + df_combo_box_->setFocus(Qt::ShortcutFocusReason); + return; + } + + if (mainApp->focusWidget() == main_ui_->goToLineEdit) { + if (event->modifiers() == Qt::NoModifier) { + if (event->key() == Qt::Key_Escape) { + on_goToCancel_clicked(); + } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { + on_goToGo_clicked(); + } + } + return; // goToLineEdit didn't want it and we don't either. + } + + // Move up & down the packet list. + if (event->key() == Qt::Key_F7) { + packet_list_->goPreviousPacket(); + } else if (event->key() == Qt::Key_F8) { + packet_list_->goNextPacket(); + } + + // Move along, citizen. + QMainWindow::keyPressEvent(event); +} + +void LogwolfMainWindow::closeEvent(QCloseEvent *event) { + saveWindowGeometry(); + + /* If we're in the middle of stopping a capture, don't do anything; + the user can try deleting the window after the capture stops. */ + if (capture_stopping_) { + event->ignore(); + return; + } + + QString before_what(tr(" before quitting")); + if (!testCaptureFileClose(before_what, Quit)) { + event->ignore(); + return; + } + +#ifdef HAVE_LIBPCAP + if (capture_options_dialog_) capture_options_dialog_->close(); +#endif + // Make sure we kill any open dumpcap processes. + delete welcome_page_; + + // One of the many places we assume one main window. + if (!mainApp->isInitialized()) { + // If we're still initializing, QCoreApplication::quit() won't + // exit properly because we are not in the event loop. This + // means that the application won't clean up after itself. We + // might want to call mainApp->processEvents() during startup + // instead so that we can do a normal exit here. + exit(0); + } + mainApp->quit(); + // When the main loop is not yet running (i.e. when openCaptureFile is + // executing in main.cpp), the above quit action has no effect. + // Schedule a quit action for the next execution of the main loop. + QMetaObject::invokeMethod(mainApp, "quit", Qt::QueuedConnection); +} + +// XXX On windows the drag description is "Copy". It should be "Open" or +// "Merge" as appropriate. It looks like we need access to IDataObject in +// order to set DROPDESCRIPTION. +void LogwolfMainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + if (!event->mimeData()->hasUrls()) + { + event->ignore(); + return; + } + + if (!main_ui_->actionFileOpen->isEnabled()) { + // We could alternatively call setAcceptDrops(!capture_in_progress) + // in setMenusForCaptureInProgress but that wouldn't provide feedback. + + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to drop files during capture.")); + event->setDropAction(Qt::IgnoreAction); + event->ignore(); + return; + } + + bool have_files = false; + foreach(QUrl drag_url, event->mimeData()->urls()) { + if (!drag_url.toLocalFile().isEmpty()) { + have_files = true; + break; + } + } + + if (have_files) { + event->acceptProposedAction(); + } +} + +void LogwolfMainWindow::dropEvent(QDropEvent *event) +{ + if (!event->mimeData()->hasUrls()) + { + event->ignore(); + return; + } + + QList local_files; + int max_dropped_files = 100; // Arbitrary + + foreach(QUrl drop_url, event->mimeData()->urls()) { + QString drop_file = drop_url.toLocalFile(); + if (!drop_file.isEmpty()) { + local_files << drop_file.toUtf8(); + if (local_files.size() >= max_dropped_files) { + break; + } + } + } + + event->acceptProposedAction(); + + if (local_files.size() < 1) { + event->ignore(); + return; + } + + event->accept(); + + if (local_files.size() == 1) { + openCaptureFile(local_files.at(0)); + return; + } + + const char **in_filenames = g_new(const char *, local_files.size()); + char *tmpname = NULL; + + for (int i = 0; i < local_files.size(); i++) { + in_filenames[i] = local_files.at(i).constData(); + } + + /* merge the files in chronological order */ + if (cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, static_cast(local_files.size()), + in_filenames, + wtap_pcapng_file_type_subtype(), + FALSE) == CF_OK) { + /* Merge succeeded; close the currently-open file and try + to open the merged capture file. */ + openCaptureFile(tmpname, QString(), WTAP_TYPE_AUTO, TRUE); + } + + g_free(tmpname); + g_free(in_filenames); +} + +// Apply recent settings to the main window geometry. +// We haven't loaded the preferences at this point so we assume that the +// position and size preference are enabled. +// Note we might end up with unexpected screen geometries if the user +// unplugs or plugs in a monitor: +// https://bugreports.qt.io/browse/QTBUG-44213 +void LogwolfMainWindow::loadWindowGeometry() +{ + int min_sensible_dimension = 200; + +#ifndef Q_OS_MAC + if (recent.gui_geometry_main_maximized) { + setWindowState(Qt::WindowMaximized); + } else +#endif + { + QRect recent_geom(recent.gui_geometry_main_x, recent.gui_geometry_main_y, + recent.gui_geometry_main_width, recent.gui_geometry_main_height); + if (!rect_on_screen(recent_geom)) { + // We're not visible on any screens. See if we can move onscreen + // without resizing. + recent_geom.moveTo(50, 50); // recent.c defaults to 20. + } + + if (!rect_on_screen(recent_geom)) { + // Give up and use the default geometry. + return; + } + +// if (prefs.gui_geometry_save_position) { + move(recent_geom.topLeft()); +// } + + if (// prefs.gui_geometry_save_size && + recent_geom.width() > min_sensible_dimension && + recent_geom.height() > min_sensible_dimension) { + resize(recent_geom.size()); + } + } +} + +void LogwolfMainWindow::saveWindowGeometry() +{ + if (prefs.gui_geometry_save_position) { + recent.gui_geometry_main_x = pos().x(); + recent.gui_geometry_main_y = pos().y(); + } + + if (prefs.gui_geometry_save_size) { + recent.gui_geometry_main_width = size().width(); + recent.gui_geometry_main_height = size().height(); + } + + if (prefs.gui_geometry_save_maximized) { + // On macOS this is false when it shouldn't be + recent.gui_geometry_main_maximized = isMaximized(); + } + + if (master_split_.sizes().length() > 0) { + recent.gui_geometry_main_upper_pane = master_split_.sizes()[0]; + } + + if (master_split_.sizes().length() > 2) { + recent.gui_geometry_main_lower_pane = master_split_.sizes()[1]; + } else if (extra_split_.sizes().length() > 0) { + recent.gui_geometry_main_lower_pane = extra_split_.sizes()[0]; + } +} + +// Our event loop becomes nested whenever we call update_progress_dlg, which +// includes several places in file.c. The GTK+ UI stays out of trouble by +// showing a modal progress dialog. We attempt to do the equivalent below by +// disabling parts of the main window. At a minumum the ProgressFrame in the +// main status bar must remain accessible. +// +// We might want to do this any time the main status bar progress frame is +// shown and hidden. +void LogwolfMainWindow::freeze() +{ + freeze_focus_ = mainApp->focusWidget(); + + // XXX Alternatively we could just disable and enable the main menu. + for (int i = 0; i < freeze_actions_.size(); i++) { + QAction *action = freeze_actions_[i].first; + freeze_actions_[i].second = action->isEnabled(); + action->setEnabled(false); + } + main_ui_->centralWidget->setEnabled(false); +} + +void LogwolfMainWindow::thaw() +{ + main_ui_->centralWidget->setEnabled(true); + for (int i = 0; i < freeze_actions_.size(); i++) { + freeze_actions_[i].first->setEnabled(freeze_actions_[i].second); + } + + if (freeze_focus_) freeze_focus_->setFocus(); + freeze_focus_ = NULL; +} + +void LogwolfMainWindow::mergeCaptureFile() +{ + QString file_name = ""; + QString read_filter = ""; + dfilter_t *rfcode = NULL; + int err; + + if (!capture_file_.capFile()) + return; + + if (prefs.gui_ask_unsaved) { + if (cf_has_unsaved_data(capture_file_.capFile())) { + QMessageBox msg_dialog; + gchar *display_basename; + int response; + + msg_dialog.setIcon(QMessageBox::Question); + /* This file has unsaved data; ask the user whether to save + the capture. */ + if (capture_file_.capFile()->is_tempfile) { + msg_dialog.setText(tr("Save packets before merging?")); + msg_dialog.setInformativeText(tr("A temporary capture file can't be merged.")); + } else { + /* + * Format the message. + */ + display_basename = g_filename_display_basename(capture_file_.capFile()->filename); + msg_dialog.setText(QString(tr("Save changes in \"%1\" before merging?")).arg(display_basename)); + g_free(display_basename); + msg_dialog.setInformativeText(tr("Changes must be saved before the files can be merged.")); + } + + msg_dialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); + msg_dialog.setDefaultButton(QMessageBox::Save); + + response = msg_dialog.exec(); + + switch (response) { + + case QMessageBox::Save: + /* Save the file but don't close it */ + saveCaptureFile(capture_file_.capFile(), false); + break; + + case QMessageBox::Cancel: + default: + /* Don't do the merge. */ + return; + } + } + } + + for (;;) { + CaptureFileDialog merge_dlg(this, capture_file_.capFile(), read_filter); + int file_type; + cf_status_t merge_status; + char *in_filenames[2]; + char *tmpname; + + if (merge_dlg.merge(file_name)) { + gchar *err_msg; + + if (!dfilter_compile(qUtf8Printable(read_filter), &rfcode, &err_msg)) { + /* Not valid. Tell the user, and go back and run the file + selection box again once they dismiss the alert. */ + // Similar to commandline_info.jfilter section in main(). + QMessageBox::warning(this, tr("Invalid Read Filter"), + QString(tr("The filter expression %1 isn't a valid read filter. (%2).").arg(read_filter, err_msg)), + QMessageBox::Ok); + g_free(err_msg); + continue; + } + } else { + return; + } + + file_type = capture_file_.capFile()->cd_t; + + /* Try to merge or append the two files */ + if (merge_dlg.mergeType() == 0) { + /* chronological order */ + in_filenames[0] = g_strdup(capture_file_.capFile()->filename); + in_filenames[1] = qstring_strdup(file_name); + merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, FALSE); + } else if (merge_dlg.mergeType() <= 0) { + /* prepend file */ + in_filenames[0] = qstring_strdup(file_name); + in_filenames[1] = g_strdup(capture_file_.capFile()->filename); + merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, TRUE); + } else { + /* append file */ + in_filenames[0] = g_strdup(capture_file_.capFile()->filename); + in_filenames[1] = qstring_strdup(file_name); + merge_status = cf_merge_files_to_tempfile(this, global_capture_opts.temp_dir, &tmpname, 2, in_filenames, file_type, TRUE); + } + + g_free(in_filenames[0]); + g_free(in_filenames[1]); + + if (merge_status != CF_OK) { + dfilter_free(rfcode); + g_free(tmpname); + continue; + } + + cf_close(capture_file_.capFile()); + + /* Try to open the merged capture file. */ + CaptureFile::globalCapFile()->window = this; + if (cf_open(CaptureFile::globalCapFile(), tmpname, WTAP_TYPE_AUTO, TRUE /* temporary file */, &err) != CF_OK) { + /* We couldn't open it; fail. */ + CaptureFile::globalCapFile()->window = NULL; + dfilter_free(rfcode); + g_free(tmpname); + return; + } + + /* Attach the new read filter to "cf" ("cf_open()" succeeded, so + it closed the previous capture file, and thus destroyed any + previous read filter attached to "cf"). */ + cf_set_rfcode(CaptureFile::globalCapFile(), rfcode); + + switch (cf_read(CaptureFile::globalCapFile(), FALSE)) { + + case CF_READ_OK: + case CF_READ_ERROR: + /* Just because we got an error, that doesn't mean we were unable + to read any of the file; we handle what we could get from the + file. */ + break; + + case CF_READ_ABORTED: + /* The user bailed out of re-reading the capture file; the + capture file has been closed - just free the capture file name + string and return (without changing the last containing + directory). */ + g_free(tmpname); + return; + } + + /* Save the name of the containing directory specified in the path name. */ + mainApp->setLastOpenDirFromFilename(tmpname); + g_free(tmpname); + main_ui_->statusBar->showExpert(); + return; + } + +} + +void LogwolfMainWindow::importCaptureFile() { + ImportTextDialog import_dlg; + + QString before_what(tr(" before importing a capture")); + if (!testCaptureFileClose(before_what)) + return; + + import_dlg.exec(); + + if (import_dlg.result() != QDialog::Accepted) { + showWelcome(); + return; + } + + openCaptureFile(import_dlg.capfileName()); +} + +bool LogwolfMainWindow::saveCaptureFile(capture_file *cf, bool dont_reopen) { + QString file_name; + gboolean discard_comments; + + if (cf->is_tempfile) { + /* This is a temporary capture file, so saving it means saving + it to a permanent file. Prompt the user for a location + to which to save it. Don't require that the file format + support comments - if it's a temporary capture file, it's + probably pcapng, which supports comments and, if it's + not pcapng, let the user decide what they want to do + if they've added comments. */ + return saveAsCaptureFile(cf, FALSE, dont_reopen); + } else { + if (cf->unsaved_changes) { + cf_write_status_t status; + + /* This is not a temporary capture file, but it has unsaved + changes, so saving it means doing a "safe save" on top + of the existing file, in the same format - no UI needed + unless the file has comments and the file's format doesn't + support them. + + If the file has comments, does the file's format support them? + If not, ask the user whether they want to discard the comments + or choose a different format. */ + switch (CaptureFileDialog::checkSaveAsWithComments(this, cf, cf->cd_t)) { + + case SAVE: + /* The file can be saved in the specified format as is; + just drive on and save in the format they selected. */ + discard_comments = FALSE; + break; + + case SAVE_WITHOUT_COMMENTS: + /* The file can't be saved in the specified format as is, + but it can be saved without the comments, and the user + said "OK, discard the comments", so save it in the + format they specified without the comments. */ + discard_comments = TRUE; + break; + + case SAVE_IN_ANOTHER_FORMAT: + /* There are file formats in which we can save this that + support comments, and the user said not to delete the + comments. Do a "Save As" so the user can select + one of those formats and choose a file name. */ + return saveAsCaptureFile(cf, TRUE, dont_reopen); + + case CANCELLED: + /* The user said "forget it". Just return. */ + return false; + + default: + /* Squelch warnings that discard_comments is being used + uninitialized. */ + ws_assert_not_reached(); + return false; + } + + /* XXX - cf->filename might get freed out from under us, because + the code path through which cf_save_records() goes currently + closes the current file and then opens and reloads the saved file, + so make a copy and free it later. */ + file_name = cf->filename; + status = cf_save_records(cf, qUtf8Printable(file_name), cf->cd_t, cf->compression_type, + discard_comments, dont_reopen); + switch (status) { + + case CF_WRITE_OK: + /* The save succeeded; we're done. + If we discarded comments, redraw the packet list to reflect + any packets that no longer have comments. */ + if (discard_comments) + packet_list_queue_draw(); + + cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes + updateForUnsavedChanges(); // we update the title bar to remove the * + break; + + case CF_WRITE_ERROR: + /* The write failed. + XXX - OK, what do we do now? Let them try a + "Save As", in case they want to try to save to a + different directory or file system? */ + break; + + case CF_WRITE_ABORTED: + /* The write was aborted; just drive on. */ + return false; + } + } + /* Otherwise just do nothing. */ + } + + return true; +} + +bool LogwolfMainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool dont_reopen) { + QString file_name = ""; + int file_type; + wtap_compression_type compression_type; + cf_write_status_t status; + gchar *dirname; + gboolean discard_comments = FALSE; + + if (!cf) { + return false; + } + + for (;;) { + CaptureFileDialog save_as_dlg(this, cf); + + /* If the file has comments, does the format the user selected + support them? If not, ask the user whether they want to + discard the comments or choose a different format. */ + switch (save_as_dlg.saveAs(file_name, must_support_comments)) { + + case SAVE: + /* The file can be saved in the specified format as is; + just drive on and save in the format they selected. */ + discard_comments = FALSE; + break; + + case SAVE_WITHOUT_COMMENTS: + /* The file can't be saved in the specified format as is, + but it can be saved without the comments, and the user + said "OK, discard the comments", so save it in the + format they specified without the comments. */ + discard_comments = TRUE; + break; + + case SAVE_IN_ANOTHER_FORMAT: + /* There are file formats in which we can save this that + support comments, and the user said not to delete the + comments. The combo box of file formats has had the + formats that don't support comments trimmed from it, + so run the dialog again, to let the user decide + whether to save in one of those formats or give up. */ + must_support_comments = TRUE; + continue; + + case CANCELLED: + /* The user said "forget it". Just get rid of the dialog box + and return. */ + return false; + } + file_type = save_as_dlg.selectedFileType(); + if (file_type == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) { + /* This "should not happen". */ + QMessageBox msg_dialog; + + msg_dialog.setIcon(QMessageBox::Critical); + msg_dialog.setText(tr("Unknown file type returned by merge dialog.")); + msg_dialog.setInformativeText(tr("Please report this as a Wireshark issue at https://gitlab.com/wireshark/wireshark/-/issues.")); + msg_dialog.exec(); + return false; + } + compression_type = save_as_dlg.compressionType(); + +#ifdef Q_OS_WIN + // the Windows dialog does not fixup extensions, do it manually here. + fileAddExtension(file_name, file_type, compression_type); +#endif // Q_OS_WIN + +//#ifndef _WIN32 +// /* If the file exists and it's user-immutable or not writable, +// ask the user whether they want to override that. */ +// if (!file_target_unwritable_ui(top_level, qUtf8Printable(file_name))) { +// /* They don't. Let them try another file name or cancel. */ +// continue; +// } +//#endif + + /* Attempt to save the file */ + status = cf_save_records(cf, qUtf8Printable(file_name), file_type, compression_type, + discard_comments, dont_reopen); + switch (status) { + + case CF_WRITE_OK: + /* The save succeeded; we're done. */ + /* Save the directory name for future file dialogs. */ + dirname = qstring_strdup(file_name); /* Overwrites cf_name */ + set_last_open_dir(get_dirname(dirname)); + g_free(dirname); + /* If we discarded comments, redraw the packet list to reflect + any packets that no longer have comments. */ + if (discard_comments) + packet_list_queue_draw(); + + cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes + updateForUnsavedChanges(); // we update the title bar to remove the * + /* Add this filename to the list of recent files in the "Recent Files" submenu */ + add_menu_recent_capture_file(qUtf8Printable(file_name)); + return true; + + case CF_WRITE_ERROR: + /* The save failed; let the user try again. */ + continue; + + case CF_WRITE_ABORTED: + /* The user aborted the save; just return. */ + return false; + } + } + return true; +} + +void LogwolfMainWindow::exportSelectedPackets() { + QString file_name = ""; + int file_type; + wtap_compression_type compression_type; + packet_range_t range; + cf_write_status_t status; + gchar *dirname; + bool discard_comments = false; + + if (!capture_file_.capFile()) + return; + + /* Init the packet range */ + packet_range_init(&range, capture_file_.capFile()); + range.process_filtered = TRUE; + range.include_dependents = TRUE; + + QList rows = packet_list_->selectedRows(true); + + QStringList entries; + foreach (int row, rows) + entries << QString::number(row); + QString selRange = entries.join(","); + + for (;;) { + CaptureFileDialog esp_dlg(this, capture_file_.capFile()); + + /* If the file has comments, does the format the user selected + support them? If not, ask the user whether they want to + discard the comments or choose a different format. */ + switch (esp_dlg.exportSelectedPackets(file_name, &range, selRange)) { + + case SAVE: + /* The file can be saved in the specified format as is; + just drive on and save in the format they selected. */ + discard_comments = FALSE; + break; + + case SAVE_WITHOUT_COMMENTS: + /* The file can't be saved in the specified format as is, + but it can be saved without the comments, and the user + said "OK, discard the comments", so save it in the + format they specified without the comments. */ + discard_comments = TRUE; + break; + + case SAVE_IN_ANOTHER_FORMAT: + /* There are file formats in which we can save this that + support comments, and the user said not to delete the + comments. The combo box of file formats has had the + formats that don't support comments trimmed from it, + so run the dialog again, to let the user decide + whether to save in one of those formats or give up. */ + continue; + + case CANCELLED: + /* The user said "forget it". Just get rid of the dialog box + and return. */ + goto cleanup; + } + + /* + * Check that we're not going to save on top of the current + * capture file. + * We do it here so we catch all cases ... + * Unfortunately, the file requester gives us an absolute file + * name and the read file name may be relative (if supplied on + * the command line). From Joerg Mayer. + */ + if (files_identical(capture_file_.capFile()->filename, qUtf8Printable(file_name))) { + QMessageBox msg_box; + gchar *display_basename = g_filename_display_basename(qUtf8Printable(file_name)); + + msg_box.setIcon(QMessageBox::Critical); + msg_box.setText(QString(tr("Unable to export to \"%1\".").arg(display_basename))); + msg_box.setInformativeText(tr("You cannot export packets to the current capture file.")); + msg_box.setStandardButtons(QMessageBox::Ok); + msg_box.setDefaultButton(QMessageBox::Ok); + msg_box.exec(); + g_free(display_basename); + continue; + } + + file_type = esp_dlg.selectedFileType(); + if (file_type == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) { + /* This "should not happen". */ + QMessageBox msg_box; + + msg_box.setIcon(QMessageBox::Critical); + msg_box.setText(tr("Unknown file type returned by export dialog.")); + msg_box.setInformativeText(tr("Please report this as a Wireshark issue at https://gitlab.com/wireshark/wireshark/-/issues.")); + msg_box.exec(); + goto cleanup; + } + compression_type = esp_dlg.compressionType(); +#ifdef Q_OS_WIN + // the Windows dialog does not fixup extensions, do it manually here. + fileAddExtension(file_name, file_type, compression_type); +#endif // Q_OS_WIN + +//#ifndef _WIN32 +// /* If the file exists and it's user-immutable or not writable, +// ask the user whether they want to override that. */ +// if (!file_target_unwritable_ui(top_level, qUtf8Printable(file_name))) { +// /* They don't. Let them try another file name or cancel. */ +// continue; +// } +//#endif + + /* Attempt to save the file */ + status = cf_export_specified_packets(capture_file_.capFile(), qUtf8Printable(file_name), &range, file_type, compression_type); + switch (status) { + + case CF_WRITE_OK: + /* The save succeeded; we're done. */ + /* Save the directory name for future file dialogs. */ + dirname = qstring_strdup(file_name); /* Overwrites cf_name */ + set_last_open_dir(get_dirname(dirname)); + g_free(dirname); + /* If we discarded comments, redraw the packet list to reflect + any packets that no longer have comments. */ + if (discard_comments) + packet_list_queue_draw(); + /* Add this filename to the list of recent files in the "Recent Files" submenu */ + add_menu_recent_capture_file(qUtf8Printable(file_name)); + goto cleanup; + + case CF_WRITE_ERROR: + /* The save failed; let the user try again. */ + continue; + + case CF_WRITE_ABORTED: + /* The user aborted the save; just return. */ + goto cleanup; + } + } + +cleanup: + packet_range_cleanup(&range); +} + +void LogwolfMainWindow::exportDissections(export_type_e export_type) { + capture_file *cf = capture_file_.capFile(); + g_return_if_fail(cf); + + QList rows = packet_list_->selectedRows(true); + + QStringList entries; + foreach (int row, rows) + entries << QString::number(row); + QString selRange = entries.join(","); + + ExportDissectionDialog *ed_dlg = new ExportDissectionDialog(this, cf, export_type, selRange); + ed_dlg->setWindowModality(Qt::ApplicationModal); + ed_dlg->setAttribute(Qt::WA_DeleteOnClose); + ed_dlg->show(); +} + +#ifdef Q_OS_WIN +/* + * Ensure that: + * + * If the file is to be compressed: + * + * if there is a set of extensions used by the file type to be used, + * the file name has one of those extensions followed by the extension + * for the compression type to be used; + * + * otherwise, the file name has the extension for the compression type + * to be used; + * + * otherwise: + * + * if there is a set of extensions used by the file type to be used, + * the file name has one of those extensions. + */ +void LogwolfMainWindow::fileAddExtension(QString &file_name, int file_type, wtap_compression_type compression_type) { + QString file_name_lower; + GSList *extensions_list; + const char *compressed_file_extension; + gboolean add_extension_for_file_type; + + /* Lower-case the file name, so the extension matching is case-insensitive. */ + file_name_lower = file_name.toLower(); + + /* Get a list of all extensions used for this file type; don't + include the ones with compression type extensions, as we + only want to check for the extension for the compression + type we'll be using. */ + extensions_list = wtap_get_file_extensions_list(file_type, FALSE); + + /* Get the extension for the compression type we'll be using; + NULL is returned if the type isn't supported or compression + is not being done. */ + compressed_file_extension = wtap_compression_type_extension(compression_type); + + if (extensions_list != NULL) { + GSList *extension; + + /* This file type has one or more extensions. + Start out assuming we need to add the default one. */ + add_extension_for_file_type = TRUE; + + /* OK, see if the file has one of those extensions, followed + by the appropriate compression type extension if it's to be + compressed. */ + for (extension = extensions_list; extension != NULL; + extension = g_slist_next(extension)) { + QString file_suffix = QString(".") + (char *)extension->data; + if (compressed_file_extension != NULL) + file_suffix += QString(".") + compressed_file_extension; + if (file_name_lower.endsWith(file_suffix)) { + /* + * The file name has one of the extensions for this file + * type, followed by a compression type extension if + * appropriate, so we don't need to add an extension for + * the file type or the compression type. + */ + add_extension_for_file_type = FALSE; + break; + } + } + } else { + /* We have no extensions for this file type. Just check + to see if we need to add an extension for the compressed + file type. + + Start out assuming we do. */ + add_extension_for_file_type = TRUE; + if (compressed_file_extension != NULL) { + QString file_suffix = QString(".") + compressed_file_extension; + if (file_name_lower.endsWith(file_suffix)) { + /* + * The file name has the appropriate compressed file extension, + * so we don't need to add an extension for the compression + * type. + */ + add_extension_for_file_type = FALSE; + } + } + } + + /* + * If we need to add an extension for the file type or compressed + * file type, do so. + */ + if (add_extension_for_file_type) { + if (wtap_default_file_extension(file_type) != NULL) { + /* This file type has a default extension; append it. */ + file_name += QString(".") + wtap_default_file_extension(file_type); + } + if (compression_type != WTAP_UNCOMPRESSED) { + /* + * The file is to be compressed, so append the extension for + * its compression type. + */ + file_name += QString(".") + compressed_file_extension; + } + } +} +#endif // Q_OS_WIN + +bool LogwolfMainWindow::testCaptureFileClose(QString before_what, FileCloseContext context) { + bool capture_in_progress = false; + bool do_close_file = false; + + if (!capture_file_.capFile() || capture_file_.capFile()->state == FILE_CLOSED) + return true; /* Already closed, nothing to do */ + + if (capture_file_.capFile()->read_lock) { + /* + * If the file is being redissected, we cannot stop the capture since + * that would crash and burn "cf_read", so stop early. Ideally all + * callers should be modified to check this condition and act + * accordingly (ignore action or queue it up), so print a warning. + */ + ws_warning("Refusing to close \"%s\" which is being read.", capture_file_.capFile()->filename); + return false; + } + +#ifdef HAVE_LIBPCAP + if (capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + /* + * This (FILE_READ_IN_PROGRESS) is true if we're reading a capture file + * *or* if we're doing a live capture. From the capture file itself we + * cannot differentiate the cases, so check the current capture session. + */ + capture_in_progress = captureSession()->state != CAPTURE_STOPPED; + } +#endif + + if (prefs.gui_ask_unsaved) { + if (cf_has_unsaved_data(capture_file_.capFile())) { + QMessageBox msg_dialog; + QString question; + QString infotext; + QPushButton *save_button; + QPushButton *discard_button; + + msg_dialog.setIcon(QMessageBox::Question); + msg_dialog.setWindowTitle("Unsaved packets" UTF8_HORIZONTAL_ELLIPSIS); + + /* This file has unsaved data or there's a capture in + progress; ask the user whether to save the data. */ + if (capture_in_progress && context != Restart) { + question = tr("Do you want to stop the capture and save the captured packets%1?").arg(before_what); + infotext = tr("Your captured packets will be lost if you don't save them."); + } else if (capture_file_.capFile()->is_tempfile) { + if (context == Reload) { + // Reloading a tempfile will keep the packets, so this is not unsaved packets + question = tr("Do you want to save the changes you've made%1?").arg(before_what); + infotext = tr("Your changes will be lost if you don't save them."); + } else { + question = tr("Do you want to save the captured packets%1?").arg(before_what); + infotext = tr("Your captured packets will be lost if you don't save them."); + } + } else { + // No capture in progress and not a tempfile, so this is not unsaved packets + gchar *display_basename = g_filename_display_basename(capture_file_.capFile()->filename); + question = tr("Do you want to save the changes you've made to the capture file \"%1\"%2?").arg(display_basename, before_what); + infotext = tr("Your changes will be lost if you don't save them."); + g_free(display_basename); + } + + msg_dialog.setText(question); + msg_dialog.setInformativeText(infotext); + + // XXX Text comes from ui/gtk/stock_icons.[ch] + // Note that the button roles differ from the GTK+ version. + // Cancel = RejectRole + // Save = AcceptRole + // Don't Save = DestructiveRole + msg_dialog.addButton(QMessageBox::Cancel); + + if (capture_in_progress) { + QString save_button_text; + if (context == Restart) { + save_button_text = tr("Save before Continue"); + } else { + save_button_text = tr("Stop and Save"); + } + save_button = msg_dialog.addButton(save_button_text, QMessageBox::AcceptRole); + } else { + save_button = msg_dialog.addButton(QMessageBox::Save); + } + msg_dialog.setDefaultButton(save_button); + + QString discard_button_text; + if (capture_in_progress) { + switch (context) { + case Quit: + discard_button_text = tr("Stop and Quit &without Saving"); + break; + case Restart: + discard_button_text = tr("Continue &without Saving"); + break; + default: + discard_button_text = tr("Stop and Continue &without Saving"); + break; + } + } else { + switch (context) { + case Quit: + discard_button_text = tr("Quit &without Saving"); + break; + case Restart: + default: + discard_button_text = tr("Continue &without Saving"); + break; + } + } + discard_button = msg_dialog.addButton(discard_button_text, QMessageBox::DestructiveRole); + +#if defined(Q_OS_MAC) + /* + * In macOS, the "default button" is not necessarily the + * button that has the input focus; Enter/Return activates + * the default button, and the spacebar activates the button + * that has the input focus, and they might be different + * buttons. + * + * In a "do you want to save" dialog, for example, the + * "save" button is the default button, and the "don't + * save" button has the input focus, so you can press + * Enter/Return to save or space not to save (or Escape + * to dismiss the dialog). + * + * In Qt terms, this means "no auto-default", as auto-default + * makes the button with the input focus the default button, + * so that Enter/Return will activate it. + */ + QList buttons = msg_dialog.buttons(); + for (int i = 0; i < buttons.size(); ++i) { + QPushButton *button = static_cast(buttons.at(i));; + button->setAutoDefault(false); + } + + /* + * It also means that the "don't save" button should be the one + * initially given the focus. + */ + discard_button->setFocus(); +#endif + + msg_dialog.exec(); + /* According to the Qt doc: + * when using QMessageBox with custom buttons, exec() function returns an opaque value. + * + * Therefore we should use clickedButton() to determine which button was clicked. */ + + if (msg_dialog.clickedButton() == save_button) { +#ifdef HAVE_LIBPCAP + /* If there's a capture in progress, we have to stop the capture + and then do the save. */ + if (capture_in_progress) + captureStop(); +#endif + /* Save the file and close it */ + // XXX if no packets were captured, any unsaved comments set by + // the user are silently discarded because capFile() is null. + if (capture_file_.capFile() && saveCaptureFile(capture_file_.capFile(), true) == false) + return false; + do_close_file = true; + } else if (msg_dialog.clickedButton() == discard_button) { + /* Just close the file, discarding changes */ + do_close_file = true; + } else { + // cancelButton or some other unspecified button + return false; + } + } else { + /* Unchanged file or capturing with no packets */ + do_close_file = true; + } + } else { + /* User asked not to be bothered by those prompts, just close it. + XXX - should that apply only to saving temporary files? */ + do_close_file = true; + } + + /* + * Are we done with this file and should we close the file? + */ + if (do_close_file) { +#ifdef HAVE_LIBPCAP + /* If there's a capture in progress, we have to stop the capture + and then do the close. */ + if (capture_in_progress) + captureStop(); + else if (capture_file_.capFile() && capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + /* + * When an offline capture is being read, mark it as aborted. + * cf_read will be responsible for actually closing the capture. + * + * We cannot just invoke cf_close here since cf_read is up in the + * call chain. (update_progress_dlg can end up processing the Quit + * event from the user which then ends up here.) + * See also the above "read_lock" check. + */ + capture_file_.capFile()->state = FILE_READ_ABORTED; + return true; + } +#endif + /* Clear MainWindow file name details */ + gbl_cur_main_window_->setMwFileName(""); + + /* captureStop() will close the file if not having any packets */ + if (capture_file_.capFile() && context != Restart && context != Reload) + // Don't really close if Restart or Reload + cf_close(capture_file_.capFile()); + } + + return true; /* File closed */ +} + +void LogwolfMainWindow::captureStop() { + stopCapture(); + + while (capture_file_.capFile() && capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + WiresharkApplication::processEvents(); + } +} + +void LogwolfMainWindow::findTextCodecs() { + const QList mibs = QTextCodec::availableMibs(); + QRegularExpression ibmRegExp("^IBM([0-9]+).*$"); + QRegularExpression iso8859RegExp("^ISO-8859-([0-9]+).*$"); + QRegularExpression windowsRegExp("^WINDOWS-([0-9]+).*$"); + QRegularExpressionMatch match; + for (int mib : mibs) { + QTextCodec *codec = QTextCodec::codecForMib(mib); + QString key = codec->name().toUpper(); + char rank; + + if (key.localeAwareCompare("IBM") < 0) { + rank = 1; + } else if ((match = ibmRegExp.match(key)).hasMatch()) { + rank = match.captured(1).size(); // Up to 5 + } else if (key.localeAwareCompare("ISO-8859-") < 0) { + rank = 6; + } else if ((match = iso8859RegExp.match(key)).hasMatch()) { + rank = 6 + match.captured(1).size(); // Up to 6 + 2 + } else if (key.localeAwareCompare("WINDOWS-") < 0) { + rank = 9; + } else if ((match = windowsRegExp.match(key)).hasMatch()) { + rank = 9 + match.captured(1).size(); // Up to 9 + 4 + } else { + rank = 14; + } + // This doesn't perfectly well order the IBM codecs because it's + // annoying to properly place IBM00858 and IBM00924 in the middle of + // code page numbers not zero padded to 5 digits. + // We could manipulate the key further to have more commonly used + // charsets earlier. IANA MIB ordering would be unxpected: + // https://www.iana.org/assignments/character-sets/character-sets.xml + // For data about use in HTTP (other protocols can be quite different): + // https://w3techs.com/technologies/overview/character_encoding + + key.prepend(char('0' + rank)); + // We use a map here because, due to backwards compatibility, + // the same QTextCodec may be returned for multiple MIBs, which + // happens for GBK/GB2312, EUC-KR/windows-949/UHC, and others. + text_codec_map_.insert(key, codec); + } +} + +void LogwolfMainWindow::initMainToolbarIcons() +{ + // Normally 16 px. Reflects current GTK+ behavior and other Windows apps. + int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); +#if !defined(Q_OS_WIN) + // Force icons to 24x24 for now, otherwise actionFileOpen looks wonky. + // The macOS HIG specifies 32-pixel icons but they're a little too + // large IMHO. + icon_size = icon_size * 3 / 2; +#endif + main_ui_->mainToolBar->setIconSize(QSize(icon_size, icon_size)); + + // Toolbar actions. The GNOME HIG says that we should have a menu icon for each + // toolbar item but that clutters up our menu. Set menu icons sparingly. + + main_ui_->actionCaptureStart->setIcon(StockIcon("x-capture-start")); + main_ui_->actionCaptureStop->setIcon(StockIcon("x-capture-stop")); + main_ui_->actionCaptureRestart->setIcon(StockIcon("x-capture-restart")); + main_ui_->actionCaptureOptions->setIcon(StockIcon("x-capture-options")); + + // Menu icons are disabled in main_window.ui for these items. + main_ui_->actionFileOpen->setIcon(StockIcon("document-open")); + main_ui_->actionFileSave->setIcon(StockIcon("x-capture-file-save")); + main_ui_->actionFileClose->setIcon(StockIcon("x-capture-file-close")); + main_ui_->actionViewReload->setIcon(StockIcon("x-capture-file-reload")); + + main_ui_->actionEditFindPacket->setIcon(StockIcon("edit-find")); + main_ui_->actionGoPreviousPacket->setIcon(StockIcon("go-previous")); + main_ui_->actionGoNextPacket->setIcon(StockIcon("go-next")); + main_ui_->actionGoGoToPacket->setIcon(StockIcon("go-jump")); + main_ui_->actionGoFirstPacket->setIcon(StockIcon("go-first")); + main_ui_->actionGoLastPacket->setIcon(StockIcon("go-last")); + main_ui_->actionGoPreviousConversationPacket->setIcon(StockIcon("go-previous")); + main_ui_->actionGoNextConversationPacket->setIcon(StockIcon("go-next")); +#if defined(Q_OS_MAC) + main_ui_->actionGoPreviousConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Comma)); + main_ui_->actionGoNextConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Period)); +#endif + main_ui_->actionGoPreviousHistoryPacket->setIcon(StockIcon("go-previous")); + main_ui_->actionGoNextHistoryPacket->setIcon(StockIcon("go-next")); + main_ui_->actionGoAutoScroll->setIcon(StockIcon("x-stay-last")); + + main_ui_->actionViewColorizePacketList->setIcon(StockIcon("x-colorize-packets")); + + QList zi_seq = main_ui_->actionViewZoomIn->shortcuts(); + zi_seq << QKeySequence(Qt::CTRL | Qt::Key_Equal); + main_ui_->actionViewZoomIn->setIcon(StockIcon("zoom-in")); + main_ui_->actionViewZoomIn->setShortcuts(zi_seq); + main_ui_->actionViewZoomOut->setIcon(StockIcon("zoom-out")); + main_ui_->actionViewNormalSize->setIcon(StockIcon("zoom-original")); + main_ui_->actionViewResizeColumns->setIcon(StockIcon("x-resize-columns")); + + main_ui_->actionNewDisplayFilterExpression->setIcon(StockIcon("list-add")); +} + +void LogwolfMainWindow::initShowHideMainWidgets() +{ + if (show_hide_actions_) { + return; + } + + show_hide_actions_ = new QActionGroup(this); + QMap shmw_actions; + + show_hide_actions_->setExclusive(false); + shmw_actions[main_ui_->actionViewMainToolbar] = main_ui_->mainToolBar; + shmw_actions[main_ui_->actionViewFilterToolbar] = main_ui_->displayFilterToolBar; +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + shmw_actions[main_ui_->actionViewWirelessToolbar] = main_ui_->wirelessToolBar; +#endif + shmw_actions[main_ui_->actionViewStatusBar] = main_ui_->statusBar; + shmw_actions[main_ui_->actionViewPacketList] = packet_list_; + shmw_actions[main_ui_->actionViewPacketDetails] = proto_tree_; + shmw_actions[main_ui_->actionViewPacketBytes] = byte_view_tab_; + shmw_actions[main_ui_->actionViewPacketDiagram] = packet_diagram_; + + foreach(QAction *shmwa, shmw_actions.keys()) { + shmwa->setData(QVariant::fromValue(shmw_actions[shmwa])); + show_hide_actions_->addAction(shmwa); + } + + // Initial hide the Interface Toolbar submenu + main_ui_->menuInterfaceToolbars->menuAction()->setVisible(false); + + /* Initially hide the additional toolbars menus */ + main_ui_->menuAdditionalToolbars->menuAction()->setVisible(false); + + connect(show_hide_actions_, SIGNAL(triggered(QAction*)), this, SLOT(showHideMainWidgets(QAction*))); +} + +void LogwolfMainWindow::initTimeDisplayFormatMenu() +{ + if (time_display_actions_) { + return; + } + + time_display_actions_ = new QActionGroup(this); + + td_actions[main_ui_->actionViewTimeDisplayFormatDateYMDandTimeOfDay] = TS_ABSOLUTE_WITH_YMD; + td_actions[main_ui_->actionViewTimeDisplayFormatDateYDOYandTimeOfDay] = TS_ABSOLUTE_WITH_YDOY; + td_actions[main_ui_->actionViewTimeDisplayFormatTimeOfDay] = TS_ABSOLUTE; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSinceEpoch] = TS_EPOCH; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSinceBeginningOfCapture] = TS_RELATIVE; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSincePreviousCapturedPacket] = TS_DELTA; + td_actions[main_ui_->actionViewTimeDisplayFormatSecondsSincePreviousDisplayedPacket] = TS_DELTA_DIS; + td_actions[main_ui_->actionViewTimeDisplayFormatUTCDateYMDandTimeOfDay] = TS_UTC_WITH_YMD; + td_actions[main_ui_->actionViewTimeDisplayFormatUTCDateYDOYandTimeOfDay] = TS_UTC_WITH_YDOY; + td_actions[main_ui_->actionViewTimeDisplayFormatUTCTimeOfDay] = TS_UTC; + + foreach(QAction* tda, td_actions.keys()) { + tda->setData(QVariant::fromValue(td_actions[tda])); + time_display_actions_->addAction(tda); + } + + connect(time_display_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setTimestampFormat(QAction*))); +} + +void LogwolfMainWindow::initTimePrecisionFormatMenu() +{ + if (time_precision_actions_) { + return; + } + + time_precision_actions_ = new QActionGroup(this); + + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionAutomatic] = TS_PREC_AUTO; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionSeconds] = TS_PREC_FIXED_SEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionDeciseconds] = TS_PREC_FIXED_DSEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionCentiseconds] = TS_PREC_FIXED_CSEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionMilliseconds] = TS_PREC_FIXED_MSEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionMicroseconds] = TS_PREC_FIXED_USEC; + tp_actions[main_ui_->actionViewTimeDisplayFormatPrecisionNanoseconds] = TS_PREC_FIXED_NSEC; + + foreach(QAction* tpa, tp_actions.keys()) { + tpa->setData(QVariant::fromValue(tp_actions[tpa])); + time_precision_actions_->addAction(tpa); + } + + connect(time_precision_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setTimestampPrecision(QAction*))); +} + +// Menu items which will be disabled when we freeze() and whose state will +// be restored when we thaw(). Add to the list as needed. +void LogwolfMainWindow::initFreezeActions() +{ + QList freeze_actions = QList() + << main_ui_->actionFileClose + << main_ui_->actionViewReload + << main_ui_->actionEditMarkPacket + << main_ui_->actionEditMarkAllDisplayed + << main_ui_->actionEditUnmarkAllDisplayed + << main_ui_->actionEditIgnorePacket + << main_ui_->actionEditIgnoreAllDisplayed + << main_ui_->actionEditUnignoreAllDisplayed + << main_ui_->actionEditSetTimeReference + << main_ui_->actionEditUnsetAllTimeReferences; + + foreach(QAction *action, freeze_actions) { + freeze_actions_ << QPair(action, false); + } +} + +void LogwolfMainWindow::initConversationMenus() +{ + int i; + + QList cc_actions = QList() + << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2 + << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4 + << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6 + << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8 + << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10; + + for (GList *conv_filter_list_entry = conv_filter_list; conv_filter_list_entry; conv_filter_list_entry = gxx_list_next(conv_filter_list_entry)) { + // Main menu items + conversation_filter_t* conv_filter = gxx_list_data(conversation_filter_t *, conv_filter_list_entry); + ConversationAction *conv_action = new ConversationAction(main_ui_->menuConversationFilter, conv_filter); + main_ui_->menuConversationFilter->addAction(conv_action); + + connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); + connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter())); + + // Packet list context menu items + packet_list_->conversationMenu()->addAction(conv_action); + + QMenu *submenu = packet_list_->colorizeMenu()->addMenu(conv_action->text()); + i = 1; + + foreach(QAction *cc_action, cc_actions) { + conv_action = new ConversationAction(submenu, conv_filter); + conv_action->setText(cc_action->text()); + conv_action->setIcon(cc_action->icon()); + conv_action->setColorNumber(i++); + submenu->addAction(conv_action); + connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); + connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); + } + + conv_action = new ConversationAction(submenu, conv_filter); + conv_action->setText(main_ui_->actionViewColorizeNewColoringRule->text()); + submenu->addAction(conv_action); + connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*))); + connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); + + // Proto tree conversation menu is filled in in ProtoTree::contextMenuEvent. + // We should probably do that here. + } + + // Proto tree colorization items + i = 1; + ColorizeAction *colorize_action; + foreach(QAction *cc_action, cc_actions) { + colorize_action = new ColorizeAction(proto_tree_->colorizeMenu()); + colorize_action->setText(cc_action->text()); + colorize_action->setIcon(cc_action->icon()); + colorize_action->setColorNumber(i++); + proto_tree_->colorizeMenu()->addAction(colorize_action); + connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray))); + connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); + } + + colorize_action = new ColorizeAction(proto_tree_->colorizeMenu()); + colorize_action->setText(main_ui_->actionViewColorizeNewColoringRule->text()); + proto_tree_->colorizeMenu()->addAction(colorize_action); + connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray))); + connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered())); +} + +gboolean LogwolfMainWindow::addExportObjectsMenuItem(const void *, void *value, void *userdata) +{ + register_eo_t *eo = (register_eo_t*)value; + LogwolfMainWindow *window = (LogwolfMainWindow*)userdata; + + ExportObjectAction *export_action = new ExportObjectAction(window->main_ui_->menuFileExportObjects, eo); + window->main_ui_->menuFileExportObjects->addAction(export_action); + + //initially disable until a file is loaded (then file signals will take over) + export_action->setEnabled(false); + + connect(&window->capture_file_, SIGNAL(captureEvent(CaptureEvent)), export_action, SLOT(captureFileEvent(CaptureEvent))); + connect(export_action, SIGNAL(triggered()), window, SLOT(applyExportObject())); + return FALSE; +} + +void LogwolfMainWindow::initExportObjectsMenus() +{ + eo_iterate_tables(addExportObjectsMenuItem, this); +} + +// Titlebar +void LogwolfMainWindow::setTitlebarForCaptureFile() +{ + if (capture_file_.capFile() && capture_file_.capFile()->filename) { + setWSWindowTitle(QString("[*]%1").arg(capture_file_.fileDisplayName())); + // + // XXX - on non-Mac platforms, put in the application + // name? Or do so only for temporary files? + // + if (!capture_file_.capFile()->is_tempfile) { + // + // Set the file path; that way, for macOS, it'll set the + // "proxy icon". + // + setWindowFilePath(capture_file_.filePath()); + } + setWindowModified(cf_has_unsaved_data(capture_file_.capFile())); + } else { + /* We have no capture file. */ + setWSWindowTitle(); + } +} + +QString LogwolfMainWindow::replaceWindowTitleVariables(QString title) +{ + title.replace("%P", get_profile_name()); + title.replace("%V", get_ws_vcs_version_info()); + + if (title.contains("%F")) { + // %F is file path of the capture file. + if (capture_file_.capFile()) { + // get_dirname() will overwrite the argument so make a copy first + char *filename = g_strdup(capture_file_.capFile()->filename); + QString file(get_dirname(filename)); + g_free(filename); +#ifndef _WIN32 + // Substitute HOME with ~ + QString homedir(g_getenv("HOME")); + if (!homedir.isEmpty()) { + homedir.remove(QRegularExpression("[/]+$")); + file.replace(homedir, "~"); + } +#endif + title.replace("%F", file); + } else { + // No file loaded, no folder name + title.remove("%F"); + } + } + + if (title.contains("%S")) { + // %S is a conditional separator (" - ") that only shows when surrounded by variables + // with values or static text. Remove repeating, leading and trailing separators. + title.replace(QRegularExpression("(%S)+"), "%S"); + title.remove(QRegularExpression("^%S|%S$")); +#ifdef __APPLE__ + // On macOS we separate with a unicode em dash + title.replace("%S", " " UTF8_EM_DASH " "); +#else + title.replace("%S", " - "); +#endif + } + + return title; +} + +void LogwolfMainWindow::setWSWindowTitle(QString title) +{ + if (title.isEmpty()) { + title = tr("The Wireshark Network Analyzer"); + } + + if (prefs.gui_prepend_window_title && prefs.gui_prepend_window_title[0]) { + QString custom_title = replaceWindowTitleVariables(prefs.gui_prepend_window_title); + if (custom_title.length() > 0) { + title.prepend(QString("[%1] ").arg(custom_title)); + } + } + + if (prefs.gui_window_title && prefs.gui_window_title[0]) { + QString custom_title = replaceWindowTitleVariables(prefs.gui_window_title); + if (custom_title.length() > 0) { +#ifdef __APPLE__ + // On macOS we separate the titles with a unicode em dash + title.append(QString(" %1 %2").arg(UTF8_EM_DASH).arg(custom_title)); +#else + title.append(QString(" [%1]").arg(custom_title)); +#endif + } + } + + setWindowTitle(title); + setWindowFilePath(NULL); +} + +void LogwolfMainWindow::setTitlebarForCaptureInProgress() +{ + if (capture_file_.capFile()) { + setWSWindowTitle(tr("Capturing from %1").arg(cf_get_tempfile_source(capture_file_.capFile()))); + } else { + /* We have no capture in progress. */ + setWSWindowTitle(); + } +} + +// Menu state + +/* Enable or disable menu items based on whether you have a capture file + you've finished reading and, if you have one, whether it's been saved + and whether it could be saved except by copying the raw packet data. */ +void LogwolfMainWindow::setMenusForCaptureFile(bool force_disable) +{ + bool enable = true; + bool can_write = false; + bool can_save = false; + bool can_save_as = false; + + if (force_disable || capture_file_.capFile() == NULL || capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) { + /* We have no capture file or we're currently reading a file */ + enable = false; + } else { + /* We have a capture file. Can we write or save? */ + can_write = cf_can_write_with_wiretap(capture_file_.capFile()); + can_save = cf_can_save(capture_file_.capFile()); + can_save_as = cf_can_save_as(capture_file_.capFile()); + } + + main_ui_->actionViewReload_as_File_Format_or_Capture->setEnabled(enable); + main_ui_->actionFileMerge->setEnabled(can_write); + main_ui_->actionFileClose->setEnabled(enable); + main_ui_->actionFileSave->setEnabled(can_save); + main_ui_->actionFileSaveAs->setEnabled(can_save_as); + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(enable); + /* + * "Export Specified Packets..." should be available only if + * we can write the file out in at least one format. + */ + main_ui_->actionFileExportPackets->setEnabled(can_write); + + main_ui_->actionFileExportAsCArrays->setEnabled(enable); + main_ui_->actionFileExportAsCSV->setEnabled(enable); + main_ui_->actionFileExportAsPDML->setEnabled(enable); + main_ui_->actionFileExportAsPlainText->setEnabled(enable); + main_ui_->actionFileExportAsPSML->setEnabled(enable); + main_ui_->actionFileExportAsJSON->setEnabled(enable); + + main_ui_->actionFileExportPacketBytes->setEnabled(enable); + main_ui_->actionFileExportPDU->setEnabled(enable); + main_ui_->actionFileExportTLSSessionKeys->setEnabled(enable); + + foreach(QAction *eo_action, main_ui_->menuFileExportObjects->actions()) { + eo_action->setEnabled(enable); + } + + main_ui_->actionViewReload->setEnabled(enable); + +#ifdef HAVE_SOFTWARE_UPDATE + // We might want to enable or disable automatic checks here as well. + update_action_->setEnabled(!can_save); +#endif +} + +void LogwolfMainWindow::setMenusForCaptureInProgress(bool capture_in_progress) { + /* Either a capture was started or stopped; in either case, it's not + in the process of stopping, so allow quitting. */ + + main_ui_->actionFileOpen->setEnabled(!capture_in_progress); + main_ui_->menuOpenRecentCaptureFile->setEnabled(!capture_in_progress); + + main_ui_->actionFileExportAsCArrays->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsCSV->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsPDML->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsPlainText->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsPSML->setEnabled(capture_in_progress); + main_ui_->actionFileExportAsJSON->setEnabled(capture_in_progress); + + main_ui_->actionFileExportPacketBytes->setEnabled(capture_in_progress); + main_ui_->actionFileExportPDU->setEnabled(!capture_in_progress); + main_ui_->actionFileExportTLSSessionKeys->setEnabled(capture_in_progress); + + foreach(QAction *eo_action, main_ui_->menuFileExportObjects->actions()) { + eo_action->setEnabled(capture_in_progress); + } + + main_ui_->menuFileSet->setEnabled(!capture_in_progress); + main_ui_->actionFileQuit->setEnabled(true); +#ifdef HAVE_SOFTWARE_UPDATE + // We might want to enable or disable automatic checks here as well. + update_action_->setEnabled(!capture_in_progress); +#endif + + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(capture_in_progress); + + // XXX Fix packet list heading menu sensitivity + // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortAscending", + // !capture_in_progress); + // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortDescending", + // !capture_in_progress); + // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/NoSorting", + // !capture_in_progress); + +#ifdef HAVE_LIBPCAP + main_ui_->actionCaptureOptions->setEnabled(!capture_in_progress); + main_ui_->actionCaptureStart->setEnabled(!capture_in_progress); + main_ui_->actionCaptureStart->setChecked(capture_in_progress); + main_ui_->actionCaptureStop->setEnabled(capture_in_progress); + main_ui_->actionCaptureRestart->setEnabled(capture_in_progress); + main_ui_->actionCaptureRefreshInterfaces->setEnabled(!capture_in_progress); +#endif /* HAVE_LIBPCAP */ + +} + +void LogwolfMainWindow::setMenusForCaptureStopping() { + main_ui_->actionFileQuit->setEnabled(false); +#ifdef HAVE_SOFTWARE_UPDATE + update_action_->setEnabled(false); +#endif + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(false); +#ifdef HAVE_LIBPCAP + main_ui_->actionCaptureStart->setChecked(false); + main_ui_->actionCaptureStop->setEnabled(false); + main_ui_->actionCaptureRestart->setEnabled(false); +#endif /* HAVE_LIBPCAP */ +} + +void LogwolfMainWindow::setForCapturedPackets(bool have_captured_packets) +{ + main_ui_->actionFilePrint->setEnabled(have_captured_packets); + +// set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/Print", +// have_captured_packets); + + main_ui_->actionEditFindPacket->setEnabled(have_captured_packets); + main_ui_->actionEditFindNext->setEnabled(have_captured_packets); + main_ui_->actionEditFindPrevious->setEnabled(have_captured_packets); + + main_ui_->actionGoGoToPacket->setEnabled(have_captured_packets); + main_ui_->actionGoPreviousPacket->setEnabled(have_captured_packets); + main_ui_->actionGoNextPacket->setEnabled(have_captured_packets); + main_ui_->actionGoFirstPacket->setEnabled(have_captured_packets); + main_ui_->actionGoLastPacket->setEnabled(have_captured_packets); + main_ui_->actionGoNextConversationPacket->setEnabled(have_captured_packets); + main_ui_->actionGoPreviousConversationPacket->setEnabled(have_captured_packets); + + main_ui_->actionViewZoomIn->setEnabled(have_captured_packets); + main_ui_->actionViewZoomOut->setEnabled(have_captured_packets); + main_ui_->actionViewNormalSize->setEnabled(have_captured_packets); + main_ui_->actionViewResizeColumns->setEnabled(have_captured_packets); + + main_ui_->actionStatisticsCaptureFileProperties->setEnabled(have_captured_packets); + main_ui_->actionStatisticsProtocolHierarchy->setEnabled(have_captured_packets); + main_ui_->actionStatisticsIOGraph->setEnabled(have_captured_packets); +} + +void LogwolfMainWindow::setMenusForFileSet(bool enable_list_files) { + bool enable_next = fileset_get_next() != NULL && enable_list_files; + bool enable_prev = fileset_get_previous() != NULL && enable_list_files; + + main_ui_->actionFileSetListFiles->setEnabled(enable_list_files); + main_ui_->actionFileSetNextFile->setEnabled(enable_next); + main_ui_->actionFileSetPreviousFile->setEnabled(enable_prev); +} + +void LogwolfMainWindow::setWindowIcon(const QIcon &icon) { + mainApp->setWindowIcon(icon); + QMainWindow::setWindowIcon(icon); +} + +void LogwolfMainWindow::updateForUnsavedChanges() { + setTitlebarForCaptureFile(); + setMenusForCaptureFile(); +} + +void LogwolfMainWindow::changeEvent(QEvent* event) +{ + if (0 != event) + { + switch (event->type()) + { + case QEvent::LanguageChange: + main_ui_->retranslateUi(this); + // make sure that the "Clear Menu" item is retranslated + mainApp->emitAppSignal(WiresharkApplication::RecentCapturesChanged); + break; + case QEvent::LocaleChange: { + QString locale = QLocale::system().name(); + locale.truncate(locale.lastIndexOf('_')); + mainApp->loadLanguage(locale); + } + break; + case QEvent::WindowStateChange: + main_ui_->actionViewFullScreen->setChecked(this->isFullScreen()); + break; + default: + break; + } + } + QMainWindow::changeEvent(event); +} + +/* Update main window items based on whether there's a capture in progress. */ +void LogwolfMainWindow::setForCaptureInProgress(bool capture_in_progress, bool handle_toolbars, GArray *ifaces) +{ + setMenusForCaptureInProgress(capture_in_progress); + +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + wireless_frame_->setCaptureInProgress(capture_in_progress); +#endif + +#ifdef HAVE_LIBPCAP + packet_list_->setCaptureInProgress(capture_in_progress); + packet_list_->setVerticalAutoScroll(capture_in_progress && main_ui_->actionGoAutoScroll->isChecked()); + +// set_capture_if_dialog_for_capture_in_progress(capture_in_progress); +#endif + + if (handle_toolbars) { + QList toolbars = findChildren(); + foreach(InterfaceToolbar *toolbar, toolbars) { + if (capture_in_progress) { + toolbar->startCapture(ifaces); + } else { + toolbar->stopCapture(); + } + } + } +} + +static QList menu_groups = QList() + << REGISTER_ANALYZE_GROUP_UNSORTED + << REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER + << REGISTER_STAT_GROUP_UNSORTED + << REGISTER_STAT_GROUP_GENERIC + << REGISTER_STAT_GROUP_CONVERSATION_LIST + << REGISTER_STAT_GROUP_ENDPOINT_LIST + << REGISTER_STAT_GROUP_RESPONSE_TIME + << REGISTER_STAT_GROUP_RSERPOOL + << REGISTER_STAT_GROUP_TELEPHONY + << REGISTER_STAT_GROUP_TELEPHONY_ANSI + << REGISTER_STAT_GROUP_TELEPHONY_GSM + << REGISTER_STAT_GROUP_TELEPHONY_LTE + << REGISTER_STAT_GROUP_TELEPHONY_MTP3 + << REGISTER_STAT_GROUP_TELEPHONY_SCTP + << REGISTER_TOOLS_GROUP_UNSORTED; + +void LogwolfMainWindow::addMenuActions(QList &actions, int menu_group) +{ + foreach(QAction *action, actions) { + switch (menu_group) { + case REGISTER_ANALYZE_GROUP_UNSORTED: + case REGISTER_STAT_GROUP_UNSORTED: + main_ui_->menuStatistics->insertAction( + main_ui_->actionStatistics_REGISTER_STAT_GROUP_UNSORTED, + action); + break; + case REGISTER_STAT_GROUP_RESPONSE_TIME: + main_ui_->menuServiceResponseTime->addAction(action); + break; + case REGISTER_STAT_GROUP_RSERPOOL: + main_ui_->menuRSerPool->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY: + main_ui_->menuTelephony->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_ANSI: + main_ui_->menuANSI->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_GSM: + main_ui_->menuGSM->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_LTE: + main_ui_->menuLTE->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_MTP3: + main_ui_->menuMTP3->addAction(action); + break; + case REGISTER_TOOLS_GROUP_UNSORTED: + { + // Allow the creation of submenus. Mimics the behavor of + // ui/gtk/main_menubar.c:add_menu_item_to_main_menubar + // and GtkUIManager. + // + // For now we limit the insanity to the "Tools" menu. + QStringList menu_path = action->text().split('/'); + QMenu *cur_menu = main_ui_->menuTools; + while (menu_path.length() > 1) { + QString menu_title = menu_path.takeFirst(); + QMenu *submenu = cur_menu->findChild(menu_title.toLower(), Qt::FindDirectChildrenOnly); + if (!submenu) { + submenu = cur_menu->addMenu(menu_title); + submenu->setObjectName(menu_title.toLower()); + } + cur_menu = submenu; + } + action->setText(menu_path.last()); + cur_menu->addAction(action); + break; + } + default: +// qDebug() << "FIX: Add" << action->text() << "to the menu"; + break; + } + + // Connect each action type to its corresponding slot. We to + // distinguish various types of actions. Setting their objectName + // seems to work OK. + if (action->objectName() == TapParameterDialog::actionName()) { + connect(action, SIGNAL(triggered(bool)), this, SLOT(openTapParameterDialog())); + } else if (action->objectName() == FunnelStatistics::actionName()) { + connect(action, SIGNAL(triggered(bool)), funnel_statistics_, SLOT(funnelActionTriggered())); + } + } +} +void LogwolfMainWindow::removeMenuActions(QList &actions, int menu_group) +{ + foreach(QAction *action, actions) { + switch (menu_group) { + case REGISTER_ANALYZE_GROUP_UNSORTED: + case REGISTER_STAT_GROUP_UNSORTED: + main_ui_->menuStatistics->removeAction(action); + break; + case REGISTER_STAT_GROUP_RESPONSE_TIME: + main_ui_->menuServiceResponseTime->removeAction(action); + break; + case REGISTER_STAT_GROUP_RSERPOOL: + main_ui_->menuRSerPool->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY: + main_ui_->menuTelephony->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_ANSI: + main_ui_->menuANSI->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_GSM: + main_ui_->menuGSM->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_LTE: + main_ui_->menuLTE->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_MTP3: + main_ui_->menuMTP3->removeAction(action); + break; + case REGISTER_TOOLS_GROUP_UNSORTED: + { + // Allow removal of submenus. + // For now we limit the insanity to the "Tools" menu. + QStringList menu_path = action->text().split('/'); + QMenu *cur_menu = main_ui_->menuTools; + while (menu_path.length() > 1) { + QString menu_title = menu_path.takeFirst(); + QMenu *submenu = cur_menu->findChild(menu_title.toLower(), Qt::FindDirectChildrenOnly); + cur_menu = submenu; + } + cur_menu->removeAction(action); + break; + } + default: +// qDebug() << "FIX: Remove" << action->text() << "from the menu"; + break; + } + } +} + +void LogwolfMainWindow::addDynamicMenus() +{ + // Manual additions + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_GSM, main_ui_->actionTelephonyGsmMapSummary); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteMacStatistics); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcStatistics); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcGraph); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_MTP3, main_ui_->actionTelephonyMtp3Summary); + mainApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY, main_ui_->actionTelephonySipFlows); + + // Fill in each menu + foreach(register_stat_group_t menu_group, menu_groups) { + QListactions = mainApp->dynamicMenuGroupItems(menu_group); + addMenuActions(actions, menu_group); + } + + // Empty menus don't show up: https://bugreports.qt.io/browse/QTBUG-33728 + // We've added a placeholder in order to make sure some menus are visible. + // Hide them as needed. + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_ANSI).length() > 0) { + main_ui_->actionTelephonyANSIPlaceholder->setVisible(false); + } + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_GSM).length() > 0) { + main_ui_->actionTelephonyGSMPlaceholder->setVisible(false); + } + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_LTE).length() > 0) { + main_ui_->actionTelephonyLTEPlaceholder->setVisible(false); + } + if (mainApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_MTP3).length() > 0) { + main_ui_->actionTelephonyMTP3Placeholder->setVisible(false); + } +} + +void LogwolfMainWindow::reloadDynamicMenus() +{ + foreach(register_stat_group_t menu_group, menu_groups) { + QListactions = mainApp->removedMenuGroupItems(menu_group); + removeMenuActions(actions, menu_group); + + actions = mainApp->addedMenuGroupItems(menu_group); + addMenuActions(actions, menu_group); + } + + mainApp->clearAddedMenuGroupItems(); + mainApp->clearRemovedMenuGroupItems(); +} + +void LogwolfMainWindow::externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth) +{ + QAction * itemAction = Q_NULLPTR; + ext_menubar_t * item = Q_NULLPTR; + GList * children = Q_NULLPTR; + + /* There must exists an xpath parent */ + Q_ASSERT(subMenu != NULL); + + /* If the depth counter exceeds, something must have gone wrong */ + Q_ASSERT(depth < EXT_MENUBAR_MAX_DEPTH); + + children = menu->children; + /* Iterate the child entries */ + while (children && children->data) { + item = gxx_list_data(ext_menubar_t *, children); + + if (item->type == EXT_MENUBAR_MENU) { + /* Handle Submenu entry */ + this->externalMenuHelper(item, subMenu->addMenu(item->label), depth++); + } else if (item->type == EXT_MENUBAR_SEPARATOR) { + subMenu->addSeparator(); + } else if (item->type == EXT_MENUBAR_ITEM || item->type == EXT_MENUBAR_URL) { + itemAction = subMenu->addAction(item->name); + itemAction->setData(QVariant::fromValue(static_cast(item))); + itemAction->setText(item->label); + connect(itemAction, SIGNAL(triggered()), + this, SLOT(externalMenuItem_triggered())); + } + + /* Iterate Loop */ + children = gxx_list_next(children); + } +} + +QMenu * LogwolfMainWindow::searchSubMenu(QString objectName) +{ + QList lst; + + if (objectName.length() > 0) { + QString searchName = QString("menu") + objectName; + + lst = main_ui_->menuBar->findChildren(); + foreach(QMenu* m, lst) { + if (QString::compare(m->objectName(), searchName) == 0) + return m; + } + } + + return 0; +} + +void LogwolfMainWindow::addPluginIFStructures() +{ + GList *user_menu = ext_menubar_get_entries(); + + while (user_menu && user_menu->data) { + QMenu *subMenu = Q_NULLPTR; + ext_menu_t *menu = gxx_list_data(ext_menu_t *, user_menu); + + /* On this level only menu items should exist. Not doing an assert here, + * as it could be an honest mistake */ + if (menu->type != EXT_MENUBAR_MENU) { + user_menu = gxx_list_next(user_menu); + continue; + } + + /* Create main submenu and add it to the menubar */ + if (menu->parent_menu) { + QMenu *sortUnderneath = searchSubMenu(QString(menu->parent_menu)); + if (sortUnderneath) + subMenu = sortUnderneath->addMenu(menu->label); + } + + if (!subMenu) + subMenu = main_ui_->menuBar->addMenu(menu->label); + + /* This will generate the action structure for each menu. It is recursive, + * therefore a sub-routine, and we have a depth counter to prevent endless loops. */ + this->externalMenuHelper(menu, subMenu, 0); + + /* Iterate Loop */ + user_menu = gxx_list_next(user_menu); + } + + int cntToolbars = 0; + + QMenu *tbMenu = main_ui_->menuAdditionalToolbars; + GList *if_toolbars = ext_toolbar_get_entries(); + while (if_toolbars && if_toolbars->data) { + ext_toolbar_t *toolbar = gxx_list_data(ext_toolbar_t*, if_toolbars); + + if (toolbar->type != EXT_TOOLBAR_BAR) { + if_toolbars = gxx_list_next(if_toolbars); + continue; + } + + bool visible = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, reinterpret_cast(strcmp)) ? true : false; + + AdditionalToolBar *ifToolBar = AdditionalToolBar::create(this, toolbar); + + if (ifToolBar) { + ifToolBar->setVisible(visible); + + QAction *iftbAction = new QAction(QString(toolbar->name), this); + iftbAction->setToolTip(toolbar->tooltip); + iftbAction->setEnabled(true); + iftbAction->setCheckable(true); + iftbAction->setChecked(visible); + iftbAction->setToolTip(tr("Show or hide the toolbar")); + iftbAction->setData(VariantPointer::asQVariant(toolbar)); + + QAction *before = Q_NULLPTR; + + foreach(QAction *action, tbMenu->actions()) { + /* Ensure we add the menu entries in sorted order */ + if (action->text().compare(toolbar->name, Qt::CaseInsensitive) > 0) { + before = action; + break; + } + } + + tbMenu->insertAction(before, iftbAction); + + addToolBar(Qt::TopToolBarArea, ifToolBar); + insertToolBarBreak(ifToolBar); + + if (show_hide_actions_) + show_hide_actions_->addAction(iftbAction); + + cntToolbars++; + } + + if_toolbars = gxx_list_next(if_toolbars); + } + + if (cntToolbars) + tbMenu->menuAction()->setVisible(true); +} + +void LogwolfMainWindow::removeAdditionalToolbar(QString toolbarName) +{ + if (toolbarName.length() == 0) + return; + + QList toolbars = findChildren(); + foreach(QToolBar *tb, toolbars) { + AdditionalToolBar *ifToolBar = dynamic_cast(tb); + + if (ifToolBar && ifToolBar->menuName().compare(toolbarName)) { + GList *entry = g_list_find_custom(recent.gui_additional_toolbars, qUtf8Printable(ifToolBar->menuName()), reinterpret_cast(strcmp)); + if (entry) { + recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data); + } + QList actions = main_ui_->menuAdditionalToolbars->actions(); + foreach(QAction *action, actions) { + ext_toolbar_t *item = VariantPointer::asPtr(action->data()); + if (item && ifToolBar->menuName().compare(item->name)) { + if (show_hide_actions_) + show_hide_actions_->removeAction(action); + main_ui_->menuAdditionalToolbars->removeAction(action); + } + } + break; + } + } + +} + +QString LogwolfMainWindow::getMwFileName() +{ + return mwFileName_; +} + +void LogwolfMainWindow::setMwFileName(QString fileName) +{ + mwFileName_ = fileName; + return; +} + +frame_data * LogwolfMainWindow::frameDataForRow(int row) const +{ + if (packet_list_) + return packet_list_->getFDataForRow(row); + + return Q_NULLPTR; +} + +// Finds rtp id for selected stream and adds it to stream_ids +// If reverse is set, tries to find reverse stream too +// Return error string if error happens +// +// Note: Caller must free each returned rtpstream_info_t +QString LogwolfMainWindow::findRtpStreams(QVector *stream_ids, bool reverse) +{ + rtpstream_tapinfo_t tapinfo; + rtpstream_id_t *fwd_id, *rev_id; + bool fwd_id_used, rev_id_used; + const gchar filter_text[] = "rtp && rtp.version == 2 && rtp.ssrc && (ip || ipv6)"; + dfilter_t *sfcode; + gchar *err_msg; + + /* Try to get the hfid for "rtp.ssrc". */ + int hfid_rtp_ssrc = proto_registrar_get_id_byname("rtp.ssrc"); + if (hfid_rtp_ssrc == -1) { + return tr("There is no \"rtp.ssrc\" field in this version of Wireshark."); + } + + /* Try to compile the filter. */ + if (!dfilter_compile(filter_text, &sfcode, &err_msg)) { + QString err = QString(err_msg); + g_free(err_msg); + return err; + } + + if (!capture_file_.capFile() || !capture_file_.capFile()->current_frame) close(); + + if (!cf_read_current_record(capture_file_.capFile())) close(); + + frame_data *fdata = capture_file_.capFile()->current_frame; + + epan_dissect_t edt; + + epan_dissect_init(&edt, capture_file_.capFile()->epan, true, false); + epan_dissect_prime_with_dfilter(&edt, sfcode); + epan_dissect_prime_with_hfid(&edt, hfid_rtp_ssrc); + epan_dissect_run(&edt, capture_file_.capFile()->cd_t, + &capture_file_.capFile()->rec, + frame_tvbuff_new_buffer( + &capture_file_.capFile()->provider, fdata, + &capture_file_.capFile()->buf), + fdata, NULL); + + /* + * Packet must be an RTPv2 packet with an SSRC; we use the filter to + * check. + */ + if (!dfilter_apply_edt(sfcode, &edt)) { + epan_dissect_cleanup(&edt); + dfilter_free(sfcode); + return tr("Please select an RTPv2 packet with an SSRC value"); + } + + dfilter_free(sfcode); + + /* We need the SSRC value of the current frame; try to get it. */ + GPtrArray *gp = proto_get_finfo_ptr_array(edt.tree, hfid_rtp_ssrc); + if (gp == NULL || gp->len == 0) { + /* XXX - should not happen, as the filter includes rtp.ssrc */ + epan_dissect_cleanup(&edt); + return tr("SSRC value not found."); + } + + /* + * OK, we have the SSRC value, so we can proceed. + * Allocate RTP stream ID structures. + */ + fwd_id = g_new0(rtpstream_id_t, 1); + fwd_id_used = false; + rev_id = g_new0(rtpstream_id_t, 1); + rev_id_used = false; + + /* Get the IP and port values for the forward direction. */ + rtpstream_id_copy_pinfo(&(edt.pi), fwd_id, false); + + /* assume the inverse ip/port combination for the reverse direction */ + rtpstream_id_copy_pinfo(&(edt.pi), rev_id, true); + + /* Save the SSRC value for the forward direction. */ + fwd_id->ssrc = fvalue_get_uinteger(&((field_info *)gp->pdata[0])->value); + + epan_dissect_cleanup(&edt); + + /* Register the tap listener */ + memset(&tapinfo, 0, sizeof(rtpstream_tapinfo_t)); + tapinfo.tap_data = this; + tapinfo.mode = TAP_ANALYSE; + + /* Scan for RTP streams (redissect all packets) */ + rtpstream_scan(&tapinfo, capture_file_.capFile(), Q_NULLPTR); + + for (GList *strinfo_list = g_list_first(tapinfo.strinfo_list); strinfo_list; strinfo_list = gxx_list_next(strinfo_list)) { + rtpstream_info_t * strinfo = gxx_list_data(rtpstream_info_t*, strinfo_list); + if (rtpstream_id_equal(&(strinfo->id), fwd_id,RTPSTREAM_ID_EQUAL_NONE)) + { + *stream_ids << fwd_id; + fwd_id_used = true; + } + + if (rtpstream_id_equal(&(strinfo->id), rev_id,RTPSTREAM_ID_EQUAL_NONE)) + { + if (rev_id->ssrc == 0) { + rev_id->ssrc = strinfo->id.ssrc; + } + if (reverse) { + *stream_ids << rev_id; + rev_id_used = true; + } + } + } + + // + // XXX - is it guaranteed that fwd_id and rev_id were both added to + // *stream_ids? If so, this isn't necessary. + // + if (!fwd_id_used) { + rtpstream_id_free(fwd_id); + } + if (!rev_id_used) { + rtpstream_id_free(rev_id); + } + return NULL; +} + diff --git a/ui/qt_logshark/logwolf_main_window.h b/ui/qt_logshark/logwolf_main_window.h new file mode 100644 index 0000000000..df1e76e8e3 --- /dev/null +++ b/ui/qt_logshark/logwolf_main_window.h @@ -0,0 +1,703 @@ +/** @file + * + * Logwolf - Event log analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef LOGWOLF_MAIN_WINDOW_H +#define LOGWOLF_MAIN_WINDOW_H + +/** @defgroup main_window_group Main window + * The main window has the following submodules: + @dot + digraph main_dependencies { + node [shape=record, fontname=Helvetica, fontsize=10]; + main [ label="main window" URL="\ref main.h"]; + menu [ label="menubar" URL="\ref menus.h"]; + toolbar [ label="toolbar" URL="\ref main_toolbar.h"]; + packet_list [ label="packet list pane" URL="\ref packet_list.h"]; + proto_draw [ label="packet details & bytes panes" URL="\ref main_proto_draw.h"]; + recent [ label="recent user settings" URL="\ref recent.h"]; + main -> menu [ arrowhead="open", style="solid" ]; + main -> toolbar [ arrowhead="open", style="solid" ]; + main -> packet_list [ arrowhead="open", style="solid" ]; + main -> proto_draw [ arrowhead="open", style="solid" ]; + main -> recent [ arrowhead="open", style="solid" ]; + } + @enddot + */ + +/** @file + * The Logwolf main window + * @ingroup main_window_group + * @ingroup windows_group + */ + +#include + +#include + +#include + +#include "file.h" + +#include "ui/ws_ui_util.h" +#include "ui/iface_toolbar.h" + +#include +#include + +#ifdef HAVE_LIBPCAP +#include "capture_opts.h" +#endif +#include + +#include +#include +#include + +#ifdef _WIN32 +# include +#else +# include +#endif + +#include "capture_file.h" +#include "capture_file_dialog.h" +#include "print_dialog.h" +#include "capture_file_properties_dialog.h" +#include +#include +#include "follow_stream_dialog.h" +#include "main_window.h" +#include "rtp_stream_dialog.h" +#include "voip_calls_dialog.h" +#include "rtp_analysis_dialog.h" + +class AccordionFrame; +class ByteViewTab; +class CaptureOptionsDialog; +class PrintDialog; +class FileSetDialog; +class FilterDialog; +class FunnelStatistics; +class WelcomePage; +class PacketCommentDialog; +class PacketDiagram; +class PacketList; +class ProtoTree; +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) +class WirelessFrame; +#endif +class FilterExpressionToolBar; +class WiresharkApplication; + +class QAction; +class QActionGroup; + +namespace Ui { + class LogwolfMainWindow; +} + +Q_DECLARE_METATYPE(ts_type) +Q_DECLARE_METATYPE(ts_precision) + +class LogwolfMainWindow : public MainWindow +{ + Q_OBJECT + +public: + explicit LogwolfMainWindow(QWidget *parent = nullptr); + ~LogwolfMainWindow(); + void setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb); + +#ifdef HAVE_LIBPCAP + capture_session *captureSession() { return &cap_session_; } + info_data_t *captureInfoData() { return &info_data_; } +#endif + + virtual QMenu *createPopupMenu(); + + CaptureFile *captureFile() { return &capture_file_; } + + void removeAdditionalToolbar(QString toolbarName); + + void addInterfaceToolbar(const iface_toolbar *toolbar_entry); + void removeInterfaceToolbar(const gchar *menu_title); + + QString getMwFileName(); + void setMwFileName(QString fileName); + + frame_data * frameDataForRow(int row) const; + +protected: + virtual bool eventFilter(QObject *obj, QEvent *event); + virtual bool event(QEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void closeEvent(QCloseEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); + virtual void changeEvent(QEvent* event); + +private: + // XXX Move to FilterUtils + enum MatchSelected { + MatchSelectedReplace, + MatchSelectedAnd, + MatchSelectedOr, + MatchSelectedNot, + MatchSelectedAndNot, + MatchSelectedOrNot + }; + + enum CopySelected { + CopyAllVisibleItems, + CopyAllVisibleSelectedTreeItems, + CopySelectedDescription, + CopySelectedFieldName, + CopySelectedValue, + CopyListAsText, + CopyListAsCSV, + CopyListAsYAML + }; + + enum FileCloseContext { + Default, + Quit, + Restart, + Reload + }; + + Ui::LogwolfMainWindow *main_ui_; + CaptureFile capture_file_; + QFont mono_font_; + QMap text_codec_map_; +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + WirelessFrame *wireless_frame_; +#endif + QWidget *previous_focus_; + FileSetDialog *file_set_dialog_; + QActionGroup *show_hide_actions_; + QActionGroup *time_display_actions_; + QActionGroup *time_precision_actions_; + FunnelStatistics *funnel_statistics_; + QList > freeze_actions_; + QPointer freeze_focus_; + QMap td_actions; + QMap tp_actions; + bool was_maximized_; + + /* the following values are maintained so that the capture file name and status + is available when there is no cf structure available */ + QString mwFileName_; + + bool capture_stopping_; + bool capture_filter_valid_; +#ifdef HAVE_LIBPCAP + capture_session cap_session_; + CaptureOptionsDialog *capture_options_dialog_; + info_data_t info_data_; +#endif + FilterDialog *display_filter_dlg_; + FilterDialog *capture_filter_dlg_; + + // Pipe input + gint pipe_source_; + gpointer pipe_user_data_; + ws_process_id *pipe_child_process_; + pipe_input_cb_t pipe_input_cb_; +#ifdef _WIN32 + QTimer *pipe_timer_; +#else + QSocketNotifier *pipe_notifier_; +#endif + +#if defined(Q_OS_MAC) + QMenu *dock_menu_; +#endif + +#ifdef HAVE_SOFTWARE_UPDATE + QAction *update_action_; +#endif + + QPoint dragStartPosition; + + void freeze(); + void thaw(); + + void mergeCaptureFile(); + void importCaptureFile(); + bool saveCaptureFile(capture_file *cf, bool dont_reopen); + bool saveAsCaptureFile(capture_file *cf, bool must_support_comments = false, bool dont_reopen = false); + void exportSelectedPackets(); + void exportDissections(export_type_e export_type); + +#ifdef Q_OS_WIN + void fileAddExtension(QString &file_name, int file_type, wtap_compression_type compression_type); +#endif // Q_OS_WIN + bool testCaptureFileClose(QString before_what, FileCloseContext context = Default); + void captureStop(); + + void findTextCodecs(); + + void initMainToolbarIcons(); + void initShowHideMainWidgets(); + void initTimeDisplayFormatMenu(); + void initTimePrecisionFormatMenu(); + void initFreezeActions(); + + void setTitlebarForCaptureInProgress(); + void setMenusForCaptureFile(bool force_disable = false); + void setMenusForCaptureInProgress(bool capture_in_progress = false); + void setMenusForCaptureStopping(); + void setForCapturedPackets(bool have_captured_packets); + void setMenusForFileSet(bool enable_list_files); + void setWindowIcon(const QIcon &icon); + QString replaceWindowTitleVariables(QString title); + + void externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth); + + void setForCaptureInProgress(bool capture_in_progress = false, bool handle_toolbars = false, GArray *ifaces = NULL); + QMenu* findOrAddMenu(QMenu *parent_menu, QString& menu_text); + + void captureFileReadStarted(const QString &action); + + void addMenuActions(QList &actions, int menu_group); + void removeMenuActions(QList &actions, int menu_group); + void goToConversationFrame(bool go_next); + void colorizeWithFilter(QByteArray filter, int color_number = -1); + +signals: + void setDissectedCaptureFile(capture_file *cf); + void displayFilterSuccess(bool success); + void closePacketDialogs(); + void reloadFields(); + void packetInfoChanged(struct _packet_info *pinfo); + void fieldFilterChanged(const QByteArray field_filter); + + void fieldHighlight(FieldInformation *); + + void captureActive(int); + void selectRtpStream(rtpstream_id_t *id); + void deselectRtpStream(rtpstream_id_t *id); + +#ifdef HAVE_LIBPCAP + void showExtcapOptions(QString &device_name, bool startCaptureOnClose); +#endif + +public slots: + // in main_window_slots.cpp + /** + * Open a capture file. + * @param cf_path Path to the file. + * @param display_filter Display filter to apply. May be empty. + * @param type File type. + * @param is_tempfile TRUE/FALSE. + * @return True on success, false on failure. + */ + // XXX We might want to return a cf_read_status_t or a CaptureFile. + bool openCaptureFile(QString cf_path, QString display_filter, unsigned int type, gboolean is_tempfile = FALSE); + bool openCaptureFile(QString cf_path = QString(), QString display_filter = QString()) { return openCaptureFile(cf_path, display_filter, WTAP_TYPE_AUTO); } + void filterPackets(QString new_filter = QString(), bool force = false); + void updateForUnsavedChanges(); + void layoutToolbars(); + void updatePreferenceActions(); + void updateRecentActions(); + + void setTitlebarForCaptureFile(); + void setWSWindowTitle(QString title = QString()); + +#ifdef HAVE_LIBPCAP + void captureCapturePrepared(capture_session *); + void captureCaptureUpdateStarted(capture_session *); + void captureCaptureUpdateFinished(capture_session *); + void captureCaptureFixedFinished(capture_session *cap_session); + void captureCaptureFailed(capture_session *); +#endif + + void captureFileOpened(); + void captureFileReadFinished(); + void captureFileClosing(); + void captureFileClosed(); + + void launchRLCGraph(bool channelKnown, guint16 ueid, guint8 rlcMode, + guint16 channelType, guint16 channelId, guint8 direction); + + void on_actionViewFullScreen_triggered(bool checked); + + void rtpPlayerDialogReplaceRtpStreams(QVector stream_ids); + void rtpPlayerDialogAddRtpStreams(QVector stream_ids); + void rtpPlayerDialogRemoveRtpStreams(QVector stream_ids); + void rtpAnalysisDialogReplaceRtpStreams(QVector stream_ids); + void rtpAnalysisDialogAddRtpStreams(QVector stream_ids); + void rtpAnalysisDialogRemoveRtpStreams(QVector stream_ids); + void rtpStreamsDialogSelectRtpStreams(QVector stream_ids); + void rtpStreamsDialogDeselectRtpStreams(QVector stream_ids); + +private slots: + + void captureEventHandler(CaptureEvent ev); + + // Manually connected slots (no "on__"). + + void initViewColorizeMenu(); + void initConversationMenus(); + static gboolean addExportObjectsMenuItem(const void *key, void *value, void *userdata); + void initExportObjectsMenus(); + + // in main_window_slots.cpp + /** + * @brief startCapture + * Start capturing from the selected interfaces using the capture filter + * shown in the main welcome screen. + */ + void startCapture(QStringList); + void startCapture(); + void pipeTimeout(); + void pipeActivated(int source); + void pipeNotifierDestroyed(); + void stopCapture(); + + void loadWindowGeometry(); + void saveWindowGeometry(); + void mainStackChanged(int); + void updateRecentCaptures(); + void recentActionTriggered(); + void actionAddPacketComment(); + void actionEditPacketComment(); + void actionDeletePacketComment(); + void actionDeleteCommentsFromPackets(); + QString commentToMenuText(QString text, int max_len = 40); + void setEditCommentsMenu(); + void setMenusForSelectedPacket(); + void setMenusForSelectedTreeRow(FieldInformation *fi = NULL); + void interfaceSelectionChanged(); + void captureFilterSyntaxChanged(bool valid); + void redissectPackets(); + void checkDisplayFilter(); + void fieldsChanged(); + void reloadLuaPlugins(); + void showAccordionFrame(AccordionFrame *show_frame, bool toggle = false); + void showColumnEditor(int column); + void showPreferenceEditor(); // module_t *, pref * + void addStatsPluginsToMenu(); + void addDynamicMenus(); + void reloadDynamicMenus(); + void addPluginIFStructures(); + QMenu * searchSubMenu(QString objectName); + void activatePluginIFToolbar(bool); + + void startInterfaceCapture(bool valid, const QString capture_filter); + + void applyGlobalCommandLineOptions(); + void setFeaturesEnabled(bool enabled = true); + + void on_actionDisplayFilterExpression_triggered(); + void on_actionNewDisplayFilterExpression_triggered(); + void onFilterSelected(QString, bool); + void onFilterPreferences(); + void onFilterEdit(int uatIndex); + + // Handle FilterAction signals + void queuedFilterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type); + + /** Pass stat cmd arguments to a slot. + * @param menu_path slot Partial slot name, e.g. "StatisticsIOGraph". + * @param arg "-z" argument, e.g. "io,stat". + * @param userdata Optional user data. + */ + void openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata); + + /** Pass tap parameter arguments to a slot. + * @param cfg_str slot Partial slot name, e.g. "StatisticsAFPSrt". + * @param arg "-z" argument, e.g. "afp,srt". + * @param userdata Optional user data. + */ + void openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata); + void openTapParameterDialog(); + +#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) + void softwareUpdateRequested(); +#endif + + // Automatically connected slots ("on__"). + // + // The slots below follow the naming conventaion described in + // https://doc.qt.io/archives/qt-4.8/qmetaobject.html#connectSlotsByName + // and are automatically connected at initialization time via + // main_ui_->setupUi, which in turn calls connectSlotsByName. + // + // If you're manually connecting a signal to a slot, don't prefix its name + // with "on_". Otherwise you'll get runtime warnings. + + // We might want move these to main_window_actions.cpp similar to + // gtk/main_menubar.c + + void on_actionFileOpen_triggered(); + void on_actionFileMerge_triggered(); + void on_actionFileImportFromHexDump_triggered(); + void on_actionFileClose_triggered(); + void on_actionFileSave_triggered(); + void on_actionFileSaveAs_triggered(); + void on_actionFileSetListFiles_triggered(); + void on_actionFileSetNextFile_triggered(); + void on_actionFileSetPreviousFile_triggered(); + void on_actionFileExportPackets_triggered(); + void on_actionFileExportAsPlainText_triggered(); + // We're dropping PostScript exports + void on_actionFileExportAsCSV_triggered(); + void on_actionFileExportAsCArrays_triggered(); + void on_actionFileExportAsPSML_triggered(); + void on_actionFileExportAsPDML_triggered(); + void on_actionFileExportAsJSON_triggered(); + void on_actionFileExportPacketBytes_triggered(); + void on_actionFilePrint_triggered(); + + void on_actionFileExportPDU_triggered(); + void on_actionFileExportTLSSessionKeys_triggered(); + + void actionEditCopyTriggered(LogwolfMainWindow::CopySelected selection_type); + void on_actionCopyAllVisibleItems_triggered(); + void on_actionCopyAllVisibleSelectedTreeItems_triggered(); + void on_actionCopyListAsText_triggered(); + void on_actionCopyListAsCSV_triggered(); + void on_actionCopyListAsYAML_triggered(); + void on_actionEditCopyDescription_triggered(); + void on_actionEditCopyFieldName_triggered(); + void on_actionEditCopyValue_triggered(); + void on_actionEditCopyAsFilter_triggered(); + void on_actionEditFindPacket_triggered(); + void on_actionEditFindNext_triggered(); + void on_actionEditFindPrevious_triggered(); + void on_actionEditMarkPacket_triggered(); + void on_actionEditMarkAllDisplayed_triggered(); + void on_actionEditUnmarkAllDisplayed_triggered(); + void on_actionEditNextMark_triggered(); + void on_actionEditPreviousMark_triggered(); + void on_actionEditIgnorePacket_triggered(); + void on_actionEditIgnoreAllDisplayed_triggered(); + void on_actionEditUnignoreAllDisplayed_triggered(); + void on_actionEditSetTimeReference_triggered(); + void on_actionEditUnsetAllTimeReferences_triggered(); + void on_actionEditNextTimeReference_triggered(); + void on_actionEditPreviousTimeReference_triggered(); + void on_actionEditTimeShift_triggered(); + void editTimeShiftFinished(int); + void addPacketCommentFinished(PacketCommentDialog* pc_dialog, int result); + void editPacketCommentFinished(PacketCommentDialog* pc_dialog, int result, guint nComment); + void on_actionDeleteAllPacketComments_triggered(); + void deleteAllPacketCommentsFinished(int result); + void on_actionEditConfigurationProfiles_triggered(); + void showPreferencesDialog(QString module_name); + void on_actionEditPreferences_triggered(); + + void showHideMainWidgets(QAction *action); + void setTimestampFormat(QAction *action); + void setTimestampPrecision(QAction *action); + void on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked); + void on_actionViewEditResolvedName_triggered(); + void setNameResolution(); + void on_actionViewNameResolutionPhysical_triggered(); + void on_actionViewNameResolutionNetwork_triggered(); + void on_actionViewNameResolutionTransport_triggered(); + // XXX We're not porting the concurrency action from GTK+ on purpose. + void zoomText(); + void on_actionViewZoomIn_triggered(); + void on_actionViewZoomOut_triggered(); + void on_actionViewNormalSize_triggered(); + void on_actionViewColorizePacketList_triggered(bool checked); + void on_actionViewColoringRules_triggered(); + void colorizeConversation(bool create_rule = false); + void colorizeActionTriggered(); + void on_actionViewColorizeResetColorization_triggered(); + void on_actionViewColorizeNewColoringRule_triggered(); + void on_actionViewResetLayout_triggered(); + void on_actionViewResizeColumns_triggered(); + + void on_actionViewInternalsConversationHashTables_triggered(); + void on_actionViewInternalsDissectorTables_triggered(); + void on_actionViewInternalsSupportedProtocols_triggered(); + + void openPacketDialog(bool from_reference = false); + void on_actionViewShowPacketInNewWindow_triggered(); + void on_actionContextShowLinkedPacketInNewWindow_triggered(); + void on_actionViewReload_triggered(); + void on_actionViewReload_as_File_Format_or_Capture_triggered(); + + void on_actionGoGoToPacket_triggered(); + void on_actionGoGoToLinkedPacket_triggered(); + void on_actionGoNextConversationPacket_triggered(); + void on_actionGoPreviousConversationPacket_triggered(); + void on_actionGoAutoScroll_toggled(bool checked); + void resetPreviousFocus(); + + void on_actionCaptureOptions_triggered(); +#ifdef HAVE_LIBPCAP + void on_actionCaptureRefreshInterfaces_triggered(); +#endif + void on_actionCaptureCaptureFilters_triggered(); + + void on_actionAnalyzeDisplayFilters_triggered(); + void on_actionAnalyzeDisplayFilterMacros_triggered(); + void matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type); + void on_actionAnalyzeCreateAColumn_triggered(); + + void filterMenuAboutToShow(); + + void applyConversationFilter(); + void applyExportObject(); + + void on_actionAnalyzeEnabledProtocols_triggered(); + void on_actionAnalyzeDecodeAs_triggered(); + void on_actionAnalyzeReloadLuaPlugins_triggered(); + + void openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index = true); + void openFollowStreamDialogForType(follow_type_t type); + void on_actionAnalyzeFollowTCPStream_triggered(); + void on_actionAnalyzeFollowUDPStream_triggered(); + void on_actionAnalyzeFollowDCCPStream_triggered(); + void on_actionAnalyzeFollowTLSStream_triggered(); + void on_actionAnalyzeFollowHTTPStream_triggered(); + void on_actionAnalyzeFollowHTTP2Stream_triggered(); + void on_actionAnalyzeFollowQUICStream_triggered(); + void on_actionAnalyzeFollowSIPCall_triggered(); + + void statCommandExpertInfo(const char *, void *); + void on_actionAnalyzeExpertInfo_triggered(); + + void on_actionHelpContents_triggered(); + void on_actionHelpMPWireshark_triggered(); + void on_actionHelpMPWireshark_Filter_triggered(); + void on_actionHelpMPCapinfos_triggered(); + void on_actionHelpMPDumpcap_triggered(); + void on_actionHelpMPEditcap_triggered(); + void on_actionHelpMPMergecap_triggered(); + void on_actionHelpMPRawshark_triggered(); + void on_actionHelpMPReordercap_triggered(); + void on_actionHelpMPText2pcap_triggered(); + void on_actionHelpMPTShark_triggered(); + void on_actionHelpWebsite_triggered(); + void on_actionHelpFAQ_triggered(); + void on_actionHelpAsk_triggered(); + void on_actionHelpDownloads_triggered(); + void on_actionHelpWiki_triggered(); + void on_actionHelpSampleCaptures_triggered(); + void on_actionHelpAbout_triggered(); + +#ifdef HAVE_SOFTWARE_UPDATE + void checkForUpdates(); +#endif + + void on_goToCancel_clicked(); + void on_goToGo_clicked(); + void on_goToLineEdit_returnPressed(); + void on_actionCaptureStart_triggered(); + void on_actionCaptureStop_triggered(); + void on_actionCaptureRestart_triggered(); + + void on_actionStatisticsCaptureFileProperties_triggered(); + void on_actionStatisticsResolvedAddresses_triggered(); + void on_actionStatisticsProtocolHierarchy_triggered(); + void on_actionStatisticsFlowGraph_triggered(); + void openTcpStreamDialog(int graph_type); + void on_actionStatisticsTcpStreamStevens_triggered(); + void on_actionStatisticsTcpStreamTcptrace_triggered(); + void on_actionStatisticsTcpStreamThroughput_triggered(); + void on_actionStatisticsTcpStreamRoundTripTime_triggered(); + void on_actionStatisticsTcpStreamWindowScaling_triggered(); + void openSCTPAllAssocsDialog(); + void on_actionSCTPShowAllAssociations_triggered(); + void on_actionSCTPAnalyseThisAssociation_triggered(); + void on_actionSCTPFilterThisAssociation_triggered(); + void statCommandMulticastStatistics(const char *arg, void *); + void on_actionStatisticsUdpMulticastStreams_triggered(); + + void openStatisticsTreeDialog(const gchar *abbr); + void on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered(); + void on_actionStatistics29WestTopics_Advertisements_by_Source_triggered(); + void on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered(); + void on_actionStatistics29WestTopics_Queries_by_Topic_triggered(); + void on_actionStatistics29WestTopics_Queries_by_Receiver_triggered(); + void on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered(); + void on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered(); + void on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered(); + void on_actionStatistics29WestQueues_Advertisements_by_Source_triggered(); + void on_actionStatistics29WestQueues_Queries_by_Queue_triggered(); + void on_actionStatistics29WestQueues_Queries_by_Receiver_triggered(); + void on_actionStatistics29WestUIM_Streams_triggered(); + void on_actionStatistics29WestLBTRM_triggered(); + void on_actionStatistics29WestLBTRU_triggered(); + void on_actionStatisticsANCP_triggered(); + void on_actionStatisticsBACappInstanceId_triggered(); + void on_actionStatisticsBACappIP_triggered(); + void on_actionStatisticsBACappObjectId_triggered(); + void on_actionStatisticsBACappService_triggered(); + void on_actionStatisticsCollectd_triggered(); + void statCommandConversations(const char *arg = NULL, void *userdata = NULL); + void on_actionStatisticsConversations_triggered(); + void statCommandEndpoints(const char *arg = NULL, void *userdata = NULL); + void on_actionStatisticsEndpoints_triggered(); + void on_actionStatisticsHART_IP_triggered(); + void on_actionStatisticsHTTPPacketCounter_triggered(); + void on_actionStatisticsHTTPRequests_triggered(); + void on_actionStatisticsHTTPLoadDistribution_triggered(); + void on_actionStatisticsHTTPRequestSequences_triggered(); + void on_actionStatisticsPacketLengths_triggered(); + void statCommandIOGraph(const char *, void *); + void on_actionStatisticsIOGraph_triggered(); + void on_actionStatisticsSametime_triggered(); + void on_actionStatisticsDNS_triggered(); + void actionStatisticsPlugin_triggered(); + void on_actionStatisticsHpfeeds_triggered(); + void on_actionStatisticsHTTP2_triggered(); + void on_actionStatisticsSOMEIPmessages_triggered(); + void on_actionStatisticsSOMEIPSDentries_triggered(); + + RtpStreamDialog *openTelephonyRtpStreamsDialog(); + RtpPlayerDialog *openTelephonyRtpPlayerDialog(); + VoipCallsDialog *openTelephonyVoipCallsDialogVoip(); + VoipCallsDialog *openTelephonyVoipCallsDialogSip(); + RtpAnalysisDialog *openTelephonyRtpAnalysisDialog(); + void on_actionTelephonyVoipCalls_triggered(); + void on_actionTelephonyGsmMapSummary_triggered(); + void statCommandLteMacStatistics(const char *arg, void *); + void on_actionTelephonyLteRlcStatistics_triggered(); + void statCommandLteRlcStatistics(const char *arg, void *); + void on_actionTelephonyLteMacStatistics_triggered(); + void on_actionTelephonyLteRlcGraph_triggered(); + void on_actionTelephonyIax2StreamAnalysis_triggered(); + void on_actionTelephonyISUPMessages_triggered(); + void on_actionTelephonyMtp3Summary_triggered(); + void on_actionTelephonyOsmuxPacketCounter_triggered(); + void on_actionTelephonyRtpStreams_triggered(); + void on_actionTelephonyRtpStreamAnalysis_triggered(); + void on_actionTelephonyRtpPlayer_triggered(); + void on_actionTelephonyRTSPPacketCounter_triggered(); + void on_actionTelephonySMPPOperations_triggered(); + void on_actionTelephonyUCPMessages_triggered(); + void on_actionTelephonyF1APMessages_triggered(); + void on_actionTelephonyNGAPMessages_triggered(); + void on_actionTelephonySipFlows_triggered(); + + void on_actionToolsFirewallAclRules_triggered(); + void on_actionToolsCredentials_triggered(); + + void externalMenuItem_triggered(); + + void on_actionAnalyzeShowPacketBytes_triggered(); + + void on_actionContextWikiProtocolPage_triggered(); + void on_actionContextFilterFieldReference_triggered(); + + void extcap_options_finished(int result); + void showExtcapOptionsDialog(QString & device_name, bool startCaptureOnClose); + + QString findRtpStreams(QVector *stream_ids, bool reverse); + + friend class MainApplication; +}; + +#endif // LOGWOLF_MAIN_WINDOW_H diff --git a/ui/qt_logshark/logwolf_main_window.ui b/ui/qt_logshark/logwolf_main_window.ui new file mode 100644 index 0000000000..fadc2e711e --- /dev/null +++ b/ui/qt_logshark/logwolf_main_window.ui @@ -0,0 +1,3069 @@ + + + LogwolfMainWindow + + + + 0 + 0 + 960 + 768 + + + + true + + + Wireshark + + + true + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 10 + + + + + + + + Packet: + + + + + + + + + + + + 16777215 + 27 + + + + Go to packet + + + true + + + + + + + + 16777215 + 27 + + + + Cancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + 0 + 0 + 960 + 22 + + + + + &File + + + + Open &Recent + + + + + + File Set + + + + + + + + Export Packet Dissections + + + + + + + + + + + + Export Objects + + + + + + + + + + + + + + + + + + + + + + + + + + + &Capture + + + + + + + + + + + + &Help + + + true + + + + Manual pages + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &Go + + + + + + + + + + + + + + + + + + &View + + + + Interface Toolbars + + + + + &Zoom + + + + + + + + &Time Display Format + + + + + + + + + + + + + + + + + + + + + + + + + Name Resol&ution + + + + + + + + + + Colorize Conversation + + + + + + + + + + + + + + + + + + Internals + + + + + + + + Additional Toolbars + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &Analyze + + + + Apply as Filter + + + + + Prepare as Filter + + + + + SCTP + + + + + + + + Follow + + + + + + + + + + + + + Conversation Filter + + + + + + + + + + + + + + + + + + + + + + + + true + + + &Statistics + + + + TCP Stream Graphs + + + + + + + + + + BACnet + + + + + + + + + HTTP + + + + + + + + + 29West + + + + Topics + + + + + + + + + + + + Queues + + + + + + + + + UIM + + + + + + + + + + + + Service &Response Time + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Reliable Server Pooling (RSerPool) + + + + + + + SOME/IP + + + + + + + + Telephon&y + + + + RTSP + + + + + + &RTP + + + + + + + + S&CTP + + + + + + + &ANSI + + + + + + &GSM + + + + + + &LTE + + + + + + &MTP3 + + + + + + Osmux + + + + + + + + + + + + + + + + + + + + + + &Edit + + + + Copy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Packet Comments + + + + + + + + + + + &Tools + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Main Toolbar + + + false + + + + 32 + 32 + + + + Qt::ToolButtonIconOnly + + + TopToolBarArea + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Display Filter Toolbar + + + false + + + + 14 + 14 + + + + TopToolBarArea + + + true + + + + + + Wireless Toolbar + + + false + + + TopToolBarArea + + + true + + + + + &Open + + + Open a capture file + + + Ctrl+O + + + false + + + + + &Quit + + + Quit Wireshark + + + Ctrl+Q + + + QAction::QuitRole + + + + + true + + + &Start + + + Start capturing packets + + + Ctrl+E + + + + + S&top + + + Stop capturing packets + + + Ctrl+E + + + + + &Close + + + Close this capture file + + + Ctrl+W + + + false + + + + + false + + + No files found + + + + + &Contents + + + Help contents + + + F1 + + + true + + + + + Wireshark + + + + + Wireshark Filter + + + + + TShark + + + + + Rawshark + + + + + Dumpcap + + + + + Mergecap + + + + + Editcap + + + + + Text2pcap + + + + + + :/menu/help/wsicon16.png:/menu/help/wsicon16.png + + + Website + + + + + FAQs + + + + + Downloads + + + + + + :/menu/help/wsicon16.png:/menu/help/wsicon16.png + + + Wiki + + + true + + + + + Sample Captures + + + + + &About Wireshark + + + QAction::AboutRole + + + + + + :/menu/help/wsicon-ask.png:/menu/help/wsicon-ask.png + + + Ask (Q&&A) + + + true + + + + + Next Packet + + + Go to the next packet + + + Ctrl+Down + + + + + Previous Packet + + + Go to the previous packet + + + Ctrl+Up + + + + + Next Packet in Conversation + + + Go to the next packet in this conversation + + + Ctrl+. + + + + + Previous Packet in Conversation + + + Go to the previous packet in this conversation + + + Ctrl+, + + + + + Next Packet In History + + + Go to the next packet in your selection history + + + Alt+Right + + + + + Previous Packet In History + + + Go to the previous packet in your selection history + + + Alt+Left + + + + + First Packet + + + Go to the first packet + + + Ctrl+Home + + + + + Last Packet + + + Go to the last packet + + + Ctrl+End + + + + + false + + + E&xpand Subtrees + + + Expand the current packet detail + + + Shift+Right + + + + + false + + + Collapse Subtrees + + + Collapse the current packet detail + + + Shift+Left + + + + + &Expand All + + + Expand packet details + + + Ctrl+Right + + + + + Collapse &All + + + Collapse all packet details + + + Ctrl+Left + + + + + true + + + Go to Packet… + + + Go to specified packet + + + Ctrl+G + + + + + &Merge… + + + Merge one or more files + + + + + &Import from Hex Dump… + + + Import a file + + + + + &Save + + + Save this capture file + + + Ctrl+S + + + false + + + + + Save &As… + + + Save as a different file + + + Ctrl+Shift+S + + + + + Export Specified Packets… + + + Export specified packets + + + + + Export Packet &Bytes… + + + Ctrl+Shift+X + + + + + Export TLS Session Keys… + + + + + &Print… + + + Ctrl+P + + + + + List Files + + + + + Next File + + + + + Previous File + + + + + &Reload + + + Reload this file + + + Ctrl+R + + + true + + + + + Reload as File Format/Capture + + + Ctrl+Shift+F + + + + + &Options… + + + Options + + + Capture options + + + Ctrl+K + + + QAction::NoRole + + + + + Capture &Filters… + + + Capture filters + + + + + Refresh Interfaces + + + Refresh interfaces + + + F5 + + + + + &Restart + + + Restart current capture + + + Ctrl+R + + + + + As Plain &Text… + + + + + As &CSV… + + + + + As "C" &Arrays… + + + + + As P&SML XML… + + + + + As P&DML XML… + + + + + As &JSON… + + + + + Description + + + Copy this item's description + + + Ctrl+Alt+Shift+D + + + + + As Plain &Text + + + + + As &CSV + + + + + As &YAML + + + + + All Visible Items + + + Ctrl+Alt+Shift+A + + + + + All Visible Selected Tree Items + + + + + Field Name + + + Copy this item's field name + + + Ctrl+Alt+Shift+F + + + + + Value + + + Copy this item's value + + + Ctrl+Alt+Shift+V + + + + + As Filter + + + Copy this item as a display filter + + + Ctrl+Shift+C + + + + + Display &Filters… + + + + + Display Filter &Macros… + + + + + Apply as Column + + + Create a packet list column from the selected field. + + + Ctrl+Shift+I + + + + + &Find Packet… + + + Find a packet + + + Ctrl+F + + + + + Find Ne&xt + + + Find the next packet + + + Ctrl+N + + + + + Find Pre&vious + + + Find the previous packet + + + Ctrl+B + + + + + &Mark/Unmark Packet(s) + + + Mark or unmark each selected packet + + + Ctrl+M + + + + + Mark All Displayed + + + Mark all displayed packets + + + Ctrl+Shift+M + + + + + &Unmark All Displayed + + + Unmark all displayed packets + + + Ctrl+Alt+M + + + + + Next Mark + + + Go to the next marked packet + + + Ctrl+Shift+N + + + + + Previous Mark + + + Go to the previous marked packet + + + Ctrl+Shift+B + + + + + &Ignore/Unignore Packet(s) + + + Ignore or unignore each selected packet + + + Ctrl+D + + + + + Ignore All Displayed + + + Ignore all displayed packets + + + Ctrl+Shift+D + + + + + U&nignore All Displayed + + + Unignore all displayed packets + + + Ctrl+Alt+D + + + + + Set/Unset Time Reference + + + Set or unset a time reference for this packet + + + Ctrl+T + + + + + Unset All Time References + + + Remove all time references + + + Ctrl+Alt+T + + + + + Next Time Reference + + + Go to the next time reference + + + Ctrl+Alt+N + + + + + Previous Time Reference + + + Go to the previous time reference + + + Ctrl+Alt+B + + + + + Time Shift… + + + Shift or change packet timestamps + + + Ctrl+Shift+T + + + + + Delete All Packet Comments + + + Remove all packet comments in the capture file + + + + + false + + + &Configuration Profiles… + + + Configuration profiles + + + Manage your configuration profiles + + + Ctrl+Shift+A + + + QAction::NoRole + + + + + &Preferences… + + + Manage Wireshark's preferences + + + Ctrl+Shift+P + + + QAction::PreferencesRole + + + + + false + + + Capture File Properties + + + Capture file properties + + + Ctrl+Alt+Shift+C + + + + + false + + + &Protocol Hierarchy + + + Show a summary of protocols present in the capture file. + + + + + Capinfos + + + + + Reordercap + + + + + Time Sequence (Stevens) + + + TCP time sequence graph (Stevens) + + + + + Throughput + + + TCP throughput + + + + + Round Trip Time + + + TCP round trip time + + + + + Window Scaling + + + TCP window scaling + + + + + false + + + TCP Stream + + + Ctrl+Alt+Shift+T + + + + + false + + + UDP Stream + + + Ctrl+Alt+Shift+U + + + + + false + + + DCCP Stream + + + Ctrl+Alt+Shift+E + + + + + false + + + TLS Stream + + + Ctrl+Alt+Shift+S + + + + + false + + + HTTP Stream + + + Ctrl+Alt+Shift+H + + + + + false + + + HTTP/2 Stream + + + + + false + + + QUIC Stream + + + + + false + + + SIP Call + + + + + Time Sequence (tcptrace) + + + TCP time sequence graph (tcptrace) + + + + + Analyse this Association + + + + + Show All Associations + + + + + Flow Graph + + + Flow sequence diagram + + + + + ANCP + + + ANCP statistics + + + + + Packets sorted by Instance ID + + + BACapp statistics sorted by instance ID + + + + + Packets sorted by IP + + + BACapp statistics sorted by IP + + + + + Packets sorted by object type + + + BACapp statistics sorted by object type + + + + + Packets sorted by service + + + BACapp statistics sorted by service + + + + + Collectd + + + Collectd statistics + + + + + DNS + + + DNS statistics + + + + + HART-IP + + + HART-IP statistics + + + + + HPFEEDS + + + hpfeeds statistics + + + + + HTTP2 + + + HTTP2 statistics + + + + + Packet Counter + + + HTTP packet counter + + + + + Requests + + + HTTP requests + + + + + Load Distribution + + + HTTP load distribution + + + + + Request Sequences + + + HTTP Request Sequences + + + + + Packet Lengths + + + Packet length statistics + + + + + Sametime + + + Sametime statistics + + + + + SOME/IP Messages + + + SOME/IP Message statistics + + + + + SOME/IP-SD Entries + + + SOME/IP-SD Entries statistics + + + + + &ISUP Messages + + + ISUP message statistics + + + + + Packet Counter + + + Osmux packet counts + + + + + Packet Counter + + + RTSP packet counts + + + + + SM&PP Operations + + + SMPP operation statistics + + + + + &UCP Messages + + + UCP message statistics + + + + + F1AP + + + F1AP Messages + + + + + NGAP + + + NGAP Messages + + + + + Decode &As… + + + Change the way packets are dissected + + + Ctrl+Shift+U + + + + + Reload Lua Plugins + + + Reload Lua plugins + + + Ctrl+Shift+L + + + + + 29West + + + + + Advertisements by Topic + + + + + Advertisements by Source + + + + + Advertisements by Transport + + + + + Queries by Topic + + + + + Queries by Receiver + + + + + Wildcard Queries by Pattern + + + + + Wildcard Queries by Receiver + + + + + Advertisements by Queue + + + + + Advertisements by Source + + + + + Queries by Queue + + + + + Queries by Receiver + + + + + Streams + + + + + LBT-RM + + + + + LBT-RU + + + + + Filter this Association + + + Filter this Association + + + + + Export PDUs to File… + + + + + &I/O Graphs + + + Create graphs based on display filter fields + + + + + true + + + true + + + &Main Toolbar + + + Show or hide the main toolbar + + + + + true + + + true + + + &Filter Toolbar + + + Show or hide the display filter toolbar + + + + + &Conversations + + + Conversations at different protocol levels + + + + + &Endpoints + + + Endpoints at different protocol levels + + + + + true + + + Colorize Packet List + + + Draw packets using your coloring rules + + + + + &Zoom In + + + Enlarge the main window text + + + Ctrl++ + + + + + Zoom Out + + + Shrink the main window text + + + Ctrl+- + + + + + Normal Size + + + Return the main window text to its normal size + + + Ctrl+0 + + + + + Reset Layout + + + Reset appearance layout to default size + + + Ctrl+Shift+W + + + + + Resize Columns + + + Resize packet list columns to fit contents + + + Ctrl+Shift+R + + + + + true + + + Date and Time of Day (1970-01-01 01:02:03.123456) + + + Show packet times as the date and time of day. + + + Ctrl+Alt+1 + + + + + true + + + Year, Day of Year, and Time of Day (1970/001 01:02:03.123456) + + + Show packet times as the year, day of the year and time of day. + + + + + true + + + Time of Day (01:02:03.123456) + + + Show packet times as the date and time of day. + + + Ctrl+Alt+2 + + + + + true + + + Seconds Since 1970-01-01 + + + Show packet times as the seconds since the UNIX / POSIX epoch (1970-01-01). + + + Ctrl+Alt+3 + + + + + true + + + Seconds Since Beginning of Capture + + + Show packet times as the date and time of day. + + + Ctrl+Alt+4 + + + + + true + + + Seconds Since Previous Captured Packet + + + Show packet times as the seconds since the previous captured packet. + + + Ctrl+Alt+5 + + + + + true + + + Seconds Since Previous Displayed Packet + + + Show packet times as the seconds since the previous displayed packet. + + + Ctrl+Alt+6 + + + + + true + + + UTC Date and Time of Day (1970-01-01 01:02:03.123456) + + + Show packet times as the UTC date and time of day. + + + Ctrl+Alt+7 + + + + + true + + + UTC Year, Day of Year, and Time of Day (1970/001 01:02:03.123456) + + + Show packet times as the UTC year, day of the year and time of day. + + + + + true + + + UTC Time of Day (01:02:03.123456) + + + Show packet times as the UTC time of day. + + + Ctrl+Alt+8 + + + + + true + + + Automatic (from capture file) + + + Use the time precision indicated in the capture file. + + + + + true + + + Seconds + + + + + true + + + Tenths of a second + + + + + true + + + Hundredths of a second + + + + + true + + + Milliseconds + + + + + true + + + Microseconds + + + + + true + + + Nanoseconds + + + + + true + + + Display Seconds With Hours and Minutes + + + Display seconds with hours and minutes + + + + + true + + + Resolve &Physical Addresses + + + Show names for known MAC addresses. Lookups use a local database. + + + + + true + + + Resolve &Network Addresses + + + Show names for known IPv4, IPv6, and IPX addresses. Lookups can generate network traffic. + + + + + true + + + Resolve &Transport Addresses + + + Show names for known TCP, UDP, and SCTP services. Lookups can generate traffic on some systems. + + + + + true + + + Wire&less Toolbar + + + Show or hide the wireless toolbar + + + + + true + + + true + + + &Status Bar + + + Show or hide the status bar + + + + + true + + + true + + + Packet &List + + + Show or hide the packet list + + + + + true + + + true + + + Packet &Details + + + Show or hide the packet details + + + + + true + + + true + + + Packet &Bytes + + + Show or hide the packet bytes + + + + + true + + + true + + + Packet &Diagram + + + Show or hide the packet diagram + + + + + &Conversation Hash Tables + + + Show each conversation hash table + + + + + &Dissector Tables + + + Show each dissector table and its entries + + + + + &Supported Protocols + + + Show the currently supported protocols and display filter fields + + + + + MAP Summary + + + GSM MAP summary statistics + + + + + MAC Statistics + + + LTE MAC statistics + + + + + RLC Statistics + + + LTE RLC statistics + + + + + RLC &Graph + + + LTE RLC graph + + + + + MTP3 Summary + + + MTP3 summary statistics + + + + + &VoIP Calls + + + All VoIP Calls + + + + + SIP &Flows + + + SIP Flows + + + + + RTP Streams + + + + + &Coloring Rules… + + + Edit the packet list coloring rules. + + + + + Show Packet in New &Window + + + Show this packet in a separate window. + + + + + Show Linked Packet in New Window + + + Show the linked packet in a separate window. + + + + + true + + + Auto Scroll in Li&ve Capture + + + Automatically scroll to the last packet during a live capture. + + + + + Expert Information + + + Show expert notifications + + + + + Display Filter &Expression… + + + Display Filter Expression… + + + Add an expression to the display filter. + + + + + REGISTER_STAT_GROUP_UNSORTED + + + Start of "REGISTER_STAT_GROUP_UNSORTED" + + + false + + + QAction::NoRole + + + + + REGISTER_STAT_GROUP_RSERPOOL + + + Start of "REGISTER_STAT_GROUP_RSERPOOL" + + + false + + + QAction::NoRole + + + + + false + + + No ANSI statistics registered + + + + + false + + + No GSM statistics registered + + + + + false + + + No LTE statistics registered + + + + + false + + + No MTP3 statistics registered + + + + + Resolved Addresses + + + Show each table of resolved addresses as copyable text. + + + + + Color &1 + + + Mark the current conversation with its own color. + + + Ctrl+1 + + + + + Color &2 + + + Mark the current conversation with its own color. + + + Ctrl+2 + + + + + Color &3 + + + Mark the current conversation with its own color. + + + Ctrl+3 + + + + + Color &4 + + + Mark the current conversation with its own color. + + + Ctrl+4 + + + + + Color &5 + + + Mark the current conversation with its own color. + + + Ctrl+5 + + + + + Color &6 + + + Mark the current conversation with its own color. + + + Ctrl+6 + + + + + Color &7 + + + Mark the current conversation with its own color. + + + Ctrl+7 + + + + + Color &8 + + + Mark the current conversation with its own color. + + + Ctrl+8 + + + + + Color &9 + + + Mark the current conversation with its own color. + + + Ctrl+9 + + + + + Color 1&0 + + + Mark the current conversation with its own color. + + + + + New Coloring Rule… + + + Create a new coloring rule based on this field. + + + + + Reset Colorization + + + Reset colorized conversations. + + + Ctrl+Space + + + + + RTP Stream Analysis + + + RTP Stream Analysis for selected stream. Press CTRL key for adding reverse stream too. + + + + + RTP Player + + + Play selected stream. Press CTRL key for playing reverse stream too. + + + + + IA&X2 Stream Analysis + + + IAX2 Stream Analysis + + + + + Edit Resolved Name + + + Manually edit a name resolution entry. + + + + + Enabled Protocols… + + + Enable and disable specific protocols + + + Ctrl+Shift+E + + + + + Show Packet Bytes… + + + Ctrl+Shift+O + + + + + Wiki Protocol Page + + + Open the Wireshark wiki page for this protocol. + + + + + Filter Field Reference + + + Open the display filter reference page for this filter field. + + + + + Go to &Linked Packet + + + Go to the packet referenced by the selected field. + + + + + UDP Multicast Streams + + + Show UTP multicast stream statistics. + + + + + Add a display filter button. + + + + + Firewall ACL Rules + + + Create firewall ACL rules + + + + + true + + + &Full Screen + + + + + Credentials + + + + + + + AccordionFrame + QFrame +
accordion_frame.h
+ 1 +
+ + MainStatusBar + QStatusBar +
main_status_bar.h
+
+ + WelcomePage + QFrame +
welcome_page.h
+ 1 +
+ + SearchFrame + QWidget +
search_frame.h
+
+ + ColumnEditorFrame + QFrame +
column_editor_frame.h
+ 1 +
+ + PreferenceEditorFrame + QFrame +
preference_editor_frame.h
+ 1 +
+ + AddressEditorFrame + QFrame +
address_editor_frame.h
+ 1 +
+ + FilterExpressionFrame + QFrame +
filter_expression_frame.h
+ 1 +
+ + WirelessTimeline + QWidget +
widgets/wireless_timeline.h
+ 1 +
+
+ + + + + + actionFileQuit + triggered() + LogwolfMainWindow + close() + + + -1 + -1 + + + 408 + 258 + + + + +
diff --git a/ui/qt_logshark/logwolf_main_window_slots.cpp b/ui/qt_logshark/logwolf_main_window_slots.cpp new file mode 100644 index 0000000000..6f4764c3a6 --- /dev/null +++ b/ui/qt_logshark/logwolf_main_window_slots.cpp @@ -0,0 +1,4197 @@ +/* main_window_slots.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include + +// Qt 5.5.0 + Visual C++ 2013 +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4996) +#endif + +#include "logwolf_main_window.h" + +/* + * The generated Ui_LogwolfMainWindow::setupUi() can grow larger than our configured limit, + * so turn off -Wframe-larger-than= for ui_main_window.h. + */ +DIAG_OFF(frame-larger-than=) +#include +DIAG_ON(frame-larger-than=) + +#ifdef _WIN32 +#include +#endif + +#include "ui/dissect_opts.h" + +#ifdef HAVE_LIBPCAP +#include "ui/capture.h" +#endif + +#include "ui/commandline.h" + +#include "ui/urls.h" + +#include "epan/color_filters.h" +#include "epan/export_object.h" + +#include "wsutil/file_util.h" +#include "wsutil/filesystem.h" +#include +#include + +#include "epan/addr_resolv.h" +#include "epan/column.h" +#include "epan/dfilter/dfilter-macro.h" +#include "epan/conversation_filter.h" +#include "epan/epan_dissect.h" +#include "epan/filter_expressions.h" +#include "epan/prefs.h" +#include "epan/plugin_if.h" +#include "epan/uat.h" +#include "epan/uat-int.h" +#include "epan/value_string.h" + +#ifdef HAVE_LUA +#include +#endif + +#include "ui/alert_box.h" +#ifdef HAVE_LIBPCAP +#include "ui/capture_ui_utils.h" +#endif + +#include "ui/capture_globals.h" +#include "ui/help_url.h" +#include "ui/main_statusbar.h" +#include "ui/preference_utils.h" +#include "ui/recent.h" +#include "ui/recent_utils.h" +#include "ui/ssl_key_export.h" +#include "ui/ws_ui_util.h" +#include "ui/all_files_wildcard.h" +#include "ui/qt/simple_dialog.h" + +#include +#include +#include "ui/qt/widgets/wireshark_file_dialog.h" + +#ifdef HAVE_SOFTWARE_UPDATE +#include "ui/software_update.h" +#endif + +#include "about_dialog.h" +#include "capture_file_dialog.h" +#include "capture_file_properties_dialog.h" +#ifdef HAVE_LIBPCAP +#include "capture_options_dialog.h" +#endif +#include +#include "coloring_rules_dialog.h" +#include "conversation_dialog.h" +#include "conversation_colorize_action.h" +#include "conversation_hash_tables_dialog.h" +#include "enabled_protocols_dialog.h" +#include "decode_as_dialog.h" +#include +#include "display_filter_expression_dialog.h" +#include "dissector_tables_dialog.h" +#include "endpoint_dialog.h" +#include "expert_info_dialog.h" +#include "export_object_action.h" +#include "export_object_dialog.h" +#include "export_pdu_dialog.h" +#include "extcap_options_dialog.h" +#include "file_set_dialog.h" +#include "filter_action.h" +#include "filter_dialog.h" +#include "firewall_rules_dialog.h" +#include "funnel_statistics.h" +#include "gsm_map_summary_dialog.h" +#include "iax2_analysis_dialog.h" +#include "interface_toolbar.h" +#include "io_graph_dialog.h" +#include +#include "lbm_stream_dialog.h" +#include "lbm_lbtrm_transport_dialog.h" +#include "lbm_lbtru_transport_dialog.h" +#include "lte_mac_statistics_dialog.h" +#include "lte_rlc_statistics_dialog.h" +#include "lte_rlc_graph_dialog.h" +#include "main_application.h" +#include "mtp3_summary_dialog.h" +#include "multicast_statistics_dialog.h" +#include "packet_comment_dialog.h" +#include "packet_diagram.h" +#include "packet_dialog.h" +#include "packet_list.h" +#include "credentials_dialog.h" +#include "preferences_dialog.h" +#include "print_dialog.h" +#include "profile_dialog.h" +#include "protocol_hierarchy_dialog.h" +#include +#include "resolved_addresses_dialog.h" +#include "rpc_service_response_time_dialog.h" +#include "rtp_stream_dialog.h" +#include "rtp_analysis_dialog.h" +#include "sctp_all_assocs_dialog.h" +#include "sctp_assoc_analyse_dialog.h" +#include "sctp_graph_dialog.h" +#include "sequence_dialog.h" +#include "show_packet_bytes_dialog.h" +#include "stats_tree_dialog.h" +#include +#include "supported_protocols_dialog.h" +#include "tap_parameter_dialog.h" +#include "tcp_stream_dialog.h" +#include "time_shift_dialog.h" +#include "uat_dialog.h" +#include "voip_calls_dialog.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// XXX You must uncomment QT_WINEXTRAS_LIB lines in CMakeList.txt and +// cmakeconfig.h.in. +// #if defined(QT_WINEXTRAS_LIB) +// #include +// #include +// #include +// #endif + +// +// Public slots +// + +bool LogwolfMainWindow::openCaptureFile(QString cf_path, QString read_filter, unsigned int type, gboolean is_tempfile) +{ + QString file_name = ""; + dfilter_t *rfcode = NULL; + gchar *err_msg; + int err; + gboolean name_param; + gboolean ret = true; + + // was a file name given as function parameter? + name_param = !cf_path.isEmpty(); + + for (;;) { + + if (cf_path.isEmpty()) { + CaptureFileDialog open_dlg(this, capture_file_.capFile(), read_filter); + + if (open_dlg.open(file_name, type)) { + cf_path = file_name; + } else { + ret = false; + goto finish; + } + } else { + this->welcome_page_->getInterfaceFrame()->showRunOnFile(); + } + + // TODO detect call from "cf_read" -> "update_progress_dlg" + // ("capture_file_.capFile()->read_lock"), possibly queue opening the + // file and return early to avoid the warning in testCaptureFileClose. + + QString before_what(tr(" before opening another file")); + if (!testCaptureFileClose(before_what)) { + ret = false; + goto finish; + } + + if (dfilter_compile(qUtf8Printable(read_filter), &rfcode, &err_msg)) { + cf_set_rfcode(CaptureFile::globalCapFile(), rfcode); + } else { + /* Not valid. Tell the user, and go back and run the file + selection box again once they dismiss the alert. */ + //bad_dfilter_alert_box(top_level, read_filter->str); + QMessageBox::warning(this, tr("Invalid Display Filter"), + QString("The filter expression ") + + read_filter + + QString(" isn't a valid display filter. (") + + err_msg + QString(")."), + QMessageBox::Ok); + + if (!name_param) { + // go back to the selection dialogue only if the file + // was selected from this dialogue + cf_path.clear(); + continue; + } + } + + /* Make the file name available via MainWindow */ + setMwFileName(cf_path); + + /* Try to open the capture file. This closes the current file if it succeeds. */ + CaptureFile::globalCapFile()->window = this; + if (cf_open(CaptureFile::globalCapFile(), qUtf8Printable(cf_path), type, is_tempfile, &err) != CF_OK) { + /* We couldn't open it; don't dismiss the open dialog box, + just leave it around so that the user can, after they + dismiss the alert box popped up for the open error, + try again. */ + CaptureFile::globalCapFile()->window = NULL; + dfilter_free(rfcode); + cf_path.clear(); + continue; + } + + switch (cf_read(CaptureFile::globalCapFile(), FALSE)) { + case CF_READ_OK: + case CF_READ_ERROR: + /* Just because we got an error, that doesn't mean we were unable + to read any of the file; we handle what we could get from the + file. */ + break; + + case CF_READ_ABORTED: + /* The user bailed out of re-reading the capture file; the + capture file has been closed - just free the capture file name + string and return (without changing the last containing + directory). */ + capture_file_.setCapFile(NULL); + ret = false; + goto finish; + } + break; + } + + mainApp->setLastOpenDirFromFilename(cf_path); + + main_ui_->statusBar->showExpert(); + +finish: +#ifdef HAVE_LIBPCAP + if (global_commandline_info.quit_after_cap) + exit(0); +#endif + return ret; +} + +void LogwolfMainWindow::filterPackets(QString new_filter, bool force) +{ + cf_status_t cf_status; + + cf_status = cf_filter_packets(CaptureFile::globalCapFile(), new_filter.toUtf8().data(), force); + + if (cf_status == CF_OK) { + if (new_filter.length() > 0) { + int index = df_combo_box_->findText(new_filter); + if (index == -1) { + df_combo_box_->insertItem(0, new_filter); + df_combo_box_->setCurrentIndex(0); + } else { + df_combo_box_->setCurrentIndex(index); + } + } else { + df_combo_box_->lineEdit()->clear(); + } + // Only after the display filter has been updated, + // disable the arrow button + emit displayFilterSuccess(true); + } else { + emit displayFilterSuccess(false); + } + if (packet_list_) { + packet_list_->resetColumns(); + } +} + +void LogwolfMainWindow::layoutToolbars() +{ + Qt::ToolButtonStyle tbstyle = Qt::ToolButtonIconOnly; + switch (prefs.gui_toolbar_main_style) { + case TB_STYLE_TEXT: + tbstyle = Qt::ToolButtonTextOnly; + break; + case TB_STYLE_BOTH: + tbstyle = Qt::ToolButtonTextUnderIcon; + break; + } + + main_ui_->mainToolBar->setToolButtonStyle(tbstyle); + + main_ui_->mainToolBar->setVisible(recent.main_toolbar_show); + main_ui_->displayFilterToolBar->setVisible(recent.filter_toolbar_show); +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + main_ui_->wirelessToolBar->setVisible(recent.wireless_toolbar_show); +#endif + main_ui_->statusBar->setVisible(recent.statusbar_show); + + foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + QToolBar *toolbar = action->data().value(); + if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp)) { + toolbar->setVisible(true); + } else { + toolbar->setVisible(false); + } + } + + QList toolbars = findChildren(); + foreach(QToolBar *bar, toolbars) { + AdditionalToolBar *iftoolbar = dynamic_cast(bar); + if (iftoolbar) { + bool visible = false; + if (g_list_find_custom(recent.gui_additional_toolbars, qUtf8Printable(iftoolbar->menuName()), (GCompareFunc)strcmp)) + visible = true; + + iftoolbar->setVisible(visible); + + } + } +} + +void LogwolfMainWindow::updatePreferenceActions() +{ + main_ui_->actionViewPacketList->setEnabled(prefs_has_layout_pane_content(layout_pane_content_plist)); + main_ui_->actionViewPacketDetails->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdetails)); + main_ui_->actionViewPacketBytes->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pbytes)); + main_ui_->actionViewPacketDiagram->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdiagram)); + + main_ui_->actionViewNameResolutionPhysical->setChecked(gbl_resolv_flags.mac_name); + main_ui_->actionViewNameResolutionNetwork->setChecked(gbl_resolv_flags.network_name); + main_ui_->actionViewNameResolutionTransport->setChecked(gbl_resolv_flags.transport_name); + + // Should this be a "recent" setting? + main_ui_->actionGoAutoScroll->setChecked(prefs.capture_auto_scroll); +} + +void LogwolfMainWindow::updateRecentActions() +{ + main_ui_->actionViewMainToolbar->setChecked(recent.main_toolbar_show); + main_ui_->actionViewFilterToolbar->setChecked(recent.filter_toolbar_show); + main_ui_->actionViewWirelessToolbar->setChecked(recent.wireless_toolbar_show); + main_ui_->actionViewStatusBar->setChecked(recent.statusbar_show); + main_ui_->actionViewPacketList->setChecked(recent.packet_list_show && prefs_has_layout_pane_content(layout_pane_content_plist)); + main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show && prefs_has_layout_pane_content(layout_pane_content_pdetails)); + main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show && prefs_has_layout_pane_content(layout_pane_content_pbytes)); + main_ui_->actionViewPacketDiagram->setChecked(recent.packet_diagram_show && prefs_has_layout_pane_content(layout_pane_content_pdiagram)); + + foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp)) { + action->setChecked(true); + } else { + action->setChecked(false); + } + } + + foreach(QAction * action, main_ui_->menuAdditionalToolbars->actions()) { + ext_toolbar_t * toolbar = VariantPointer::asPtr(action->data()); + bool checked = false; + if (toolbar && g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc)strcmp)) + checked = true; + + action->setChecked(checked); + } + + foreach(QAction* tda, td_actions.keys()) { + if (recent.gui_time_format == td_actions[tda]) { + tda->setChecked(true); + } + } + foreach(QAction* tpa, tp_actions.keys()) { + if (recent.gui_time_precision == tp_actions[tpa]) { + tpa->setChecked(true); + break; + } + } + main_ui_->actionViewTimeDisplaySecondsWithHoursAndMinutes->setChecked(recent.gui_seconds_format == TS_SECONDS_HOUR_MIN_SEC); + + main_ui_->actionViewColorizePacketList->setChecked(recent.packet_list_colorize); +} + +// Don't connect to this directly. Connect to or emit fiterAction(...) instead. +void LogwolfMainWindow::queuedFilterAction(QString action_filter, FilterAction::Action action, FilterAction::ActionType type) +{ + QString cur_filter, new_filter; + + if (!df_combo_box_) return; + cur_filter = df_combo_box_->lineEdit()->text(); + + switch (type) { + case FilterAction::ActionTypePlain: + new_filter = action_filter; + break; + case FilterAction::ActionTypeAnd: + if (cur_filter.length()) { + new_filter = "(" + cur_filter + ") && (" + action_filter + ")"; + } + else { + new_filter = action_filter; + } + break; + case FilterAction::ActionTypeOr: + if (cur_filter.length()) { + new_filter = "(" + cur_filter + ") || (" + action_filter + ")"; + } else { + new_filter = action_filter; + } + break; + case FilterAction::ActionTypeNot: + new_filter = "!(" + action_filter + ")"; + break; + case FilterAction::ActionTypeAndNot: + if (cur_filter.length()) { + new_filter = "(" + cur_filter + ") && !(" + action_filter + ")"; + } else { + new_filter = "!(" + action_filter + ")"; + } + break; + case FilterAction::ActionTypeOrNot: + if (cur_filter.length()) { + new_filter = "(" + cur_filter + ") || !(" + action_filter + ")"; + } else { + new_filter = "!(" + action_filter + ")"; + } + break; + default: + ws_assert_not_reached(); + break; + } + + switch (action) { + case FilterAction::ActionApply: + df_combo_box_->lineEdit()->setText(new_filter); + df_combo_box_->applyDisplayFilter(); + break; + case FilterAction::ActionColorize: + colorizeWithFilter(new_filter.toUtf8()); + break; + case FilterAction::ActionCopy: + mainApp->clipboard()->setText(new_filter); + break; + case FilterAction::ActionFind: + main_ui_->searchFrame->findFrameWithFilter(new_filter); + break; + case FilterAction::ActionPrepare: + df_combo_box_->lineEdit()->setText(new_filter); + df_combo_box_->lineEdit()->setFocus(); + break; + case FilterAction::ActionWebLookup: + { + QString url = QString("https://www.google.com/search?q=") + new_filter; + QDesktopServices::openUrl(QUrl(url)); + break; + } + default: + ws_assert_not_reached(); + break; + } +} + +// Capture callbacks + +#ifdef HAVE_LIBPCAP +void LogwolfMainWindow::captureCapturePrepared(capture_session *session) { + setTitlebarForCaptureInProgress(); + + setWindowIcon(mainApp->captureIcon()); + + /* Disable menu items that make no sense if you're currently running + a capture. */ + bool handle_toolbars = (session->session_will_restart ? false : true); + setForCaptureInProgress(true, handle_toolbars, session->capture_opts->ifaces); +// set_capture_if_dialog_for_capture_in_progress(TRUE); + +// /* Don't set up main window for a capture file. */ +// main_set_for_capture_file(FALSE); + showCapture(); +} + +void LogwolfMainWindow::captureCaptureUpdateStarted(capture_session *session) { + + /* We've done this in "prepared" above, but it will be cleared while + switching to the next multiple file. */ + setTitlebarForCaptureInProgress(); + + bool handle_toolbars = (session->session_will_restart ? false : true); + setForCaptureInProgress(true, handle_toolbars, session->capture_opts->ifaces); + + setForCapturedPackets(true); +} + +void LogwolfMainWindow::captureCaptureUpdateFinished(capture_session *session) { + + /* The capture isn't stopping any more - it's stopped. */ + capture_stopping_ = false; + + /* Update the main window as appropriate */ + updateForUnsavedChanges(); + + /* Enable menu items that make sense if you're not currently running + a capture. */ + bool handle_toolbars = (session->session_will_restart ? false : true); + setForCaptureInProgress(false, handle_toolbars); + setMenusForCaptureFile(); + + setWindowIcon(mainApp->normalIcon()); + + if (global_commandline_info.quit_after_cap) { + // Command line asked us to quit after capturing. + // Don't pop up a dialog to ask for unsaved files etc. + exit(0); + } +} + +void LogwolfMainWindow::captureCaptureFixedFinished(capture_session *) { + + /* The capture isn't stopping any more - it's stopped. */ + capture_stopping_ = false; + + /* Enable menu items that make sense if you're not currently running + a capture. */ + setForCaptureInProgress(false); + /* There isn't a real capture_file structure yet, so just force disabling + menu options. They will "refresh" when the capture file is reloaded to + display packets */ + setMenusForCaptureFile(true); + + setWindowIcon(mainApp->normalIcon()); + + if (global_commandline_info.quit_after_cap) { + // Command line asked us to quit after capturing. + // Don't pop up a dialog to ask for unsaved files etc. + exit(0); + } +} + +void LogwolfMainWindow::captureCaptureFailed(capture_session *) { + /* Capture isn't stopping any more. */ + capture_stopping_ = false; + + setForCaptureInProgress(false); + showWelcome(); + + // Reset expert information indicator + main_ui_->statusBar->captureFileClosing(); + mainApp->popStatus(WiresharkApplication::FileStatus); + + setWindowIcon(mainApp->normalIcon()); + + if (global_commandline_info.quit_after_cap) { + // Command line asked us to quit after capturing. + // Don't pop up a dialog to ask for unsaved files etc. + exit(0); + } +} +#endif // HAVE_LIBPCAP + +// Callbacks from cfile.c and file.c via CaptureFile::captureFileCallback + +void LogwolfMainWindow::captureEventHandler(CaptureEvent ev) +{ + switch (ev.captureContext()) { + + case CaptureEvent::File: + switch (ev.eventType()) { + case CaptureEvent::Opened: + captureFileOpened(); + break; + case CaptureEvent::Closing: + captureFileClosing(); + break; + case CaptureEvent::Closed: + captureFileClosed(); + break; + case CaptureEvent::Started: + captureFileReadStarted(tr("Loading")); + break; + case CaptureEvent::Finished: + captureFileReadFinished(); + break; + default: + break; + } + break; + + case CaptureEvent::Reload: + switch (ev.eventType()) { + case CaptureEvent::Started: + captureFileReadStarted(tr("Reloading")); + break; + case CaptureEvent::Finished: + captureFileReadFinished(); + break; + default: + break; + } + break; + + case CaptureEvent::Rescan: + switch (ev.eventType()) { + case CaptureEvent::Started: + setMenusForCaptureFile(true); + captureFileReadStarted(tr("Rescanning")); + break; + case CaptureEvent::Finished: + captureFileReadFinished(); + break; + default: + break; + } + break; + + case CaptureEvent::Retap: + switch (ev.eventType()) { + case CaptureEvent::Started: + freeze(); + break; + case CaptureEvent::Finished: + thaw(); + break; + case CaptureEvent::Flushed: + draw_tap_listeners(FALSE); + break; + default: + break; + } + break; + + case CaptureEvent::Merge: + switch (ev.eventType()) { + case CaptureEvent::Started: + mainApp->popStatus(WiresharkApplication::FileStatus); + mainApp->pushStatus(WiresharkApplication::FileStatus, tr("Merging files."), QString()); + break; + case CaptureEvent::Finished: + mainApp->popStatus(WiresharkApplication::FileStatus); + break; + default: + break; + } + break; + + case CaptureEvent::Save: + switch (ev.eventType()) { + case CaptureEvent::Started: + { + QFileInfo file_info(ev.filePath()); + mainApp->popStatus(WiresharkApplication::FileStatus); + mainApp->pushStatus(WiresharkApplication::FileStatus, tr("Saving %1…").arg(file_info.fileName())); + break; + } + default: + break; + } + break; + +#ifdef HAVE_LIBPCAP + case CaptureEvent::Capture: + switch (ev.eventType()) { + case CaptureEvent::Prepared: + captureCapturePrepared(ev.capSession()); + break; + case CaptureEvent::Stopping: + capture_stopping_ = true; + setMenusForCaptureStopping(); + break; + case CaptureEvent::Failed: + captureCaptureFailed(ev.capSession()); + default: + break; + } + break; + + case CaptureEvent::Update: + switch (ev.eventType()) { + case CaptureEvent::Started: + captureCaptureUpdateStarted(ev.capSession()); + break; + case CaptureEvent::Finished: + captureCaptureUpdateFinished(ev.capSession()); + break; + default: + break; + } + break; + + case CaptureEvent::Fixed: + switch (ev.eventType()) { + case CaptureEvent::Finished: + captureCaptureFixedFinished(ev.capSession()); + break; + default: + break; + } + break; +#endif + } +} + +void LogwolfMainWindow::captureFileOpened() { + if (capture_file_.window() != this) return; + + file_set_dialog_->fileOpened(capture_file_.capFile()); + setMenusForFileSet(true); + emit setCaptureFile(capture_file_.capFile()); +} + +void LogwolfMainWindow::captureFileReadStarted(const QString &action) { +// tap_param_dlg_update(); + + /* Set up main window for a capture file. */ +// main_set_for_capture_file(TRUE); + + mainApp->popStatus(WiresharkApplication::FileStatus); + QString msg = QString(tr("%1: %2")).arg(action).arg(capture_file_.fileName()); + QString msgtip = QString(); + mainApp->pushStatus(WiresharkApplication::FileStatus, msg, msgtip); + showCapture(); + main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(false); + main_ui_->wirelessTimelineWidget->captureFileReadStarted(capture_file_.capFile()); +} + +void LogwolfMainWindow::captureFileReadFinished() { + if (!capture_file_.capFile()->is_tempfile && capture_file_.capFile()->filename) { + /* Add this filename to the list of recent files in the "Recent Files" submenu */ + add_menu_recent_capture_file(capture_file_.capFile()->filename); + + /* Remember folder for next Open dialog and save it in recent */ + mainApp->setLastOpenDirFromFilename(capture_file_.capFile()->filename); + } + + /* Update the appropriate parts of the main window. */ + updateForUnsavedChanges(); + + /* enable wireless timeline if capture allows it */ + main_ui_->wirelessTimelineWidget->captureFileReadFinished(); + + /* Enable menu items that make sense if you have some captured packets. */ + setForCapturedPackets(true); + + main_ui_->statusBar->setFileName(capture_file_); + main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(true); + + packet_list_->captureFileReadFinished(); + + emit setDissectedCaptureFile(capture_file_.capFile()); +} + +void LogwolfMainWindow::captureFileClosing() { + setMenusForCaptureFile(true); + setForCapturedPackets(false); + setForCaptureInProgress(false); + + // Reset expert information indicator + main_ui_->statusBar->captureFileClosing(); + main_ui_->searchFrame->animatedHide(); + main_ui_->goToFrame->animatedHide(); + // gtk_widget_show(expert_info_none); + emit setCaptureFile(NULL); + emit setDissectedCaptureFile(NULL); +} + +void LogwolfMainWindow::captureFileClosed() { + packets_bar_update(); + + file_set_dialog_->fileClosed(); + setMenusForFileSet(false); + setWindowModified(false); + + // Reset expert information indicator + main_ui_->statusBar->captureFileClosing(); + mainApp->popStatus(WiresharkApplication::FileStatus); + + setWSWindowTitle(); + setWindowIcon(mainApp->normalIcon()); + setMenusForSelectedPacket(); + setMenusForSelectedTreeRow(); + +#ifdef HAVE_LIBPCAP + if (!global_capture_opts.multi_files_on) + showWelcome(); +#endif +} + +// +// Private slots +// + +// ui/gtk/capture_dlg.c:start_capture_confirmed + +void LogwolfMainWindow::startCapture() { + startCapture(QStringList()); +} + +void LogwolfMainWindow::startCapture(QStringList interfaces _U_) { +#ifdef HAVE_LIBPCAP + interface_options *interface_opts; + guint i; + interface_t *device; + gboolean can_start_capture = TRUE; + + /* did the user ever select a capture interface before? */ + if (global_capture_opts.num_selected == 0) { + QString msg = QString(tr("No interface selected.")); + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, msg); + main_ui_->actionCaptureStart->setChecked(false); + return; + } + + for (i = 0; i < global_capture_opts.all_ifaces->len; i++) { + device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i); + if (device->selected && (device->if_info.type == IF_EXTCAP)) { + /* device is EXTCAP and is selected. Check if all mandatory + * settings are set. + */ + if (extcap_has_configuration(device->name, TRUE)) + { + /* Request openning of extcap options dialog */ + QString device_name(device->name); + emit showExtcapOptions(device_name, false); + /* Cancel start of capture */ + can_start_capture = FALSE; + } + } + } + + /* If some of extcap was not configured, do not start with the capture */ + if (!can_start_capture) { + QString msg = QString(tr("Configure all extcaps before start of capture.")); + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, msg); + main_ui_->actionCaptureStart->setChecked(false); + return; + } + + // Ideally we should have disabled the start capture + // toolbar buttons and menu items. This may not be the + // case, e.g. with QtMacExtras. + if (!capture_filter_valid_) { + QString msg = QString(tr("Invalid capture filter.")); + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, msg); + main_ui_->actionCaptureStart->setChecked(false); + return; + } + + showCapture(); + + /* XXX - we might need to init other pref data as well... */ + + /* XXX - can this ever happen? */ + if (cap_session_.state != CAPTURE_STOPPED) + return; + + /* close the currently loaded capture file */ + cf_close((capture_file *)cap_session_.cf); + + /* Copy the selected interfaces to the set of interfaces to use for + this capture. */ + collect_ifaces(&global_capture_opts); + + CaptureFile::globalCapFile()->window = this; + info_data_.ui.ui = this; + if (capture_start(&global_capture_opts, NULL, &cap_session_, &info_data_, + main_window_update)) { + capture_options *capture_opts = cap_session_.capture_opts; + GString *interface_names; + + /* Add "interface name" on main status bar */ + interface_names = get_iface_list_string(capture_opts, 0); + if (strlen(interface_names->str) > 0) { + g_string_append(interface_names, ":"); + } + g_string_append(interface_names, " "); + + mainApp->popStatus(WiresharkApplication::FileStatus); + QString msg = QString("%1").arg(interface_names->str); + QString msgtip = QString("to file: "); + if (capture_opts->save_file) + msgtip += capture_opts->save_file; + mainApp->pushStatus(WiresharkApplication::FileStatus, msg, msgtip); + g_string_free(interface_names, TRUE); + + /* The capture succeeded, which means the capture filter syntax is + valid; add this capture filter to the recent capture filter list. */ + QByteArray filter_ba; + for (i = 0; i < global_capture_opts.ifaces->len; i++) { + interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i); + if (interface_opts->cfilter) { + recent_add_cfilter(interface_opts->name, interface_opts->cfilter); + if (filter_ba.isEmpty()) { + filter_ba = interface_opts->cfilter; + } else { + /* Not the first selected interface; is its capture filter + the same as the one the other interfaces we've looked + at have? */ + if (strcmp(interface_opts->cfilter, filter_ba.constData()) != 0) { + /* No, so not all selected interfaces have the same capture + filter. */ + filter_ba.clear(); + } + } + } + } + if (!filter_ba.isEmpty()) { + recent_add_cfilter(NULL, filter_ba.constData()); + } + } else { + CaptureFile::globalCapFile()->window = NULL; + } +#endif // HAVE_LIBPCAP +} + +// Copied from ui/gtk/gui_utils.c +void LogwolfMainWindow::pipeTimeout() { +#ifdef _WIN32 + HANDLE handle; + DWORD avail = 0; + gboolean result, result1; + DWORD childstatus; + gint iterations = 0; + + + /* try to read data from the pipe only 5 times, to avoid blocking */ + while (iterations < 5) { + /* Oddly enough although Named pipes don't work on win9x, + PeekNamedPipe does !!! */ + handle = (HANDLE)_get_osfhandle(pipe_source_); + result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); + + /* Get the child process exit status */ + result1 = GetExitCodeProcess((HANDLE)*(pipe_child_process_), + &childstatus); + + /* If the Peek returned an error, or there are bytes to be read + or the childwatcher thread has terminated then call the normal + callback */ + if (!result || avail > 0 || childstatus != STILL_ACTIVE) { + + /* And call the real handler */ + if (!pipe_input_cb_(pipe_source_, pipe_user_data_)) { + ws_log(LOG_DOMAIN_MAIN, LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations); + /* pipe closed, return false so that the old timer is not run again */ + delete pipe_timer_; + return; + } + } else { + /* No data, stop now */ + break; + } + + iterations++; + } +#endif // _WIN32 +} + +void LogwolfMainWindow::pipeActivated(int source) { + Q_UNUSED(source) + +#ifndef _WIN32 + ws_assert(source == pipe_source_); + + pipe_notifier_->setEnabled(false); + if (pipe_input_cb_(pipe_source_, pipe_user_data_)) { + pipe_notifier_->setEnabled(true); + } + else { + delete pipe_notifier_; + } +#endif // _WIN32 +} + +void LogwolfMainWindow::pipeNotifierDestroyed() +{ + /* Pop the "" message off the status bar. */ + main_ui_->statusBar->setFileName(capture_file_); + +#ifdef _WIN32 + pipe_timer_ = NULL; +#else + pipe_notifier_ = NULL; +#endif // _WIN32 +} + +void LogwolfMainWindow::stopCapture() { +//#ifdef HAVE_AIRPCAP +// if (airpcap_if_active) +// airpcap_set_toolbar_stop_capture(airpcap_if_active); +//#endif + +#ifdef HAVE_LIBPCAP + capture_stop(&cap_session_); +#endif // HAVE_LIBPCAP + +} + +// Keep focus rects from showing through the welcome screen. Primarily for +// macOS. +void LogwolfMainWindow::mainStackChanged(int) +{ + for (int i = 0; i < main_ui_->mainStack->count(); i++) { + main_ui_->mainStack->widget(i)->setEnabled(i == main_ui_->mainStack->currentIndex()); + } +} + +// XXX - Copied from ui/gtk/menus.c + +/** + * Add the capture filename (with an absolute path) to the "Recent Files" menu. + */ +// XXX - We should probably create a RecentFile class. +void LogwolfMainWindow::updateRecentCaptures() { + QAction *ra; + QMenu *recentMenu = main_ui_->menuOpenRecentCaptureFile; + QString action_cf_name; + + if (!recentMenu) { + return; + } + recentMenu->clear(); + +#if 0 +#if defined(QT_WINEXTRAS_LIB) + QWinJumpList recent_jl(this); + QWinJumpListCategory *recent_jlc = recent_jl.recent(); + if (recent_jlc) { + recent_jlc->clear(); + recent_jlc->setVisible(true); + } +#endif +#endif +#if defined(Q_OS_MAC) + if (!dock_menu_) { + dock_menu_ = new QMenu(); + dock_menu_->setAsDockMenu(); + } + dock_menu_->clear(); +#endif + + /* Iterate through the actions in menuOpenRecentCaptureFile, + * removing special items, a maybe duplicate entry and every item above count_max */ + int shortcut = Qt::Key_0; + foreach(recent_item_status *ri, mainApp->recentItems()) { + // Add the new item + ra = new QAction(recentMenu); + ra->setData(ri->filename); + // XXX - Needs get_recent_item_status or equivalent + ra->setEnabled(ri->accessible); + recentMenu->insertAction(NULL, ra); + action_cf_name = ra->data().toString(); + if (shortcut <= Qt::Key_9) { + ra->setShortcut(Qt::META | (Qt::Key)shortcut); + shortcut++; + } + ra->setText(action_cf_name); + connect(ra, SIGNAL(triggered()), this, SLOT(recentActionTriggered())); + +/* This is slow, at least on my VM here. The added links also open Wireshark + * in a new window. It might make more sense to add a recent item when we + * open a capture file. */ +#if 0 +#if defined(QT_WINEXTRAS_LIB) + if (recent_jlc) { + QFileInfo fi(ri->filename); + QWinJumpListItem *jli = recent_jlc->addLink( + fi.fileName(), + QApplication::applicationFilePath(), + QStringList() << "-r" << ri->filename + ); + // XXX set icon + jli->setWorkingDirectory(QDir::toNativeSeparators(QApplication::applicationDirPath())); + } +#endif +#endif +#if defined(Q_OS_MAC) + QAction *rda = new QAction(dock_menu_); + QFileInfo fi(ri->filename); + rda->setText(fi.fileName()); + dock_menu_->insertAction(NULL, rda); + connect(rda, SIGNAL(triggered()), ra, SLOT(trigger())); +#endif + } + + if (recentMenu->actions().count() > 0) { + // Separator + "Clear" + // XXX - Do we really need this? + ra = new QAction(recentMenu); + ra->setSeparator(true); + recentMenu->insertAction(NULL, ra); + + ra = new QAction(recentMenu); + ra->setText(tr("Clear Menu")); + recentMenu->insertAction(NULL, ra); + connect(ra, SIGNAL(triggered()), mainApp, SLOT(clearRecentCaptures())); + } else { + if (main_ui_->actionDummyNoFilesFound) { + recentMenu->addAction(main_ui_->actionDummyNoFilesFound); + } + } +} + +void LogwolfMainWindow::recentActionTriggered() { + QAction *ra = qobject_cast(sender()); + + if (ra) { + QString cfPath = ra->data().toString(); + openCaptureFile(cfPath); + } +} + +QString LogwolfMainWindow::commentToMenuText(QString text, int max_len) +{ + text = text.trimmed().replace(QRegularExpression("(\\r?\\n|\\r\\n?)+"), " "); + if (text.size() > 0) { + if (text.size() > max_len) { + text.truncate(max_len); + text += "…"; + } + } + else { + text = tr("(empty comment)", "placeholder for empty comment"); + } + return text; +} + +void LogwolfMainWindow::setEditCommentsMenu() +{ + main_ui_->menuPacketComment->clear(); + main_ui_->menuPacketComment->addAction(tr("Add New Comment…"), this, SLOT(actionAddPacketComment()), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_C)); + if (selectedRows().count() == 1) { + const int thisRow = selectedRows().first(); + frame_data * current_frame = frameDataForRow(thisRow); + wtap_block_t pkt_block = cf_get_packet_block(capture_file_.capFile(), current_frame); + guint nComments = wtap_block_count_option(pkt_block, OPT_COMMENT); + if (nComments > 0) { + QAction *aPtr; + main_ui_->menuPacketComment->addSeparator(); + for (guint i = 0; i < nComments; i++) { + QString comment = packet_list_->getPacketComment(i); + comment = this->commentToMenuText(comment); + aPtr = main_ui_->menuPacketComment->addAction(tr("Edit \"%1\"", "edit packet comment").arg(comment), + this, SLOT(actionEditPacketComment())); + aPtr->setData(i); + } + + main_ui_->menuPacketComment->addSeparator(); + for (guint i = 0; i < nComments; i++) { + QString comment = packet_list_->getPacketComment(i); + comment = this->commentToMenuText(comment); + aPtr = main_ui_->menuPacketComment->addAction(tr("Delete \"%1\"", "delete packet comment").arg(comment), + this, SLOT(actionDeletePacketComment())); + aPtr->setData(i); + } + main_ui_->menuPacketComment->addSeparator(); + main_ui_->menuPacketComment->addAction(tr("Delete packet comments"), this, SLOT(actionDeleteCommentsFromPackets())); + } + wtap_block_unref(pkt_block); + } + if (selectedRows().count() > 1) { + main_ui_->menuPacketComment->addSeparator(); + main_ui_->menuPacketComment->addAction(tr("Delete comments from %n packet(s)", nullptr, static_cast(selectedRows().count())), this, SLOT(actionDeleteCommentsFromPackets())); + } +} + +void LogwolfMainWindow::setMenusForSelectedPacket() +{ + gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_dccp = FALSE, is_sctp = FALSE, is_tls = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE, + is_http = FALSE, is_http2 = FALSE, is_quic = FALSE, is_sip = FALSE, is_exported_pdu = FALSE; + + /* Making the menu context-sensitive allows for easier selection of the + desired item and has the added benefit, with large captures, of + avoiding needless looping through huge lists for marked, ignored, + or time-referenced packets. */ + + /* We have one or more items in the packet list */ + bool have_frames = false; + /* A frame is selected */ + bool frame_selected = false; + bool multi_selection = false; + /* A visible packet comes after this one in the selection history */ + bool next_selection_history = false; + /* A visible packet comes before this one in the selection history */ + bool previous_selection_history = false; + /* We have marked frames. (XXX - why check frame_selected?) */ + bool have_marked = false; + /* We have a marked frame other than the current frame (i.e., + we have at least one marked frame, and either there's more + than one marked frame or the current frame isn't marked). */ + bool another_is_marked = false; + /* One or more frames are hidden by a display filter */ + bool have_filtered = false; + /* One or more frames have been ignored */ + bool have_ignored = false; + bool have_time_ref = false; + /* We have a time reference frame other than the current frame (i.e., + we have at least one time reference frame, and either there's more + than one time reference frame or the current frame isn't a + time reference frame). (XXX - why check frame_selected?) */ + bool another_is_time_ref = false; + + QList cc_actions = QList() + << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2 + << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4 + << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6 + << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8 + << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10; + + if (capture_file_.capFile()) { + QList rows = selectedRows(); + frame_data * current_frame = 0; + if (rows.count() > 0) + current_frame = frameDataForRow(rows.at(0)); + + frame_selected = rows.count() == 1; + if (packet_list_->multiSelectActive()) + { + frame_selected = false; + multi_selection = true; + } + next_selection_history = packet_list_->haveNextHistory(); + previous_selection_history = packet_list_->havePreviousHistory(); + have_frames = capture_file_.capFile()->count > 0; + have_marked = capture_file_.capFile()->marked_count > 0; + another_is_marked = have_marked && rows.count() <= 1 && + !(capture_file_.capFile()->marked_count == 1 && frame_selected && current_frame->marked); + have_filtered = capture_file_.capFile()->displayed_count > 0 && capture_file_.capFile()->displayed_count != capture_file_.capFile()->count; + have_ignored = capture_file_.capFile()->ignored_count > 0; + have_time_ref = capture_file_.capFile()->ref_time_count > 0; + another_is_time_ref = have_time_ref && rows.count() <= 1 && + !(capture_file_.capFile()->ref_time_count == 1 && frame_selected && current_frame->ref_time); + + if (capture_file_.capFile()->edt && ! multi_selection) + { + proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers, + &is_ip, &is_tcp, &is_udp, &is_sctp, + &is_tls, &is_rtp, &is_lte_rlc); + is_dccp = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "dccp"); + is_http = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http"); + is_http2 = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http2"); + /* TODO: to follow a QUIC stream we need a *decrypted* QUIC connection, i.e. checking for "quic" in the protocol stack is not enough */ + is_quic = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "quic"); + is_sip = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "sip"); + is_exported_pdu = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "exported_pdu"); + /* For Exported PDU there is a tag inserting IP addresses into the SRC and DST columns */ + if (is_exported_pdu && + (capture_file_.capFile()->edt->pi.net_src.type == AT_IPv4 || capture_file_.capFile()->edt->pi.net_src.type == AT_IPv6) && + (capture_file_.capFile()->edt->pi.net_dst.type == AT_IPv4 || capture_file_.capFile()->edt->pi.net_dst.type == AT_IPv6)) { + is_ip = TRUE; + } + } + } + + main_ui_->actionEditMarkPacket->setText(tr("&Mark/Unmark Packet(s)", "", static_cast(selectedRows().count()))); + main_ui_->actionEditIgnorePacket->setText(tr("&Ignore/Unignore Packet(s)", "", static_cast(selectedRows().count()))); + + main_ui_->actionCopyListAsText->setEnabled(selectedRows().count() > 0); + main_ui_->actionCopyListAsCSV->setEnabled(selectedRows().count() > 0); + main_ui_->actionCopyListAsYAML->setEnabled(selectedRows().count() > 0); + + main_ui_->actionEditMarkPacket->setEnabled(frame_selected || multi_selection); + main_ui_->actionEditMarkAllDisplayed->setEnabled(have_frames); + /* Unlike un-ignore, do not allow unmark of all frames when no frames are displayed */ + main_ui_->actionEditUnmarkAllDisplayed->setEnabled(have_marked); + main_ui_->actionEditNextMark->setEnabled(another_is_marked); + main_ui_->actionEditPreviousMark->setEnabled(another_is_marked); + + GArray * linkTypes = Q_NULLPTR; + if (capture_file_.capFile() && capture_file_.capFile()->linktypes) + linkTypes = capture_file_.capFile()->linktypes; + + bool enableEditComments = linkTypes && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET); + main_ui_->menuPacketComment->setEnabled(enableEditComments && selectedRows().count() > 0); + main_ui_->actionDeleteAllPacketComments->setEnabled(enableEditComments); + + main_ui_->actionEditIgnorePacket->setEnabled(frame_selected || multi_selection); + main_ui_->actionEditIgnoreAllDisplayed->setEnabled(have_filtered); + /* Allow un-ignore of all frames even with no frames currently displayed */ + main_ui_->actionEditUnignoreAllDisplayed->setEnabled(have_ignored); + + main_ui_->actionEditSetTimeReference->setEnabled(frame_selected); + main_ui_->actionEditUnsetAllTimeReferences->setEnabled(have_time_ref); + main_ui_->actionEditNextTimeReference->setEnabled(another_is_time_ref); + main_ui_->actionEditPreviousTimeReference->setEnabled(another_is_time_ref); + main_ui_->actionEditTimeShift->setEnabled(have_frames); + + main_ui_->actionGoGoToLinkedPacket->setEnabled(false); + main_ui_->actionGoNextHistoryPacket->setEnabled(next_selection_history); + main_ui_->actionGoPreviousHistoryPacket->setEnabled(previous_selection_history); + + main_ui_->actionAnalyzeFollowTCPStream->setEnabled(is_tcp); + main_ui_->actionAnalyzeFollowUDPStream->setEnabled(is_udp); + main_ui_->actionAnalyzeFollowDCCPStream->setEnabled(is_dccp); + main_ui_->actionAnalyzeFollowTLSStream->setEnabled(is_tls && !is_quic); + main_ui_->actionAnalyzeFollowHTTPStream->setEnabled(is_http); + main_ui_->actionAnalyzeFollowHTTP2Stream->setEnabled(is_http2); + main_ui_->actionAnalyzeFollowQUICStream->setEnabled(is_quic); + main_ui_->actionAnalyzeFollowSIPCall->setEnabled(is_sip); + + foreach(QAction *cc_action, cc_actions) { + cc_action->setEnabled(frame_selected); + } + main_ui_->actionViewColorizeNewColoringRule->setEnabled(frame_selected); + + main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used()); + + main_ui_->actionViewShowPacketInNewWindow->setEnabled(frame_selected); + main_ui_->actionViewEditResolvedName->setEnabled(frame_selected && is_ip); + + emit packetInfoChanged(capture_file_.packetInfo()); + +// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NameResolution/ResolveName", +// frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name || +// gbl_resolv_flags.transport_name)); + + main_ui_->actionToolsFirewallAclRules->setEnabled(frame_selected); + + main_ui_->actionStatisticsTcpStreamRoundTripTime->setEnabled(is_tcp); + main_ui_->actionStatisticsTcpStreamStevens->setEnabled(is_tcp); + main_ui_->actionStatisticsTcpStreamTcptrace->setEnabled(is_tcp); + main_ui_->actionStatisticsTcpStreamThroughput->setEnabled(is_tcp); + main_ui_->actionStatisticsTcpStreamWindowScaling->setEnabled(is_tcp); + + main_ui_->actionSCTPAnalyseThisAssociation->setEnabled(is_sctp); + main_ui_->actionSCTPShowAllAssociations->setEnabled(is_sctp); + main_ui_->actionSCTPFilterThisAssociation->setEnabled(is_sctp); + main_ui_->actionTelephonyRtpStreamAnalysis->setEnabled(is_rtp); + main_ui_->actionTelephonyRtpPlayer->setEnabled(is_rtp); + main_ui_->actionTelephonyLteRlcGraph->setEnabled(is_lte_rlc); +} + +void LogwolfMainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) { + + bool can_match_selected = false; + bool is_framenum = false; + bool have_field_info = false; + bool have_subtree = false; + bool can_open_url = false; + bool have_packet_bytes = false; + QByteArray field_filter; + int field_id = -1; + + field_info * fi = 0; + if (finfo) + fi = finfo->fieldInfo(); + + if (capture_file_.capFile()) { + capture_file_.capFile()->finfo_selected = fi; + + if (fi && fi->tree_type != -1) { + have_subtree = true; + } + + if (fi && fi->ds_tvb) { + have_packet_bytes = true; + } + } + + if (capture_file_.capFile() != NULL && fi != NULL) { + header_field_info *hfinfo = fi->hfinfo; + int linked_frame = -1; + + have_field_info = true; + can_match_selected = proto_can_match_selected(capture_file_.capFile()->finfo_selected, capture_file_.capFile()->edt); + if (hfinfo && hfinfo->type == FT_FRAMENUM) { + is_framenum = true; + linked_frame = fvalue_get_uinteger(&fi->value); + } + + char *tmp_field = proto_construct_match_selected_string(fi, capture_file_.capFile()->edt); + field_filter = tmp_field; + wmem_free(NULL, tmp_field); + + field_id = fi->hfinfo->id; + /* if the selected field isn't a protocol, get its parent */ + if (!proto_registrar_is_protocol(field_id)) { + field_id = proto_registrar_get_parent(fi->hfinfo->id); + } + + if (field_id >= 0) { + can_open_url = true; + main_ui_->actionContextWikiProtocolPage->setData(field_id); + main_ui_->actionContextFilterFieldReference->setData(field_id); + } else { + main_ui_->actionContextWikiProtocolPage->setData(QVariant()); + main_ui_->actionContextFilterFieldReference->setData(QVariant()); + } + + if (linked_frame > 0) { + main_ui_->actionGoGoToLinkedPacket->setData(linked_frame); + } else { + main_ui_->actionGoGoToLinkedPacket->setData(QVariant()); + } + } + + // Always enable / disable the following items. + main_ui_->actionFileExportPacketBytes->setEnabled(have_field_info); + + main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL && ! packet_list_->multiSelectActive()); + main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected); + main_ui_->actionEditCopyDescription->setEnabled(can_match_selected); + main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected); + main_ui_->actionEditCopyValue->setEnabled(can_match_selected); + main_ui_->actionEditCopyAsFilter->setEnabled(can_match_selected); + + main_ui_->actionAnalyzeShowPacketBytes->setEnabled(have_packet_bytes); + main_ui_->actionFileExportPacketBytes->setEnabled(have_packet_bytes); + + main_ui_->actionViewExpandSubtrees->setEnabled(have_subtree); + main_ui_->actionViewCollapseSubtrees->setEnabled(have_subtree); + + main_ui_->actionGoGoToLinkedPacket->setEnabled(is_framenum); + + main_ui_->actionAnalyzeCreateAColumn->setEnabled(can_match_selected); + + main_ui_->actionContextShowLinkedPacketInNewWindow->setEnabled(is_framenum); + + main_ui_->actionContextWikiProtocolPage->setEnabled(can_open_url); + main_ui_->actionContextFilterFieldReference->setEnabled(can_open_url); + + +// Only enable / disable the following items if we have focus so that we +// don't clobber anything we may have set in setMenusForSelectedPacket. + if (!proto_tree_ || !proto_tree_->hasFocus()) return; + + emit packetInfoChanged(capture_file_.packetInfo()); + emit fieldFilterChanged(field_filter); + + // set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ResolveName", + // frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name || + // gbl_resolv_flags.transport_name)); + +} + +void LogwolfMainWindow::interfaceSelectionChanged() +{ +#ifdef HAVE_LIBPCAP + // XXX This doesn't disable the toolbar button when using + // QtMacExtras. + if (global_capture_opts.num_selected > 0 && capture_filter_valid_) { + main_ui_->actionCaptureStart->setEnabled(true); + } else { + main_ui_->actionCaptureStart->setEnabled(false); + } +#endif // HAVE_LIBPCAP +} + +void LogwolfMainWindow::captureFilterSyntaxChanged(bool valid) +{ + capture_filter_valid_ = valid; + interfaceSelectionChanged(); +} + +void LogwolfMainWindow::startInterfaceCapture(bool valid, const QString capture_filter) +{ + capture_filter_valid_ = valid; + welcome_page_->setCaptureFilter(capture_filter); + QString before_what(tr(" before starting a new capture")); + if (testCaptureFileClose(before_what)) { + // The interface tree will update the selected interfaces via its timer + // so no need to do anything here. + startCapture(); + } +} + +void LogwolfMainWindow::applyGlobalCommandLineOptions() +{ + if (global_dissect_options.time_format != TS_NOT_SET) { + foreach(QAction* tda, td_actions.keys()) { + if (global_dissect_options.time_format == td_actions[tda]) { + tda->setChecked(true); + recent.gui_time_format = global_dissect_options.time_format; + timestamp_set_type(global_dissect_options.time_format); + break; + } + } + } + if (global_commandline_info.full_screen) { + this->showFullScreen(); + } +} + +void LogwolfMainWindow::redissectPackets() +{ + if (capture_file_.capFile()) { + cf_redissect_packets(capture_file_.capFile()); + main_ui_->statusBar->expertUpdate(); + } + + proto_free_deregistered_fields(); +} + +void LogwolfMainWindow::checkDisplayFilter() +{ + if (!df_combo_box_->checkDisplayFilter()) { + g_free(CaptureFile::globalCapFile()->dfilter); + CaptureFile::globalCapFile()->dfilter = NULL; + } +} + +void LogwolfMainWindow::fieldsChanged() +{ + gchar *err_msg = NULL; + if (!color_filters_reload(&err_msg, color_filter_add_cb)) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg); + g_free(err_msg); + } + tap_listeners_dfilter_recompile(); + + emit checkDisplayFilter(); + + if (have_custom_cols(&CaptureFile::globalCapFile()->cinfo)) { + // Recreate packet list columns according to new/changed/deleted fields + packet_list_->fieldsChanged(CaptureFile::globalCapFile()); + } + + emit reloadFields(); +} + +void LogwolfMainWindow::reloadLuaPlugins() +{ +#ifdef HAVE_LUA + if (mainApp->isReloadingLua()) + return; + + gboolean uses_lua_filehandler = FALSE; + + if (capture_file_.capFile()) { + // Check if the current capture file is opened with a Lua FileHandler + capture_file *cf = capture_file_.capFile(); + uses_lua_filehandler = wtap_uses_lua_filehandler(cf->provider.wth); + + if (uses_lua_filehandler && cf->unsaved_changes) { + // Prompt to save the file before reloading, in case the FileHandler has changed + QString before_what(tr(" before reloading Lua plugins")); + if (!testCaptureFileClose(before_what, Reload)) { + return; + } + } + } + + mainApp->setReloadingLua(true); + + wslua_reload_plugins(NULL, NULL); + funnel_statistics_reload_menus(); + reloadDynamicMenus(); + closePacketDialogs(); + + // Preferences may have been deleted so close all widgets using prefs + main_ui_->preferenceEditorFrame->animatedHide(); + + mainApp->readConfigurationFiles(true); + commandline_options_reapply(); + + fieldsChanged(); + prefs_apply_all(); + + if (uses_lua_filehandler) { + // Reload the file in case the FileHandler has changed + if (cf_reload(capture_file_.capFile()) != CF_OK) { + cf_close(capture_file_.capFile()); + } + proto_free_deregistered_fields(); + } else { + redissectPackets(); + } + + mainApp->setReloadingLua(false); + SimpleDialog::displayQueuedMessages(); +#endif +} + +void LogwolfMainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle) +{ + QListframe_list = QList() + << main_ui_->goToFrame << main_ui_->searchFrame + << main_ui_->addressEditorFrame << main_ui_->columnEditorFrame + << main_ui_->preferenceEditorFrame << main_ui_->filterExpressionFrame; + + frame_list.removeAll(show_frame); + foreach(AccordionFrame *af, frame_list) af->animatedHide(); + + if (toggle) { + if (show_frame->isVisible()) { + show_frame->animatedHide(); + return; + } + } + show_frame->animatedShow(); +} + +void LogwolfMainWindow::showColumnEditor(int column) +{ + previous_focus_ = mainApp->focusWidget(); + connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus())); + main_ui_->columnEditorFrame->editColumn(column); + showAccordionFrame(main_ui_->columnEditorFrame); +} + +void LogwolfMainWindow::showPreferenceEditor() +{ + showAccordionFrame(main_ui_->preferenceEditorFrame); +} + +void LogwolfMainWindow::initViewColorizeMenu() +{ + QList cc_actions = QList() + << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2 + << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4 + << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6 + << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8 + << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10; + + guint8 color_num = 1; + + foreach(QAction *cc_action, cc_actions) { + cc_action->setData(color_num); + connect(cc_action, SIGNAL(triggered()), this, SLOT(colorizeConversation())); + + const color_filter_t *colorf = color_filters_tmp_color(color_num); + if (colorf) { + QColor bg = ColorUtils::fromColorT(colorf->bg_color); + QColor fg = ColorUtils::fromColorT(colorf->fg_color); + cc_action->setIcon(StockIcon::colorIcon(bg.rgb(), fg.rgb(), QString::number(color_num))); + } + color_num++; + } + +#ifdef Q_OS_MAC + // Spotlight uses Cmd+Space + main_ui_->actionViewColorizeResetColorization->setShortcut(QKeySequence("Meta+Space")); +#endif +} + +void LogwolfMainWindow::addStatsPluginsToMenu() { + GList *cfg_list = stats_tree_get_cfg_list(); + GList *iter = g_list_first(cfg_list); + QAction *stats_tree_action; + QMenu *parent_menu; + bool first_item = true; + + while (iter) { + stats_tree_cfg *cfg = gxx_list_data(stats_tree_cfg *, iter); + if (cfg->plugin) { + if (first_item) { + main_ui_->menuStatistics->addSeparator(); + first_item = false; + } + + parent_menu = main_ui_->menuStatistics; + // gtk/main_menubar.c compresses double slashes, hence SkipEmptyParts +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + QStringList cfg_name_parts = QString(cfg->name).split("/", Qt::SkipEmptyParts); +#else + QStringList cfg_name_parts = QString(cfg->name).split("/", QString::SkipEmptyParts); +#endif + if (cfg_name_parts.isEmpty()) continue; + + QString stat_name = cfg_name_parts.takeLast(); + if (!cfg_name_parts.isEmpty()) { + QString menu_name = cfg_name_parts.join("/"); + parent_menu = findOrAddMenu(parent_menu, menu_name); + } + + stats_tree_action = new QAction(stat_name, this); + stats_tree_action->setData(cfg->abbr); + parent_menu->addAction(stats_tree_action); + connect(stats_tree_action, SIGNAL(triggered()), this, SLOT(actionStatisticsPlugin_triggered())); + } + iter = gxx_list_next(iter); + } + g_list_free(cfg_list); +} + +void LogwolfMainWindow::setFeaturesEnabled(bool enabled) +{ + main_ui_->menuBar->setEnabled(enabled); + main_ui_->mainToolBar->setEnabled(enabled); + main_ui_->displayFilterToolBar->setEnabled(enabled); + if (enabled) + { + main_ui_->statusBar->clearMessage(); +#ifdef HAVE_LIBPCAP + main_ui_->actionGoAutoScroll->setChecked(auto_scroll_live); +#endif + } + else + { + main_ui_->statusBar->showMessage(tr("Please wait while Wireshark is initializing…")); + } +} + +// Display Filter Toolbar + +void LogwolfMainWindow::on_actionDisplayFilterExpression_triggered() +{ + DisplayFilterExpressionDialog *dfe_dialog = new DisplayFilterExpressionDialog(this); + + connect(dfe_dialog, SIGNAL(insertDisplayFilter(QString)), + df_combo_box_->lineEdit(), SLOT(insertFilter(const QString &))); + + dfe_dialog->show(); +} + +void LogwolfMainWindow::on_actionNewDisplayFilterExpression_triggered() +{ + main_ui_->filterExpressionFrame->addExpression(df_combo_box_->lineEdit()->text()); +} + +void LogwolfMainWindow::onFilterSelected(QString filterText, bool prepare) +{ + if (filterText.length() <= 0) + return; + + df_combo_box_->setDisplayFilter(filterText); + // Holding down the Shift key will only prepare filter. + if (!prepare) + df_combo_box_->applyDisplayFilter(); +} + +void LogwolfMainWindow::onFilterPreferences() +{ + emit showPreferencesDialog(PrefsModel::typeToString(PrefsModel::FilterButtons)); +} + +void LogwolfMainWindow::onFilterEdit(int uatIndex) +{ + main_ui_->filterExpressionFrame->editExpression(uatIndex); +} + +void LogwolfMainWindow::openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata) +{ + QString slot = QString("statCommand%1").arg(menu_path); + QMetaObject::invokeMethod(this, slot.toLatin1().constData(), Q_ARG(const char *, arg), Q_ARG(void *, userdata)); +} + +void LogwolfMainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata) +{ + TapParameterDialog *tp_dialog = TapParameterDialog::showTapParameterStatistics(*this, capture_file_, cfg_str, arg, userdata); + if (!tp_dialog) return; + + connect(tp_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + connect(tp_dialog, SIGNAL(updateFilter(QString)), + df_combo_box_->lineEdit(), SLOT(setText(QString))); + tp_dialog->show(); +} + +void LogwolfMainWindow::openTapParameterDialog() +{ + QAction *tpa = qobject_cast(QObject::sender()); + if (!tpa) return; + + const QString cfg_str = tpa->data().toString(); + openTapParameterDialog(cfg_str, NULL, NULL); +} + +#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN) +void LogwolfMainWindow::softwareUpdateRequested() { + // We could call testCaptureFileClose here, but that would give us yet + // another dialog. Just try again later. + if (capture_file_.capFile() && capture_file_.capFile()->state != FILE_CLOSED) { + mainApp->rejectSoftwareUpdate(); + } +} +#endif + +// File Menu + +void LogwolfMainWindow::on_actionFileOpen_triggered() +{ + openCaptureFile(); +} + +void LogwolfMainWindow::on_actionFileMerge_triggered() +{ + mergeCaptureFile(); +} + +void LogwolfMainWindow::on_actionFileImportFromHexDump_triggered() +{ + importCaptureFile(); +} + +void LogwolfMainWindow::on_actionFileClose_triggered() { + QString before_what(tr(" before closing the file")); + if (testCaptureFileClose(before_what)) + showWelcome(); +} + +void LogwolfMainWindow::on_actionFileSave_triggered() +{ + saveCaptureFile(capture_file_.capFile(), false); +} + +void LogwolfMainWindow::on_actionFileSaveAs_triggered() +{ + saveAsCaptureFile(capture_file_.capFile()); +} + +void LogwolfMainWindow::on_actionFileSetListFiles_triggered() +{ + file_set_dialog_->show(); +} + +void LogwolfMainWindow::on_actionFileSetNextFile_triggered() +{ + fileset_entry *entry = fileset_get_next(); + + if (entry) { + QString new_cf_path = entry->fullname; + openCaptureFile(new_cf_path); + } +} + +void LogwolfMainWindow::on_actionFileSetPreviousFile_triggered() +{ + fileset_entry *entry = fileset_get_previous(); + + if (entry) { + QString new_cf_path = entry->fullname; + openCaptureFile(new_cf_path); + } +} + +void LogwolfMainWindow::on_actionFileExportPackets_triggered() +{ + exportSelectedPackets(); +} + +void LogwolfMainWindow::on_actionFileExportAsPlainText_triggered() +{ + exportDissections(export_type_text); +} + +void LogwolfMainWindow::on_actionFileExportAsCSV_triggered() +{ + exportDissections(export_type_csv); +} + +void LogwolfMainWindow::on_actionFileExportAsCArrays_triggered() +{ + exportDissections(export_type_carrays); +} + +void LogwolfMainWindow::on_actionFileExportAsPSML_triggered() +{ + exportDissections(export_type_psml); +} + +void LogwolfMainWindow::on_actionFileExportAsPDML_triggered() +{ + exportDissections(export_type_pdml); +} + +void LogwolfMainWindow::on_actionFileExportAsJSON_triggered() +{ + exportDissections(export_type_json); +} + +void LogwolfMainWindow::on_actionFileExportPacketBytes_triggered() +{ + QString file_name; + + if (!capture_file_.capFile() || !capture_file_.capFile()->finfo_selected) return; + + file_name = WiresharkFileDialog::getSaveFileName(this, + mainApp->windowTitleString(tr("Export Selected Packet Bytes")), + mainApp->lastOpenDir().canonicalPath(), + tr("Raw data (*.bin *.dat *.raw);;All Files (" ALL_FILES_WILDCARD ")") + ); + + if (file_name.length() > 0) { + const guint8 *data_p; + + data_p = tvb_get_ptr(capture_file_.capFile()->finfo_selected->ds_tvb, 0, -1) + + capture_file_.capFile()->finfo_selected->start; + write_file_binary_mode(qUtf8Printable(file_name), data_p, capture_file_.capFile()->finfo_selected->length); + + /* Save the directory name for future file dialogs. */ + mainApp->setLastOpenDirFromFilename(file_name); + } +} + +void LogwolfMainWindow::on_actionAnalyzeShowPacketBytes_triggered() +{ + ShowPacketBytesDialog *spbd = new ShowPacketBytesDialog(*this, capture_file_); + spbd->addCodecs(text_codec_map_); + spbd->show(); +} + +void LogwolfMainWindow::on_actionFileExportPDU_triggered() +{ + ExportPDUDialog *exportpdu_dialog = new ExportPDUDialog(this); + + if (exportpdu_dialog->isMinimized() == true) + { + exportpdu_dialog->showNormal(); + } + else + { + exportpdu_dialog->show(); + } + + exportpdu_dialog->raise(); + exportpdu_dialog->activateWindow(); +} + +void LogwolfMainWindow::on_actionFileExportTLSSessionKeys_triggered() +{ + QString file_name; + QString save_title; + int keylist_len; + + keylist_len = ssl_session_key_count(); + /* don't show up the dialog, if no data has to be saved */ + if (keylist_len < 1) { + /* shouldn't happen as the menu item should have been greyed out */ + QMessageBox::warning( + this, + tr("No Keys"), + tr("There are no TLS Session Keys to save."), + QMessageBox::Ok + ); + return; + } + + save_title.append(mainApp->windowTitleString(tr("Export TLS Session Keys (%Ln key(s))", "", keylist_len))); + file_name = WiresharkFileDialog::getSaveFileName(this, + save_title, + mainApp->lastOpenDir().canonicalPath(), + tr("TLS Session Keys (*.keys *.txt);;All Files (" ALL_FILES_WILDCARD ")") + ); + if (file_name.length() > 0) { + gsize keylist_length; + gchar *keylist = ssl_export_sessions(&keylist_length); + write_file_binary_mode(qUtf8Printable(file_name), keylist, keylist_length); + + /* Save the directory name for future file dialogs. */ + mainApp->setLastOpenDirFromFilename(file_name); + g_free(keylist); + } +} + +void LogwolfMainWindow::on_actionStatisticsHpfeeds_triggered() +{ + openStatisticsTreeDialog("hpfeeds"); +} + +void LogwolfMainWindow::on_actionFilePrint_triggered() +{ + capture_file *cf = capture_file_.capFile(); + g_return_if_fail(cf); + + QList rows = packet_list_->selectedRows(true); + + QStringList entries; + foreach (int row, rows) + entries << QString::number(row); + QString selRange = entries.join(","); + + PrintDialog * pdlg_ = new PrintDialog(this, cf, selRange); + pdlg_->setWindowModality(Qt::ApplicationModal); + pdlg_->show(); +} + +// Edit Menu + +// XXX This should probably be somewhere else. +void LogwolfMainWindow::actionEditCopyTriggered(LogwolfMainWindow::CopySelected selection_type) +{ + char label_str[ITEM_LABEL_LENGTH]; + QString clip; + + if (!capture_file_.capFile()) return; + + field_info *finfo_selected = capture_file_.capFile()->finfo_selected; + + switch (selection_type) { + case CopySelectedDescription: + if (proto_tree_->selectionModel()->hasSelection()) { + QModelIndex idx = proto_tree_->selectionModel()->selectedIndexes().first(); + clip = idx.data(Qt::DisplayRole).toString(); + } + break; + case CopySelectedFieldName: + if (finfo_selected && finfo_selected->hfinfo->abbrev != 0) { + clip.append(finfo_selected->hfinfo->abbrev); + } + break; + case CopySelectedValue: + if (finfo_selected && capture_file_.capFile()->edt != 0) { + gchar* field_str = get_node_field_value(finfo_selected, capture_file_.capFile()->edt); + clip.append(field_str); + g_free(field_str); + } + break; + case CopyAllVisibleItems: + clip = proto_tree_->toString(); + break; + case CopyAllVisibleSelectedTreeItems: + if (proto_tree_->selectionModel()->hasSelection()) { + clip = proto_tree_->toString(proto_tree_->selectionModel()->selectedIndexes().first()); + } + break; + case CopyListAsText: + case CopyListAsCSV: + case CopyListAsYAML: + if (packet_list_->selectedRows().count() > 0) + { + QList rows = packet_list_->selectedRows(); + QStringList content; + + PacketList::SummaryCopyType copyType = PacketList::CopyAsText; + if (selection_type == CopyListAsCSV) + copyType = PacketList::CopyAsCSV; + else if (selection_type == CopyListAsYAML) + copyType = PacketList::CopyAsYAML; + + if ((copyType == PacketList::CopyAsText) || + (copyType == PacketList::CopyAsCSV)) { + QString headerEntry = packet_list_->createHeaderSummaryText(copyType); + content << headerEntry; + } + foreach (int row, rows) + { + QModelIndex idx = packet_list_->model()->index(row, 0); + if (! idx.isValid()) + continue; + + QString entry = packet_list_->createSummaryText(idx, copyType); + content << entry; + } + + if (content.count() > 0) { + clip = content.join("\n"); + // + // Each YAML item ends with a newline, so the string + // ends with a newline already if it's CopyListAsYAML. + // If we add a newline, there'd be an extra blank + // line. + // + // Otherwise, we've used newlines as separators, not + // terminators, so there's no final newline. Add it. + // + if (selection_type != CopyListAsYAML) + clip += "\n"; + } + } + break; + } + + if (clip.length() == 0) { + /* If no representation then... Try to read the value */ + proto_item_fill_label(capture_file_.capFile()->finfo_selected, label_str); + clip.append(label_str); + } + + if (clip.length()) { + mainApp->clipboard()->setText(clip); + } else { + QString err = tr("Couldn't copy text. Try another item."); + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, err); + } +} + +void LogwolfMainWindow::on_actionCopyAllVisibleItems_triggered() +{ + actionEditCopyTriggered(CopyAllVisibleItems); +} + +void LogwolfMainWindow::on_actionCopyListAsText_triggered() +{ + actionEditCopyTriggered(CopyListAsText); +} + +void LogwolfMainWindow::on_actionCopyListAsCSV_triggered() +{ + actionEditCopyTriggered(CopyListAsCSV); +} + +void LogwolfMainWindow::on_actionCopyListAsYAML_triggered() +{ + actionEditCopyTriggered(CopyListAsYAML); +} + +void LogwolfMainWindow::on_actionCopyAllVisibleSelectedTreeItems_triggered() +{ + actionEditCopyTriggered(CopyAllVisibleSelectedTreeItems); +} + +void LogwolfMainWindow::on_actionEditCopyDescription_triggered() +{ + actionEditCopyTriggered(CopySelectedDescription); +} + +void LogwolfMainWindow::on_actionEditCopyFieldName_triggered() +{ + actionEditCopyTriggered(CopySelectedFieldName); +} + +void LogwolfMainWindow::on_actionEditCopyValue_triggered() +{ + actionEditCopyTriggered(CopySelectedValue); +} + +void LogwolfMainWindow::on_actionEditCopyAsFilter_triggered() +{ + matchFieldFilter(FilterAction::ActionCopy, FilterAction::ActionTypePlain); +} + +void LogwolfMainWindow::on_actionEditFindPacket_triggered() +{ + if (! packet_list_->model() || packet_list_->model()->rowCount() < 1) { + return; + } + previous_focus_ = mainApp->focusWidget(); + connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus())); + if (!main_ui_->searchFrame->isVisible()) { + showAccordionFrame(main_ui_->searchFrame, true); + } else { + main_ui_->searchFrame->animatedHide(); + } + main_ui_->searchFrame->setFocus(); +} + +void LogwolfMainWindow::on_actionEditFindNext_triggered() +{ + main_ui_->searchFrame->findNext(); +} + +void LogwolfMainWindow::on_actionEditFindPrevious_triggered() +{ + main_ui_->searchFrame->findPrevious(); +} + +void LogwolfMainWindow::on_actionEditMarkPacket_triggered() +{ + freeze(); + packet_list_->markFrame(); + thaw(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditMarkAllDisplayed_triggered() +{ + freeze(); + packet_list_->markAllDisplayedFrames(true); + thaw(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditUnmarkAllDisplayed_triggered() +{ + freeze(); + packet_list_->markAllDisplayedFrames(false); + thaw(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditNextMark_triggered() +{ + if (capture_file_.capFile()) + cf_find_packet_marked(capture_file_.capFile(), SD_FORWARD); +} + +void LogwolfMainWindow::on_actionEditPreviousMark_triggered() +{ + if (capture_file_.capFile()) + cf_find_packet_marked(capture_file_.capFile(), SD_BACKWARD); +} + +void LogwolfMainWindow::on_actionEditIgnorePacket_triggered() +{ + freeze(); + packet_list_->ignoreFrame(); + thaw(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditIgnoreAllDisplayed_triggered() +{ + freeze(); + packet_list_->ignoreAllDisplayedFrames(true); + thaw(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditUnignoreAllDisplayed_triggered() +{ + freeze(); + packet_list_->ignoreAllDisplayedFrames(false); + thaw(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditSetTimeReference_triggered() +{ + packet_list_->setTimeReference(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditUnsetAllTimeReferences_triggered() +{ + packet_list_->unsetAllTimeReferences(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionEditNextTimeReference_triggered() +{ + if (!capture_file_.capFile()) return; + cf_find_packet_time_reference(capture_file_.capFile(), SD_FORWARD); +} + +void LogwolfMainWindow::on_actionEditPreviousTimeReference_triggered() +{ + if (!capture_file_.capFile()) return; + cf_find_packet_time_reference(capture_file_.capFile(), SD_BACKWARD); +} + +void LogwolfMainWindow::on_actionEditTimeShift_triggered() +{ + TimeShiftDialog *ts_dialog = new TimeShiftDialog(this, capture_file_.capFile()); + connect(ts_dialog, SIGNAL(finished(int)), this, SLOT(editTimeShiftFinished(int))); + + connect(this, SIGNAL(setCaptureFile(capture_file*)), + ts_dialog, SLOT(setCaptureFile(capture_file*))); + connect(ts_dialog, SIGNAL(timeShifted()), packet_list_, SLOT(applyTimeShift())); + + ts_dialog->setWindowModality(Qt::ApplicationModal); + ts_dialog->setAttribute(Qt::WA_DeleteOnClose); + ts_dialog->show(); +} + +void LogwolfMainWindow::editTimeShiftFinished(int) +{ + if (capture_file_.capFile()->unsaved_changes) { + updateForUnsavedChanges(); + } +} + +void LogwolfMainWindow::actionAddPacketComment() +{ + QList rows = selectedRows(); + if (rows.count() == 0) + return; + + frame_data * fdata = frameDataForRow(rows.at(0)); + if (! fdata) + return; + + PacketCommentDialog* pc_dialog; + pc_dialog = new PacketCommentDialog(false, this, NULL); + connect(pc_dialog, &QDialog::finished, std::bind(&LogwolfMainWindow::addPacketCommentFinished, this, pc_dialog, std::placeholders::_1)); + pc_dialog->setWindowModality(Qt::ApplicationModal); + pc_dialog->setAttribute(Qt::WA_DeleteOnClose); + pc_dialog->show(); +} + +void LogwolfMainWindow::addPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_) +{ + if (result == QDialog::Accepted) { + packet_list_->addPacketComment(pc_dialog->text()); + updateForUnsavedChanges(); + } +} + +void LogwolfMainWindow::actionEditPacketComment() +{ + QList rows = selectedRows(); + if (rows.count() != 1) + return; + + QAction *ra = qobject_cast(sender()); + guint nComment = ra->data().toUInt(); + PacketCommentDialog* pc_dialog; + pc_dialog = new PacketCommentDialog(true, this, packet_list_->getPacketComment(nComment)); + connect(pc_dialog, &QDialog::finished, std::bind(&LogwolfMainWindow::editPacketCommentFinished, this, pc_dialog, std::placeholders::_1, nComment)); + pc_dialog->setWindowModality(Qt::ApplicationModal); + pc_dialog->setAttribute(Qt::WA_DeleteOnClose); + pc_dialog->show(); +} + +void LogwolfMainWindow::editPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_, guint nComment) +{ + if (result == QDialog::Accepted) { + packet_list_->setPacketComment(nComment, pc_dialog->text()); + updateForUnsavedChanges(); + } +} + +void LogwolfMainWindow::actionDeletePacketComment() +{ + QAction *ra = qobject_cast(sender()); + guint nComment = ra->data().toUInt(); + packet_list_->setPacketComment(nComment, QString("")); + updateForUnsavedChanges(); +} + +void LogwolfMainWindow::actionDeleteCommentsFromPackets() +{ + packet_list_->deleteCommentsFromPackets(); + updateForUnsavedChanges(); +} + +void LogwolfMainWindow::on_actionDeleteAllPacketComments_triggered() +{ + QMessageBox *msg_dialog = new QMessageBox(); + connect(msg_dialog, SIGNAL(finished(int)), this, SLOT(deleteAllPacketCommentsFinished(int))); + + msg_dialog->setIcon(QMessageBox::Question); + msg_dialog->setText(tr("Are you sure you want to remove all packet comments?")); + + msg_dialog->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msg_dialog->setDefaultButton(QMessageBox::Ok); + + msg_dialog->setWindowModality(Qt::ApplicationModal); + msg_dialog->setAttribute(Qt::WA_DeleteOnClose); + msg_dialog->show(); +} + +void LogwolfMainWindow::deleteAllPacketCommentsFinished(int result) +{ + if (result == QMessageBox::Ok) { + /* XXX Do we need a wait/hourglass for large files? */ + packet_list_->deleteAllPacketComments(); + updateForUnsavedChanges(); + } +} + +void LogwolfMainWindow::on_actionEditConfigurationProfiles_triggered() +{ + ProfileDialog *cp_dialog = new ProfileDialog(); + cp_dialog->setWindowModality(Qt::ApplicationModal); + cp_dialog->setAttribute(Qt::WA_DeleteOnClose); + cp_dialog->show(); +} + +void LogwolfMainWindow::showPreferencesDialog(QString module_name) +{ + PreferencesDialog *pref_dialog = new PreferencesDialog(this); + connect(pref_dialog, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals())); + saveWindowGeometry(); // Save in case the layout panes are rearranged + + pref_dialog->setPane(module_name); + pref_dialog->setWindowModality(Qt::ApplicationModal); + pref_dialog->setAttribute(Qt::WA_DeleteOnClose); + pref_dialog->show(); +} + +void LogwolfMainWindow::on_actionEditPreferences_triggered() +{ + showPreferencesDialog(PrefsModel::typeToString(PrefsModel::Appearance)); +} + +// View Menu + +void LogwolfMainWindow::showHideMainWidgets(QAction *action) +{ + if (!action) { + return; + } + bool show = action->isChecked(); + QWidget *widget = action->data().value(); + + // We may have come from the toolbar context menu, so check/uncheck each + // action as well. + if (widget == main_ui_->mainToolBar) { + recent.main_toolbar_show = show; + main_ui_->actionViewMainToolbar->setChecked(show); + } else if (widget == main_ui_->displayFilterToolBar) { + recent.filter_toolbar_show = show; + main_ui_->actionViewFilterToolbar->setChecked(show); +#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) + } else if (widget == main_ui_->wirelessToolBar) { + recent.wireless_toolbar_show = show; + main_ui_->actionViewWirelessToolbar->setChecked(show); +#endif + } else if (widget == main_ui_->statusBar) { + recent.statusbar_show = show; + main_ui_->actionViewStatusBar->setChecked(show); + } else if (widget == packet_list_) { + recent.packet_list_show = show; + main_ui_->actionViewPacketList->setChecked(show); + } else if (widget == proto_tree_) { + recent.tree_view_show = show; + main_ui_->actionViewPacketDetails->setChecked(show); + } else if (widget == byte_view_tab_) { + recent.byte_view_show = show; + main_ui_->actionViewPacketBytes->setChecked(show); + } else if (widget == packet_diagram_) { + recent.packet_diagram_show = show; + main_ui_->actionViewPacketDiagram->setChecked(show); + } else { + foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + QToolBar *toolbar = action->data().value(); + if (widget == toolbar) { + GList *entry = g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp); + if (show && !entry) { + recent.interface_toolbars = g_list_append(recent.interface_toolbars, g_strdup(action->text().toUtf8())); + } else if (!show && entry) { + recent.interface_toolbars = g_list_remove(recent.interface_toolbars, entry->data); + } + action->setChecked(show); + } + } + + ext_toolbar_t * toolbar = VariantPointer::asPtr(action->data()); + if (toolbar) { + GList *entry = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc)strcmp); + if (show && !entry) { + recent.gui_additional_toolbars = g_list_append(recent.gui_additional_toolbars, g_strdup(toolbar->name)); + } else if (!show && entry) { + recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data); + } + action->setChecked(show); + + QList toolbars = findChildren(); + foreach(QToolBar *bar, toolbars) { + AdditionalToolBar *iftoolbar = dynamic_cast(bar); + if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) { + iftoolbar->setVisible(show); + } + } + } + } + + if (widget) { + widget->setVisible(show); + } +} + +void LogwolfMainWindow::setTimestampFormat(QAction *action) +{ + if (!action) { + return; + } + ts_type tsf = action->data().value(); + if (recent.gui_time_format != tsf) { + timestamp_set_type(tsf); + recent.gui_time_format = tsf; + + if (packet_list_) { + packet_list_->resetColumns(); + } + if (capture_file_.capFile()) { + /* This call adjusts column width */ + cf_timestamp_auto_precision(capture_file_.capFile()); + } + } +} + +void LogwolfMainWindow::setTimestampPrecision(QAction *action) +{ + if (!action) { + return; + } + ts_precision tsp = action->data().value(); + if (recent.gui_time_precision != tsp) { + /* the actual precision will be set in packet_list_queue_draw() below */ + timestamp_set_precision(tsp); + recent.gui_time_precision = tsp; + + if (packet_list_) { + packet_list_->resetColumns(); + } + if (capture_file_.capFile()) { + /* This call adjusts column width */ + cf_timestamp_auto_precision(capture_file_.capFile()); + } + } +} + +void LogwolfMainWindow::on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked) +{ + if (checked) { + recent.gui_seconds_format = TS_SECONDS_HOUR_MIN_SEC; + } else { + recent.gui_seconds_format = TS_SECONDS_DEFAULT; + } + timestamp_set_seconds_type(recent.gui_seconds_format); + + if (packet_list_) { + packet_list_->resetColumns(); + } + if (capture_file_.capFile()) { + /* This call adjusts column width */ + cf_timestamp_auto_precision(capture_file_.capFile()); + } +} + +void LogwolfMainWindow::on_actionViewEditResolvedName_triggered() +{ + //int column = packet_list_->selectedColumn(); + int column = -1; + + if (packet_list_->currentIndex().isValid()) { + column = packet_list_->currentIndex().column(); + } + + main_ui_->addressEditorFrame->editAddresses(capture_file_, column); + showAccordionFrame(main_ui_->addressEditorFrame); +} + +void LogwolfMainWindow::setNameResolution() +{ + gbl_resolv_flags.mac_name = main_ui_->actionViewNameResolutionPhysical->isChecked() ? TRUE : FALSE; + gbl_resolv_flags.network_name = main_ui_->actionViewNameResolutionNetwork->isChecked() ? TRUE : FALSE; + gbl_resolv_flags.transport_name = main_ui_->actionViewNameResolutionTransport->isChecked() ? TRUE : FALSE; + + if (packet_list_) { + packet_list_->resetColumns(); + } + mainApp->emitAppSignal(WiresharkApplication::NameResolutionChanged); +} + +void LogwolfMainWindow::on_actionViewNameResolutionPhysical_triggered() +{ + setNameResolution(); +} + +void LogwolfMainWindow::on_actionViewNameResolutionNetwork_triggered() +{ + setNameResolution(); +} + +void LogwolfMainWindow::on_actionViewNameResolutionTransport_triggered() +{ + setNameResolution(); +} + +void LogwolfMainWindow::zoomText() +{ + mainApp->zoomTextFont(recent.gui_zoom_level); +} + +void LogwolfMainWindow::on_actionViewZoomIn_triggered() +{ + recent.gui_zoom_level++; + zoomText(); +} + +void LogwolfMainWindow::on_actionViewZoomOut_triggered() +{ + recent.gui_zoom_level--; + zoomText(); +} + +void LogwolfMainWindow::on_actionViewNormalSize_triggered() +{ + recent.gui_zoom_level = 0; + zoomText(); +} + +void LogwolfMainWindow::on_actionViewColorizePacketList_triggered(bool checked) { + recent.packet_list_colorize = checked; + packet_list_recolor_packets(); + packet_list_->resetColorized(); +} + +void LogwolfMainWindow::on_actionViewColoringRules_triggered() +{ + ColoringRulesDialog *coloring_rules_dialog = new ColoringRulesDialog(this); + connect(coloring_rules_dialog, SIGNAL(accepted()), + packet_list_, SLOT(recolorPackets())); + connect(coloring_rules_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + + coloring_rules_dialog->setWindowModality(Qt::ApplicationModal); + coloring_rules_dialog->setAttribute(Qt::WA_DeleteOnClose); + coloring_rules_dialog->show(); +} + +// actionViewColorizeConversation1 - 10 +void LogwolfMainWindow::colorizeConversation(bool create_rule) +{ + QAction *colorize_action = qobject_cast(sender()); + if (!colorize_action) return; + + if (capture_file_.capFile() && selectedRows().count() > 0) { + packet_info *pi = capture_file_.packetInfo(); + guint8 cc_num = colorize_action->data().toUInt(); + gchar *filter = conversation_filter_from_packet(pi); + if (filter == NULL) { + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to build conversation filter.")); + return; + } + + if (create_rule) { + ColoringRulesDialog coloring_rules_dialog(this, filter); + connect(&coloring_rules_dialog, SIGNAL(accepted()), + packet_list_, SLOT(recolorPackets())); + connect(&coloring_rules_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + coloring_rules_dialog.exec(); + } else { + gchar *err_msg = NULL; + if (!color_filters_set_tmp(cc_num, filter, FALSE, &err_msg)) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg); + g_free(err_msg); + } + packet_list_->recolorPackets(); + } + } + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::colorizeActionTriggered() +{ + QByteArray filter; + int color_number = -1; + + ConversationAction *conv_action = qobject_cast(sender()); + if (conv_action) { + filter = conv_action->filter(); + color_number = conv_action->colorNumber(); + } else { + ColorizeAction *colorize_action = qobject_cast(sender()); + if (colorize_action) { + filter = colorize_action->filter(); + color_number = colorize_action->colorNumber(); + } + } + + colorizeWithFilter(filter, color_number); +} + +void LogwolfMainWindow::colorizeWithFilter(QByteArray filter, int color_number) +{ + if (filter.isEmpty()) return; + + if (color_number > 0) { + // Assume "Color X" + gchar *err_msg = NULL; + if (!color_filters_set_tmp(color_number, filter.constData(), FALSE, &err_msg)) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg); + g_free(err_msg); + } + packet_list_->recolorPackets(); + } else { + // New coloring rule + ColoringRulesDialog coloring_rules_dialog(window(), filter); + connect(&coloring_rules_dialog, SIGNAL(accepted()), + packet_list_, SLOT(recolorPackets())); + connect(&coloring_rules_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + coloring_rules_dialog.exec(); + } + main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used()); +} + +void LogwolfMainWindow::on_actionViewColorizeResetColorization_triggered() +{ + gchar *err_msg = NULL; + if (!color_filters_reset_tmp(&err_msg)) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg); + g_free(err_msg); + } + packet_list_->recolorPackets(); + setMenusForSelectedPacket(); +} + +void LogwolfMainWindow::on_actionViewColorizeNewColoringRule_triggered() +{ + colorizeConversation(true); +} + +void LogwolfMainWindow::on_actionViewResetLayout_triggered() +{ + recent.gui_geometry_main_upper_pane = 0; + recent.gui_geometry_main_lower_pane = 0; + + applyRecentPaneGeometry(); +} + +void LogwolfMainWindow::on_actionViewResizeColumns_triggered() +{ + if (! packet_list_->model()) + return; + for (int col = 0; col < packet_list_->model()->columnCount(); col++) { + packet_list_->resizeColumnToContents(col); + recent_set_column_width(col, packet_list_->columnWidth(col)); + } +} + +void LogwolfMainWindow::openPacketDialog(bool from_reference) +{ + frame_data * fdata = Q_NULLPTR; + + /* Find the frame for which we're popping up a dialog */ + if (from_reference) { + guint32 framenum = fvalue_get_uinteger(&(capture_file_.capFile()->finfo_selected->value)); + if (framenum == 0) + return; + + fdata = frame_data_sequence_find(capture_file_.capFile()->provider.frames, framenum); + } else if (selectedRows().count() == 1) { + fdata = frameDataForRow(selectedRows().at(0)); + } else if (selectedRows().count() > 1) + return; + + /* If we have a frame, pop up the dialog */ + if (fdata) { + PacketDialog *packet_dialog = new PacketDialog(*this, capture_file_, fdata); + + connect(packet_dialog, SIGNAL(showProtocolPreferences(QString)), + this, SLOT(showPreferencesDialog(QString))); + connect(packet_dialog, SIGNAL(editProtocolPreference(preference*, pref_module*)), + main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*))); + + connect(this, SIGNAL(closePacketDialogs()), + packet_dialog, SLOT(close())); + zoomText(); // Emits mainApp->zoomMonospaceFont(QFont) + + packet_dialog->show(); + } +} + +void LogwolfMainWindow::on_actionViewInternalsConversationHashTables_triggered() +{ + ConversationHashTablesDialog *conversation_hash_tables_dlg = new ConversationHashTablesDialog(this); + conversation_hash_tables_dlg->show(); +} + +void LogwolfMainWindow::on_actionViewInternalsDissectorTables_triggered() +{ + DissectorTablesDialog *dissector_tables_dlg = new DissectorTablesDialog(this); + dissector_tables_dlg->show(); +} + +void LogwolfMainWindow::on_actionViewInternalsSupportedProtocols_triggered() +{ + SupportedProtocolsDialog *supported_protocols_dlg = new SupportedProtocolsDialog(this); + supported_protocols_dlg->show(); +} + +void LogwolfMainWindow::on_actionViewShowPacketInNewWindow_triggered() +{ + openPacketDialog(); +} + +// This is only used in ProtoTree. Defining it here makes more sense. +void LogwolfMainWindow::on_actionContextShowLinkedPacketInNewWindow_triggered() +{ + openPacketDialog(true); +} + +void LogwolfMainWindow::on_actionViewReload_triggered() +{ + capture_file *cf = CaptureFile::globalCapFile(); + + if (cf->unsaved_changes) { + QString before_what(tr(" before reloading the file")); + if (!testCaptureFileClose(before_what, Reload)) + return; + } + + cf_reload(cf); +} + +void LogwolfMainWindow::on_actionViewReload_as_File_Format_or_Capture_triggered() +{ + capture_file *cf = CaptureFile::globalCapFile(); + + if (cf->unsaved_changes) { + QString before_what(tr(" before reloading the file")); + if (!testCaptureFileClose(before_what, Reload)) + return; + } + + if (cf->open_type == WTAP_TYPE_AUTO) + cf->open_type = open_info_name_to_type("MIME Files Format"); + else /* TODO: This should be latest format chosen by user */ + cf->open_type = WTAP_TYPE_AUTO; + + cf_reload(cf); +} + + +// Expand / collapse slots in proto_tree + +// Go Menu + +// Analyze Menu + +void LogwolfMainWindow::filterMenuAboutToShow() +{ + QMenu * menu = qobject_cast(sender()); + QString field_filter; + + if (capture_file_.capFile() && capture_file_.capFile()->finfo_selected) { + char *tmp_field = proto_construct_match_selected_string(capture_file_.capFile()->finfo_selected, + capture_file_.capFile()->edt); + field_filter = QString(tmp_field); + wmem_free(NULL, tmp_field); + } + bool enable = ! field_filter.isEmpty(); + bool prepare = menu->objectName().compare("menuPrepareAFilter") == 0; + + menu->clear(); + QActionGroup * group = FilterAction::createFilterGroup(field_filter, prepare, enable, menu); + menu->addActions(group->actions()); +} + +void LogwolfMainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type) +{ + QString field_filter; + + if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) { + field_filter = packet_list_->getFilterFromRowAndColumn(packet_list_->currentIndex()); + } else if (capture_file_.capFile() && capture_file_.capFile()->finfo_selected) { + char *tmp_field = proto_construct_match_selected_string(capture_file_.capFile()->finfo_selected, + capture_file_.capFile()->edt); + field_filter = QString(tmp_field); + wmem_free(NULL, tmp_field); + } + + if (field_filter.isEmpty()) { + QString err = tr("No filter available. Try another %1.").arg(packet_list_->contextMenuActive() ? tr("column") : tr("item")); + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, err); + return; + } + + setDisplayFilter(field_filter, action, filter_type); +} + +void LogwolfMainWindow::on_actionAnalyzeDisplayFilters_triggered() +{ + if (!display_filter_dlg_) { + display_filter_dlg_ = new FilterDialog(this, FilterDialog::DisplayFilter); + } + display_filter_dlg_->show(); + display_filter_dlg_->raise(); + display_filter_dlg_->activateWindow(); +} + +struct epan_uat; +void LogwolfMainWindow::on_actionAnalyzeDisplayFilterMacros_triggered() +{ + struct epan_uat* dfm_uat; + dfilter_macro_get_uat(&dfm_uat); + UatDialog *uat_dlg = new UatDialog(parentWidget(), dfm_uat); + connect(uat_dlg, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals())); + + uat_dlg->setWindowModality(Qt::ApplicationModal); + uat_dlg->setAttribute(Qt::WA_DeleteOnClose); + uat_dlg->show(); +} + +void LogwolfMainWindow::on_actionAnalyzeCreateAColumn_triggered() +{ + if (capture_file_.capFile() != 0 && capture_file_.capFile()->finfo_selected != 0) { + header_field_info *hfinfo = capture_file_.capFile()->finfo_selected->hfinfo; + int col = column_prefs_has_custom(hfinfo->abbrev); + if (col == -1) { + insertColumn(hfinfo->name, hfinfo->abbrev); + } else { + QString status; + if (QString(hfinfo->name) == get_column_title(col)) { + status = tr("The \"%1\" column already exists.").arg(hfinfo->name); + } else { + status = tr("The \"%1\" column already exists as \"%2\".").arg(hfinfo->name).arg(get_column_title(col)); + } + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, status); + + if (!get_column_visible(col)) { + packet_list_->setColumnHidden(col, false); + set_column_visible(col, TRUE); + prefs_main_write(); + } + } + } +} + +void LogwolfMainWindow::applyConversationFilter() +{ + ConversationAction *conv_action = qobject_cast(sender()); + if (!conv_action) return; + + packet_info *pinfo = capture_file_.packetInfo(); + if (!pinfo) return; + + QByteArray conv_filter = conv_action->filter(); + if (conv_filter.isEmpty()) return; + + if (conv_action->isFilterValid(pinfo)) { + + df_combo_box_->lineEdit()->setText(conv_filter); + df_combo_box_->applyDisplayFilter(); + } +} + +void LogwolfMainWindow::applyExportObject() +{ + ExportObjectAction *export_action = qobject_cast(sender()); + if (!export_action) + return; + + ExportObjectDialog* export_dialog = new ExportObjectDialog(*this, capture_file_, export_action->exportObject()); + export_dialog->setWindowModality(Qt::ApplicationModal); + export_dialog->setAttribute(Qt::WA_DeleteOnClose); + export_dialog->show(); +} + +void LogwolfMainWindow::on_actionAnalyzeEnabledProtocols_triggered() +{ + EnabledProtocolsDialog *enable_proto_dialog = new EnabledProtocolsDialog(this); + connect(enable_proto_dialog, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals())); + + enable_proto_dialog->setWindowModality(Qt::ApplicationModal); + enable_proto_dialog->setAttribute(Qt::WA_DeleteOnClose); + enable_proto_dialog->show(); +} + +void LogwolfMainWindow::on_actionAnalyzeDecodeAs_triggered() +{ + QAction *da_action = qobject_cast(sender()); + bool create_new = da_action && da_action->property("create_new").toBool(); + + DecodeAsDialog *da_dialog = new DecodeAsDialog(this, capture_file_.capFile(), create_new); + connect(da_dialog, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals())); + + da_dialog->setWindowModality(Qt::ApplicationModal); + da_dialog->setAttribute(Qt::WA_DeleteOnClose); + da_dialog->show(); +} + +void LogwolfMainWindow::on_actionAnalyzeReloadLuaPlugins_triggered() +{ + reloadLuaPlugins(); +} + +void LogwolfMainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index) { + FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type); + connect(fsd, SIGNAL(updateFilter(QString, bool)), this, SLOT(filterPackets(QString, bool))); + connect(fsd, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int))); + fsd->addCodecs(text_codec_map_); + fsd->show(); + if (use_stream_index) { + // If a specific conversation was requested, then ignore any previous + // display filters and display all related packets. + fsd->follow("", true, stream_num, sub_stream_num); + } else { + fsd->follow(getFilter()); + } +} + +void LogwolfMainWindow::openFollowStreamDialogForType(follow_type_t type) { + openFollowStreamDialog(type, 0, 0, false); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowTCPStream_triggered() +{ + openFollowStreamDialogForType(FOLLOW_TCP); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowUDPStream_triggered() +{ + openFollowStreamDialogForType(FOLLOW_UDP); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowDCCPStream_triggered() +{ + openFollowStreamDialogForType(FOLLOW_DCCP); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowTLSStream_triggered() +{ + openFollowStreamDialogForType(FOLLOW_TLS); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowHTTPStream_triggered() +{ + openFollowStreamDialogForType(FOLLOW_HTTP); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowHTTP2Stream_triggered() +{ + openFollowStreamDialogForType(FOLLOW_HTTP2); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowQUICStream_triggered() +{ + openFollowStreamDialogForType(FOLLOW_QUIC); +} + +void LogwolfMainWindow::on_actionAnalyzeFollowSIPCall_triggered() +{ + openFollowStreamDialogForType(FOLLOW_SIP); +} + +void LogwolfMainWindow::openSCTPAllAssocsDialog() +{ + SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile()); + connect(sctp_dialog, SIGNAL(filterPackets(QString, bool)), + this, SLOT(filterPackets(QString, bool))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + sctp_dialog, SLOT(setCaptureFile(capture_file*))); + sctp_dialog->fillTable(); + + if (sctp_dialog->isMinimized() == true) + { + sctp_dialog->showNormal(); + } + else + { + sctp_dialog->show(); + } + + sctp_dialog->raise(); + sctp_dialog->activateWindow(); +} + +void LogwolfMainWindow::on_actionSCTPShowAllAssociations_triggered() +{ + openSCTPAllAssocsDialog(); +} + +void LogwolfMainWindow::on_actionSCTPAnalyseThisAssociation_triggered() +{ + const sctp_assoc_info_t* assoc = SCTPAssocAnalyseDialog::findAssocForPacket(capture_file_.capFile()); + if (!assoc) { + return; + } + SCTPAssocAnalyseDialog *sctp_analyse = new SCTPAssocAnalyseDialog(this, assoc, capture_file_.capFile()); + connect(sctp_analyse, SIGNAL(filterPackets(QString, bool)), + this, SLOT(filterPackets(QString, bool))); + + if (sctp_analyse->isMinimized() == true) + { + sctp_analyse->showNormal(); + } + else + { + sctp_analyse->show(); + } + + sctp_analyse->raise(); + sctp_analyse->activateWindow(); +} + +void LogwolfMainWindow::on_actionSCTPFilterThisAssociation_triggered() +{ + const sctp_assoc_info_t* assoc = SCTPAssocAnalyseDialog::findAssocForPacket(capture_file_.capFile()); + if (assoc) { + QString newFilter = QString("sctp.assoc_index==%1").arg(assoc->assoc_id); + assoc = NULL; + emit filterPackets(newFilter, false); + } +} + +// -z expert +void LogwolfMainWindow::statCommandExpertInfo(const char *, void *) +{ + ExpertInfoDialog *expert_dialog = new ExpertInfoDialog(*this, capture_file_); + const DisplayFilterEdit *df_edit = dynamic_cast(df_combo_box_->lineEdit()); + + expert_dialog->setDisplayFilter(df_edit->text()); + + connect(expert_dialog->getExpertInfoView(), SIGNAL(goToPacket(int, int)), + packet_list_, SLOT(goToPacket(int, int))); + connect(expert_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + + expert_dialog->show(); +} + +void LogwolfMainWindow::on_actionAnalyzeExpertInfo_triggered() +{ + statCommandExpertInfo(NULL, NULL); +} + + +// Next / previous / first / last slots in packet_list + +// Statistics Menu + +void LogwolfMainWindow::on_actionStatisticsFlowGraph_triggered() +{ + SequenceDialog *sequence_dialog = new SequenceDialog(*this, capture_file_); + sequence_dialog->show(); +} + +void LogwolfMainWindow::openTcpStreamDialog(int graph_type) +{ + TCPStreamDialog *stream_dialog = new TCPStreamDialog(this, capture_file_.capFile(), (tcp_graph_type)graph_type); + connect(stream_dialog, SIGNAL(goToPacket(int)), + packet_list_, SLOT(goToPacket(int))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + stream_dialog, SLOT(setCaptureFile(capture_file*))); + if (stream_dialog->result() == QDialog::Accepted) { + stream_dialog->show(); + } +} + +void LogwolfMainWindow::on_actionStatisticsTcpStreamStevens_triggered() +{ + openTcpStreamDialog(GRAPH_TSEQ_STEVENS); +} + +void LogwolfMainWindow::on_actionStatisticsTcpStreamTcptrace_triggered() +{ + openTcpStreamDialog(GRAPH_TSEQ_TCPTRACE); +} + +void LogwolfMainWindow::on_actionStatisticsTcpStreamThroughput_triggered() +{ + openTcpStreamDialog(GRAPH_THROUGHPUT); +} + +void LogwolfMainWindow::on_actionStatisticsTcpStreamRoundTripTime_triggered() +{ + openTcpStreamDialog(GRAPH_RTT); +} + +void LogwolfMainWindow::on_actionStatisticsTcpStreamWindowScaling_triggered() +{ + openTcpStreamDialog(GRAPH_WSCALE); +} + +// -z mcast,stat +void LogwolfMainWindow::statCommandMulticastStatistics(const char *arg, void *) +{ + MulticastStatisticsDialog *mcast_stats_dlg = new MulticastStatisticsDialog(*this, capture_file_, arg); + connect(mcast_stats_dlg, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + mcast_stats_dlg->show(); +} + +void LogwolfMainWindow::on_actionStatisticsUdpMulticastStreams_triggered() +{ + statCommandMulticastStatistics(NULL, NULL); +} + +void LogwolfMainWindow::openStatisticsTreeDialog(const gchar *abbr) +{ + StatsTreeDialog *st_dialog = new StatsTreeDialog(*this, capture_file_, abbr); +// connect(st_dialog, SIGNAL(goToPacket(int)), +// packet_list_, SLOT(goToPacket(int))); + st_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered() +{ + openStatisticsTreeDialog("lbmr_topic_ads_topic"); +} + +void LogwolfMainWindow::on_actionStatistics29WestTopics_Advertisements_by_Source_triggered() +{ + openStatisticsTreeDialog("lbmr_topic_ads_source"); +} + +void LogwolfMainWindow::on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered() +{ + openStatisticsTreeDialog("lbmr_topic_ads_transport"); +} + +void LogwolfMainWindow::on_actionStatistics29WestTopics_Queries_by_Topic_triggered() +{ + openStatisticsTreeDialog("lbmr_topic_queries_topic"); +} + +void LogwolfMainWindow::on_actionStatistics29WestTopics_Queries_by_Receiver_triggered() +{ + openStatisticsTreeDialog("lbmr_topic_queries_receiver"); +} + +void LogwolfMainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered() +{ + openStatisticsTreeDialog("lbmr_topic_queries_pattern"); +} + +void LogwolfMainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered() +{ + openStatisticsTreeDialog("lbmr_topic_queries_pattern_receiver"); +} + +void LogwolfMainWindow::on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered() +{ + openStatisticsTreeDialog("lbmr_queue_ads_queue"); +} + +void LogwolfMainWindow::on_actionStatistics29WestQueues_Advertisements_by_Source_triggered() +{ + openStatisticsTreeDialog("lbmr_queue_ads_source"); +} + +void LogwolfMainWindow::on_actionStatistics29WestQueues_Queries_by_Queue_triggered() +{ + openStatisticsTreeDialog("lbmr_queue_queries_queue"); +} + +void LogwolfMainWindow::on_actionStatistics29WestQueues_Queries_by_Receiver_triggered() +{ + openStatisticsTreeDialog("lbmr_queue_queries_receiver"); +} + +void LogwolfMainWindow::on_actionStatistics29WestUIM_Streams_triggered() +{ + LBMStreamDialog *stream_dialog = new LBMStreamDialog(this, capture_file_.capFile()); +// connect(stream_dialog, SIGNAL(goToPacket(int)), +// packet_list_, SLOT(goToPacket(int))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + stream_dialog, SLOT(setCaptureFile(capture_file*))); + stream_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatistics29WestLBTRM_triggered() +{ + LBMLBTRMTransportDialog * lbtrm_dialog = new LBMLBTRMTransportDialog(this, capture_file_.capFile()); + connect(lbtrm_dialog, SIGNAL(goToPacket(int)), + packet_list_, SLOT(goToPacket(int))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + lbtrm_dialog, SLOT(setCaptureFile(capture_file*))); + lbtrm_dialog->show(); +} +void LogwolfMainWindow::on_actionStatistics29WestLBTRU_triggered() +{ + LBMLBTRUTransportDialog * lbtru_dialog = new LBMLBTRUTransportDialog(this, capture_file_.capFile()); + connect(lbtru_dialog, SIGNAL(goToPacket(int)), + packet_list_, SLOT(goToPacket(int))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + lbtru_dialog, SLOT(setCaptureFile(capture_file*))); + lbtru_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatisticsANCP_triggered() +{ + openStatisticsTreeDialog("ancp"); +} + + +void LogwolfMainWindow::on_actionStatisticsBACappInstanceId_triggered() +{ + openStatisticsTreeDialog("bacapp_instanceid"); +} + +void LogwolfMainWindow::on_actionStatisticsBACappIP_triggered() +{ + openStatisticsTreeDialog("bacapp_ip"); +} + +void LogwolfMainWindow::on_actionStatisticsBACappObjectId_triggered() +{ + openStatisticsTreeDialog("bacapp_objectid"); +} + +void LogwolfMainWindow::on_actionStatisticsBACappService_triggered() +{ + openStatisticsTreeDialog("bacapp_service"); +} + +void LogwolfMainWindow::on_actionStatisticsCollectd_triggered() +{ + openStatisticsTreeDialog("collectd"); +} + +// -z conv,... +void LogwolfMainWindow::statCommandConversations(const char *arg, void *userdata) +{ + ConversationDialog *conv_dialog = new ConversationDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg); + connect(conv_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + connect(conv_dialog, SIGNAL(openFollowStreamDialog(follow_type_t, guint, guint)), + this, SLOT(openFollowStreamDialog(follow_type_t, guint, guint))); + connect(conv_dialog, SIGNAL(openTcpStreamGraph(int)), + this, SLOT(openTcpStreamDialog(int))); + conv_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatisticsConversations_triggered() +{ + statCommandConversations(NULL, NULL); +} + +// -z endpoints,... +void LogwolfMainWindow::statCommandEndpoints(const char *arg, void *userdata) +{ + EndpointDialog *endp_dialog = new EndpointDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg); + connect(endp_dialog, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + connect(endp_dialog, SIGNAL(openFollowStreamDialog(follow_type_t)), + this, SLOT(openFollowStreamDialogForType(follow_type_t))); + connect(endp_dialog, SIGNAL(openTcpStreamGraph(int)), + this, SLOT(openTcpStreamDialog(int))); + endp_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatisticsEndpoints_triggered() +{ + statCommandEndpoints(NULL, NULL); +} + +void LogwolfMainWindow::on_actionStatisticsHART_IP_triggered() +{ + openStatisticsTreeDialog("hart_ip"); +} + +void LogwolfMainWindow::on_actionStatisticsHTTPPacketCounter_triggered() +{ + openStatisticsTreeDialog("http"); +} + +void LogwolfMainWindow::on_actionStatisticsHTTPRequests_triggered() +{ + openStatisticsTreeDialog("http_req"); +} + +void LogwolfMainWindow::on_actionStatisticsHTTPLoadDistribution_triggered() +{ + openStatisticsTreeDialog("http_srv"); +} + +void LogwolfMainWindow::on_actionStatisticsHTTPRequestSequences_triggered() +{ + openStatisticsTreeDialog("http_seq"); +} + +void LogwolfMainWindow::on_actionStatisticsPacketLengths_triggered() +{ + openStatisticsTreeDialog("plen"); +} + +// -z io,stat +void LogwolfMainWindow::statCommandIOGraph(const char *, void *) +{ + const DisplayFilterEdit *df_edit = qobject_cast(df_combo_box_->lineEdit()); + QString displayFilter; + if (df_edit) + displayFilter = df_edit->text(); + + IOGraphDialog *iog_dialog = new IOGraphDialog(*this, capture_file_, displayFilter); + connect(iog_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int))); + connect(this, SIGNAL(reloadFields()), iog_dialog, SLOT(reloadFields())); + iog_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatisticsIOGraph_triggered() +{ + statCommandIOGraph(NULL, NULL); +} + +void LogwolfMainWindow::on_actionStatisticsSametime_triggered() +{ + openStatisticsTreeDialog("sametime"); +} + +void LogwolfMainWindow::on_actionStatisticsDNS_triggered() +{ + openStatisticsTreeDialog("dns"); +} + +void LogwolfMainWindow::actionStatisticsPlugin_triggered() +{ + QAction* action = qobject_cast(sender()); + if (action) { + openStatisticsTreeDialog(action->data().toString().toUtf8()); + } +} + +void LogwolfMainWindow::on_actionStatisticsHTTP2_triggered() +{ + openStatisticsTreeDialog("http2"); + +} + +void LogwolfMainWindow::on_actionStatisticsSOMEIPmessages_triggered() +{ + openStatisticsTreeDialog("someip_messages"); +} + +void LogwolfMainWindow::on_actionStatisticsSOMEIPSDentries_triggered() +{ + openStatisticsTreeDialog("someipsd_entries"); +} + +// Telephony Menu + +RtpPlayerDialog *LogwolfMainWindow::openTelephonyRtpPlayerDialog() +{ + RtpPlayerDialog *dialog; + +#ifdef HAVE_LIBPCAP + dialog = RtpPlayerDialog::openRtpPlayerDialog(*this, capture_file_, packet_list_, captureSession()->state != CAPTURE_STOPPED); +#else + dialog = RtpPlayerDialog::openRtpPlayerDialog(*this, capture_file_, packet_list_, false); +#endif + + dialog->show(); + + return dialog; +} + +VoipCallsDialog *LogwolfMainWindow::openTelephonyVoipCallsDialogVoip() +{ + VoipCallsDialog *dialog; + + dialog = VoipCallsDialog::openVoipCallsDialogVoip(*this, capture_file_, packet_list_); + dialog->show(); + + return dialog; +} + +VoipCallsDialog *LogwolfMainWindow::openTelephonyVoipCallsDialogSip() +{ + VoipCallsDialog *dialog; + + dialog = VoipCallsDialog::openVoipCallsDialogSip(*this, capture_file_, packet_list_); + dialog->show(); + + return dialog; +} + +RtpAnalysisDialog *LogwolfMainWindow::openTelephonyRtpAnalysisDialog() +{ + RtpAnalysisDialog *dialog; + + dialog = RtpAnalysisDialog::openRtpAnalysisDialog(*this, capture_file_, packet_list_); + dialog->show(); + + return dialog; +} + +void LogwolfMainWindow::on_actionTelephonyVoipCalls_triggered() +{ + openTelephonyVoipCallsDialogVoip(); +} + +void LogwolfMainWindow::on_actionTelephonyGsmMapSummary_triggered() +{ + GsmMapSummaryDialog *gms_dialog = new GsmMapSummaryDialog(*this, capture_file_); + gms_dialog->show(); +} + +void LogwolfMainWindow::on_actionTelephonyIax2StreamAnalysis_triggered() +{ + Iax2AnalysisDialog *iax2_analysis_dialog = new Iax2AnalysisDialog(*this, capture_file_); + connect(iax2_analysis_dialog, SIGNAL(goToPacket(int)), + packet_list_, SLOT(goToPacket(int))); + iax2_analysis_dialog->show(); +} + +void LogwolfMainWindow::on_actionTelephonyISUPMessages_triggered() +{ + openStatisticsTreeDialog("isup_msg"); +} + +// -z mac-lte,stat +void LogwolfMainWindow::statCommandLteMacStatistics(const char *arg, void *) +{ + LteMacStatisticsDialog *lte_mac_stats_dlg = new LteMacStatisticsDialog(*this, capture_file_, arg); + connect(lte_mac_stats_dlg, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + lte_mac_stats_dlg->show(); +} + +void LogwolfMainWindow::on_actionTelephonyLteMacStatistics_triggered() +{ + statCommandLteMacStatistics(NULL, NULL); +} + +void LogwolfMainWindow::statCommandLteRlcStatistics(const char *arg, void *) +{ + LteRlcStatisticsDialog *lte_rlc_stats_dlg = new LteRlcStatisticsDialog(*this, capture_file_, arg); + connect(lte_rlc_stats_dlg, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + // N.B. It is necessary for the RLC Statistics window to launch the RLC graph in this way, to ensure + // that the goToPacket() signal/slot connection gets set up... + connect(lte_rlc_stats_dlg, SIGNAL(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8)), + this, SLOT(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8))); + + lte_rlc_stats_dlg->show(); +} + +void LogwolfMainWindow::on_actionTelephonyLteRlcStatistics_triggered() +{ + statCommandLteRlcStatistics(NULL, NULL); +} + +void LogwolfMainWindow::launchRLCGraph(bool channelKnown, + guint16 ueid, guint8 rlcMode, + guint16 channelType, guint16 channelId, guint8 direction) +{ + LteRlcGraphDialog *lrg_dialog = new LteRlcGraphDialog(*this, capture_file_, channelKnown); + connect(lrg_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int))); + // This is a bit messy, but wanted to hide these parameters from users of + // on_actionTelephonyLteRlcGraph_triggered(). + if (channelKnown) { + lrg_dialog->setChannelInfo(ueid, rlcMode, channelType, channelId, direction); + } + lrg_dialog->show(); +} + +void LogwolfMainWindow::on_actionTelephonyLteRlcGraph_triggered() +{ + // We don't yet know the channel. + launchRLCGraph(false, 0, 0, 0, 0, 0); +} + +void LogwolfMainWindow::on_actionTelephonyMtp3Summary_triggered() +{ + Mtp3SummaryDialog *mtp3s_dialog = new Mtp3SummaryDialog(*this, capture_file_); + mtp3s_dialog->show(); +} + +void LogwolfMainWindow::on_actionTelephonyOsmuxPacketCounter_triggered() +{ + openStatisticsTreeDialog("osmux"); +} + +RtpStreamDialog *LogwolfMainWindow::openTelephonyRtpStreamsDialog() +{ + RtpStreamDialog *dialog; + + dialog = RtpStreamDialog::openRtpStreamDialog(*this, capture_file_, packet_list_); + dialog->show(); + + return dialog; +} + +void LogwolfMainWindow::on_actionTelephonyRtpStreams_triggered() +{ + openTelephonyRtpStreamsDialog(); +} + +void LogwolfMainWindow::on_actionTelephonyRtpStreamAnalysis_triggered() +{ + QVector stream_ids; + QString err; + + if (QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { + err = findRtpStreams(&stream_ids, true); + } else { + err = findRtpStreams(&stream_ids, false); + } + if (!err.isNull()) { + QMessageBox::warning(this, tr("RTP packet search failed"), + err, + QMessageBox::Ok); + } else { + openTelephonyRtpAnalysisDialog()->addRtpStreams(stream_ids); + } + foreach(rtpstream_id_t *id, stream_ids) { + rtpstream_id_free(id); + } +} + +void LogwolfMainWindow::on_actionTelephonyRtpPlayer_triggered() +{ + QVector stream_ids; + QString err; + + if (QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { + err = findRtpStreams(&stream_ids, true); + } else { + err = findRtpStreams(&stream_ids, false); + } + if (!err.isNull()) { + QMessageBox::warning(this, tr("RTP packet search failed"), + err, + QMessageBox::Ok); +#ifdef QT_MULTIMEDIA_LIB + } else { + openTelephonyRtpPlayerDialog()->addRtpStreams(stream_ids); +#endif // QT_MULTIMEDIA_LIB + } + foreach(rtpstream_id_t *id, stream_ids) { + rtpstream_id_free(id); + } +} + +void LogwolfMainWindow::on_actionTelephonyRTSPPacketCounter_triggered() +{ + openStatisticsTreeDialog("rtsp"); +} + +void LogwolfMainWindow::on_actionTelephonySMPPOperations_triggered() +{ + openStatisticsTreeDialog("smpp_commands"); +} + +void LogwolfMainWindow::on_actionTelephonyUCPMessages_triggered() +{ + openStatisticsTreeDialog("ucp_messages"); +} + +void LogwolfMainWindow::on_actionTelephonyF1APMessages_triggered() +{ + openStatisticsTreeDialog("f1ap"); +} + +void LogwolfMainWindow::on_actionTelephonyNGAPMessages_triggered() +{ + openStatisticsTreeDialog("ngap"); +} + +void LogwolfMainWindow::on_actionTelephonySipFlows_triggered() +{ + openTelephonyVoipCallsDialogSip(); +} + +// Tools Menu + +void LogwolfMainWindow::on_actionToolsFirewallAclRules_triggered() +{ + FirewallRulesDialog *firewall_rules_dialog = new FirewallRulesDialog(*this, capture_file_); + firewall_rules_dialog->show(); +} + +void LogwolfMainWindow::on_actionToolsCredentials_triggered() +{ + CredentialsDialog *credentials_dialog = new CredentialsDialog(*this, capture_file_, packet_list_); + credentials_dialog->show(); +} + +// Help Menu +void LogwolfMainWindow::on_actionHelpContents_triggered() { + + mainApp->helpTopicAction(HELP_CONTENT); +} + +void LogwolfMainWindow::on_actionHelpMPWireshark_triggered() { + + mainApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK); +} + +void LogwolfMainWindow::on_actionHelpMPWireshark_Filter_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK_FILTER); +} + +void LogwolfMainWindow::on_actionHelpMPCapinfos_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_CAPINFOS); +} + +void LogwolfMainWindow::on_actionHelpMPDumpcap_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_DUMPCAP); +} + +void LogwolfMainWindow::on_actionHelpMPEditcap_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_EDITCAP); +} + +void LogwolfMainWindow::on_actionHelpMPMergecap_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_MERGECAP); +} + +void LogwolfMainWindow::on_actionHelpMPRawshark_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_RAWSHARK); +} + +void LogwolfMainWindow::on_actionHelpMPReordercap_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_REORDERCAP); +} + +void LogwolfMainWindow::on_actionHelpMPText2pcap_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_TEXT2PCAP); +} + +void LogwolfMainWindow::on_actionHelpMPTShark_triggered() { + mainApp->helpTopicAction(LOCALPAGE_MAN_TSHARK); +} + +void LogwolfMainWindow::on_actionHelpWebsite_triggered() { + + mainApp->helpTopicAction(ONLINEPAGE_HOME); +} + +void LogwolfMainWindow::on_actionHelpFAQ_triggered() { + + mainApp->helpTopicAction(ONLINEPAGE_FAQ); +} + +void LogwolfMainWindow::on_actionHelpAsk_triggered() { + + mainApp->helpTopicAction(ONLINEPAGE_ASK); +} + +void LogwolfMainWindow::on_actionHelpDownloads_triggered() { + + mainApp->helpTopicAction(ONLINEPAGE_DOWNLOAD); +} + +void LogwolfMainWindow::on_actionHelpWiki_triggered() { + + mainApp->helpTopicAction(ONLINEPAGE_WIKI); +} + +void LogwolfMainWindow::on_actionHelpSampleCaptures_triggered() { + + mainApp->helpTopicAction(ONLINEPAGE_SAMPLE_FILES); +} + +#ifdef HAVE_SOFTWARE_UPDATE +void LogwolfMainWindow::checkForUpdates() +{ + software_update_check(); +} +#endif + +void LogwolfMainWindow::on_actionHelpAbout_triggered() +{ + AboutDialog *about_dialog = new AboutDialog(this); + + if (about_dialog->isMinimized() == true) + { + about_dialog->showNormal(); + } + else + { + about_dialog->show(); + } + + about_dialog->raise(); + about_dialog->activateWindow(); +} + +void LogwolfMainWindow::on_actionGoGoToPacket_triggered() { + if (! packet_list_->model() || packet_list_->model()->rowCount() < 1) { + return; + } + previous_focus_ = mainApp->focusWidget(); + connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus())); + + showAccordionFrame(main_ui_->goToFrame, true); + if (main_ui_->goToFrame->isVisible()) { + main_ui_->goToLineEdit->clear(); + main_ui_->goToLineEdit->setFocus(); + } +} + +void LogwolfMainWindow::on_actionGoGoToLinkedPacket_triggered() +{ + QAction *gta = qobject_cast(sender()); + if (!gta) return; + + bool ok = false; + int packet_num = gta->data().toInt(&ok); + if (!ok) return; + + packet_list_->goToPacket(packet_num); +} + +// gtk/main_menubar.c:goto_conversation_frame +void LogwolfMainWindow::goToConversationFrame(bool go_next) { + gchar *filter = NULL; + dfilter_t *dfcode = NULL; + gboolean found_packet = FALSE; + packet_info *pi = capture_file_.packetInfo(); + + if (!pi) { + // No packet was selected, or multiple packets were selected. + return; + } + + /* Try to build a conversation + * filter in the order TCP, UDP, IP, Ethernet and apply the + * coloring */ + filter = conversation_filter_from_packet(pi); + if (filter == NULL) { + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to build conversation filter.")); + g_free(filter); + return; + } + + if (!dfilter_compile(filter, &dfcode, NULL)) { + /* The attempt failed; report an error. */ + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Error compiling filter for this conversation.")); + g_free(filter); + return; + } + + found_packet = cf_find_packet_dfilter(capture_file_.capFile(), dfcode, go_next ? SD_FORWARD : SD_BACKWARD); + + if (!found_packet) { + /* We didn't find a packet */ + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("No previous/next packet in conversation.")); + } + + dfilter_free(dfcode); + g_free(filter); +} + +void LogwolfMainWindow::on_actionGoNextConversationPacket_triggered() +{ + goToConversationFrame(true); +} + +void LogwolfMainWindow::on_actionGoPreviousConversationPacket_triggered() +{ + goToConversationFrame(false); +} + +void LogwolfMainWindow::on_actionGoAutoScroll_toggled(bool checked) +{ + packet_list_->setVerticalAutoScroll(checked); +} + +void LogwolfMainWindow::resetPreviousFocus() { + previous_focus_ = NULL; +} + +void LogwolfMainWindow::on_goToCancel_clicked() +{ + main_ui_->goToFrame->animatedHide(); + if (previous_focus_) { + disconnect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus())); + previous_focus_->setFocus(); + resetPreviousFocus(); + } +} + +void LogwolfMainWindow::on_goToGo_clicked() +{ + gotoFrame(main_ui_->goToLineEdit->text().toInt()); + + on_goToCancel_clicked(); +} + +void LogwolfMainWindow::on_goToLineEdit_returnPressed() +{ + on_goToGo_clicked(); +} + +void LogwolfMainWindow::on_actionCaptureStart_triggered() +{ +//#ifdef HAVE_AIRPCAP +// airpcap_if_active = airpcap_if_selected; +// if (airpcap_if_active) +// airpcap_set_toolbar_start_capture(airpcap_if_active); +//#endif + +// if (cap_open_w) { +// /* +// * There's an options dialog; get the values from it and close it. +// */ +// gboolean success; + +// /* Determine if "capture start" while building of the "capture options" window */ +// /* is in progress. If so, ignore the "capture start. */ +// /* XXX: Would it be better/cleaner for the "capture options" window code to */ +// /* disable the capture start button temporarily ? */ +// if (cap_open_complete == FALSE) { +// return; /* Building options window: ignore "capture start" */ +// } +// success = capture_dlg_prep(cap_open_w); +// window_destroy(GTK_WIDGET(cap_open_w)); +// if (!success) +// return; /* error in options dialog */ +// } + +#ifdef HAVE_LIBPCAP + if (global_capture_opts.num_selected == 0) { + QString err_msg = tr("No Interface Selected."); + mainApp->pushStatus(WiresharkApplication::TemporaryStatus, err_msg); + main_ui_->actionCaptureStart->setChecked(false); + return; + } + + /* XXX - will closing this remove a temporary file? */ + QString before_what(tr(" before starting a new capture")); + if (testCaptureFileClose(before_what)) { + startCapture(); + } else { + // simply clicking the button sets it to 'checked' even though we've + // decided to do nothing, so undo that + main_ui_->actionCaptureStart->setChecked(false); + } +#endif // HAVE_LIBPCAP +} + +void LogwolfMainWindow::on_actionCaptureStop_triggered() +{ + stopCapture(); +} + +void LogwolfMainWindow::on_actionCaptureRestart_triggered() +{ +#ifdef HAVE_LIBPCAP + QString before_what(tr(" before restarting the capture")); + cap_session_.capture_opts->restart = TRUE; + if (!testCaptureFileClose(before_what, Restart)) + return; + + startCapture(); +#endif // HAVE_LIBPCAP +} + +void LogwolfMainWindow::on_actionCaptureCaptureFilters_triggered() +{ + if (!capture_filter_dlg_) { + capture_filter_dlg_ = new FilterDialog(this, FilterDialog::CaptureFilter); + } + capture_filter_dlg_->show(); + capture_filter_dlg_->raise(); + capture_filter_dlg_->activateWindow(); +} + +void LogwolfMainWindow::on_actionStatisticsCaptureFileProperties_triggered() +{ + CaptureFilePropertiesDialog *capture_file_properties_dialog = new CaptureFilePropertiesDialog(*this, capture_file_); + connect(capture_file_properties_dialog, SIGNAL(captureCommentChanged()), + this, SLOT(updateForUnsavedChanges())); + capture_file_properties_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatisticsResolvedAddresses_triggered() +{ + QString capFileName; + wtap* wth = Q_NULLPTR; + if (capture_file_.isValid()) + { + capFileName = capture_file_.capFile()->filename; + wth = capture_file_.capFile()->provider.wth; + } + ResolvedAddressesDialog *resolved_addresses_dialog = + new ResolvedAddressesDialog(this, capFileName, wth); + resolved_addresses_dialog->show(); +} + +void LogwolfMainWindow::on_actionStatisticsProtocolHierarchy_triggered() +{ + ProtocolHierarchyDialog *phd = new ProtocolHierarchyDialog(*this, capture_file_); + connect(phd, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType)), + this, SIGNAL(filterAction(QString, FilterAction::Action, FilterAction::ActionType))); + phd->show(); +} + +void LogwolfMainWindow::on_actionCaptureOptions_triggered() +{ +#ifdef HAVE_LIBPCAP + if (!capture_options_dialog_) { + capture_options_dialog_ = new CaptureOptionsDialog(this); + + connect(capture_options_dialog_, SIGNAL(startCapture()), this, SLOT(startCapture())); + connect(capture_options_dialog_, SIGNAL(stopCapture()), this, SLOT(stopCapture())); + + connect(capture_options_dialog_, SIGNAL(getPoints(int, PointList*)), + this->welcome_page_->getInterfaceFrame(), SLOT(getPoints(int, PointList*))); + connect(capture_options_dialog_, SIGNAL(interfacesChanged()), + this->welcome_page_, SLOT(interfaceSelected())); + connect(capture_options_dialog_, SIGNAL(interfacesChanged()), + this->welcome_page_->getInterfaceFrame(), SLOT(updateSelectedInterfaces())); + connect(capture_options_dialog_, SIGNAL(interfaceListChanged()), + this->welcome_page_->getInterfaceFrame(), SLOT(interfaceListChanged())); + connect(capture_options_dialog_, SIGNAL(captureFilterTextEdited(QString)), + this->welcome_page_, SLOT(setCaptureFilterText(QString))); + // Propagate selection changes from main UI to dialog. + connect(this->welcome_page_, SIGNAL(interfacesChanged()), + capture_options_dialog_, SLOT(interfaceSelected())); + + connect(capture_options_dialog_, SIGNAL(setFilterValid(bool, const QString)), + this, SLOT(startInterfaceCapture(bool, const QString))); + + connect(capture_options_dialog_, SIGNAL(showExtcapOptions(QString&, bool)), + this, SLOT(showExtcapOptionsDialog(QString&, bool))); + } + capture_options_dialog_->setTab(0); + capture_options_dialog_->updateInterfaces(); + + if (capture_options_dialog_->isMinimized()) { + capture_options_dialog_->showNormal(); + } else { + capture_options_dialog_->show(); + } + + capture_options_dialog_->raise(); + capture_options_dialog_->activateWindow(); +#endif +} + +#ifdef HAVE_LIBPCAP +void LogwolfMainWindow::on_actionCaptureRefreshInterfaces_triggered() +{ + main_ui_->actionCaptureRefreshInterfaces->setEnabled(false); + mainApp->refreshLocalInterfaces(); + main_ui_->actionCaptureRefreshInterfaces->setEnabled(true); +} +#endif + +void LogwolfMainWindow::externalMenuItem_triggered() +{ + QAction * triggerAction = NULL; + QVariant v; + ext_menubar_t * entry = NULL; + + if (QObject::sender()) { + triggerAction = (QAction *)QObject::sender(); + v = triggerAction->data(); + + if (v.canConvert()) { + entry = (ext_menubar_t *)v.value(); + + if (entry->type == EXT_MENUBAR_ITEM) { + entry->callback(EXT_MENUBAR_QT_GUI, (gpointer)((void *)main_ui_), entry->user_data); + } else { + QDesktopServices::openUrl(QUrl(QString((gchar *)entry->user_data))); + } + } + } +} + +void LogwolfMainWindow::extcap_options_finished(int result) +{ + if (result == QDialog::Accepted) { + QString before_what(tr(" before starting a new capture")); + if (testCaptureFileClose(before_what)) { + startCapture(); + } + } + this->welcome_page_->getInterfaceFrame()->interfaceListChanged(); +} + +void LogwolfMainWindow::showExtcapOptionsDialog(QString &device_name, bool startCaptureOnClose) +{ + ExtcapOptionsDialog * extcap_options_dialog = ExtcapOptionsDialog::createForDevice(device_name, startCaptureOnClose, this); + /* The dialog returns null, if the given device name is not a valid extcap device */ + if (extcap_options_dialog) { + extcap_options_dialog->setModal(true); + extcap_options_dialog->setAttribute(Qt::WA_DeleteOnClose); + if (startCaptureOnClose) { + connect(extcap_options_dialog, SIGNAL(finished(int)), + this, SLOT(extcap_options_finished(int))); + } +#ifdef HAVE_LIBPCAP + if (capture_options_dialog_ && startCaptureOnClose) { + /* Allow capture options dialog to close */ + connect(extcap_options_dialog, SIGNAL(accepted()), + capture_options_dialog_, SLOT(accept())); + } +#endif + extcap_options_dialog->show(); + } +} + +void LogwolfMainWindow::on_actionContextWikiProtocolPage_triggered() +{ + QAction *wa = qobject_cast(sender()); + if (!wa) return; + + bool ok = false; + int field_id = wa->data().toInt(&ok); + if (!ok) return; + + const QString proto_abbrev = proto_registrar_get_abbrev(field_id); + + int ret = QMessageBox::question(this, mainApp->windowTitleString(tr("Wiki Page for %1").arg(proto_abbrev)), + tr("

The Wireshark Wiki is maintained by the community.

" + "

The page you are about to load might be wonderful, " + "incomplete, wrong, or nonexistent.

" + "

Proceed to the wiki?

"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + + if (ret != QMessageBox::Yes) return; + + QUrl wiki_url = QString(WS_WIKI_URL("Protocols/%1")).arg(proto_abbrev); + QDesktopServices::openUrl(wiki_url); +} + +void LogwolfMainWindow::on_actionContextFilterFieldReference_triggered() +{ + QAction *wa = qobject_cast(sender()); + if (!wa) return; + + bool ok = false; + int field_id = wa->data().toInt(&ok); + if (!ok) return; + + const QString proto_abbrev = proto_registrar_get_abbrev(field_id); + + QUrl dfref_url = QString(WS_DOCS_URL "/dfref/%1/%2") + .arg(proto_abbrev[0]) + .arg(proto_abbrev); + QDesktopServices::openUrl(dfref_url); +} + +void LogwolfMainWindow::on_actionViewFullScreen_triggered(bool checked) +{ + if (checked) { + // Save the state for future restore + was_maximized_ = this->isMaximized(); + this->showFullScreen(); + } else { + // Restore the previous state + if (was_maximized_) + this->showMaximized(); + else + this->showNormal(); + } +} + +void LogwolfMainWindow::activatePluginIFToolbar(bool) +{ + QAction *sendingAction = dynamic_cast(sender()); + if (!sendingAction || !sendingAction->data().isValid()) + return; + + ext_toolbar_t *toolbar = VariantPointer::asPtr(sendingAction->data()); + + QList toolbars = findChildren(); + foreach(QToolBar *bar, toolbars) { + AdditionalToolBar *iftoolbar = dynamic_cast(bar); + if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) { + if (iftoolbar->isVisible()) { + iftoolbar->setVisible(false); + sendingAction->setChecked(true); + } else { + iftoolbar->setVisible(true); + sendingAction->setChecked(true); + } + } + } +} + +void LogwolfMainWindow::rtpPlayerDialogReplaceRtpStreams(QVector stream_ids _U_) +{ +#ifdef QT_MULTIMEDIA_LIB + openTelephonyRtpPlayerDialog()->replaceRtpStreams(stream_ids); +#endif +} + +void LogwolfMainWindow::rtpPlayerDialogAddRtpStreams(QVector stream_ids _U_) +{ +#ifdef QT_MULTIMEDIA_LIB + openTelephonyRtpPlayerDialog()->addRtpStreams(stream_ids); +#endif +} + +void LogwolfMainWindow::rtpPlayerDialogRemoveRtpStreams(QVector stream_ids _U_) +{ +#ifdef QT_MULTIMEDIA_LIB + openTelephonyRtpPlayerDialog()->removeRtpStreams(stream_ids); +#endif +} + +void LogwolfMainWindow::rtpAnalysisDialogReplaceRtpStreams(QVector stream_ids) +{ + openTelephonyRtpAnalysisDialog()->replaceRtpStreams(stream_ids); +} + +void LogwolfMainWindow::rtpAnalysisDialogAddRtpStreams(QVector stream_ids) +{ + openTelephonyRtpAnalysisDialog()->addRtpStreams(stream_ids); +} + +void LogwolfMainWindow::rtpAnalysisDialogRemoveRtpStreams(QVector stream_ids) +{ + openTelephonyRtpAnalysisDialog()->removeRtpStreams(stream_ids); +} + +void LogwolfMainWindow::rtpStreamsDialogSelectRtpStreams(QVector stream_ids) +{ + openTelephonyRtpStreamsDialog()->selectRtpStream(stream_ids); +} + +void LogwolfMainWindow::rtpStreamsDialogDeselectRtpStreams(QVector stream_ids) +{ + openTelephonyRtpStreamsDialog()->deselectRtpStream(stream_ids); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/ui/qt_logshark/ls_main.cpp b/ui/qt_logshark/ls_main.cpp index a68396bd97..abc141ed87 100644 --- a/ui/qt_logshark/ls_main.cpp +++ b/ui/qt_logshark/ls_main.cpp @@ -81,7 +81,7 @@ #include "ui/qt/utils/color_utils.h" #include "ui/qt/coloring_rules_dialog.h" #include "ui/qt/endpoint_dialog.h" -#include "ui/qt/main_window.h" +#include "ui/qt_logshark/logwolf_main_window.h" #include "ui/qt/response_time_delay_dialog.h" #include "ui/qt/service_response_time_dialog.h" #include "ui/qt/simple_dialog.h" @@ -418,7 +418,7 @@ macos_enable_layer_backing(void) /* And now our feature presentation... [ fade to music ] */ int main(int argc, char *qt_argv[]) { - MainWindow *main_w; + LogwolfMainWindow *main_w; #ifdef _WIN32 LPWSTR *wc_argv; @@ -697,7 +697,7 @@ int main(int argc, char *qt_argv[]) /* ws_log(LOG_DOMAIN_MAIN, LOG_LEVEL_DEBUG, "Translator %s", language); */ // Init the main window (and splash) - main_w = new(MainWindow); + main_w = new(LogwolfMainWindow); main_w->show(); // We may not need a queued connection here but it would seem to make sense // to force the issue.