Qt: Add separators between filter expression buttons.
[metze/wireshark/wip.git] / ui / qt / main_window_slots.cpp
1 /* main_window_slots.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9
10 #include <config.h>
11
12 // Qt 5.5.0 + Visual C++ 2013
13 #ifdef _MSC_VER
14 #pragma warning(push)
15 #pragma warning(disable:4996)
16 #endif
17
18 #include "main_window.h"
19
20 /*
21  * The generated Ui_MainWindow::setupUi() can grow larger than our configured limit,
22  * so turn off -Wframe-larger-than= for ui_main_window.h.
23  */
24 DIAG_OFF(frame-larger-than=)
25 #include <ui_main_window.h>
26 DIAG_ON(frame-larger-than=)
27
28 #ifdef _WIN32
29 #include <windows.h>
30 #endif
31
32 #include "ui/dissect_opts.h"
33
34 #ifdef HAVE_LIBPCAP
35 #include "ui/capture.h"
36 #endif
37
38 #include "ui/commandline.h"
39
40 #include "epan/color_filters.h"
41 #include "epan/export_object.h"
42
43 #include "wsutil/file_util.h"
44 #include "wsutil/filesystem.h"
45
46 #include "epan/addr_resolv.h"
47 #include "epan/column.h"
48 #include "epan/dfilter/dfilter-macro.h"
49 #include "epan/dissector_filters.h"
50 #include "epan/epan_dissect.h"
51 #include "epan/filter_expressions.h"
52 #include "epan/prefs.h"
53 #include "epan/plugin_if.h"
54 #include "epan/uat.h"
55 #include "epan/uat-int.h"
56 #include "epan/value_string.h"
57
58 #ifdef HAVE_LUA
59 #include <epan/wslua/init_wslua.h>
60 #endif
61
62 #include "ui/alert_box.h"
63 #ifdef HAVE_LIBPCAP
64 #include "ui/capture_ui_utils.h"
65 #endif
66
67 #include "ui/capture_globals.h"
68 #include "ui/help_url.h"
69 #include "ui/main_statusbar.h"
70 #include "ui/preference_utils.h"
71 #include "ui/recent.h"
72 #include "ui/recent_utils.h"
73 #include "ui/ssl_key_export.h"
74 #include "ui/ws_ui_util.h"
75 #include "ui/all_files_wildcard.h"
76 #include "ui/qt/simple_dialog.h"
77
78 #include <ui/qt/utils/variant_pointer.h>
79 #include <ui/qt/widgets/drag_drop_toolbar.h>
80
81 #ifdef HAVE_SOFTWARE_UPDATE
82 #include "ui/software_update.h"
83 #endif
84
85 #include "about_dialog.h"
86 #include "bluetooth_att_server_attributes_dialog.h"
87 #include "bluetooth_devices_dialog.h"
88 #include "bluetooth_hci_summary_dialog.h"
89 #include "capture_file_dialog.h"
90 #include "capture_file_properties_dialog.h"
91 #ifdef HAVE_LIBPCAP
92 #include "capture_interfaces_dialog.h"
93 #endif
94 #include <ui/qt/utils/color_utils.h>
95 #include "coloring_rules_dialog.h"
96 #include "conversation_dialog.h"
97 #include "conversation_colorize_action.h"
98 #include "conversation_hash_tables_dialog.h"
99 #include "enabled_protocols_dialog.h"
100 #include "decode_as_dialog.h"
101 #include <ui/qt/widgets/display_filter_edit.h>
102 #include "display_filter_expression_dialog.h"
103 #include "dissector_tables_dialog.h"
104 #include "endpoint_dialog.h"
105 #include "expert_info_dialog.h"
106 #include "export_object_action.h"
107 #include "export_object_dialog.h"
108 #include "export_pdu_dialog.h"
109 #include "extcap_options_dialog.h"
110 #include "file_set_dialog.h"
111 #include "filter_action.h"
112 #include "filter_dialog.h"
113 #include "firewall_rules_dialog.h"
114 #include "funnel_statistics.h"
115 #include "gsm_map_summary_dialog.h"
116 #include "iax2_analysis_dialog.h"
117 #include "interface_toolbar.h"
118 #include "io_graph_dialog.h"
119 #include <ui/qt/widgets/additional_toolbar.h>
120 #include "lbm_stream_dialog.h"
121 #include "lbm_lbtrm_transport_dialog.h"
122 #include "lbm_lbtru_transport_dialog.h"
123 #include "lte_mac_statistics_dialog.h"
124 #include "lte_rlc_statistics_dialog.h"
125 #include "lte_rlc_graph_dialog.h"
126 #include "mtp3_summary_dialog.h"
127 #include "multicast_statistics_dialog.h"
128 #include "packet_comment_dialog.h"
129 #include "packet_dialog.h"
130 #include "packet_list.h"
131 #include "preferences_dialog.h"
132 #include "print_dialog.h"
133 #include "profile_dialog.h"
134 #include "protocol_hierarchy_dialog.h"
135 #include <ui/qt/utils/qt_ui_utils.h>
136 #include "resolved_addresses_dialog.h"
137 #include "rpc_service_response_time_dialog.h"
138 #include "rtp_stream_dialog.h"
139 #include "rtp_analysis_dialog.h"
140 #include "sctp_all_assocs_dialog.h"
141 #include "sctp_assoc_analyse_dialog.h"
142 #include "sctp_graph_dialog.h"
143 #include "sequence_dialog.h"
144 #include "show_packet_bytes_dialog.h"
145 #include "stats_tree_dialog.h"
146 #include <ui/qt/utils/stock_icon.h>
147 #include "supported_protocols_dialog.h"
148 #include "tap_parameter_dialog.h"
149 #include "tcp_stream_dialog.h"
150 #include "time_shift_dialog.h"
151 #include "uat_dialog.h"
152 #include "voip_calls_dialog.h"
153 #include "wireshark_application.h"
154 #include "wlan_statistics_dialog.h"
155 #include "wireless_timeline.h"
156
157 #include <QClipboard>
158 #include <QFileInfo>
159 #include <QMessageBox>
160 #include <QMetaObject>
161 #include <QToolBar>
162 #include <QDesktopServices>
163 #include <QUrl>
164
165 // XXX You must uncomment QT_WINEXTRAS_LIB lines in CMakeList.txt and
166 // cmakeconfig.h.in.
167 // #if defined(QT_WINEXTRAS_LIB) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
168 // #include <QWinJumpList>
169 // #include <QWinJumpListCategory>
170 // #include <QWinJumpListItem>
171 // #endif
172
173 //
174 // Public slots
175 //
176
177 static const char *dfe_property_ = "display filter expression"; //TODO : Fix Translate
178 static const char *dfe_property_label_ = "display_filter_expression_label";
179 static const char *dfe_property_expression_ = "display_filter_expression_expr";
180
181 bool MainWindow::openCaptureFile(QString cf_path, QString read_filter, unsigned int type, gboolean is_tempfile)
182 {
183     QString file_name = "";
184     dfilter_t *rfcode = NULL;
185     gchar *err_msg;
186     int err;
187     gboolean name_param;
188     gboolean ret = true;
189
190     // was a file name given as function parameter?
191     name_param = !cf_path.isEmpty();
192
193     for (;;) {
194
195         if (cf_path.isEmpty()) {
196             CaptureFileDialog open_dlg(this, capture_file_.capFile(), read_filter);
197
198             if (open_dlg.open(file_name, type)) {
199                 cf_path = file_name;
200             } else {
201                 ret = false;
202                 goto finish;
203             }
204         }
205
206         QString before_what(tr(" before opening another file"));
207         if (!testCaptureFileClose(before_what)) {
208             ret = false;
209             goto finish;
210         }
211
212         if (dfilter_compile(qUtf8Printable(read_filter), &rfcode, &err_msg)) {
213             cf_set_rfcode(CaptureFile::globalCapFile(), rfcode);
214         } else {
215             /* Not valid.  Tell the user, and go back and run the file
216                selection box again once they dismiss the alert. */
217             //bad_dfilter_alert_box(top_level, read_filter->str);
218             QMessageBox::warning(this, tr("Invalid Display Filter"),
219                     QString("The filter expression ") +
220                     read_filter +
221                     QString(" isn't a valid display filter. (") +
222                     err_msg + QString(")."),
223                     QMessageBox::Ok);
224
225             if (!name_param) {
226                 // go back to the selection dialogue only if the file
227                 // was selected from this dialogue
228                 cf_path.clear();
229                 continue;
230             }
231         }
232
233         /* Make the file name available via MainWindow */
234         setMwFileName(cf_path);
235
236         /* Try to open the capture file. This closes the current file if it succeeds. */
237         CaptureFile::globalCapFile()->window = this;
238         if (cf_open(CaptureFile::globalCapFile(), qUtf8Printable(cf_path), type, is_tempfile, &err) != CF_OK) {
239             /* We couldn't open it; don't dismiss the open dialog box,
240                just leave it around so that the user can, after they
241                dismiss the alert box popped up for the open error,
242                try again. */
243             CaptureFile::globalCapFile()->window = NULL;
244             dfilter_free(rfcode);
245             cf_path.clear();
246             continue;
247         }
248
249         switch (cf_read(CaptureFile::globalCapFile(), FALSE)) {
250
251         case CF_READ_OK:
252         case CF_READ_ERROR:
253             /* Just because we got an error, that doesn't mean we were unable
254                to read any of the file; we handle what we could get from the
255                file. */
256             break;
257
258         case CF_READ_ABORTED:
259             /* The user bailed out of re-reading the capture file; the
260                capture file has been closed - just free the capture file name
261                string and return (without changing the last containing
262                directory). */
263             capture_file_.setCapFile(NULL);
264             ret = false;
265             goto finish;
266         }
267         break;
268     }
269     // get_dirname overwrites its path.
270     wsApp->setLastOpenDir(get_dirname(cf_path.toUtf8().data()));
271
272     main_ui_->statusBar->showExpert();
273
274 finish:
275 #ifdef HAVE_LIBPCAP
276     if (global_commandline_info.quit_after_cap)
277         exit(0);
278 #endif
279     return ret;
280 }
281
282 void MainWindow::filterPackets(QString new_filter, bool force)
283 {
284     cf_status_t cf_status;
285
286     cf_status = cf_filter_packets(CaptureFile::globalCapFile(), new_filter.toUtf8().data(), force);
287
288     if (cf_status == CF_OK) {
289         emit displayFilterSuccess(true);
290         if (new_filter.length() > 0) {
291             int index = df_combo_box_->findText(new_filter);
292             if (index == -1) {
293                 df_combo_box_->insertItem(0, new_filter);
294                 df_combo_box_->setCurrentIndex(0);
295             } else {
296                 df_combo_box_->setCurrentIndex(index);
297             }
298         } else {
299             df_combo_box_->lineEdit()->clear();
300         }
301     } else {
302         emit displayFilterSuccess(false);
303     }
304     if (packet_list_) {
305         packet_list_->resetColumns();
306     }
307 }
308
309 // A new layout should be applied when it differs from the old layout AND
310 // at the following times:
311 // - At startup
312 // - When the preferences change
313 // - When the profile changes
314 void MainWindow::layoutPanes()
315 {
316     QVector<unsigned> new_layout = QVector<unsigned>() << prefs.gui_layout_type
317                                                        << prefs.gui_layout_content_1
318                                                        << prefs.gui_layout_content_2
319                                                        << prefs.gui_layout_content_3
320                                                        << recent.packet_list_show
321                                                        << recent.tree_view_show
322                                                        << recent.byte_view_show;
323
324     if (cur_layout_ == new_layout) return;
325
326     QSplitter *parents[3];
327
328     // Reparent all widgets and add them back in the proper order below.
329     // This hides each widget as well.
330     packet_list_->freeze(); // Clears tree and byte view tabs.
331     packet_list_->setParent(main_ui_->mainStack);
332     proto_tree_->setParent(main_ui_->mainStack);
333     byte_view_tab_->setParent(main_ui_->mainStack);
334     empty_pane_.setParent(main_ui_->mainStack);
335     extra_split_.setParent(main_ui_->mainStack);
336
337     // XXX We should try to preserve geometries if we can, e.g. by
338     // checking to see if the layout type is the same.
339     switch(prefs.gui_layout_type) {
340     case(layout_type_2):
341     case(layout_type_1):
342         extra_split_.setOrientation(Qt::Horizontal);
343         /* Fall Through */
344     case(layout_type_5):
345         master_split_.setOrientation(Qt::Vertical);
346         break;
347
348     case(layout_type_4):
349     case(layout_type_3):
350         extra_split_.setOrientation(Qt::Vertical);
351         /* Fall Through */
352     case(layout_type_6):
353         master_split_.setOrientation(Qt::Horizontal);
354         break;
355
356     default:
357         g_assert_not_reached();
358     }
359
360     switch(prefs.gui_layout_type) {
361     case(layout_type_5):
362     case(layout_type_6):
363         parents[0] = &master_split_;
364         parents[1] = &master_split_;
365         parents[2] = &master_split_;
366         break;
367     case(layout_type_2):
368     case(layout_type_4):
369         parents[0] = &master_split_;
370         parents[1] = &extra_split_;
371         parents[2] = &extra_split_;
372         break;
373     case(layout_type_1):
374     case(layout_type_3):
375         parents[0] = &extra_split_;
376         parents[1] = &extra_split_;
377         parents[2] = &master_split_;
378         break;
379     default:
380         g_assert_not_reached();
381     }
382
383     if (parents[0] == &extra_split_) {
384         master_split_.addWidget(&extra_split_);
385     }
386
387     parents[0]->addWidget(getLayoutWidget(prefs.gui_layout_content_1));
388
389     if (parents[2] == &extra_split_) {
390         master_split_.addWidget(&extra_split_);
391     }
392
393     parents[1]->addWidget(getLayoutWidget(prefs.gui_layout_content_2));
394     parents[2]->addWidget(getLayoutWidget(prefs.gui_layout_content_3));
395
396     const QList<QWidget *> ms_children = master_split_.findChildren<QWidget *>();
397
398     extra_split_.setVisible(ms_children.contains(&extra_split_));
399     packet_list_->setVisible(ms_children.contains(packet_list_) && recent.packet_list_show);
400     proto_tree_->setVisible(ms_children.contains(proto_tree_) && recent.tree_view_show);
401     byte_view_tab_->setVisible(ms_children.contains(byte_view_tab_) && recent.byte_view_show);
402
403     packet_list_->thaw(true);
404     cur_layout_ = new_layout;
405 }
406
407 // The recent layout geometry should be applied after the layout has been
408 // applied AND at the following times:
409 // - At startup
410 // - When the profile changes
411 void MainWindow::applyRecentPaneGeometry()
412 {
413     // XXX This shrinks slightly each time the application is run. For some
414     // reason the master_split_ geometry is two pixels shorter when
415     // saveWindowGeometry is invoked.
416
417     // This is also an awful lot of trouble to go through to reuse the GTK+
418     // pane settings. We might want to add gui.geometry_main_master_sizes
419     // and gui.geometry_main_extra_sizes and save QSplitter::saveState in
420     // each.
421
422     // Force a geometry recalculation
423     QWidget *cur_w = main_ui_->mainStack->currentWidget();
424     main_ui_->mainStack->setCurrentWidget(&master_split_);
425     QRect geom = main_ui_->mainStack->geometry();
426     QList<int> master_sizes = master_split_.sizes();
427     QList<int> extra_sizes = extra_split_.sizes();
428     main_ui_->mainStack->setCurrentWidget(cur_w);
429
430     int master_last_size = master_split_.orientation() == Qt::Vertical ? geom.height() : geom.width();
431     master_last_size -= master_split_.handleWidth() * (master_sizes.length() - 1);
432
433     int extra_last_size = extra_split_.orientation() == Qt::Vertical ? geom.height() : geom.width();
434     extra_last_size -= extra_split_.handleWidth();
435
436     if (recent.gui_geometry_main_upper_pane > 0) {
437         master_sizes[0] = recent.gui_geometry_main_upper_pane;
438         master_last_size -= recent.gui_geometry_main_upper_pane;
439     } else {
440         master_sizes[0] = master_last_size / master_sizes.length();
441         master_last_size -= master_last_size / master_sizes.length();
442     }
443
444     if (recent.gui_geometry_main_lower_pane > 0) {
445         if (master_sizes.length() > 2) {
446             master_sizes[1] = recent.gui_geometry_main_lower_pane;
447             master_last_size -= recent.gui_geometry_main_lower_pane;
448         } else if (extra_sizes.length() > 0) {
449             extra_sizes[0] = recent.gui_geometry_main_lower_pane;
450             extra_last_size -= recent.gui_geometry_main_lower_pane;
451             extra_sizes.last() = extra_last_size;
452         }
453     } else {
454         if (master_sizes.length() > 2) {
455             master_sizes[1] = master_last_size / 2;
456             master_last_size -= master_last_size / 2;
457         } else {
458             extra_sizes[0] = extra_last_size / 2;
459             extra_last_size -= extra_last_size / 2;
460             extra_sizes.last() = extra_last_size;
461         }
462     }
463
464     master_sizes.last() = master_last_size;
465
466     master_split_.setSizes(master_sizes);
467     extra_split_.setSizes(extra_sizes);
468 }
469
470 void MainWindow::layoutToolbars()
471 {
472     Qt::ToolButtonStyle tbstyle = Qt::ToolButtonIconOnly;
473     switch (prefs.gui_toolbar_main_style) {
474     case TB_STYLE_TEXT:
475         tbstyle = Qt::ToolButtonTextOnly;
476         break;
477     case TB_STYLE_BOTH:
478         tbstyle = Qt::ToolButtonTextUnderIcon;
479         break;
480     }
481
482     main_ui_->mainToolBar->setToolButtonStyle(tbstyle);
483
484     main_ui_->mainToolBar->setVisible(recent.main_toolbar_show);
485     main_ui_->displayFilterToolBar->setVisible(recent.filter_toolbar_show);
486     main_ui_->wirelessToolBar->setVisible(recent.wireless_toolbar_show);
487     main_ui_->statusBar->setVisible(recent.statusbar_show);
488
489     foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
490         QToolBar *toolbar = action->data().value<QToolBar *>();
491         if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp)) {
492             toolbar->setVisible(true);
493         } else {
494             toolbar->setVisible(false);
495         }
496     }
497
498     QList<QToolBar *> toolbars = findChildren<QToolBar *>();
499     foreach (QToolBar *bar, toolbars) {
500         AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
501         if (iftoolbar) {
502             bool visible = false;
503             if (g_list_find_custom(recent.gui_additional_toolbars, qUtf8Printable(iftoolbar->menuName()), (GCompareFunc) strcmp))
504                 visible = true;
505
506             iftoolbar->setVisible(visible);
507
508         }
509     }
510 }
511
512 void MainWindow::updatePreferenceActions()
513 {
514     main_ui_->actionViewPacketList->setEnabled(prefs_has_layout_pane_content(layout_pane_content_plist));
515     main_ui_->actionViewPacketDetails->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdetails));
516     main_ui_->actionViewPacketBytes->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pbytes));
517
518     main_ui_->actionViewNameResolutionPhysical->setChecked(gbl_resolv_flags.mac_name);
519     main_ui_->actionViewNameResolutionNetwork->setChecked(gbl_resolv_flags.network_name);
520     main_ui_->actionViewNameResolutionTransport->setChecked(gbl_resolv_flags.transport_name);
521
522     // Should this be a "recent" setting?
523     main_ui_->actionGoAutoScroll->setChecked(prefs.capture_auto_scroll);
524 }
525
526 void MainWindow::updateRecentActions()
527 {
528     main_ui_->actionViewMainToolbar->setChecked(recent.main_toolbar_show);
529     main_ui_->actionViewFilterToolbar->setChecked(recent.filter_toolbar_show);
530     main_ui_->actionViewWirelessToolbar->setChecked(recent.wireless_toolbar_show);
531     main_ui_->actionViewStatusBar->setChecked(recent.statusbar_show);
532     main_ui_->actionViewPacketList->setChecked(recent.packet_list_show && prefs_has_layout_pane_content(layout_pane_content_plist));
533     main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show && prefs_has_layout_pane_content(layout_pane_content_pdetails));
534     main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show && prefs_has_layout_pane_content(layout_pane_content_pbytes));
535
536     foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
537         if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp)) {
538             action->setChecked(true);
539         } else {
540             action->setChecked(false);
541         }
542     }
543
544     foreach (QAction * action, main_ui_->menuAdditionalToolbars->actions()) {
545         ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data());
546         bool checked = false;
547         if (toolbar && g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc) strcmp))
548             checked = true;
549
550         action->setChecked(checked);
551     }
552
553     foreach (QAction* tda, td_actions.keys()) {
554         if (recent.gui_time_format == td_actions[tda]) {
555             tda->setChecked(true);
556         }
557     }
558     foreach (QAction* tpa, tp_actions.keys()) {
559         if (recent.gui_time_precision == tp_actions[tpa]) {
560             tpa->setChecked(true);
561             break;
562         }
563     }
564     main_ui_->actionViewTimeDisplaySecondsWithHoursAndMinutes->setChecked(recent.gui_seconds_format == TS_SECONDS_HOUR_MIN_SEC);
565
566     main_ui_->actionViewColorizePacketList->setChecked(recent.packet_list_colorize);
567 }
568
569 // Don't connect to this directly. Connect to or emit fiterAction(...) instead.
570 void MainWindow::queuedFilterAction(QString action_filter, FilterAction::Action action, FilterAction::ActionType type)
571 {
572     QString cur_filter, new_filter;
573
574     if (!df_combo_box_) return;
575     cur_filter = df_combo_box_->lineEdit()->text();
576
577     switch (type) {
578     case FilterAction::ActionTypePlain:
579         new_filter = action_filter;
580         break;
581     case FilterAction::ActionTypeAnd:
582         if (cur_filter.length()) {
583             new_filter = "(" + cur_filter + ") && (" + action_filter + ")";
584         } else {
585             new_filter = action_filter;
586         }
587         break;
588     case FilterAction::ActionTypeOr:
589         if (cur_filter.length()) {
590             new_filter = "(" + cur_filter + ") || (" + action_filter + ")";
591         } else {
592             new_filter = action_filter;
593         }
594         break;
595     case FilterAction::ActionTypeNot:
596         new_filter = "!(" + action_filter + ")";
597         break;
598     case FilterAction::ActionTypeAndNot:
599         if (cur_filter.length()) {
600             new_filter = "(" + cur_filter + ") && !(" + action_filter + ")";
601         } else {
602             new_filter = "!(" + action_filter + ")";
603         }
604         break;
605     case FilterAction::ActionTypeOrNot:
606         if (cur_filter.length()) {
607             new_filter = "(" + cur_filter + ") || !(" + action_filter + ")";
608         } else {
609             new_filter = "!(" + action_filter + ")";
610         }
611         break;
612     default:
613         g_assert_not_reached();
614         break;
615     }
616
617     switch(action) {
618     case FilterAction::ActionApply:
619         df_combo_box_->lineEdit()->setText(new_filter);
620         df_combo_box_->applyDisplayFilter();
621         break;
622     case FilterAction::ActionColorize:
623         colorizeWithFilter(new_filter.toUtf8());
624         break;
625     case FilterAction::ActionCopy:
626         wsApp->clipboard()->setText(new_filter);
627         break;
628     case FilterAction::ActionFind:
629         main_ui_->searchFrame->findFrameWithFilter(new_filter);
630         break;
631     case FilterAction::ActionPrepare:
632         df_combo_box_->lineEdit()->setText(new_filter);
633         df_combo_box_->lineEdit()->setFocus();
634         break;
635     case FilterAction::ActionWebLookup:
636     {
637         QString url = QString("https://www.google.com/search?q=") + new_filter;
638         QDesktopServices::openUrl(QUrl(url));
639         break;
640     }
641     default:
642         g_assert_not_reached();
643         break;
644     }
645 }
646
647 // Capture callbacks
648
649 void MainWindow::captureCapturePrepared(capture_session *) {
650 #ifdef HAVE_LIBPCAP
651     setTitlebarForCaptureInProgress();
652
653     setWindowIcon(wsApp->captureIcon());
654
655     /* Disable menu items that make no sense if you're currently running
656        a capture. */
657     setForCaptureInProgress(true);
658 //    set_capture_if_dialog_for_capture_in_progress(TRUE);
659
660 //    /* Don't set up main window for a capture file. */
661 //    main_set_for_capture_file(FALSE);
662     main_ui_->mainStack->setCurrentWidget(&master_split_);
663 #endif // HAVE_LIBPCAP
664 }
665
666 void MainWindow::captureCaptureUpdateStarted(capture_session *session) {
667 #ifdef HAVE_LIBPCAP
668
669     /* We've done this in "prepared" above, but it will be cleared while
670        switching to the next multiple file. */
671     setTitlebarForCaptureInProgress();
672
673     setForCaptureInProgress(true, session->capture_opts->ifaces);
674
675     setForCapturedPackets(true);
676 #else
677     Q_UNUSED(session)
678 #endif // HAVE_LIBPCAP
679 }
680 void MainWindow::captureCaptureUpdateFinished(capture_session *) {
681 #ifdef HAVE_LIBPCAP
682
683     /* The capture isn't stopping any more - it's stopped. */
684     capture_stopping_ = false;
685
686     /* Update the main window as appropriate */
687     updateForUnsavedChanges();
688
689     /* Enable menu items that make sense if you're not currently running
690      a capture. */
691     setForCaptureInProgress(false);
692     setMenusForCaptureFile();
693
694     setWindowIcon(wsApp->normalIcon());
695
696     if (global_commandline_info.quit_after_cap) {
697         // Command line asked us to quit after capturing.
698         // Don't pop up a dialog to ask for unsaved files etc.
699         exit(0);
700     }
701 #endif // HAVE_LIBPCAP
702 }
703
704 void MainWindow::captureCaptureFixedFinished(capture_session *) {
705 #ifdef HAVE_LIBPCAP
706
707     /* The capture isn't stopping any more - it's stopped. */
708     capture_stopping_ = false;
709
710     /* Enable menu items that make sense if you're not currently running
711      a capture. */
712     setForCaptureInProgress(false);
713     /* There isn't a real capture_file structure yet, so just force disabling
714        menu options.  They will "refresh" when the capture file is reloaded to
715        display packets */
716     setMenusForCaptureFile(true);
717
718     setWindowIcon(wsApp->normalIcon());
719
720     if (global_commandline_info.quit_after_cap) {
721         // Command line asked us to quit after capturing.
722         // Don't pop up a dialog to ask for unsaved files etc.
723         exit(0);
724     }
725 #endif // HAVE_LIBPCAP
726 }
727
728 void MainWindow::captureCaptureFailed(capture_session *) {
729 #ifdef HAVE_LIBPCAP
730     /* Capture isn't stopping any more. */
731     capture_stopping_ = false;
732
733     setForCaptureInProgress(false);
734     main_ui_->mainStack->setCurrentWidget(main_welcome_);
735
736     // Reset expert information indicator
737     main_ui_->statusBar->captureFileClosing();
738     main_ui_->statusBar->popFileStatus();
739
740     setWindowIcon(wsApp->normalIcon());
741
742     if (global_commandline_info.quit_after_cap) {
743         // Command line asked us to quit after capturing.
744         // Don't pop up a dialog to ask for unsaved files etc.
745         exit(0);
746     }
747 #endif // HAVE_LIBPCAP
748 }
749
750 // Callbacks from cfile.c and file.c via CaptureFile::captureFileCallback
751
752 void MainWindow::captureEventHandler(CaptureEvent * ev)
753 {
754     switch (ev->captureContext()) {
755
756     case CaptureEvent::File:
757         switch (ev->eventType()) {
758         case CaptureEvent::Opened:
759             captureFileOpened();
760             break;
761         case CaptureEvent::Closing:
762             captureFileClosing();
763             break;
764         case CaptureEvent::Closed:
765             captureFileClosed();
766             break;
767         case CaptureEvent::Started:
768             captureFileReadStarted(tr("Loading"));
769             break;
770         case CaptureEvent::Finished:
771             captureFileReadFinished();
772             break;
773         default:
774             break;
775         }
776         break;
777
778     case CaptureEvent::Reload:
779         switch (ev->eventType()) {
780         case CaptureEvent::Started:
781             captureFileReadStarted(tr("Reloading"));
782             break;
783         case CaptureEvent::Finished:
784             captureFileReadFinished();
785             break;
786         default:
787             break;
788         }
789         break;
790
791     case CaptureEvent::Rescan:
792         switch (ev->eventType()) {
793         case CaptureEvent::Started:
794             setMenusForCaptureFile(true);
795             captureFileReadStarted(tr("Rescanning"));
796             break;
797         case CaptureEvent::Finished:
798             captureFileReadFinished();
799             break;
800         default:
801             break;
802         }
803         break;
804
805     case CaptureEvent::Retap:
806         switch (ev->eventType()) {
807         case CaptureEvent::Started:
808             freeze();
809             break;
810         case CaptureEvent::Finished:
811             thaw();
812             break;
813         case CaptureEvent::Flushed:
814             draw_tap_listeners(FALSE);
815             break;
816         default:
817             break;
818         }
819         break;
820
821     case CaptureEvent::Merge:
822         switch (ev->eventType()) {
823         case CaptureEvent::Started:
824             main_ui_->statusBar->popFileStatus();
825             main_ui_->statusBar->pushFileStatus(tr("Merging files"), QString());
826             break;
827         case CaptureEvent::Finished:
828             main_ui_->statusBar->popFileStatus();
829             break;
830         default:
831             break;
832         }
833         break;
834
835     case CaptureEvent::Save:
836         switch (ev->eventType()) {
837         case CaptureEvent::Started:
838         {
839             QFileInfo file_info(ev->filePath());
840             main_ui_->statusBar->popFileStatus();
841             main_ui_->statusBar->pushFileStatus(tr("Saving %1" UTF8_HORIZONTAL_ELLIPSIS).arg(file_info.baseName()));
842             break;
843         }
844         default:
845             break;
846         }
847         break;
848
849 #ifdef HAVE_LIBPCAP
850     case CaptureEvent::Capture:
851         switch (ev->eventType()) {
852         case CaptureEvent::Prepared:
853             captureCapturePrepared(ev->capSession());
854             break;
855         case CaptureEvent::Stopping:
856             capture_stopping_ = true;
857             setMenusForCaptureStopping();
858             break;
859         case CaptureEvent::Failed:
860             captureCaptureFailed(ev->capSession());
861         default:
862             break;
863         }
864         break;
865
866     case CaptureEvent::Update:
867         switch (ev->eventType()) {
868         case CaptureEvent::Started:
869             captureCaptureUpdateStarted(ev->capSession());
870             break;
871         case CaptureEvent::Finished:
872             captureCaptureUpdateFinished(ev->capSession());
873             break;
874         default:
875             break;
876         }
877         break;
878
879     case CaptureEvent::Fixed:
880         switch (ev->eventType()) {
881         case CaptureEvent::Finished:
882             captureCaptureFixedFinished(ev->capSession());
883             break;
884         default:
885             break;
886         }
887         break;
888 #endif
889     }
890 }
891
892 void MainWindow::captureFileOpened() {
893     if (capture_file_.window() != this) return;
894
895     file_set_dialog_->fileOpened(capture_file_.capFile());
896     setMenusForFileSet(true);
897     emit setCaptureFile(capture_file_.capFile());
898 }
899
900 void MainWindow::captureFileReadStarted(const QString &action) {
901 //    tap_param_dlg_update();
902
903     /* Set up main window for a capture file. */
904 //    main_set_for_capture_file(TRUE);
905
906     main_ui_->statusBar->popFileStatus();
907     QString msg = QString(tr("%1: %2")).arg(action).arg(capture_file_.fileName());
908     QString msgtip = QString();
909     main_ui_->statusBar->pushFileStatus(msg, msgtip);
910     main_ui_->mainStack->setCurrentWidget(&master_split_);
911     main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(false);
912     main_ui_->wirelessTimelineWidget->captureFileReadStarted(capture_file_.capFile());
913
914     WiresharkApplication::processEvents();
915 }
916
917 void MainWindow::captureFileReadFinished() {
918     gchar *dir_path;
919
920     if (!capture_file_.capFile()->is_tempfile && capture_file_.capFile()->filename) {
921         /* Add this filename to the list of recent files in the "Recent Files" submenu */
922         add_menu_recent_capture_file(capture_file_.capFile()->filename);
923
924         /* Remember folder for next Open dialog and save it in recent */
925         dir_path = g_strdup(capture_file_.capFile()->filename);
926         wsApp->setLastOpenDir(get_dirname(dir_path));
927         g_free(dir_path);
928     }
929
930     /* Update the appropriate parts of the main window. */
931     updateForUnsavedChanges();
932
933     /* enable wireless timeline if capture allows it */
934     main_ui_->wirelessTimelineWidget->captureFileReadFinished();
935
936     /* Enable menu items that make sense if you have some captured packets. */
937     setForCapturedPackets(true);
938
939     main_ui_->statusBar->setFileName(capture_file_);
940     main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(true);
941
942     packet_list_->captureFileReadFinished();
943
944     emit setDissectedCaptureFile(capture_file_.capFile());
945 }
946
947 void MainWindow::captureFileClosing() {
948     setMenusForCaptureFile(true);
949     setForCapturedPackets(false);
950     setForCaptureInProgress(false);
951
952     // Reset expert information indicator
953     main_ui_->statusBar->captureFileClosing();
954     main_ui_->searchFrame->animatedHide();
955     main_ui_->goToFrame->animatedHide();
956 //    gtk_widget_show(expert_info_none);
957     emit setCaptureFile(NULL);
958     emit setDissectedCaptureFile(NULL);
959 }
960
961 void MainWindow::captureFileClosed() {
962     packets_bar_update();
963
964     file_set_dialog_->fileClosed();
965     setMenusForFileSet(false);
966     setWindowModified(false);
967
968     // Reset expert information indicator
969     main_ui_->statusBar->captureFileClosing();
970     main_ui_->statusBar->popFileStatus();
971
972     setWSWindowTitle();
973     setWindowIcon(wsApp->normalIcon());
974     setMenusForSelectedPacket();
975     setMenusForSelectedTreeRow();
976
977 #ifdef HAVE_LIBPCAP
978     if (!global_capture_opts.multi_files_on)
979         main_ui_->mainStack->setCurrentWidget(main_welcome_);
980 #endif
981 }
982
983 struct filter_expression_data
984 {
985     MainWindow* window;
986     bool actions_added;
987 };
988
989 gboolean MainWindow::filter_expression_add_action(const void *key _U_, void *value, void *user_data)
990 {
991     filter_expression_t* fe = (filter_expression_t*)value;
992     struct filter_expression_data* data = (filter_expression_data*)user_data;
993
994     if (!fe->enabled)
995         return FALSE;
996
997     QAction *dfb_action = new QAction(fe->label, data->window->filter_expression_toolbar_);
998     if (strlen(fe->comment) > 0)
999     {
1000         QString tooltip = QString("%1\n%2").arg(fe->comment).arg(fe->expression);
1001         dfb_action->setToolTip(tooltip);
1002     }
1003     else
1004     {
1005         dfb_action->setToolTip(fe->expression);
1006     }
1007     dfb_action->setData(fe->expression);
1008     dfb_action->setProperty(dfe_property_, true);
1009     dfb_action->setProperty(dfe_property_label_, QString(fe->label));
1010     dfb_action->setProperty(dfe_property_expression_, QString(fe->expression));
1011
1012     if (data->window->filter_expression_toolbar_->actions().count() > 0) {
1013         data->window->filter_expression_toolbar_->addSeparator();
1014     }
1015     data->window->filter_expression_toolbar_->addAction(dfb_action);
1016     connect(dfb_action, SIGNAL(triggered()), data->window, SLOT(displayFilterButtonClicked()));
1017     data->actions_added = true;
1018     return FALSE;
1019 }
1020
1021 void MainWindow::filterExpressionsChanged()
1022 {
1023     struct filter_expression_data data;
1024
1025     data.window = this;
1026     data.actions_added = false;
1027
1028     filter_expression_toolbar_->clear();
1029
1030     // XXX Add a context menu for removing and changing buttons.
1031     filter_expression_iterate_expressions(filter_expression_add_action, &data);
1032
1033     if (data.actions_added) {
1034         // QToolButton calls updateGeometry+update all over the place.
1035         // updateGeometry should be sufficient here.
1036         main_ui_->displayFilterToolBar->updateGeometry();
1037     }
1038 }
1039
1040 //
1041 // Private slots
1042 //
1043
1044 // ui/gtk/capture_dlg.c:start_capture_confirmed
1045
1046 void MainWindow::startCapture() {
1047 #ifdef HAVE_LIBPCAP
1048     interface_options *interface_opts;
1049     guint i;
1050
1051     /* did the user ever select a capture interface before? */
1052     if(global_capture_opts.num_selected == 0) {
1053         QString msg = QString(tr("No interface selected"));
1054         main_ui_->statusBar->pushTemporaryStatus(msg);
1055         main_ui_->actionCaptureStart->setChecked(false);
1056         return;
1057     }
1058
1059     // Ideally we should have disabled the start capture
1060     // toolbar buttons and menu items. This may not be the
1061     // case, e.g. with QtMacExtras.
1062     if(!capture_filter_valid_) {
1063         QString msg = QString(tr("Invalid capture filter"));
1064         main_ui_->statusBar->pushTemporaryStatus(msg);
1065         main_ui_->actionCaptureStart->setChecked(false);
1066         return;
1067     }
1068
1069     main_ui_->mainStack->setCurrentWidget(&master_split_);
1070
1071     /* XXX - we might need to init other pref data as well... */
1072
1073     /* XXX - can this ever happen? */
1074     if (cap_session_.state != CAPTURE_STOPPED)
1075       return;
1076
1077     /* close the currently loaded capture file */
1078     cf_close((capture_file *) cap_session_.cf);
1079
1080     /* Copy the selected interfaces to the set of interfaces to use for
1081        this capture. */
1082     collect_ifaces(&global_capture_opts);
1083
1084     CaptureFile::globalCapFile()->window = this;
1085     if (capture_start(&global_capture_opts, &cap_session_, &info_data_, main_window_update)) {
1086         capture_options *capture_opts = cap_session_.capture_opts;
1087         GString *interface_names;
1088
1089         /* Add "interface name<live capture in progress>" on main status bar */
1090         interface_names = get_iface_list_string(capture_opts, 0);
1091         if (strlen (interface_names->str) > 0) {
1092             g_string_append(interface_names, ":");
1093         }
1094         g_string_append(interface_names, " ");
1095
1096         main_ui_->statusBar->popFileStatus();
1097         QString msg = QString().sprintf("%s<live capture in progress>", interface_names->str);
1098         QString msgtip = QString().sprintf("to file: %s", (capture_opts->save_file) ? capture_opts->save_file : "");
1099         main_ui_->statusBar->pushFileStatus(msg, msgtip);
1100         g_string_free(interface_names, TRUE);
1101
1102         /* The capture succeeded, which means the capture filter syntax is
1103          valid; add this capture filter to the recent capture filter list. */
1104         QByteArray filter_ba;
1105         for (i = 0; i < global_capture_opts.ifaces->len; i++) {
1106             interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
1107             if (interface_opts->cfilter) {
1108                 recent_add_cfilter(interface_opts->name, interface_opts->cfilter);
1109                 if (filter_ba.isEmpty()) {
1110                     filter_ba = interface_opts->cfilter;
1111                 } else {
1112                     /* Not the first selected interface; is its capture filter
1113                        the same as the one the other interfaces we've looked
1114                        at have? */
1115                     if (strcmp(interface_opts->cfilter, filter_ba.constData()) != 0) {
1116                       /* No, so not all selected interfaces have the same capture
1117                          filter. */
1118                         filter_ba.clear();
1119                     }
1120                 }
1121             }
1122         }
1123         if (!filter_ba.isEmpty()) {
1124             recent_add_cfilter(NULL, filter_ba.constData());
1125         }
1126     } else {
1127         CaptureFile::globalCapFile()->window = NULL;
1128     }
1129 #endif // HAVE_LIBPCAP
1130 }
1131
1132 // Copied from ui/gtk/gui_utils.c
1133 void MainWindow::pipeTimeout() {
1134 #ifdef _WIN32
1135     HANDLE handle;
1136     DWORD avail = 0;
1137     gboolean result, result1;
1138     DWORD childstatus;
1139     gint iterations = 0;
1140
1141
1142     /* try to read data from the pipe only 5 times, to avoid blocking */
1143     while(iterations < 5) {
1144         /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
1145
1146         /* Oddly enough although Named pipes don't work on win9x,
1147            PeekNamedPipe does !!! */
1148         handle = (HANDLE) _get_osfhandle (pipe_source_);
1149         result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
1150
1151         /* Get the child process exit status */
1152         result1 = GetExitCodeProcess((HANDLE)*(pipe_child_process_),
1153                                      &childstatus);
1154
1155         /* If the Peek returned an error, or there are bytes to be read
1156            or the childwatcher thread has terminated then call the normal
1157            callback */
1158         if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
1159
1160             /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
1161
1162             /* And call the real handler */
1163             if (!pipe_input_cb_(pipe_source_, pipe_user_data_)) {
1164                 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
1165                 /* pipe closed, return false so that the old timer is not run again */
1166                 delete pipe_timer_;
1167                 return;
1168             }
1169         }
1170         else {
1171             /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
1172             /* No data, stop now */
1173             break;
1174         }
1175
1176         iterations++;
1177     }
1178 #endif // _WIN32
1179 }
1180
1181 void MainWindow::pipeActivated(int source) {
1182 #ifdef _WIN32
1183     Q_UNUSED(source)
1184 #else
1185     g_assert(source == pipe_source_);
1186
1187     pipe_notifier_->setEnabled(false);
1188     if (pipe_input_cb_(pipe_source_, pipe_user_data_)) {
1189         pipe_notifier_->setEnabled(true);
1190     } else {
1191         delete pipe_notifier_;
1192     }
1193 #endif // _WIN32
1194 }
1195
1196 void MainWindow::pipeNotifierDestroyed()
1197 {
1198     /* Pop the "<live capture in progress>" message off the status bar. */
1199     main_ui_->statusBar->setFileName(capture_file_);
1200
1201 #ifdef _WIN32
1202     pipe_timer_ = NULL;
1203 #else
1204     pipe_notifier_ = NULL;
1205 #endif // _WIN32
1206 }
1207
1208 void MainWindow::stopCapture() {
1209 //#ifdef HAVE_AIRPCAP
1210 //  if (airpcap_if_active)
1211 //    airpcap_set_toolbar_stop_capture(airpcap_if_active);
1212 //#endif
1213
1214 #ifdef HAVE_LIBPCAP
1215     capture_stop(&cap_session_);
1216 #endif // HAVE_LIBPCAP
1217
1218 }
1219
1220 // Keep focus rects from showing through the welcome screen. Primarily for
1221 // macOS.
1222 void MainWindow::mainStackChanged(int)
1223 {
1224     for (int i = 0; i < main_ui_->mainStack->count(); i++) {
1225         main_ui_->mainStack->widget(i)->setEnabled(i == main_ui_->mainStack->currentIndex());
1226     }
1227 }
1228
1229 // XXX - Copied from ui/gtk/menus.c
1230
1231 /**
1232  * Add the capture filename (with an absolute path) to the "Recent Files" menu.
1233  */
1234 // XXX - We should probably create a RecentFile class.
1235 void MainWindow::updateRecentCaptures() {
1236     QAction *ra;
1237     QMenu *recentMenu = main_ui_->menuOpenRecentCaptureFile;
1238     QString action_cf_name;
1239
1240     if (!recentMenu) {
1241         return;
1242     }
1243     recentMenu->clear();
1244
1245 // #if defined(QT_WINEXTRAS_LIB) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1246 //     QWinJumpList recent_jl(this);
1247 //     QWinJumpListCategory *recent_jlc = recent_jl.recent();
1248 //     if (recent_jlc) {
1249 //         recent_jlc->clear();
1250 //         recent_jlc->setVisible(true);
1251 //     }
1252 // #endif
1253 #if defined(Q_OS_MAC) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1254     if (!dock_menu_) {
1255         dock_menu_ = new QMenu();
1256         dock_menu_->setAsDockMenu();
1257     }
1258     dock_menu_->clear();
1259 #endif
1260
1261     /* Iterate through the actions in menuOpenRecentCaptureFile,
1262      * removing special items, a maybe duplicate entry and every item above count_max */
1263     int shortcut = Qt::Key_0;
1264     foreach (recent_item_status *ri, wsApp->recentItems()) {
1265         // Add the new item
1266         ra = new QAction(recentMenu);
1267         ra->setData(ri->filename);
1268         // XXX - Needs get_recent_item_status or equivalent
1269         ra->setEnabled(ri->accessible);
1270         recentMenu->insertAction(NULL, ra);
1271         action_cf_name = ra->data().toString();
1272         if (shortcut <= Qt::Key_9) {
1273             ra->setShortcut(Qt::META | shortcut);
1274             shortcut++;
1275         }
1276         ra->setText(action_cf_name);
1277         connect(ra, SIGNAL(triggered()), this, SLOT(recentActionTriggered()));
1278
1279 // This is slow, at least on my VM here. The added links also open Wireshark
1280 // in a new window. It might make more sense to add a recent item when we
1281 // open a capture file.
1282 // #if defined(QT_WINEXTRAS_LIB) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1283 //     if (recent_jlc) {
1284 //         QFileInfo fi(ri->filename);
1285 //         QWinJumpListItem *jli = recent_jlc->addLink(
1286 //             fi.fileName(),
1287 //             QApplication::applicationFilePath(),
1288 //             QStringList() << "-r" << ri->filename
1289 //         );
1290 //         // XXX set icon
1291 //         jli->setWorkingDirectory(QDir::toNativeSeparators(QApplication::applicationDirPath()));
1292 //     }
1293 // #endif
1294 #if defined(Q_OS_MAC) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1295         QAction *rda = new QAction(dock_menu_);
1296         QFileInfo fi(ri->filename);
1297         rda->setText(fi.fileName());
1298         dock_menu_->insertAction(NULL, rda);
1299         connect(rda, SIGNAL(triggered()), ra, SLOT(trigger()));
1300 #endif
1301     }
1302
1303     if (recentMenu->actions().count() > 0) {
1304         // Separator + "Clear"
1305         // XXX - Do we really need this?
1306         ra = new QAction(recentMenu);
1307         ra->setSeparator(true);
1308         recentMenu->insertAction(NULL, ra);
1309
1310         ra = new QAction(recentMenu);
1311         ra->setText(tr("Clear Menu"));
1312         recentMenu->insertAction(NULL, ra);
1313         connect(ra, SIGNAL(triggered()), wsApp, SLOT(clearRecentCaptures()));
1314     } else {
1315         if (main_ui_->actionDummyNoFilesFound) {
1316             recentMenu->addAction(main_ui_->actionDummyNoFilesFound);
1317         }
1318     }
1319 }
1320
1321 void MainWindow::recentActionTriggered() {
1322     QAction *ra = qobject_cast<QAction*>(sender());
1323
1324     if (ra) {
1325         QString cfPath = ra->data().toString();
1326         openCaptureFile(cfPath);
1327     }
1328 }
1329
1330 void MainWindow::setMenusForSelectedPacket()
1331 {
1332     gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_ssl = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE, is_http = FALSE;
1333
1334     /* Making the menu context-sensitive allows for easier selection of the
1335        desired item and has the added benefit, with large captures, of
1336        avoiding needless looping through huge lists for marked, ignored,
1337        or time-referenced packets. */
1338
1339     /* We have one or more items in the packet list */
1340     bool have_frames = false;
1341     /* A frame is selected */
1342     bool frame_selected = false;
1343     /* A visible packet comes after this one in the selection history */
1344     bool next_selection_history = false;
1345     /* A visible packet comes before this one in the selection history */
1346     bool previous_selection_history = false;
1347     /* We have marked frames.  (XXX - why check frame_selected?) */
1348     bool have_marked = false;
1349     /* We have a marked frame other than the current frame (i.e.,
1350        we have at least one marked frame, and either there's more
1351        than one marked frame or the current frame isn't marked). */
1352     bool another_is_marked = false;
1353     /* One or more frames are hidden by a display filter */
1354     bool have_filtered = false;
1355     /* One or more frames have been ignored */
1356     bool have_ignored = false;
1357     bool have_time_ref = false;
1358     /* We have a time reference frame other than the current frame (i.e.,
1359        we have at least one time reference frame, and either there's more
1360        than one time reference frame or the current frame isn't a
1361        time reference frame). (XXX - why check frame_selected?) */
1362     bool another_is_time_ref = false;
1363     /* We have a valid filter expression */
1364     bool have_filter_expr = false;
1365
1366     QList<QAction *> cc_actions = QList<QAction *>()
1367             << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1368             << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1369             << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1370             << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1371             << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1372
1373     if (capture_file_.capFile()) {
1374         frame_selected = capture_file_.capFile()->current_frame != NULL;
1375         next_selection_history = packet_list_->haveNextHistory();
1376         previous_selection_history = packet_list_->havePreviousHistory();
1377         have_frames = capture_file_.capFile()->count > 0;
1378         have_marked = frame_selected && capture_file_.capFile()->marked_count > 0;
1379         another_is_marked = have_marked &&
1380                 !(capture_file_.capFile()->marked_count == 1 && capture_file_.capFile()->current_frame->flags.marked);
1381         have_filtered = capture_file_.capFile()->displayed_count > 0 && capture_file_.capFile()->displayed_count != capture_file_.capFile()->count;
1382         have_ignored = capture_file_.capFile()->ignored_count > 0;
1383         have_time_ref = capture_file_.capFile()->ref_time_count > 0;
1384         another_is_time_ref = frame_selected && have_time_ref &&
1385                 !(capture_file_.capFile()->ref_time_count == 1 && capture_file_.capFile()->current_frame->flags.ref_time);
1386
1387         if (capture_file_.capFile()->edt)
1388         {
1389             proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers,
1390                                       &is_ip, &is_tcp, &is_udp, &is_sctp,
1391                                       &is_ssl, &is_rtp, &is_lte_rlc);
1392             is_http = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http");
1393         }
1394     }
1395
1396     have_filter_expr = !packet_list_->getFilterFromRowAndColumn().isEmpty();
1397
1398     main_ui_->actionEditMarkPacket->setEnabled(frame_selected);
1399     main_ui_->actionEditMarkAllDisplayed->setEnabled(have_frames);
1400     /* Unlike un-ignore, do not allow unmark of all frames when no frames are displayed  */
1401     main_ui_->actionEditUnmarkAllDisplayed->setEnabled(have_marked);
1402     main_ui_->actionEditNextMark->setEnabled(another_is_marked);
1403     main_ui_->actionEditPreviousMark->setEnabled(another_is_marked);
1404
1405     main_ui_->actionEditPacketComment->setEnabled(frame_selected && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET));
1406     main_ui_->actionDeleteAllPacketComments->setEnabled((capture_file_.capFile() != NULL) && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET));
1407
1408     main_ui_->actionEditIgnorePacket->setEnabled(frame_selected);
1409     main_ui_->actionEditIgnoreAllDisplayed->setEnabled(have_filtered);
1410     /* Allow un-ignore of all frames even with no frames currently displayed */
1411     main_ui_->actionEditUnignoreAllDisplayed->setEnabled(have_ignored);
1412
1413     main_ui_->actionEditSetTimeReference->setEnabled(frame_selected);
1414     main_ui_->actionEditUnsetAllTimeReferences->setEnabled(have_time_ref);
1415     main_ui_->actionEditNextTimeReference->setEnabled(another_is_time_ref);
1416     main_ui_->actionEditPreviousTimeReference->setEnabled(another_is_time_ref);
1417     main_ui_->actionEditTimeShift->setEnabled(have_frames);
1418
1419     main_ui_->actionGoGoToLinkedPacket->setEnabled(false);
1420     main_ui_->actionGoNextHistoryPacket->setEnabled(next_selection_history);
1421     main_ui_->actionGoPreviousHistoryPacket->setEnabled(previous_selection_history);
1422
1423     main_ui_->actionAnalyzeAAFSelected->setEnabled(have_filter_expr);
1424     main_ui_->actionAnalyzeAAFNotSelected->setEnabled(have_filter_expr);
1425     main_ui_->actionAnalyzeAAFAndSelected->setEnabled(have_filter_expr);
1426     main_ui_->actionAnalyzeAAFOrSelected->setEnabled(have_filter_expr);
1427     main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(have_filter_expr);
1428     main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(have_filter_expr);
1429
1430     main_ui_->actionAnalyzePAFSelected->setEnabled(have_filter_expr);
1431     main_ui_->actionAnalyzePAFNotSelected->setEnabled(have_filter_expr);
1432     main_ui_->actionAnalyzePAFAndSelected->setEnabled(have_filter_expr);
1433     main_ui_->actionAnalyzePAFOrSelected->setEnabled(have_filter_expr);
1434     main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(have_filter_expr);
1435     main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(have_filter_expr);
1436
1437     main_ui_->actionAnalyzeFollowTCPStream->setEnabled(is_tcp);
1438     main_ui_->actionAnalyzeFollowUDPStream->setEnabled(is_udp);
1439     main_ui_->actionAnalyzeFollowSSLStream->setEnabled(is_ssl);
1440     main_ui_->actionAnalyzeFollowHTTPStream->setEnabled(is_http);
1441
1442     foreach (QAction *cc_action, cc_actions) {
1443         cc_action->setEnabled(frame_selected);
1444     }
1445     main_ui_->actionViewColorizeNewColoringRule->setEnabled(frame_selected);
1446
1447     main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
1448
1449     main_ui_->actionViewShowPacketInNewWindow->setEnabled(frame_selected);
1450     main_ui_->actionViewEditResolvedName->setEnabled(frame_selected && is_ip);
1451
1452     emit packetInfoChanged(capture_file_.packetInfo());
1453
1454 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NameResolution/ResolveName",
1455 //                         frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1456 //                                            gbl_resolv_flags.transport_name));
1457
1458     main_ui_->actionToolsFirewallAclRules->setEnabled(frame_selected);
1459
1460     main_ui_->actionStatisticsTcpStreamRoundTripTime->setEnabled(is_tcp);
1461     main_ui_->actionStatisticsTcpStreamStevens->setEnabled(is_tcp);
1462     main_ui_->actionStatisticsTcpStreamTcptrace->setEnabled(is_tcp);
1463     main_ui_->actionStatisticsTcpStreamThroughput->setEnabled(is_tcp);
1464     main_ui_->actionStatisticsTcpStreamWindowScaling->setEnabled(is_tcp);
1465
1466     main_ui_->actionSCTPAnalyseThisAssociation->setEnabled(is_sctp);
1467     main_ui_->actionSCTPShowAllAssociations->setEnabled(is_sctp);
1468     main_ui_->actionSCTPFilterThisAssociation->setEnabled(is_sctp);
1469     main_ui_->actionTelephonyRTPStreamAnalysis->setEnabled(is_rtp);
1470     main_ui_->actionTelephonyLteRlcGraph->setEnabled(is_lte_rlc);
1471 }
1472
1473 void MainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) {
1474
1475     bool can_match_selected = false;
1476     bool is_framenum = false;
1477     bool have_field_info = false;
1478     bool have_subtree = false;
1479     bool can_open_url = false;
1480     bool have_packet_bytes = false;
1481     QByteArray field_filter;
1482     int field_id = -1;
1483
1484     field_info * fi = 0;
1485     if ( finfo )
1486         fi = finfo->fieldInfo();
1487
1488     if (capture_file_.capFile()) {
1489         capture_file_.capFile()->finfo_selected = fi;
1490
1491         if (fi && fi->tree_type != -1) {
1492             have_subtree = true;
1493         }
1494
1495         if (fi && fi->ds_tvb) {
1496             have_packet_bytes = true;
1497         }
1498     }
1499
1500     if (capture_file_.capFile() != NULL && fi != NULL) {
1501         header_field_info *hfinfo = fi->hfinfo;
1502         int linked_frame = -1;
1503
1504         have_field_info = true;
1505         can_match_selected = proto_can_match_selected(capture_file_.capFile()->finfo_selected, capture_file_.capFile()->edt);
1506         if (hfinfo && hfinfo->type == FT_FRAMENUM) {
1507             is_framenum = true;
1508             linked_frame = fvalue_get_uinteger(&fi->value);
1509         }
1510
1511         char *tmp_field = proto_construct_match_selected_string(fi, capture_file_.capFile()->edt);
1512         field_filter = tmp_field;
1513         wmem_free(NULL, tmp_field);
1514
1515         field_id = fi->hfinfo->id;
1516         /* if the selected field isn't a protocol, get its parent */
1517         if (!proto_registrar_is_protocol(field_id)) {
1518             field_id = proto_registrar_get_parent(fi->hfinfo->id);
1519         }
1520
1521         if (field_id >= 0) {
1522             can_open_url = true;
1523             main_ui_->actionContextWikiProtocolPage->setData(field_id);
1524             main_ui_->actionContextFilterFieldReference->setData(field_id);
1525         } else {
1526             main_ui_->actionContextWikiProtocolPage->setData(QVariant());
1527             main_ui_->actionContextFilterFieldReference->setData(QVariant());
1528         }
1529
1530         if (linked_frame > 0) {
1531             main_ui_->actionGoGoToLinkedPacket->setData(linked_frame);
1532         } else {
1533             main_ui_->actionGoGoToLinkedPacket->setData(QVariant());
1534         }
1535     }
1536
1537     // Always enable / disable the following items.
1538     main_ui_->actionFileExportPacketBytes->setEnabled(have_field_info);
1539
1540     main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL);
1541     main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected);
1542     main_ui_->actionEditCopyDescription->setEnabled(can_match_selected);
1543     main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected);
1544     main_ui_->actionEditCopyValue->setEnabled(can_match_selected);
1545     main_ui_->actionEditCopyAsFilter->setEnabled(can_match_selected);
1546
1547     main_ui_->actionAnalyzeShowPacketBytes->setEnabled(have_packet_bytes);
1548     main_ui_->actionFileExportPacketBytes->setEnabled(have_packet_bytes);
1549
1550     main_ui_->actionViewExpandSubtrees->setEnabled(have_subtree);
1551     main_ui_->actionViewCollapseSubtrees->setEnabled(have_subtree);
1552
1553     main_ui_->actionGoGoToLinkedPacket->setEnabled(is_framenum);
1554
1555     main_ui_->actionAnalyzeCreateAColumn->setEnabled(can_match_selected);
1556
1557     main_ui_->actionContextShowLinkedPacketInNewWindow->setEnabled(is_framenum);
1558
1559     main_ui_->actionContextWikiProtocolPage->setEnabled(can_open_url);
1560     main_ui_->actionContextFilterFieldReference->setEnabled(can_open_url);
1561
1562
1563     // Only enable / disable the following items if we have focus so that we
1564     // don't clobber anything we may have set in setMenusForSelectedPacket.
1565     if (!proto_tree_ || !proto_tree_->hasFocus()) return;
1566
1567     emit packetInfoChanged(capture_file_.packetInfo());
1568     emit fieldFilterChanged(field_filter);
1569
1570 //    set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ResolveName",
1571 //                         frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1572 //                                            gbl_resolv_flags.transport_name));
1573
1574     main_ui_->actionAnalyzeAAFSelected->setEnabled(can_match_selected);
1575     main_ui_->actionAnalyzeAAFNotSelected->setEnabled(can_match_selected);
1576     main_ui_->actionAnalyzeAAFAndSelected->setEnabled(can_match_selected);
1577     main_ui_->actionAnalyzeAAFOrSelected->setEnabled(can_match_selected);
1578     main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(can_match_selected);
1579     main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(can_match_selected);
1580
1581     main_ui_->actionAnalyzePAFSelected->setEnabled(can_match_selected);
1582     main_ui_->actionAnalyzePAFNotSelected->setEnabled(can_match_selected);
1583     main_ui_->actionAnalyzePAFAndSelected->setEnabled(can_match_selected);
1584     main_ui_->actionAnalyzePAFOrSelected->setEnabled(can_match_selected);
1585     main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(can_match_selected);
1586     main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(can_match_selected);
1587 }
1588
1589 void MainWindow::interfaceSelectionChanged()
1590 {
1591 #ifdef HAVE_LIBPCAP
1592     // XXX This doesn't disable the toolbar button when using
1593     // QtMacExtras.
1594     if (global_capture_opts.num_selected > 0 && capture_filter_valid_) {
1595         main_ui_->actionCaptureStart->setEnabled(true);
1596     } else {
1597         main_ui_->actionCaptureStart->setEnabled(false);
1598     }
1599 #endif // HAVE_LIBPCAP
1600 }
1601
1602 void MainWindow::captureFilterSyntaxChanged(bool valid)
1603 {
1604     capture_filter_valid_ = valid;
1605     interfaceSelectionChanged();
1606 }
1607
1608 void MainWindow::startInterfaceCapture(bool valid, const QString capture_filter)
1609 {
1610     capture_filter_valid_ = valid;
1611     main_welcome_->setCaptureFilter(capture_filter);
1612     // The interface tree will update the selected interfaces via its timer
1613     // so no need to do anything here.
1614     startCapture();
1615 }
1616
1617 void MainWindow::applyGlobalCommandLineOptions()
1618 {
1619     if (global_dissect_options.time_format != TS_NOT_SET) {
1620         foreach (QAction* tda, td_actions.keys()) {
1621             if (global_dissect_options.time_format == td_actions[tda]) {
1622                 tda->setChecked(true);
1623                 recent.gui_time_format = global_dissect_options.time_format;
1624                 timestamp_set_type(global_dissect_options.time_format);
1625                 break;
1626             }
1627         }
1628     }
1629     if (global_commandline_info.full_screen) {
1630         this->showFullScreen();
1631     }
1632 }
1633
1634 void MainWindow::redissectPackets()
1635 {
1636     if (capture_file_.capFile()) {
1637         cf_redissect_packets(capture_file_.capFile());
1638         main_ui_->statusBar->expertUpdate();
1639     }
1640
1641     proto_free_deregistered_fields();
1642 }
1643
1644 void MainWindow::checkDisplayFilter()
1645 {
1646     if (!df_combo_box_->checkDisplayFilter()) {
1647         g_free(CaptureFile::globalCapFile()->dfilter);
1648         CaptureFile::globalCapFile()->dfilter = NULL;
1649     }
1650 }
1651
1652 void MainWindow::fieldsChanged()
1653 {
1654     gchar *err_msg = NULL;
1655     if (!color_filters_reload(&err_msg, color_filter_add_cb)) {
1656         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
1657         g_free(err_msg);
1658     }
1659     tap_listeners_dfilter_recompile();
1660
1661     emit checkDisplayFilter();
1662
1663     if (have_custom_cols(&CaptureFile::globalCapFile()->cinfo)) {
1664         // Recreate packet list columns according to new/changed/deleted fields
1665         packet_list_->fieldsChanged(CaptureFile::globalCapFile());
1666     }
1667
1668     emit reloadFields();
1669 }
1670
1671 void MainWindow::reloadLuaPlugins()
1672 {
1673 #ifdef HAVE_LUA
1674     if (wsApp->isReloadingLua())
1675         return;
1676
1677     wsApp->setReloadingLua(true);
1678
1679     wslua_reload_plugins(NULL, NULL);
1680     funnel_statistics_reload_menus();
1681     reloadDynamicMenus();
1682     closePacketDialogs();
1683
1684     // Preferences may have been deleted so close all widgets using prefs
1685     proto_tree_->closeContextMenu();
1686     main_ui_->preferenceEditorFrame->animatedHide();
1687
1688     wsApp->readConfigurationFiles(true);
1689
1690     prefs_apply_all();
1691     fieldsChanged();
1692     redissectPackets();
1693
1694     wsApp->setReloadingLua(false);
1695     SimpleDialog::displayQueuedMessages();
1696 #endif
1697 }
1698
1699 void MainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle)
1700 {
1701     QList<AccordionFrame *>frame_list = QList<AccordionFrame *>()
1702             << main_ui_->goToFrame << main_ui_->searchFrame
1703             << main_ui_->addressEditorFrame << main_ui_->columnEditorFrame
1704             << main_ui_->preferenceEditorFrame << main_ui_->filterExpressionFrame;
1705
1706     frame_list.removeAll(show_frame);
1707     foreach (AccordionFrame *af, frame_list) af->animatedHide();
1708
1709     if (toggle) {
1710         if (show_frame->isVisible()) {
1711             show_frame->animatedHide();
1712             return;
1713         }
1714     }
1715     show_frame->animatedShow();
1716 }
1717
1718 void MainWindow::showColumnEditor(int column)
1719 {
1720     previous_focus_ = wsApp->focusWidget();
1721     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
1722     main_ui_->columnEditorFrame->editColumn(column);
1723     showAccordionFrame(main_ui_->columnEditorFrame);
1724 }
1725
1726 void MainWindow::showPreferenceEditor()
1727 {
1728     showAccordionFrame(main_ui_->preferenceEditorFrame);
1729 }
1730
1731 void MainWindow::initViewColorizeMenu()
1732 {
1733     QList<QAction *> cc_actions = QList<QAction *>()
1734             << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1735             << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1736             << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1737             << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1738             << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1739
1740     guint8 color_num = 1;
1741
1742     foreach (QAction *cc_action, cc_actions) {
1743         cc_action->setData(color_num);
1744         connect(cc_action, SIGNAL(triggered()), this, SLOT(colorizeConversation()));
1745
1746         const color_filter_t *colorf = color_filters_tmp_color(color_num);
1747         if (colorf) {
1748             QColor bg = ColorUtils::fromColorT(colorf->bg_color);
1749             QColor fg = ColorUtils::fromColorT(colorf->fg_color);
1750             cc_action->setIcon(StockIcon::colorIcon(bg.rgb(), fg.rgb(), QString::number(color_num)));
1751         }
1752         color_num++;
1753     }
1754
1755 #ifdef Q_OS_MAC
1756     // Spotlight uses Cmd+Space
1757     main_ui_->actionViewColorizeResetColorization->setShortcut(QKeySequence("Meta+Space"));
1758 #endif
1759 }
1760
1761 void MainWindow::addStatsPluginsToMenu() {
1762     GList          *cfg_list = stats_tree_get_cfg_list();
1763     GList          *iter = g_list_first(cfg_list);
1764     QAction        *stats_tree_action;
1765     QMenu          *parent_menu;
1766     bool            first_item = true;
1767
1768     while (iter) {
1769         stats_tree_cfg *cfg = (stats_tree_cfg*)iter->data;
1770         if (cfg->plugin) {
1771             if (first_item) {
1772                 main_ui_->menuStatistics->addSeparator();
1773                 first_item = false;
1774             }
1775
1776             parent_menu = main_ui_->menuStatistics;
1777             // gtk/main_menubar.c compresses double slashes, hence SkipEmptyParts
1778             QStringList cfg_name_parts = QString(cfg->name).split("/", QString::SkipEmptyParts);
1779             if (cfg_name_parts.isEmpty()) continue;
1780
1781             QString stat_name = cfg_name_parts.takeLast();
1782             if (!cfg_name_parts.isEmpty()) {
1783                 QString menu_name = cfg_name_parts.join("/");
1784                 parent_menu = findOrAddMenu(parent_menu, menu_name);
1785             }
1786
1787             stats_tree_action = new QAction(stat_name, this);
1788             stats_tree_action->setData(cfg->abbr);
1789             parent_menu->addAction(stats_tree_action);
1790             connect(stats_tree_action, SIGNAL(triggered()), this, SLOT(actionStatisticsPlugin_triggered()));
1791         }
1792         iter = g_list_next(iter);
1793     }
1794     g_list_free(cfg_list);
1795 }
1796
1797 void MainWindow::setFeaturesEnabled(bool enabled)
1798 {
1799     main_ui_->menuBar->setEnabled(enabled);
1800     main_ui_->mainToolBar->setEnabled(enabled);
1801     main_ui_->displayFilterToolBar->setEnabled(enabled);
1802     if(enabled)
1803     {
1804         main_ui_->statusBar->clearMessage();
1805 #ifdef HAVE_LIBPCAP
1806         main_ui_->actionGoAutoScroll->setChecked(auto_scroll_live);
1807 #endif
1808     }
1809     else
1810     {
1811         main_ui_->statusBar->showMessage(tr("Please wait while Wireshark is initializing" UTF8_HORIZONTAL_ELLIPSIS));
1812     }
1813 }
1814
1815 // Display Filter Toolbar
1816
1817 void MainWindow::on_actionDisplayFilterExpression_triggered()
1818 {
1819     DisplayFilterExpressionDialog *dfe_dialog = new DisplayFilterExpressionDialog(this);
1820
1821     connect(dfe_dialog, SIGNAL(insertDisplayFilter(QString)),
1822             df_combo_box_->lineEdit(), SLOT(insertFilter(const QString &)));
1823
1824     dfe_dialog->show();
1825 }
1826
1827 void MainWindow::on_actionNewDisplayFilterExpression_triggered()
1828 {
1829     main_ui_->filterExpressionFrame->addExpression(df_combo_box_->lineEdit()->text());
1830 }
1831
1832 // On Qt4 + macOS with unifiedTitleAndToolBarOnMac set it's possible to make
1833 // the main window obnoxiously wide.
1834
1835 void MainWindow::displayFilterButtonClicked()
1836 {
1837     QAction *dfb_action = qobject_cast<QAction*>(sender());
1838
1839     if (!dfb_action)
1840         return;
1841
1842     df_combo_box_->setDisplayFilter(dfb_action->data().toString());
1843     // Holding down the Shift key will only prepare filter.
1844     if (!(QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
1845         df_combo_box_->applyDisplayFilter();
1846     }
1847 }
1848
1849 void MainWindow::openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata)
1850 {
1851     QString slot = QString("statCommand%1").arg(menu_path);
1852     QMetaObject::invokeMethod(this, slot.toLatin1().constData(), Q_ARG(const char *, arg), Q_ARG(void *, userdata));
1853 }
1854
1855 void MainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata)
1856 {
1857     TapParameterDialog *tp_dialog = TapParameterDialog::showTapParameterStatistics(*this, capture_file_, cfg_str, arg, userdata);
1858     if (!tp_dialog) return;
1859
1860     connect(tp_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
1861             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
1862     connect(tp_dialog, SIGNAL(updateFilter(QString)),
1863             df_combo_box_->lineEdit(), SLOT(setText(QString)));
1864     tp_dialog->show();
1865 }
1866
1867 void MainWindow::openTapParameterDialog()
1868 {
1869     QAction *tpa = qobject_cast<QAction *>(QObject::sender());
1870     if (!tpa) return;
1871
1872     const QString cfg_str = tpa->data().toString();
1873     openTapParameterDialog(cfg_str, NULL, NULL);
1874 }
1875
1876 #ifdef HAVE_SOFTWARE_UPDATE
1877 void MainWindow::softwareUpdateRequested() {
1878     // We could call testCaptureFileClose here, but that would give us yet
1879     // another dialog. Just try again later.
1880     if (capture_file_.capFile() && capture_file_.capFile()->state != FILE_CLOSED) {
1881         wsApp->rejectSoftwareUpdate();
1882     }
1883 }
1884 #endif
1885
1886
1887 // File Menu
1888
1889 void MainWindow::on_actionFileOpen_triggered()
1890 {
1891     openCaptureFile();
1892 }
1893
1894 void MainWindow::on_actionFileMerge_triggered()
1895 {
1896     mergeCaptureFile();
1897 }
1898
1899 void MainWindow::on_actionFileImportFromHexDump_triggered()
1900 {
1901     importCaptureFile();
1902 }
1903
1904 void MainWindow::on_actionFileClose_triggered() {
1905     QString before_what(tr(" before closing the file"));
1906     if (testCaptureFileClose(before_what))
1907         main_ui_->mainStack->setCurrentWidget(main_welcome_);
1908 }
1909
1910 void MainWindow::on_actionFileSave_triggered()
1911 {
1912     saveCaptureFile(capture_file_.capFile(), false);
1913 }
1914
1915 void MainWindow::on_actionFileSaveAs_triggered()
1916 {
1917     saveAsCaptureFile(capture_file_.capFile());
1918 }
1919
1920 void MainWindow::on_actionFileSetListFiles_triggered()
1921 {
1922     file_set_dialog_->show();
1923 }
1924
1925 void MainWindow::on_actionFileSetNextFile_triggered()
1926 {
1927     fileset_entry *entry = fileset_get_next();
1928
1929     if (entry) {
1930         QString new_cf_path = entry->fullname;
1931         openCaptureFile(new_cf_path);
1932     }
1933 }
1934
1935 void MainWindow::on_actionFileSetPreviousFile_triggered()
1936 {
1937     fileset_entry *entry = fileset_get_previous();
1938
1939     if (entry) {
1940         QString new_cf_path = entry->fullname;
1941         openCaptureFile(new_cf_path);
1942     }
1943 }
1944
1945 void MainWindow::on_actionFileExportPackets_triggered()
1946 {
1947     exportSelectedPackets();
1948 }
1949
1950 void MainWindow::on_actionFileExportAsPlainText_triggered()
1951 {
1952     exportDissections(export_type_text);
1953 }
1954
1955 void MainWindow::on_actionFileExportAsCSV_triggered()
1956 {
1957     exportDissections(export_type_csv);
1958 }
1959
1960 void MainWindow::on_actionFileExportAsCArrays_triggered()
1961 {
1962     exportDissections(export_type_carrays);
1963 }
1964
1965 void MainWindow::on_actionFileExportAsPSML_triggered()
1966 {
1967     exportDissections(export_type_psml);
1968 }
1969
1970 void MainWindow::on_actionFileExportAsPDML_triggered()
1971 {
1972     exportDissections(export_type_pdml);
1973 }
1974
1975 void MainWindow::on_actionFileExportAsJSON_triggered()
1976 {
1977     exportDissections(export_type_json);
1978 }
1979
1980 void MainWindow::on_actionFileExportPacketBytes_triggered()
1981 {
1982     QString file_name;
1983
1984     if (!capture_file_.capFile() || !capture_file_.capFile()->finfo_selected) return;
1985
1986     file_name = QFileDialog::getSaveFileName(this,
1987                                              wsApp->windowTitleString(tr("Export Selected Packet Bytes")),
1988                                              wsApp->lastOpenDir().canonicalPath(),
1989                                              tr("Raw data (*.bin *.dat *.raw);;All Files (" ALL_FILES_WILDCARD ")")
1990                                              );
1991
1992     if (file_name.length() > 0) {
1993         const guint8 *data_p;
1994         int fd;
1995
1996         data_p = tvb_get_ptr(capture_file_.capFile()->finfo_selected->ds_tvb, 0, -1) +
1997                 capture_file_.capFile()->finfo_selected->start;
1998         fd = ws_open(qUtf8Printable(file_name), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
1999         if (fd == -1) {
2000             open_failure_alert_box(qUtf8Printable(file_name), errno, TRUE);
2001             return;
2002         }
2003         if (ws_write(fd, data_p, capture_file_.capFile()->finfo_selected->length) < 0) {
2004             write_failure_alert_box(qUtf8Printable(file_name), errno);
2005             ws_close(fd);
2006             return;
2007         }
2008         if (ws_close(fd) < 0) {
2009             write_failure_alert_box(qUtf8Printable(file_name), errno);
2010             return;
2011         }
2012
2013         /* Save the directory name for future file dialogs. */
2014         wsApp->setLastOpenDir(file_name);
2015     }
2016 }
2017
2018 void MainWindow::on_actionAnalyzeShowPacketBytes_triggered()
2019 {
2020     ShowPacketBytesDialog *spbd = new ShowPacketBytesDialog(*this, capture_file_);
2021     spbd->show();
2022 }
2023
2024 void MainWindow::on_actionFileExportPDU_triggered()
2025 {
2026     ExportPDUDialog *exportpdu_dialog = new ExportPDUDialog(this);
2027
2028     if (exportpdu_dialog->isMinimized() == true)
2029     {
2030         exportpdu_dialog->showNormal();
2031     }
2032     else
2033     {
2034         exportpdu_dialog->show();
2035     }
2036
2037     exportpdu_dialog->raise();
2038     exportpdu_dialog->activateWindow();
2039 }
2040
2041 void MainWindow::on_actionFileExportSSLSessionKeys_triggered()
2042 {
2043     QString file_name;
2044     QString save_title;
2045     int keylist_len;
2046
2047     keylist_len = ssl_session_key_count();
2048     /* don't show up the dialog, if no data has to be saved */
2049     if (keylist_len < 1) {
2050         /* shouldn't happen as the menu item should have been greyed out */
2051         QMessageBox::warning(
2052                     this,
2053                     tr("No Keys"),
2054                     tr("There are no SSL Session Keys to save."),
2055                     QMessageBox::Ok
2056                     );
2057         return;
2058     }
2059
2060     save_title.append(wsApp->windowTitleString(tr("Export SSL Session Keys (%Ln key(s))", "", keylist_len)));
2061     file_name = QFileDialog::getSaveFileName(this,
2062                                              save_title,
2063                                              wsApp->lastOpenDir().canonicalPath(),
2064                                              tr("SSL Session Keys (*.keys *.txt);;All Files (" ALL_FILES_WILDCARD ")")
2065                                              );
2066     if (file_name.length() > 0) {
2067         gchar *keylist;
2068         int fd;
2069
2070         keylist = ssl_export_sessions();
2071         fd = ws_open(qUtf8Printable(file_name), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
2072         if (fd == -1) {
2073             open_failure_alert_box(qUtf8Printable(file_name), errno, TRUE);
2074             g_free(keylist);
2075             return;
2076         }
2077         /*
2078          * Thanks, Microsoft, for not using size_t for the third argument to
2079          * _write().  Presumably this string will be <= 4GiB long....
2080          */
2081         if (ws_write(fd, keylist, (unsigned int)strlen(keylist)) < 0) {
2082             write_failure_alert_box(qUtf8Printable(file_name), errno);
2083             ws_close(fd);
2084             g_free(keylist);
2085             return;
2086         }
2087         if (ws_close(fd) < 0) {
2088             write_failure_alert_box(qUtf8Printable(file_name), errno);
2089             g_free(keylist);
2090             return;
2091         }
2092
2093         /* Save the directory name for future file dialogs. */
2094         wsApp->setLastOpenDir(file_name);
2095         g_free(keylist);
2096     }
2097 }
2098
2099 void MainWindow::on_actionStatisticsHpfeeds_triggered()
2100 {
2101     openStatisticsTreeDialog("hpfeeds");
2102 }
2103
2104 void MainWindow::on_actionFilePrint_triggered()
2105 {
2106     PrintDialog pdlg(this, capture_file_.capFile());
2107
2108     pdlg.exec();
2109 }
2110
2111 // Edit Menu
2112
2113 // XXX This should probably be somewhere else.
2114 void MainWindow::actionEditCopyTriggered(MainWindow::CopySelected selection_type)
2115 {
2116     char label_str[ITEM_LABEL_LENGTH];
2117     QString clip;
2118
2119     if (!capture_file_.capFile()) return;
2120
2121     field_info *finfo_selected = capture_file_.capFile()->finfo_selected;
2122
2123     switch(selection_type) {
2124     case CopySelectedDescription:
2125         if (finfo_selected && finfo_selected->rep
2126                 && strlen (finfo_selected->rep->representation) > 0) {
2127             clip.append(finfo_selected->rep->representation);
2128         }
2129         break;
2130     case CopySelectedFieldName:
2131         if (finfo_selected && finfo_selected->hfinfo->abbrev != 0) {
2132             clip.append(finfo_selected->hfinfo->abbrev);
2133         }
2134         break;
2135     case CopySelectedValue:
2136         if (finfo_selected && capture_file_.capFile()->edt != 0) {
2137             gchar* field_str = get_node_field_value(finfo_selected, capture_file_.capFile()->edt);
2138             clip.append(field_str);
2139             g_free(field_str);
2140         }
2141         break;
2142     case CopyAllVisibleItems:
2143         clip = proto_tree_->toString();
2144         break;
2145     case CopyAllVisibleSelectedTreeItems:
2146         if (proto_tree_->selectionModel()->hasSelection()) {
2147             clip = proto_tree_->toString(proto_tree_->selectionModel()->selectedIndexes().first());
2148         }
2149         break;
2150     }
2151
2152     if (clip.length() == 0) {
2153         /* If no representation then... Try to read the value */
2154         proto_item_fill_label(capture_file_.capFile()->finfo_selected, label_str);
2155         clip.append(label_str);
2156     }
2157
2158     if (clip.length()) {
2159         wsApp->clipboard()->setText(clip);
2160     } else {
2161         QString err = tr("Couldn't copy text. Try another item.");
2162         main_ui_->statusBar->pushTemporaryStatus(err);
2163     }
2164 }
2165
2166 void MainWindow::on_actionCopyAllVisibleItems_triggered()
2167 {
2168     actionEditCopyTriggered(CopyAllVisibleItems);
2169 }
2170
2171 void MainWindow::on_actionCopyAllVisibleSelectedTreeItems_triggered()
2172 {
2173     actionEditCopyTriggered(CopyAllVisibleSelectedTreeItems);
2174 }
2175
2176 void MainWindow::on_actionEditCopyDescription_triggered()
2177 {
2178     actionEditCopyTriggered(CopySelectedDescription);
2179 }
2180
2181 void MainWindow::on_actionEditCopyFieldName_triggered()
2182 {
2183     actionEditCopyTriggered(CopySelectedFieldName);
2184 }
2185
2186 void MainWindow::on_actionEditCopyValue_triggered()
2187 {
2188     actionEditCopyTriggered(CopySelectedValue);
2189 }
2190
2191 void MainWindow::on_actionEditCopyAsFilter_triggered()
2192 {
2193     matchFieldFilter(FilterAction::ActionCopy, FilterAction::ActionTypePlain);
2194 }
2195
2196 void MainWindow::on_actionEditFindPacket_triggered()
2197 {
2198     if (packet_list_->packetListModel()->rowCount() < 1) {
2199         return;
2200     }
2201     previous_focus_ = wsApp->focusWidget();
2202     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
2203     if (! main_ui_->searchFrame->isVisible()) {
2204         showAccordionFrame(main_ui_->searchFrame, true);
2205     }
2206     main_ui_->searchFrame->setFocus();
2207 }
2208
2209 void MainWindow::on_actionEditFindNext_triggered()
2210 {
2211     main_ui_->searchFrame->findNext();
2212 }
2213
2214 void MainWindow::on_actionEditFindPrevious_triggered()
2215 {
2216     main_ui_->searchFrame->findPrevious();
2217 }
2218
2219 void MainWindow::on_actionEditMarkPacket_triggered()
2220 {
2221     freeze();
2222     packet_list_->markFrame();
2223     thaw();
2224 }
2225
2226 void MainWindow::on_actionEditMarkAllDisplayed_triggered()
2227 {
2228     freeze();
2229     packet_list_->markAllDisplayedFrames(true);
2230     thaw();
2231 }
2232
2233 void MainWindow::on_actionEditUnmarkAllDisplayed_triggered()
2234 {
2235     freeze();
2236     packet_list_->markAllDisplayedFrames(false);
2237     thaw();
2238 }
2239
2240 void MainWindow::on_actionEditNextMark_triggered()
2241 {
2242     if (capture_file_.capFile())
2243         cf_find_packet_marked(capture_file_.capFile(), SD_FORWARD);
2244 }
2245
2246 void MainWindow::on_actionEditPreviousMark_triggered()
2247 {
2248     if (capture_file_.capFile())
2249         cf_find_packet_marked(capture_file_.capFile(), SD_BACKWARD);
2250 }
2251
2252 void MainWindow::on_actionEditIgnorePacket_triggered()
2253 {
2254     freeze();
2255     packet_list_->ignoreFrame();
2256     thaw();
2257 }
2258
2259 void MainWindow::on_actionEditIgnoreAllDisplayed_triggered()
2260 {
2261     freeze();
2262     packet_list_->ignoreAllDisplayedFrames(true);
2263     thaw();
2264 }
2265
2266 void MainWindow::on_actionEditUnignoreAllDisplayed_triggered()
2267 {
2268     freeze();
2269     packet_list_->ignoreAllDisplayedFrames(false);
2270     thaw();
2271 }
2272
2273 void MainWindow::on_actionEditSetTimeReference_triggered()
2274 {
2275     packet_list_->setTimeReference();
2276 }
2277
2278 void MainWindow::on_actionEditUnsetAllTimeReferences_triggered()
2279 {
2280     packet_list_->unsetAllTimeReferences();
2281 }
2282
2283 void MainWindow::on_actionEditNextTimeReference_triggered()
2284 {
2285     if (!capture_file_.capFile()) return;
2286     cf_find_packet_time_reference(capture_file_.capFile(), SD_FORWARD);
2287 }
2288
2289 void MainWindow::on_actionEditPreviousTimeReference_triggered()
2290 {
2291     if (!capture_file_.capFile()) return;
2292     cf_find_packet_time_reference(capture_file_.capFile(), SD_BACKWARD);
2293 }
2294
2295 void MainWindow::on_actionEditTimeShift_triggered()
2296 {
2297     TimeShiftDialog ts_dialog(this, capture_file_.capFile());
2298     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2299             &ts_dialog, SLOT(setCaptureFile(capture_file*)));
2300     connect(&ts_dialog, SIGNAL(timeShifted()), packet_list_, SLOT(applyTimeShift()));
2301     ts_dialog.exec();
2302 }
2303
2304 void MainWindow::on_actionEditPacketComment_triggered()
2305 {
2306     PacketCommentDialog pc_dialog(capture_file_.capFile()->current_frame->num, this, packet_list_->packetComment());
2307     if (pc_dialog.exec() == QDialog::Accepted) {
2308         packet_list_->setPacketComment(pc_dialog.text());
2309         updateForUnsavedChanges();
2310     }
2311 }
2312
2313 void MainWindow::on_actionDeleteAllPacketComments_triggered()
2314 {
2315     QMessageBox msg_dialog;
2316
2317     msg_dialog.setIcon(QMessageBox::Question);
2318     msg_dialog.setText(tr("Are you sure you want to remove all packet comments?"));
2319
2320     msg_dialog.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
2321     msg_dialog.setDefaultButton(QMessageBox::Ok);
2322
2323     if (msg_dialog.exec() == QMessageBox::Ok)
2324     {
2325         /* XXX Do we need a wait/hourglass for large files? */
2326         packet_list_->deleteAllPacketComments();
2327         updateForUnsavedChanges();
2328     }
2329 }
2330
2331 void MainWindow::on_actionEditConfigurationProfiles_triggered()
2332 {
2333     ProfileDialog cp_dialog;
2334
2335     cp_dialog.exec();
2336 }
2337
2338 void MainWindow::showPreferencesDialog(QString pane_name)
2339 {
2340     PreferencesDialog pref_dialog(this);
2341
2342     saveWindowGeometry();  // Save in case the layout panes are rearranged
2343
2344     pref_dialog.setPane(pane_name);
2345     pref_dialog.exec();
2346
2347     // Emitting PacketDissectionChanged directly from a QDialog can cause
2348     // problems on macOS.
2349     wsApp->flushAppSignals();
2350 }
2351
2352 void MainWindow::on_actionEditPreferences_triggered()
2353 {
2354     showPreferencesDialog(PrefsModel::APPEARANCE_PREFERENCE_TREE_NAME);
2355 }
2356
2357 // View Menu
2358
2359 void MainWindow::showHideMainWidgets(QAction *action)
2360 {
2361     if (!action) {
2362         return;
2363     }
2364     bool show = action->isChecked();
2365     QWidget *widget = action->data().value<QWidget*>();
2366
2367     // We may have come from the toolbar context menu, so check/uncheck each
2368     // action as well.
2369     if (widget == main_ui_->mainToolBar) {
2370         recent.main_toolbar_show = show;
2371         main_ui_->actionViewMainToolbar->setChecked(show);
2372     } else if (widget == main_ui_->displayFilterToolBar) {
2373         recent.filter_toolbar_show = show;
2374         main_ui_->actionViewFilterToolbar->setChecked(show);
2375      } else if (widget == main_ui_->wirelessToolBar) {
2376         recent.wireless_toolbar_show = show;
2377         main_ui_->actionViewWirelessToolbar->setChecked(show);
2378     } else if (widget == main_ui_->statusBar) {
2379         recent.statusbar_show = show;
2380         main_ui_->actionViewStatusBar->setChecked(show);
2381     } else if (widget == packet_list_) {
2382         recent.packet_list_show = show;
2383         main_ui_->actionViewPacketList->setChecked(show);
2384     } else if (widget == proto_tree_) {
2385         recent.tree_view_show = show;
2386         main_ui_->actionViewPacketDetails->setChecked(show);
2387     } else if (widget == byte_view_tab_) {
2388         recent.byte_view_show = show;
2389         main_ui_->actionViewPacketBytes->setChecked(show);
2390     } else {
2391         foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
2392             QToolBar *toolbar = action->data().value<QToolBar *>();
2393             if (widget == toolbar) {
2394                 GList *entry = g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp);
2395                 if (show && !entry) {
2396                     recent.interface_toolbars = g_list_append(recent.interface_toolbars, g_strdup(action->text().toUtf8()));
2397                 } else if (!show && entry) {
2398                     recent.interface_toolbars = g_list_remove(recent.interface_toolbars, entry->data);
2399                 }
2400                 action->setChecked(show);
2401             }
2402         }
2403
2404         ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data());
2405         if (toolbar) {
2406             GList *entry = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc) strcmp);
2407             if (show && !entry) {
2408                 recent.gui_additional_toolbars = g_list_append(recent.gui_additional_toolbars, g_strdup(toolbar->name));
2409             } else if (!show && entry) {
2410                 recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data);
2411             }
2412             action->setChecked(show);
2413
2414             QList<QToolBar *> toolbars = findChildren<QToolBar *>();
2415             foreach (QToolBar *bar, toolbars) {
2416                 AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
2417                 if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) {
2418                     iftoolbar->setVisible(show);
2419                 }
2420             }
2421         }
2422     }
2423
2424     if (widget) {
2425         widget->setVisible(show);
2426     }
2427 }
2428
2429 void MainWindow::setTimestampFormat(QAction *action)
2430 {
2431     if (!action) {
2432         return;
2433     }
2434     ts_type tsf = action->data().value<ts_type>();
2435     if (recent.gui_time_format != tsf) {
2436         timestamp_set_type(tsf);
2437         recent.gui_time_format = tsf;
2438
2439         if (packet_list_) {
2440             packet_list_->resetColumns();
2441         }
2442         if (capture_file_.capFile()) {
2443             /* This call adjusts column width */
2444             cf_timestamp_auto_precision(capture_file_.capFile());
2445         }
2446     }
2447 }
2448
2449 void MainWindow::setTimestampPrecision(QAction *action)
2450 {
2451     if (!action) {
2452         return;
2453     }
2454     ts_precision tsp = action->data().value<ts_precision>();
2455     if (recent.gui_time_precision != tsp) {
2456         /* the actual precision will be set in packet_list_queue_draw() below */
2457         timestamp_set_precision(tsp);
2458         recent.gui_time_precision = tsp;
2459
2460         if (packet_list_) {
2461             packet_list_->resetColumns();
2462         }
2463         if (capture_file_.capFile()) {
2464             /* This call adjusts column width */
2465             cf_timestamp_auto_precision(capture_file_.capFile());
2466         }
2467     }
2468 }
2469
2470 void MainWindow::on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked)
2471 {
2472     if (checked) {
2473         recent.gui_seconds_format = TS_SECONDS_HOUR_MIN_SEC;
2474     } else {
2475         recent.gui_seconds_format = TS_SECONDS_DEFAULT;
2476     }
2477     timestamp_set_seconds_type(recent.gui_seconds_format);
2478
2479     if (packet_list_) {
2480         packet_list_->resetColumns();
2481     }
2482     if (capture_file_.capFile()) {
2483         /* This call adjusts column width */
2484         cf_timestamp_auto_precision(capture_file_.capFile());
2485     }
2486 }
2487
2488 void MainWindow::on_actionViewEditResolvedName_triggered()
2489 {
2490 //    int column = packet_list_->selectedColumn();
2491     int column = -1;
2492
2493     if (packet_list_->currentIndex().isValid()) {
2494         column = packet_list_->currentIndex().column();
2495     }
2496
2497     main_ui_->addressEditorFrame->editAddresses(capture_file_, column);
2498     showAccordionFrame(main_ui_->addressEditorFrame);
2499 }
2500
2501 void MainWindow::setNameResolution()
2502 {
2503     gbl_resolv_flags.mac_name = main_ui_->actionViewNameResolutionPhysical->isChecked() ? TRUE : FALSE;
2504     gbl_resolv_flags.network_name = main_ui_->actionViewNameResolutionNetwork->isChecked() ? TRUE : FALSE;
2505     gbl_resolv_flags.transport_name = main_ui_->actionViewNameResolutionTransport->isChecked() ? TRUE : FALSE;
2506
2507     if (packet_list_) {
2508         packet_list_->resetColumns();
2509     }
2510     wsApp->emitAppSignal(WiresharkApplication::NameResolutionChanged);
2511 }
2512
2513 void MainWindow::on_actionViewNameResolutionPhysical_triggered()
2514 {
2515     setNameResolution();
2516 }
2517
2518 void MainWindow::on_actionViewNameResolutionNetwork_triggered()
2519 {
2520     setNameResolution();
2521 }
2522
2523 void MainWindow::on_actionViewNameResolutionTransport_triggered()
2524 {
2525     setNameResolution();
2526 }
2527
2528 void MainWindow::zoomText()
2529 {
2530     wsApp->zoomTextFont(recent.gui_zoom_level);
2531 }
2532
2533 void MainWindow::on_actionViewZoomIn_triggered()
2534 {
2535     recent.gui_zoom_level++;
2536     zoomText();
2537 }
2538
2539 void MainWindow::on_actionViewZoomOut_triggered()
2540 {
2541     recent.gui_zoom_level--;
2542     zoomText();
2543 }
2544
2545 void MainWindow::on_actionViewNormalSize_triggered()
2546 {
2547     recent.gui_zoom_level = 0;
2548     zoomText();
2549 }
2550
2551 void MainWindow::on_actionViewColorizePacketList_triggered(bool checked) {
2552     recent.packet_list_colorize = checked;
2553     packet_list_enable_color(checked);
2554     packet_list_->packetListModel()->resetColorized();
2555 }
2556
2557 void MainWindow::on_actionViewColoringRules_triggered()
2558 {
2559     ColoringRulesDialog coloring_rules_dialog(this);
2560     connect(&coloring_rules_dialog, SIGNAL(accepted()),
2561             packet_list_, SLOT(recolorPackets()));
2562     connect(&coloring_rules_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
2563             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
2564     coloring_rules_dialog.exec();
2565 }
2566
2567 // actionViewColorizeConversation1 - 10
2568 void MainWindow::colorizeConversation(bool create_rule)
2569 {
2570     QAction *colorize_action = qobject_cast<QAction *>(sender());
2571     if (!colorize_action) return;
2572
2573     if (capture_file_.capFile() && capture_file_.capFile()->current_frame) {
2574         packet_info *pi = capture_file_.packetInfo();
2575         guint8 cc_num = colorize_action->data().toUInt();
2576         gchar *filter = conversation_filter_from_packet(pi);
2577         if (filter == NULL) {
2578             main_ui_->statusBar->pushTemporaryStatus(tr("Unable to build conversation filter."));
2579             return;
2580         }
2581
2582         if (create_rule) {
2583             ColoringRulesDialog coloring_rules_dialog(this, filter);
2584             connect(&coloring_rules_dialog, SIGNAL(accepted()),
2585                     packet_list_, SLOT(recolorPackets()));
2586             connect(&coloring_rules_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
2587                     this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
2588             coloring_rules_dialog.exec();
2589         } else {
2590             gchar *err_msg = NULL;
2591             if (!color_filters_set_tmp(cc_num, filter, FALSE, &err_msg)) {
2592                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2593                 g_free(err_msg);
2594             }
2595             packet_list_->recolorPackets();
2596         }
2597     }
2598     setMenusForSelectedPacket();
2599 }
2600
2601 void MainWindow::colorizeActionTriggered()
2602 {
2603     QByteArray filter;
2604     int color_number = -1;
2605
2606     ConversationAction *conv_action = qobject_cast<ConversationAction *>(sender());
2607     if (conv_action) {
2608         filter = conv_action->filter();
2609         color_number = conv_action->colorNumber();
2610     } else {
2611         ColorizeAction *colorize_action = qobject_cast<ColorizeAction *>(sender());
2612         if (colorize_action) {
2613             filter = colorize_action->filter();
2614             color_number = colorize_action->colorNumber();
2615         }
2616     }
2617
2618     colorizeWithFilter(filter, color_number);
2619 }
2620
2621 void MainWindow::colorizeWithFilter(QByteArray filter, int color_number)
2622 {
2623     if (filter.isEmpty()) return;
2624
2625     if (color_number > 0) {
2626         // Assume "Color X"
2627         gchar *err_msg = NULL;
2628         if (!color_filters_set_tmp(color_number, filter.constData(), FALSE, &err_msg)) {
2629             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2630             g_free(err_msg);
2631         }
2632         packet_list_->recolorPackets();
2633     } else {
2634         // New coloring rule
2635         ColoringRulesDialog coloring_rules_dialog(window(), filter);
2636         connect(&coloring_rules_dialog, SIGNAL(accepted()),
2637                 packet_list_, SLOT(recolorPackets()));
2638         connect(&coloring_rules_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
2639                 this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
2640         coloring_rules_dialog.exec();
2641     }
2642     main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
2643 }
2644
2645 void MainWindow::on_actionViewColorizeResetColorization_triggered()
2646 {
2647     gchar *err_msg = NULL;
2648     if (!color_filters_reset_tmp(&err_msg)) {
2649         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2650         g_free(err_msg);
2651     }
2652     packet_list_->recolorPackets();
2653     setMenusForSelectedPacket();
2654 }
2655
2656 void MainWindow::on_actionViewColorizeNewColoringRule_triggered()
2657 {
2658     colorizeConversation(true);
2659 }
2660
2661 void MainWindow::on_actionViewResetLayout_triggered()
2662 {
2663     recent.gui_geometry_main_upper_pane = 0;
2664     recent.gui_geometry_main_lower_pane = 0;
2665
2666     applyRecentPaneGeometry();
2667 }
2668
2669 void MainWindow::on_actionViewResizeColumns_triggered()
2670 {
2671     for (int col = 0; col < packet_list_->packetListModel()->columnCount(); col++) {
2672         packet_list_->resizeColumnToContents(col);
2673         recent_set_column_width(col, packet_list_->columnWidth(col));
2674     }
2675 }
2676
2677 void MainWindow::openPacketDialog(bool from_reference)
2678 {
2679     frame_data * fdata;
2680
2681     /* Find the frame for which we're popping up a dialog */
2682     if(from_reference) {
2683         guint32 framenum = fvalue_get_uinteger(&(capture_file_.capFile()->finfo_selected->value));
2684         if (framenum == 0)
2685             return;
2686
2687         fdata = frame_data_sequence_find(capture_file_.capFile()->provider.frames, framenum);
2688     } else {
2689         fdata = capture_file_.capFile()->current_frame;
2690     }
2691
2692     /* If we have a frame, pop up the dialog */
2693     if (fdata) {
2694         PacketDialog *packet_dialog = new PacketDialog(*this, capture_file_, fdata);
2695
2696         connect(this, SIGNAL(closePacketDialogs()),
2697                 packet_dialog, SLOT(close()));
2698         zoomText(); // Emits wsApp->zoomMonospaceFont(QFont)
2699
2700         packet_dialog->show();
2701     }
2702 }
2703
2704 void MainWindow::on_actionViewInternalsConversationHashTables_triggered()
2705 {
2706     ConversationHashTablesDialog *conversation_hash_tables_dlg = new ConversationHashTablesDialog(this);
2707     conversation_hash_tables_dlg->show();
2708 }
2709
2710 void MainWindow::on_actionViewInternalsDissectorTables_triggered()
2711 {
2712     DissectorTablesDialog *dissector_tables_dlg = new DissectorTablesDialog(this);
2713     dissector_tables_dlg->show();
2714 }
2715
2716 void MainWindow::on_actionViewInternalsSupportedProtocols_triggered()
2717 {
2718     SupportedProtocolsDialog *supported_protocols_dlg = new SupportedProtocolsDialog(this);
2719     supported_protocols_dlg->show();
2720 }
2721
2722 void MainWindow::on_actionViewShowPacketInNewWindow_triggered()
2723 {
2724     openPacketDialog();
2725 }
2726
2727 // This is only used in ProtoTree. Defining it here makes more sense.
2728 void MainWindow::on_actionContextShowLinkedPacketInNewWindow_triggered()
2729 {
2730     openPacketDialog(true);
2731 }
2732
2733 void MainWindow::on_actionViewReload_triggered()
2734 {
2735     capture_file *cf = CaptureFile::globalCapFile();
2736
2737     if (cf->unsaved_changes) {
2738         QString before_what(tr(" before reloading the file"));
2739         if (!testCaptureFileClose(before_what, Reload))
2740             return;
2741     }
2742
2743     cf_reload(cf);
2744 }
2745
2746 void MainWindow::on_actionViewReload_as_File_Format_or_Capture_triggered()
2747 {
2748     capture_file *cf = CaptureFile::globalCapFile();
2749
2750     if (cf->unsaved_changes) {
2751         QString before_what(tr(" before reloading the file"));
2752         if (!testCaptureFileClose(before_what, Reload))
2753             return;
2754     }
2755
2756     if (cf->open_type == WTAP_TYPE_AUTO)
2757         cf->open_type = open_info_name_to_type("MIME Files Format");
2758     else /* TODO: This should be latest format chosen by user */
2759         cf->open_type = WTAP_TYPE_AUTO;
2760
2761     cf_reload(cf);
2762 }
2763
2764
2765 // Expand / collapse slots in proto_tree
2766
2767 // Go Menu
2768
2769 // Analyze Menu
2770
2771 void MainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type)
2772 {
2773     QString field_filter;
2774
2775     if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) {
2776         field_filter = packet_list_->getFilterFromRowAndColumn();
2777     } else if (capture_file_.capFile() && capture_file_.capFile()->finfo_selected) {
2778         char *tmp_field = proto_construct_match_selected_string(capture_file_.capFile()->finfo_selected,
2779                                                        capture_file_.capFile()->edt);
2780         field_filter = QString(tmp_field);
2781         wmem_free(NULL, tmp_field);
2782     }
2783
2784     if (field_filter.isEmpty()) {
2785         QString err = tr("No filter available. Try another ");
2786         err.append(packet_list_->contextMenuActive() ? "column" : "item");
2787         err.append(".");
2788         main_ui_->statusBar->pushTemporaryStatus(err);
2789         return;
2790     }
2791
2792     emit filterAction(field_filter, action, filter_type);
2793 }
2794
2795 void MainWindow::on_actionAnalyzeDisplayFilters_triggered()
2796 {
2797     if (!display_filter_dlg_) {
2798         display_filter_dlg_ = new FilterDialog(this, FilterDialog::DisplayFilter);
2799     }
2800     display_filter_dlg_->show();
2801     display_filter_dlg_->raise();
2802     display_filter_dlg_->activateWindow();
2803 }
2804
2805 struct epan_uat;
2806 void MainWindow::on_actionAnalyzeDisplayFilterMacros_triggered()
2807 {
2808     struct epan_uat* dfm_uat;
2809     dfilter_macro_get_uat(&dfm_uat);
2810     UatDialog uat_dlg(parentWidget(), dfm_uat);
2811
2812     uat_dlg.exec();
2813     // Emitting PacketDissectionChanged directly from a QDialog can cause
2814     // problems on macOS.
2815     wsApp->flushAppSignals();
2816 }
2817
2818 void MainWindow::on_actionAnalyzeCreateAColumn_triggered()
2819 {
2820     gint colnr = 0;
2821
2822     if (capture_file_.capFile() != 0 && capture_file_.capFile()->finfo_selected != 0) {
2823         colnr = column_prefs_add_custom(COL_CUSTOM, capture_file_.capFile()->finfo_selected->hfinfo->name,
2824                     capture_file_.capFile()->finfo_selected->hfinfo->abbrev,0);
2825
2826         packet_list_->columnsChanged();
2827         packet_list_->resizeColumnToContents(colnr);
2828
2829         prefs_main_write();
2830     }
2831 }
2832
2833 void MainWindow::applyConversationFilter()
2834 {
2835     ConversationAction *conv_action = qobject_cast<ConversationAction*>(sender());
2836     if (!conv_action) return;
2837
2838     packet_info *pinfo = capture_file_.packetInfo();
2839     if (!pinfo) return;
2840
2841     QByteArray conv_filter = conv_action->filter();
2842     if (conv_filter.isEmpty()) return;
2843
2844     if (conv_action->isFilterValid(pinfo)) {
2845
2846         df_combo_box_->lineEdit()->setText(conv_filter);
2847         df_combo_box_->applyDisplayFilter();
2848     }
2849 }
2850
2851 void MainWindow::applyExportObject()
2852 {
2853     ExportObjectAction *export_action = qobject_cast<ExportObjectAction*>(sender());
2854     if (!export_action)
2855         return;
2856
2857     ExportObjectDialog* export_dialog = new ExportObjectDialog(*this, capture_file_, export_action->exportObject());
2858
2859     connect(export_dialog->getExportObjectView(), SIGNAL(goToPacket(int)),
2860             packet_list_, SLOT(goToPacket(int)));
2861
2862 }
2863
2864 // XXX We could probably create the analyze and prepare actions
2865 // dynamically using FilterActions and consolidate the methods
2866 // below into one callback.
2867 void MainWindow::on_actionAnalyzeAAFSelected_triggered()
2868 {
2869     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypePlain);
2870 }
2871
2872 void MainWindow::on_actionAnalyzeAAFNotSelected_triggered()
2873 {
2874     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeNot);
2875 }
2876
2877 void MainWindow::on_actionAnalyzeAAFAndSelected_triggered()
2878 {
2879     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeAnd);
2880 }
2881
2882 void MainWindow::on_actionAnalyzeAAFOrSelected_triggered()
2883 {
2884     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeOr);
2885 }
2886
2887 void MainWindow::on_actionAnalyzeAAFAndNotSelected_triggered()
2888 {
2889     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeAndNot);
2890 }
2891
2892 void MainWindow::on_actionAnalyzeAAFOrNotSelected_triggered()
2893 {
2894     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeOrNot);
2895 }
2896
2897 void MainWindow::on_actionAnalyzePAFSelected_triggered()
2898 {
2899     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypePlain);
2900 }
2901
2902 void MainWindow::on_actionAnalyzePAFNotSelected_triggered()
2903 {
2904     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeNot);
2905 }
2906
2907 void MainWindow::on_actionAnalyzePAFAndSelected_triggered()
2908 {
2909     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeAnd);
2910 }
2911
2912 void MainWindow::on_actionAnalyzePAFOrSelected_triggered()
2913 {
2914     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeOr);
2915 }
2916
2917 void MainWindow::on_actionAnalyzePAFAndNotSelected_triggered()
2918 {
2919     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeAndNot);
2920 }
2921
2922 void MainWindow::on_actionAnalyzePAFOrNotSelected_triggered()
2923 {
2924     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeOrNot);
2925 }
2926
2927 void MainWindow::on_actionAnalyzeEnabledProtocols_triggered()
2928 {
2929     EnabledProtocolsDialog enable_proto_dialog(this);
2930     enable_proto_dialog.exec();
2931
2932     // Emitting PacketDissectionChanged directly from a QDialog can cause
2933     // problems on macOS.
2934     wsApp->flushAppSignals();
2935 }
2936
2937 void MainWindow::on_actionAnalyzeDecodeAs_triggered()
2938 {
2939     QAction *da_action = qobject_cast<QAction*>(sender());
2940     bool create_new = false;
2941     if (da_action && da_action->data().toBool() == true) {
2942         create_new = true;
2943     }
2944
2945     DecodeAsDialog da_dialog(this, capture_file_.capFile(), create_new);
2946     da_dialog.exec();
2947
2948     // Emitting PacketDissectionChanged directly from a QDialog can cause
2949     // problems on macOS.
2950     wsApp->flushAppSignals();
2951 }
2952
2953 void MainWindow::on_actionAnalyzeReloadLuaPlugins_triggered()
2954 {
2955     reloadLuaPlugins();
2956 }
2957
2958 void MainWindow::openFollowStreamDialog(follow_type_t type) {
2959     FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type);
2960     connect(fsd, SIGNAL(updateFilter(QString, bool)), this, SLOT(filterPackets(QString, bool)));
2961     connect(fsd, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
2962
2963     fsd->show();
2964     fsd->follow(getFilter());
2965 }
2966
2967 void MainWindow::on_actionAnalyzeFollowTCPStream_triggered()
2968 {
2969     openFollowStreamDialog(FOLLOW_TCP);
2970 }
2971
2972 void MainWindow::on_actionAnalyzeFollowUDPStream_triggered()
2973 {
2974     openFollowStreamDialog(FOLLOW_UDP);
2975 }
2976
2977 void MainWindow::on_actionAnalyzeFollowSSLStream_triggered()
2978 {
2979     openFollowStreamDialog(FOLLOW_SSL);
2980 }
2981
2982 void MainWindow::on_actionAnalyzeFollowHTTPStream_triggered()
2983 {
2984     openFollowStreamDialog(FOLLOW_HTTP);
2985 }
2986
2987 void MainWindow::openSCTPAllAssocsDialog()
2988 {
2989     SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile());
2990     connect(sctp_dialog, SIGNAL(filterPackets(QString,bool)),
2991             this, SLOT(filterPackets(QString,bool)));
2992     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2993             sctp_dialog, SLOT(setCaptureFile(capture_file*)));
2994     sctp_dialog->fillTable();
2995
2996     if (sctp_dialog->isMinimized() == true)
2997     {
2998         sctp_dialog->showNormal();
2999     }
3000     else
3001     {
3002         sctp_dialog->show();
3003     }
3004
3005     sctp_dialog->raise();
3006     sctp_dialog->activateWindow();
3007 }
3008
3009 void MainWindow::on_actionSCTPShowAllAssociations_triggered()
3010 {
3011     openSCTPAllAssocsDialog();
3012 }
3013
3014 void MainWindow::on_actionSCTPAnalyseThisAssociation_triggered()
3015 {
3016     SCTPAssocAnalyseDialog *sctp_analyse = new SCTPAssocAnalyseDialog(this, NULL, capture_file_.capFile());
3017     connect(sctp_analyse, SIGNAL(filterPackets(QString,bool)),
3018             this, SLOT(filterPackets(QString,bool)));
3019
3020     if (sctp_analyse->isMinimized() == true)
3021     {
3022         sctp_analyse->showNormal();
3023     }
3024     else
3025     {
3026         sctp_analyse->show();
3027     }
3028
3029     sctp_analyse->raise();
3030     sctp_analyse->activateWindow();
3031 }
3032
3033 void MainWindow::on_actionSCTPFilterThisAssociation_triggered()
3034 {
3035     sctp_assoc_info_t* assoc = SCTPAssocAnalyseDialog::findAssocForPacket(capture_file_.capFile());
3036     if (assoc) {
3037         QString newFilter = QString("sctp.assoc_index==%1").arg(assoc->assoc_id);
3038         assoc = NULL;
3039         emit filterPackets(newFilter, false);
3040     }
3041 }
3042
3043 // -z wlan,stat
3044 void MainWindow::statCommandWlanStatistics(const char *arg, void *)
3045 {
3046     WlanStatisticsDialog *wlan_stats_dlg = new WlanStatisticsDialog(*this, capture_file_, arg);
3047     connect(wlan_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3048             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3049     wlan_stats_dlg->show();
3050 }
3051
3052 void MainWindow::on_actionWirelessWlanStatistics_triggered()
3053 {
3054     statCommandWlanStatistics(NULL, NULL);
3055 }
3056
3057 // -z expert
3058 void MainWindow::statCommandExpertInfo(const char *, void *)
3059 {
3060     ExpertInfoDialog *expert_dialog = new ExpertInfoDialog(*this, capture_file_);
3061     const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
3062
3063     expert_dialog->setDisplayFilter(df_edit->text());
3064
3065     connect(expert_dialog->getExpertInfoView(), SIGNAL(goToPacket(int, int)),
3066             packet_list_, SLOT(goToPacket(int, int)));
3067     connect(expert_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3068             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3069
3070     expert_dialog->show();
3071 }
3072
3073 void MainWindow::on_actionAnalyzeExpertInfo_triggered()
3074 {
3075     statCommandExpertInfo(NULL, NULL);
3076 }
3077
3078
3079 // Next / previous / first / last slots in packet_list
3080
3081 // Statistics Menu
3082
3083 void MainWindow::on_actionStatisticsFlowGraph_triggered()
3084 {
3085     SequenceDialog *sequence_dialog = new SequenceDialog(*this, capture_file_);
3086     sequence_dialog->show();
3087 }
3088
3089 void MainWindow::openTcpStreamDialog(int graph_type)
3090 {
3091     TCPStreamDialog *stream_dialog = new TCPStreamDialog(this, capture_file_.capFile(), (tcp_graph_type)graph_type);
3092     connect(stream_dialog, SIGNAL(goToPacket(int)),
3093             packet_list_, SLOT(goToPacket(int)));
3094     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3095             stream_dialog, SLOT(setCaptureFile(capture_file*)));
3096     if (stream_dialog->result() == QDialog::Accepted) {
3097         stream_dialog->show();
3098     }
3099 }
3100
3101 void MainWindow::on_actionStatisticsTcpStreamStevens_triggered()
3102 {
3103     openTcpStreamDialog(GRAPH_TSEQ_STEVENS);
3104 }
3105
3106 void MainWindow::on_actionStatisticsTcpStreamTcptrace_triggered()
3107 {
3108     openTcpStreamDialog(GRAPH_TSEQ_TCPTRACE);
3109 }
3110
3111 void MainWindow::on_actionStatisticsTcpStreamThroughput_triggered()
3112 {
3113     openTcpStreamDialog(GRAPH_THROUGHPUT);
3114 }
3115
3116 void MainWindow::on_actionStatisticsTcpStreamRoundTripTime_triggered()
3117 {
3118     openTcpStreamDialog(GRAPH_RTT);
3119 }
3120
3121 void MainWindow::on_actionStatisticsTcpStreamWindowScaling_triggered()
3122 {
3123     openTcpStreamDialog(GRAPH_WSCALE);
3124 }
3125
3126 // -z mcast,stat
3127 void MainWindow::statCommandMulticastStatistics(const char *arg, void *)
3128 {
3129     MulticastStatisticsDialog *mcast_stats_dlg = new MulticastStatisticsDialog(*this, capture_file_, arg);
3130     connect(mcast_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3131             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3132     mcast_stats_dlg->show();
3133 }
3134
3135 void MainWindow::on_actionStatisticsUdpMulticastStreams_triggered()
3136 {
3137     statCommandMulticastStatistics(NULL, NULL);
3138 }
3139
3140 void MainWindow::openStatisticsTreeDialog(const gchar *abbr)
3141 {
3142     StatsTreeDialog *st_dialog = new StatsTreeDialog(*this, capture_file_, abbr);
3143 //    connect(st_dialog, SIGNAL(goToPacket(int)),
3144 //            packet_list_, SLOT(goToPacket(int)));
3145     st_dialog->show();
3146 }
3147
3148 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered()
3149 {
3150     openStatisticsTreeDialog("lbmr_topic_ads_topic");
3151 }
3152
3153 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Source_triggered()
3154 {
3155     openStatisticsTreeDialog("lbmr_topic_ads_source");
3156 }
3157
3158 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered()
3159 {
3160     openStatisticsTreeDialog("lbmr_topic_ads_transport");
3161 }
3162
3163 void MainWindow::on_actionStatistics29WestTopics_Queries_by_Topic_triggered()
3164 {
3165     openStatisticsTreeDialog("lbmr_topic_queries_topic");
3166 }
3167
3168 void MainWindow::on_actionStatistics29WestTopics_Queries_by_Receiver_triggered()
3169 {
3170     openStatisticsTreeDialog("lbmr_topic_queries_receiver");
3171 }
3172
3173 void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered()
3174 {
3175     openStatisticsTreeDialog("lbmr_topic_queries_pattern");
3176 }
3177
3178 void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered()
3179 {
3180     openStatisticsTreeDialog("lbmr_topic_queries_pattern_receiver");
3181 }
3182
3183 void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered()
3184 {
3185     openStatisticsTreeDialog("lbmr_queue_ads_queue");
3186 }
3187
3188 void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Source_triggered()
3189 {
3190     openStatisticsTreeDialog("lbmr_queue_ads_source");
3191 }
3192
3193 void MainWindow::on_actionStatistics29WestQueues_Queries_by_Queue_triggered()
3194 {
3195     openStatisticsTreeDialog("lbmr_queue_queries_queue");
3196 }
3197
3198 void MainWindow::on_actionStatistics29WestQueues_Queries_by_Receiver_triggered()
3199 {
3200     openStatisticsTreeDialog("lbmr_queue_queries_receiver");
3201 }
3202
3203 void MainWindow::on_actionStatistics29WestUIM_Streams_triggered()
3204 {
3205     LBMStreamDialog *stream_dialog = new LBMStreamDialog(this, capture_file_.capFile());
3206 //    connect(stream_dialog, SIGNAL(goToPacket(int)),
3207 //            packet_list_, SLOT(goToPacket(int)));
3208     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3209             stream_dialog, SLOT(setCaptureFile(capture_file*)));
3210     stream_dialog->show();
3211 }
3212
3213 void MainWindow::on_actionStatistics29WestLBTRM_triggered()
3214 {
3215     LBMLBTRMTransportDialog * lbtrm_dialog = new LBMLBTRMTransportDialog(this, capture_file_.capFile());
3216     connect(lbtrm_dialog, SIGNAL(goToPacket(int)),
3217             packet_list_, SLOT(goToPacket(int)));
3218     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3219             lbtrm_dialog, SLOT(setCaptureFile(capture_file*)));
3220     lbtrm_dialog->show();
3221 }
3222 void MainWindow::on_actionStatistics29WestLBTRU_triggered()
3223 {
3224     LBMLBTRUTransportDialog * lbtru_dialog = new LBMLBTRUTransportDialog(this, capture_file_.capFile());
3225     connect(lbtru_dialog, SIGNAL(goToPacket(int)),
3226             packet_list_, SLOT(goToPacket(int)));
3227     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3228             lbtru_dialog, SLOT(setCaptureFile(capture_file*)));
3229     lbtru_dialog->show();
3230 }
3231
3232 void MainWindow::on_actionStatisticsANCP_triggered()
3233 {
3234     openStatisticsTreeDialog("ancp");
3235 }
3236
3237 void MainWindow::on_actionStatisticsBACappInstanceId_triggered()
3238 {
3239     openStatisticsTreeDialog("bacapp_instanceid");
3240 }
3241
3242 void MainWindow::on_actionStatisticsBACappIP_triggered()
3243 {
3244     openStatisticsTreeDialog("bacapp_ip");
3245 }
3246
3247 void MainWindow::on_actionStatisticsBACappObjectId_triggered()
3248 {
3249     openStatisticsTreeDialog("bacapp_objectid");
3250 }
3251
3252 void MainWindow::on_actionStatisticsBACappService_triggered()
3253 {
3254     openStatisticsTreeDialog("bacapp_service");
3255 }
3256
3257 void MainWindow::on_actionStatisticsCollectd_triggered()
3258 {
3259     openStatisticsTreeDialog("collectd");
3260 }
3261
3262 // -z conv,...
3263 void MainWindow::statCommandConversations(const char *arg, void *userdata)
3264 {
3265     ConversationDialog *conv_dialog = new ConversationDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg);
3266     connect(conv_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3267             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3268     connect(conv_dialog, SIGNAL(openFollowStreamDialog(follow_type_t)),
3269             this, SLOT(openFollowStreamDialog(follow_type_t)));
3270     connect(conv_dialog, SIGNAL(openTcpStreamGraph(int)),
3271             this, SLOT(openTcpStreamDialog(int)));
3272     conv_dialog->show();
3273 }
3274
3275 void MainWindow::on_actionStatisticsConversations_triggered()
3276 {
3277     statCommandConversations(NULL, NULL);
3278 }
3279
3280 // -z endpoints,...
3281 void MainWindow::statCommandEndpoints(const char *arg, void *userdata)
3282 {
3283     EndpointDialog *endp_dialog = new EndpointDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg);
3284     connect(endp_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3285             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3286     connect(endp_dialog, SIGNAL(openFollowStreamDialog(follow_type_t)),
3287             this, SLOT(openFollowStreamDialog(follow_type_t)));
3288     connect(endp_dialog, SIGNAL(openTcpStreamGraph(int)),
3289             this, SLOT(openTcpStreamDialog(int)));
3290     endp_dialog->show();
3291 }
3292
3293 void MainWindow::on_actionStatisticsEndpoints_triggered()
3294 {
3295     statCommandEndpoints(NULL, NULL);
3296 }
3297
3298 void MainWindow::on_actionStatisticsHART_IP_triggered()
3299 {
3300     openStatisticsTreeDialog("hart_ip");
3301 }
3302
3303 void MainWindow::on_actionStatisticsHTTPPacketCounter_triggered()
3304 {
3305     openStatisticsTreeDialog("http");
3306 }
3307
3308 void MainWindow::on_actionStatisticsHTTPRequests_triggered()
3309 {
3310     openStatisticsTreeDialog("http_req");
3311 }
3312
3313 void MainWindow::on_actionStatisticsHTTPLoadDistribution_triggered()
3314 {
3315     openStatisticsTreeDialog("http_srv");
3316 }
3317
3318 void MainWindow::on_actionStatisticsHTTPReferers_triggered()
3319 {
3320     openStatisticsTreeDialog("http_ref");
3321 }
3322
3323 void MainWindow::on_actionStatisticsPacketLengths_triggered()
3324 {
3325     openStatisticsTreeDialog("plen");
3326 }
3327
3328 // -z io,stat
3329 void MainWindow::statCommandIOGraph(const char *, void *)
3330 {
3331     IOGraphDialog *iog_dialog = new IOGraphDialog(*this, capture_file_);
3332     connect(iog_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
3333     connect(this, SIGNAL(reloadFields()), iog_dialog, SLOT(reloadFields()));
3334     iog_dialog->show();
3335 }
3336
3337 void MainWindow::on_actionStatisticsIOGraph_triggered()
3338 {
3339     statCommandIOGraph(NULL, NULL);
3340 }
3341
3342 void MainWindow::on_actionStatisticsSametime_triggered()
3343 {
3344     openStatisticsTreeDialog("sametime");
3345 }
3346
3347 void MainWindow::on_actionStatisticsDNS_triggered()
3348 {
3349     openStatisticsTreeDialog("dns");
3350 }
3351
3352 void MainWindow::actionStatisticsPlugin_triggered()
3353 {
3354     QAction* action = qobject_cast<QAction*>(sender());
3355     if(action) {
3356         openStatisticsTreeDialog(action->data().toString().toUtf8());
3357     }
3358 }
3359
3360 void MainWindow::on_actionStatisticsHTTP2_triggered()
3361 {
3362     openStatisticsTreeDialog("http2");
3363
3364 }
3365
3366 // Telephony Menu
3367
3368 void MainWindow::openVoipCallsDialog(bool all_flows)
3369 {
3370     VoipCallsDialog *voip_calls_dialog = new VoipCallsDialog(*this, capture_file_, all_flows);
3371     connect(voip_calls_dialog, SIGNAL(goToPacket(int)),
3372             packet_list_, SLOT(goToPacket(int)));
3373     connect(voip_calls_dialog, SIGNAL(updateFilter(QString, bool)),
3374             this, SLOT(filterPackets(QString, bool)));
3375     voip_calls_dialog->show();
3376 }
3377
3378 void MainWindow::on_actionTelephonyVoipCalls_triggered()
3379 {
3380     openVoipCallsDialog();
3381 }
3382
3383 void MainWindow::on_actionTelephonyGsmMapSummary_triggered()
3384 {
3385     GsmMapSummaryDialog *gms_dialog = new GsmMapSummaryDialog(*this, capture_file_);
3386     gms_dialog->show();
3387 }
3388
3389 void MainWindow::on_actionTelephonyIax2StreamAnalysis_triggered()
3390 {
3391     Iax2AnalysisDialog *iax2_analysis_dialog = new  Iax2AnalysisDialog(*this, capture_file_);
3392     connect(iax2_analysis_dialog, SIGNAL(goToPacket(int)),
3393             packet_list_, SLOT(goToPacket(int)));
3394     iax2_analysis_dialog->show();
3395 }
3396
3397 void MainWindow::on_actionTelephonyISUPMessages_triggered()
3398 {
3399     openStatisticsTreeDialog("isup_msg");
3400 }
3401
3402 // -z mac-lte,stat
3403 void MainWindow::statCommandLteMacStatistics(const char *arg, void *)
3404 {
3405     LteMacStatisticsDialog *lte_mac_stats_dlg = new LteMacStatisticsDialog(*this, capture_file_, arg);
3406     connect(lte_mac_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3407             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3408     lte_mac_stats_dlg->show();
3409 }
3410
3411 void MainWindow::on_actionTelephonyLteMacStatistics_triggered()
3412 {
3413     statCommandLteMacStatistics(NULL, NULL);
3414 }
3415
3416 void MainWindow::statCommandLteRlcStatistics(const char *arg, void *)
3417 {
3418     LteRlcStatisticsDialog *lte_rlc_stats_dlg = new LteRlcStatisticsDialog(*this, capture_file_, arg);
3419     connect(lte_rlc_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3420             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3421     // N.B. It is necessary for the RLC Statistics window to launch the RLC graph in this way, to ensure
3422     // that the goToPacket() signal/slot connection gets set up...
3423     connect(lte_rlc_stats_dlg, SIGNAL(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8)),
3424             this, SLOT(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8)));
3425
3426     lte_rlc_stats_dlg->show();
3427 }
3428
3429 void MainWindow::on_actionTelephonyLteRlcStatistics_triggered()
3430 {
3431     statCommandLteRlcStatistics(NULL, NULL);
3432 }
3433
3434 void MainWindow::launchRLCGraph(bool channelKnown,
3435                                 guint16 ueid, guint8 rlcMode,
3436                                 guint16 channelType, guint16 channelId, guint8 direction)
3437 {
3438     LteRlcGraphDialog *lrg_dialog = new LteRlcGraphDialog(*this, capture_file_, channelKnown);
3439     connect(lrg_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
3440     // This is a bit messy, but wanted to hide these parameters from users of
3441     // on_actionTelephonyLteRlcGraph_triggered().
3442     if (channelKnown) {
3443         lrg_dialog->setChannelInfo(ueid, rlcMode, channelType, channelId, direction);
3444     }
3445     lrg_dialog->show();
3446 }
3447
3448 void MainWindow::on_actionTelephonyLteRlcGraph_triggered()
3449 {
3450     // We don't yet know the channel.
3451     launchRLCGraph(false, 0, 0, 0, 0, 0);
3452 }
3453
3454 void MainWindow::on_actionTelephonyMtp3Summary_triggered()
3455 {
3456     Mtp3SummaryDialog *mtp3s_dialog = new Mtp3SummaryDialog(*this, capture_file_);
3457     mtp3s_dialog->show();
3458 }
3459
3460 void MainWindow::on_actionTelephonyOsmuxPacketCounter_triggered()
3461 {
3462     openStatisticsTreeDialog("osmux");
3463 }
3464
3465 void MainWindow::on_actionTelephonyRTPStreams_triggered()
3466 {
3467     RtpStreamDialog *rtp_stream_dialog = new  RtpStreamDialog(*this, capture_file_);
3468     connect(rtp_stream_dialog, SIGNAL(packetsMarked()),
3469             packet_list_, SLOT(redrawVisiblePackets()));
3470     connect(rtp_stream_dialog, SIGNAL(goToPacket(int)),
3471             packet_list_, SLOT(goToPacket(int)));
3472     connect(rtp_stream_dialog, SIGNAL(updateFilter(QString, bool)),
3473             this, SLOT(filterPackets(QString, bool)));
3474     rtp_stream_dialog->show();
3475 }
3476
3477 void MainWindow::on_actionTelephonyRTPStreamAnalysis_triggered()
3478 {
3479     RtpAnalysisDialog *rtp_analysis_dialog = new  RtpAnalysisDialog(*this, capture_file_);
3480     connect(rtp_analysis_dialog, SIGNAL(goToPacket(int)),
3481             packet_list_, SLOT(goToPacket(int)));
3482     rtp_analysis_dialog->show();
3483 }
3484
3485 void MainWindow::on_actionTelephonyRTSPPacketCounter_triggered()
3486 {
3487     openStatisticsTreeDialog("rtsp");
3488 }
3489
3490 void MainWindow::on_actionTelephonySMPPOperations_triggered()
3491 {
3492     openStatisticsTreeDialog("smpp_commands");
3493 }
3494
3495 void MainWindow::on_actionTelephonyUCPMessages_triggered()
3496 {
3497     openStatisticsTreeDialog("ucp_messages");
3498 }
3499
3500 void MainWindow::on_actionTelephonySipFlows_triggered()
3501 {
3502     openVoipCallsDialog(true);
3503 }
3504
3505 // Wireless Menu
3506
3507 void MainWindow::on_actionBluetoothATT_Server_Attributes_triggered()
3508 {
3509     BluetoothAttServerAttributesDialog *bluetooth_att_sever_attributes_dialog = new BluetoothAttServerAttributesDialog(*this, capture_file_);
3510     connect(bluetooth_att_sever_attributes_dialog, SIGNAL(goToPacket(int)),
3511             packet_list_, SLOT(goToPacket(int)));
3512     connect(bluetooth_att_sever_attributes_dialog, SIGNAL(updateFilter(QString, bool)),
3513             this, SLOT(filterPackets(QString, bool)));
3514     bluetooth_att_sever_attributes_dialog->show();
3515 }
3516
3517 void MainWindow::on_actionBluetoothDevices_triggered()
3518 {
3519     BluetoothDevicesDialog *bluetooth_devices_dialog = new BluetoothDevicesDialog(*this, capture_file_, packet_list_);
3520     connect(bluetooth_devices_dialog, SIGNAL(goToPacket(int)),
3521             packet_list_, SLOT(goToPacket(int)));
3522     connect(bluetooth_devices_dialog, SIGNAL(updateFilter(QString, bool)),
3523             this, SLOT(filterPackets(QString, bool)));
3524     bluetooth_devices_dialog->show();
3525 }
3526
3527 void MainWindow::on_actionBluetoothHCI_Summary_triggered()
3528 {
3529     BluetoothHciSummaryDialog *bluetooth_hci_summary_dialog = new BluetoothHciSummaryDialog(*this, capture_file_);
3530     connect(bluetooth_hci_summary_dialog, SIGNAL(goToPacket(int)),
3531             packet_list_, SLOT(goToPacket(int)));
3532     connect(bluetooth_hci_summary_dialog, SIGNAL(updateFilter(QString, bool)),
3533             this, SLOT(filterPackets(QString, bool)));
3534     bluetooth_hci_summary_dialog->show();
3535 }
3536
3537 // Tools Menu
3538
3539 void MainWindow::on_actionToolsFirewallAclRules_triggered()
3540 {
3541     FirewallRulesDialog *firewall_rules_dialog = new FirewallRulesDialog(*this, capture_file_);
3542     firewall_rules_dialog->show();
3543 }
3544
3545
3546 // Help Menu
3547 void MainWindow::on_actionHelpContents_triggered() {
3548
3549     wsApp->helpTopicAction(HELP_CONTENT);
3550 }
3551
3552 void MainWindow::on_actionHelpMPWireshark_triggered() {
3553
3554     wsApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK);
3555 }
3556
3557 void MainWindow::on_actionHelpMPWireshark_Filter_triggered() {
3558     wsApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK_FILTER);
3559 }
3560
3561 void MainWindow::on_actionHelpMPCapinfos_triggered() {
3562     wsApp->helpTopicAction(LOCALPAGE_MAN_CAPINFOS);
3563 }
3564
3565 void MainWindow::on_actionHelpMPDumpcap_triggered() {
3566     wsApp->helpTopicAction(LOCALPAGE_MAN_DUMPCAP);
3567 }
3568
3569 void MainWindow::on_actionHelpMPEditcap_triggered() {
3570     wsApp->helpTopicAction(LOCALPAGE_MAN_EDITCAP);
3571 }
3572
3573 void MainWindow::on_actionHelpMPMergecap_triggered() {
3574     wsApp->helpTopicAction(LOCALPAGE_MAN_MERGECAP);
3575 }
3576
3577 void MainWindow::on_actionHelpMPRawShark_triggered() {
3578     wsApp->helpTopicAction(LOCALPAGE_MAN_RAWSHARK);
3579 }
3580
3581 void MainWindow::on_actionHelpMPReordercap_triggered() {
3582     wsApp->helpTopicAction(LOCALPAGE_MAN_REORDERCAP);
3583 }
3584
3585  void MainWindow::on_actionHelpMPText2cap_triggered() {
3586     wsApp->helpTopicAction(LOCALPAGE_MAN_TEXT2PCAP);
3587 }
3588
3589 void MainWindow::on_actionHelpMPTShark_triggered() {
3590     wsApp->helpTopicAction(LOCALPAGE_MAN_TSHARK);
3591 }
3592
3593 void MainWindow::on_actionHelpWebsite_triggered() {
3594
3595     wsApp->helpTopicAction(ONLINEPAGE_HOME);
3596 }
3597
3598 void MainWindow::on_actionHelpFAQ_triggered() {
3599
3600     wsApp->helpTopicAction(ONLINEPAGE_FAQ);
3601 }
3602
3603 void MainWindow::on_actionHelpAsk_triggered() {
3604
3605     wsApp->helpTopicAction(ONLINEPAGE_ASK);
3606 }
3607
3608 void MainWindow::on_actionHelpDownloads_triggered() {
3609
3610     wsApp->helpTopicAction(ONLINEPAGE_DOWNLOAD);
3611 }
3612
3613 void MainWindow::on_actionHelpWiki_triggered() {
3614
3615     wsApp->helpTopicAction(ONLINEPAGE_WIKI);
3616 }
3617
3618 void MainWindow::on_actionHelpSampleCaptures_triggered() {
3619
3620     wsApp->helpTopicAction(ONLINEPAGE_SAMPLE_FILES);
3621 }
3622
3623 #ifdef HAVE_SOFTWARE_UPDATE
3624 void MainWindow::checkForUpdates()
3625 {
3626     software_update_check();
3627 }
3628 #endif
3629
3630 void MainWindow::on_actionHelpAbout_triggered()
3631 {
3632     AboutDialog *about_dialog = new AboutDialog(this);
3633
3634     if (about_dialog->isMinimized() == true)
3635     {
3636         about_dialog->showNormal();
3637     }
3638     else
3639     {
3640         about_dialog->show();
3641     }
3642
3643     about_dialog->raise();
3644     about_dialog->activateWindow();
3645 }
3646
3647 void MainWindow::on_actionGoGoToPacket_triggered() {
3648     if (packet_list_->packetListModel()->rowCount() < 1) {
3649         return;
3650     }
3651     previous_focus_ = wsApp->focusWidget();
3652     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
3653
3654     showAccordionFrame(main_ui_->goToFrame, true);
3655     if (main_ui_->goToFrame->isVisible()) {
3656         main_ui_->goToLineEdit->clear();
3657         main_ui_->goToLineEdit->setFocus();
3658     }
3659 }
3660
3661 void MainWindow::on_actionGoGoToLinkedPacket_triggered()
3662 {
3663     QAction *gta = qobject_cast<QAction*>(sender());
3664     if (!gta) return;
3665
3666     bool ok = false;
3667     int packet_num = gta->data().toInt(&ok);
3668     if (!ok) return;
3669
3670     packet_list_->goToPacket(packet_num);
3671 }
3672
3673 // gtk/main_menubar.c:goto_conversation_frame
3674 void MainWindow::goToConversationFrame(bool go_next) {
3675     gchar     *filter       = NULL;
3676     dfilter_t *dfcode       = NULL;
3677     gboolean   found_packet = FALSE;
3678     packet_info *pi = &(capture_file_.capFile()->edt->pi);
3679
3680     /* Try to build a conversation
3681      * filter in the order TCP, UDP, IP, Ethernet and apply the
3682      * coloring */
3683     filter = conversation_filter_from_packet(pi);
3684     if (filter == NULL) {
3685         main_ui_->statusBar->pushTemporaryStatus(tr("Unable to build conversation filter."));
3686         g_free(filter);
3687         return;
3688     }
3689
3690     if (!dfilter_compile(filter, &dfcode, NULL)) {
3691         /* The attempt failed; report an error. */
3692         main_ui_->statusBar->pushTemporaryStatus(tr("Error compiling filter for this conversation."));
3693         g_free(filter);
3694         return;
3695     }
3696
3697     found_packet = cf_find_packet_dfilter(capture_file_.capFile(), dfcode, go_next ? SD_FORWARD : SD_BACKWARD);
3698
3699     if (!found_packet) {
3700         /* We didn't find a packet */
3701         main_ui_->statusBar->pushTemporaryStatus(tr("No previous/next packet in conversation."));
3702     }
3703
3704     dfilter_free(dfcode);
3705     g_free(filter);
3706 }
3707
3708 void MainWindow::on_actionGoNextConversationPacket_triggered()
3709 {
3710     goToConversationFrame(true);
3711 }
3712
3713 void MainWindow::on_actionGoPreviousConversationPacket_triggered()
3714 {
3715     goToConversationFrame(false);
3716 }
3717
3718 void MainWindow::on_actionGoAutoScroll_toggled(bool checked)
3719 {
3720     packet_list_->setVerticalAutoScroll(checked);
3721 }
3722
3723 void MainWindow::resetPreviousFocus() {
3724     previous_focus_ = NULL;
3725 }
3726
3727 void MainWindow::on_goToCancel_clicked()
3728 {
3729     main_ui_->goToFrame->animatedHide();
3730     if (previous_focus_) {
3731         disconnect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
3732         previous_focus_->setFocus();
3733         resetPreviousFocus();
3734     }
3735 }
3736
3737 void MainWindow::on_goToGo_clicked()
3738 {
3739     gotoFrame(main_ui_->goToLineEdit->text().toInt());
3740
3741     on_goToCancel_clicked();
3742 }
3743
3744 void MainWindow::on_goToLineEdit_returnPressed()
3745 {
3746     on_goToGo_clicked();
3747 }
3748
3749 void MainWindow::on_actionCaptureStart_triggered()
3750 {
3751 //#ifdef HAVE_AIRPCAP
3752 //  airpcap_if_active = airpcap_if_selected;
3753 //  if (airpcap_if_active)
3754 //    airpcap_set_toolbar_start_capture(airpcap_if_active);
3755 //#endif
3756
3757 //  if (cap_open_w) {
3758 //    /*
3759 //     * There's an options dialog; get the values from it and close it.
3760 //     */
3761 //    gboolean success;
3762
3763 //    /* Determine if "capture start" while building of the "capture options" window */
3764 //    /*  is in progress. If so, ignore the "capture start.                          */
3765 //    /* XXX: Would it be better/cleaner for the "capture options" window code to    */
3766 //    /*      disable the capture start button temporarily ?                         */
3767 //    if (cap_open_complete == FALSE) {
3768 //      return;  /* Building options window: ignore "capture start" */
3769 //    }
3770 //    success = capture_dlg_prep(cap_open_w);
3771 //    window_destroy(GTK_WIDGET(cap_open_w));
3772 //    if (!success)
3773 //      return;   /* error in options dialog */
3774 //  }
3775
3776 #ifdef HAVE_LIBPCAP
3777     if (global_capture_opts.num_selected == 0) {
3778         QString err_msg = tr("No Interface Selected");
3779         main_ui_->statusBar->pushTemporaryStatus(err_msg);
3780         main_ui_->actionCaptureStart->setChecked(false);
3781         return;
3782     }
3783
3784     /* XXX - will closing this remove a temporary file? */
3785     QString before_what(tr(" before starting a new capture"));
3786     if (testCaptureFileClose(before_what)) {
3787         startCapture();
3788     } else {
3789         // simply clicking the button sets it to 'checked' even though we've
3790         // decided to do nothing, so undo that
3791         main_ui_->actionCaptureStart->setChecked(false);
3792     }
3793 #endif // HAVE_LIBPCAP
3794 }
3795
3796 void MainWindow::on_actionCaptureStop_triggered()
3797 {
3798     stopCapture();
3799 }
3800
3801 void MainWindow::on_actionCaptureRestart_triggered()
3802 {
3803     QString before_what(tr(" before restarting the capture"));
3804     if (!testCaptureFileClose(before_what, Restart))
3805         return;
3806
3807 /* TODO: GTK use only this: capture_restart(&cap_session_); */
3808     startCapture();
3809 }
3810
3811 void MainWindow::on_actionCaptureCaptureFilters_triggered()
3812 {
3813     if (!capture_filter_dlg_) {
3814         capture_filter_dlg_ = new FilterDialog(this, FilterDialog::CaptureFilter);
3815     }
3816     capture_filter_dlg_->show();
3817     capture_filter_dlg_->raise();
3818     capture_filter_dlg_->activateWindow();
3819 }
3820
3821 void MainWindow::on_actionStatisticsCaptureFileProperties_triggered()
3822 {
3823     CaptureFilePropertiesDialog *capture_file_properties_dialog = new CaptureFilePropertiesDialog(*this, capture_file_);
3824     connect(capture_file_properties_dialog, SIGNAL(captureCommentChanged()),
3825             this, SLOT(updateForUnsavedChanges()));
3826     capture_file_properties_dialog->show();
3827 }
3828
3829 void MainWindow::on_actionStatisticsResolvedAddresses_triggered()
3830 {
3831     ResolvedAddressesDialog *resolved_addresses_dialog = new ResolvedAddressesDialog(this, &capture_file_);
3832     resolved_addresses_dialog->show();
3833 }
3834
3835 void MainWindow::on_actionStatisticsProtocolHierarchy_triggered()
3836 {
3837     ProtocolHierarchyDialog *phd = new ProtocolHierarchyDialog(*this, capture_file_);
3838     connect(phd, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3839             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3840     phd->show();
3841 }
3842
3843 void MainWindow::on_actionCaptureOptions_triggered()
3844 {
3845 #ifdef HAVE_LIBPCAP
3846     if (!capture_interfaces_dialog_) {
3847         capture_interfaces_dialog_ = new CaptureInterfacesDialog(this);
3848
3849         connect(capture_interfaces_dialog_, SIGNAL(startCapture()), this, SLOT(startCapture()));
3850         connect(capture_interfaces_dialog_, SIGNAL(stopCapture()), this, SLOT(stopCapture()));
3851
3852         connect(capture_interfaces_dialog_, SIGNAL(getPoints(int,PointList*)),
3853                 this->main_welcome_->getInterfaceFrame(), SLOT(getPoints(int,PointList*)));
3854         connect(capture_interfaces_dialog_, SIGNAL(interfacesChanged()),
3855                 this->main_welcome_, SLOT(interfaceSelected()));
3856         connect(capture_interfaces_dialog_, SIGNAL(interfacesChanged()),
3857                 this->main_welcome_->getInterfaceFrame(), SLOT(updateSelectedInterfaces()));
3858         connect(capture_interfaces_dialog_, SIGNAL(interfaceListChanged()),
3859                 this->main_welcome_->getInterfaceFrame(), SLOT(interfaceListChanged()));
3860         connect(capture_interfaces_dialog_, SIGNAL(captureFilterTextEdited(QString)),
3861                 this->main_welcome_, SLOT(setCaptureFilterText(QString)));
3862         // Propagate selection changes from main UI to dialog.
3863         connect(this->main_welcome_, SIGNAL(interfacesChanged()),
3864                 capture_interfaces_dialog_, SLOT(interfaceSelected()));
3865
3866         connect(capture_interfaces_dialog_, SIGNAL(setFilterValid(bool, const QString)),
3867                 this, SLOT(startInterfaceCapture(bool, const QString)));
3868     }
3869     capture_interfaces_dialog_->setTab(0);
3870     capture_interfaces_dialog_->updateInterfaces();
3871
3872     if (capture_interfaces_dialog_->isMinimized()) {
3873         capture_interfaces_dialog_->showNormal();
3874     } else {
3875         capture_interfaces_dialog_->show();
3876     }
3877
3878     capture_interfaces_dialog_->raise();
3879     capture_interfaces_dialog_->activateWindow();
3880 #endif
3881 }
3882
3883 #ifdef HAVE_LIBPCAP
3884 void MainWindow::on_actionCaptureRefreshInterfaces_triggered()
3885 {
3886     main_ui_->actionCaptureRefreshInterfaces->setEnabled(false);
3887     wsApp->refreshLocalInterfaces();
3888     main_ui_->actionCaptureRefreshInterfaces->setEnabled(true);
3889 }
3890 #endif
3891
3892 void MainWindow::externalMenuItem_triggered()
3893 {
3894     QAction * triggerAction = NULL;
3895     QVariant v;
3896     ext_menubar_t * entry = NULL;
3897
3898     if (QObject::sender()) {
3899         triggerAction = (QAction *)QObject::sender();
3900         v = triggerAction->data();
3901
3902         if (v.canConvert<void *>()) {
3903             entry = (ext_menubar_t *)v.value<void *>();
3904
3905             if (entry->type == EXT_MENUBAR_ITEM) {
3906                 entry->callback(EXT_MENUBAR_QT_GUI, (gpointer) ((void *)main_ui_), entry->user_data);
3907             } else {
3908                 QDesktopServices::openUrl(QUrl(QString((gchar *)entry->user_data)));
3909             }
3910         }
3911     }
3912 }
3913
3914 void MainWindow::gotoFrame(int packet_num)
3915 {
3916     if (packet_num > 0) {
3917         packet_list_->goToPacket(packet_num);
3918     }
3919 }
3920
3921 void MainWindow::extcap_options_finished(int result)
3922 {
3923     if (result == QDialog::Accepted) {
3924         startCapture();
3925     }
3926     this->main_welcome_->getInterfaceFrame()->interfaceListChanged();
3927 }
3928
3929 void MainWindow::showExtcapOptionsDialog(QString &device_name)
3930 {
3931     ExtcapOptionsDialog * extcap_options_dialog = ExtcapOptionsDialog::createForDevice(device_name, this);
3932     /* The dialog returns null, if the given device name is not a valid extcap device */
3933     if (extcap_options_dialog) {
3934         connect(extcap_options_dialog, SIGNAL(finished(int)),
3935                 this, SLOT(extcap_options_finished(int)));
3936         extcap_options_dialog->show();
3937     }
3938 }
3939
3940 void MainWindow::on_actionContextWikiProtocolPage_triggered()
3941 {
3942     QAction *wa = qobject_cast<QAction*>(sender());
3943     if (!wa) return;
3944
3945     bool ok = false;
3946     int field_id = wa->data().toInt(&ok);
3947     if (!ok) return;
3948
3949     const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3950
3951     int ret = QMessageBox::question(this, wsApp->windowTitleString(tr("Wiki Page for %1").arg(proto_abbrev)),
3952                                    tr("<p>The Wireshark Wiki is maintained by the community.</p>"
3953                                       "<p>The page you are about to load might be wonderful, "
3954                                       "incomplete, wrong, or nonexistent.</p>"
3955                                       "<p>Proceed to the wiki?</p>"),
3956                                    QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
3957
3958     if (ret != QMessageBox::Yes) return;
3959
3960     QUrl wiki_url = QString("https://wiki.wireshark.org/Protocols/%1").arg(proto_abbrev);
3961     QDesktopServices::openUrl(wiki_url);
3962 }
3963
3964 void MainWindow::on_actionContextFilterFieldReference_triggered()
3965 {
3966     QAction *wa = qobject_cast<QAction*>(sender());
3967     if (!wa) return;
3968
3969     bool ok = false;
3970     int field_id = wa->data().toInt(&ok);
3971     if (!ok) return;
3972
3973     const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3974
3975     QUrl dfref_url = QString("https://www.wireshark.org/docs/dfref/%1/%2")
3976             .arg(proto_abbrev[0])
3977             .arg(proto_abbrev);
3978     QDesktopServices::openUrl(dfref_url);
3979 }
3980
3981 void MainWindow::on_actionViewFullScreen_triggered(bool checked)
3982 {
3983     if (checked) {
3984         // Save the state for future restore
3985         was_maximized_ = this->isMaximized();
3986         this->showFullScreen();
3987     } else {
3988         // Restore the previous state
3989         if (was_maximized_)
3990             this->showMaximized();
3991         else
3992             this->showNormal();
3993     }
3994 }
3995
3996 void MainWindow::activatePluginIFToolbar(bool)
3997 {
3998     QAction *sendingAction = dynamic_cast<QAction *>(sender());
3999     if (!sendingAction || !sendingAction->data().isValid())
4000         return;
4001
4002     ext_toolbar_t *toolbar = VariantPointer<ext_toolbar_t>::asPtr(sendingAction->data());
4003
4004     QList<QToolBar *> toolbars = findChildren<QToolBar *>();
4005     foreach (QToolBar *bar, toolbars) {
4006         AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
4007         if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) {
4008             if (iftoolbar->isVisible()) {
4009                 iftoolbar->setVisible(false);
4010                 sendingAction->setChecked(true);
4011             } else {
4012                 iftoolbar->setVisible(true);
4013                 sendingAction->setChecked(true);
4014             }
4015         }
4016     }
4017 }
4018
4019 void MainWindow::filterToolbarCustomMenuHandler(const QPoint& pos)
4020 {
4021     QAction * filterAction = filter_expression_toolbar_->actionAt(pos);
4022     if ( ! filterAction )
4023         return;
4024
4025     QMenu * filterMenu = new QMenu(this);
4026
4027     QAction *actFilter = filterMenu->addAction(tr("Filter Button Preferences..."));
4028     connect(actFilter, SIGNAL(triggered()), this, SLOT(filterToolbarShowPreferences()));
4029     actFilter->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4030     actFilter->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4031     actFilter->setData(filterAction->data());
4032     filterMenu->addSeparator();
4033     QAction * actEdit = filterMenu->addAction(tr("Edit"));
4034     connect(actEdit, SIGNAL(triggered()), this, SLOT(filterToolbarEditFilter()));
4035     actEdit->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4036     actEdit->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4037     actEdit->setData(filterAction->data());
4038     QAction * actDisable = filterMenu->addAction(tr("Disable"));
4039     connect(actDisable, SIGNAL(triggered()), this, SLOT(filterToolbarDisableFilter()));
4040     actDisable->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4041     actDisable->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4042     actDisable->setData(filterAction->data());
4043     QAction * actRemove = filterMenu->addAction(tr("Remove"));
4044     connect(actRemove, SIGNAL(triggered()), this, SLOT(filterToolbarRemoveFilter()));
4045     actRemove->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4046     actRemove->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4047     actRemove->setData(filterAction->data());
4048
4049     filterMenu->exec(filter_expression_toolbar_->mapToGlobal(pos));
4050 }
4051
4052 void MainWindow::filterToolbarShowPreferences()
4053 {
4054     emit showPreferencesDialog(PrefsModel::FILTER_BUTTONS_PREFERENCE_TREE_NAME);
4055 }
4056
4057 int MainWindow::uatRowIndexForFilterExpression(QString label, QString expression)
4058 {
4059     int result = -1;
4060
4061     if ( expression.length() == 0 )
4062         return result;
4063
4064     UatModel * uatModel = new UatModel(this, "Display expressions");
4065
4066     QModelIndex rowIndex;
4067
4068     if ( label.length() > 0 )
4069     {
4070         for ( int cnt = 0; cnt < uatModel->rowCount() && ! rowIndex.isValid(); cnt++ )
4071         {
4072             if ( uatModel->data(uatModel->index(cnt, 1), Qt::DisplayRole).toString().compare(label) == 0 &&
4073                     uatModel->data(uatModel->index(cnt, 2), Qt::DisplayRole).toString().compare(expression) == 0 )
4074             {
4075                 rowIndex = uatModel->index(cnt, 2);
4076             }
4077         }
4078     }
4079     else
4080     {
4081         rowIndex = uatModel->findRowForColumnContent(((QAction *)sender())->data(), 2);
4082     }
4083
4084     if ( rowIndex.isValid() )
4085         result = rowIndex.row();
4086
4087     delete uatModel;
4088
4089     return result;
4090 }
4091
4092 void MainWindow::filterToolbarEditFilter()
4093 {
4094     if ( ! sender() )
4095         return;
4096
4097     QString label = ((QAction *)sender())->property(dfe_property_label_).toString();
4098     QString expr = ((QAction *)sender())->property(dfe_property_expression_).toString();
4099
4100     int idx = uatRowIndexForFilterExpression(label, expr);
4101
4102     if ( idx > -1 )
4103         main_ui_->filterExpressionFrame->editExpression(idx);
4104 }
4105
4106 void MainWindow::filterDropped(QString description, QString filter)
4107 {
4108     gchar* err = NULL;
4109     if ( filter.length() == 0 )
4110         return;
4111
4112     filter_expression_new(qUtf8Printable(description),
4113             qUtf8Printable(filter), qUtf8Printable(description), TRUE);
4114
4115     uat_save(uat_get_table_by_name("Display expressions"), &err);
4116     g_free(err);
4117
4118     filterExpressionsChanged();
4119 }
4120
4121 void MainWindow::filterToolbarDisableFilter()
4122 {
4123     gchar* err = NULL;
4124
4125     QString label = ((QAction *)sender())->property(dfe_property_label_).toString();
4126     QString expr = ((QAction *)sender())->property(dfe_property_expression_).toString();
4127
4128     int idx = uatRowIndexForFilterExpression(label, expr);
4129     UatModel * uatModel = new UatModel(this, "Display expressions");
4130
4131     QModelIndex rowIndex = uatModel->index(idx, 0);
4132     if ( rowIndex.isValid() ) {
4133         uatModel->setData(rowIndex, QVariant::fromValue(false));
4134
4135         uat_save(uat_get_table_by_name("Display expressions"), &err);
4136         g_free(err);
4137         filterExpressionsChanged();
4138     }
4139 }
4140
4141 void MainWindow::filterToolbarRemoveFilter()
4142 {
4143     gchar* err = NULL;
4144     UatModel * uatModel = new UatModel(this, "Display expressions");
4145
4146     QString label = ((QAction *)sender())->property(dfe_property_label_).toString();
4147     QString expr = ((QAction *)sender())->property(dfe_property_expression_).toString();
4148
4149     int idx = uatRowIndexForFilterExpression(label, expr);
4150
4151     QModelIndex rowIndex = uatModel->index(idx, 0);
4152     if ( rowIndex.isValid() ) {
4153         uatModel->removeRow(rowIndex.row());
4154
4155         uat_save(uat_get_table_by_name("Display expressions"), &err);
4156         g_free(err);
4157         filterExpressionsChanged();
4158     }
4159 }
4160
4161 void MainWindow::filterToolbarActionMoved(QAction* action, int oldPos, int newPos)
4162 {
4163     gchar* err = NULL;
4164     if ( oldPos == newPos )
4165         return;
4166
4167     QString label = action->property(dfe_property_label_).toString();
4168     QString expr = action->property(dfe_property_expression_).toString();
4169
4170     int idx = uatRowIndexForFilterExpression(label, expr);
4171
4172     if ( idx > -1 && oldPos > -1 && newPos > -1 )
4173     {
4174         uat_t * table = uat_get_table_by_name("Display expressions");
4175         uat_move_index(table, oldPos, newPos);
4176         uat_save(table, &err);
4177
4178         g_free(err);
4179     }
4180 }
4181
4182 #ifdef _MSC_VER
4183 #pragma warning(pop)
4184 #endif
4185
4186 /*
4187  * Editor modelines
4188  *
4189  * Local Variables:
4190  * c-basic-offset: 4
4191  * tab-width: 8
4192  * indent-tabs-mode: nil
4193  * End:
4194  *
4195  * ex: set shiftwidth=4 tabstop=8 expandtab:
4196  * :indentSize=4:tabSize=8:noTabs=true:
4197  */