Extend 'HTTP Referer statistics' to sequence HTTP Redirects
[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->actions_added) {
1013         QFrame *sep = new QFrame();
1014         sep->setEnabled(false);
1015         data->window->filter_expression_toolbar_->addWidget(sep);
1016     }
1017     data->window->filter_expression_toolbar_->addAction(dfb_action);
1018     connect(dfb_action, SIGNAL(triggered()), data->window, SLOT(displayFilterButtonClicked()));
1019     data->actions_added = true;
1020     return FALSE;
1021 }
1022
1023 void MainWindow::filterExpressionsChanged()
1024 {
1025     struct filter_expression_data data;
1026
1027     data.window = this;
1028     data.actions_added = false;
1029
1030     // Hiding and showing seems to be the only way to get the layout to
1031     // work correctly in some cases. See bug 14121 for details.
1032     setUpdatesEnabled(false);
1033     filter_expression_toolbar_->hide();
1034     filter_expression_toolbar_->clear();
1035
1036     // XXX Add a context menu for removing and changing buttons.
1037     filter_expression_iterate_expressions(filter_expression_add_action, &data);
1038
1039     filter_expression_toolbar_->show();
1040     setUpdatesEnabled(true);
1041 }
1042
1043 //
1044 // Private slots
1045 //
1046
1047 // ui/gtk/capture_dlg.c:start_capture_confirmed
1048
1049 void MainWindow::startCapture() {
1050 #ifdef HAVE_LIBPCAP
1051     interface_options *interface_opts;
1052     guint i;
1053
1054     /* did the user ever select a capture interface before? */
1055     if(global_capture_opts.num_selected == 0) {
1056         QString msg = QString(tr("No interface selected"));
1057         main_ui_->statusBar->pushTemporaryStatus(msg);
1058         main_ui_->actionCaptureStart->setChecked(false);
1059         return;
1060     }
1061
1062     // Ideally we should have disabled the start capture
1063     // toolbar buttons and menu items. This may not be the
1064     // case, e.g. with QtMacExtras.
1065     if(!capture_filter_valid_) {
1066         QString msg = QString(tr("Invalid capture filter"));
1067         main_ui_->statusBar->pushTemporaryStatus(msg);
1068         main_ui_->actionCaptureStart->setChecked(false);
1069         return;
1070     }
1071
1072     main_ui_->mainStack->setCurrentWidget(&master_split_);
1073
1074     /* XXX - we might need to init other pref data as well... */
1075
1076     /* XXX - can this ever happen? */
1077     if (cap_session_.state != CAPTURE_STOPPED)
1078       return;
1079
1080     /* close the currently loaded capture file */
1081     cf_close((capture_file *) cap_session_.cf);
1082
1083     /* Copy the selected interfaces to the set of interfaces to use for
1084        this capture. */
1085     collect_ifaces(&global_capture_opts);
1086
1087     CaptureFile::globalCapFile()->window = this;
1088     if (capture_start(&global_capture_opts, &cap_session_, &info_data_, main_window_update)) {
1089         capture_options *capture_opts = cap_session_.capture_opts;
1090         GString *interface_names;
1091
1092         /* Add "interface name<live capture in progress>" on main status bar */
1093         interface_names = get_iface_list_string(capture_opts, 0);
1094         if (strlen (interface_names->str) > 0) {
1095             g_string_append(interface_names, ":");
1096         }
1097         g_string_append(interface_names, " ");
1098
1099         main_ui_->statusBar->popFileStatus();
1100         QString msg = QString().sprintf("%s<live capture in progress>", interface_names->str);
1101         QString msgtip = QString().sprintf("to file: %s", (capture_opts->save_file) ? capture_opts->save_file : "");
1102         main_ui_->statusBar->pushFileStatus(msg, msgtip);
1103         g_string_free(interface_names, TRUE);
1104
1105         /* The capture succeeded, which means the capture filter syntax is
1106          valid; add this capture filter to the recent capture filter list. */
1107         QByteArray filter_ba;
1108         for (i = 0; i < global_capture_opts.ifaces->len; i++) {
1109             interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
1110             if (interface_opts->cfilter) {
1111                 recent_add_cfilter(interface_opts->name, interface_opts->cfilter);
1112                 if (filter_ba.isEmpty()) {
1113                     filter_ba = interface_opts->cfilter;
1114                 } else {
1115                     /* Not the first selected interface; is its capture filter
1116                        the same as the one the other interfaces we've looked
1117                        at have? */
1118                     if (strcmp(interface_opts->cfilter, filter_ba.constData()) != 0) {
1119                       /* No, so not all selected interfaces have the same capture
1120                          filter. */
1121                         filter_ba.clear();
1122                     }
1123                 }
1124             }
1125         }
1126         if (!filter_ba.isEmpty()) {
1127             recent_add_cfilter(NULL, filter_ba.constData());
1128         }
1129     } else {
1130         CaptureFile::globalCapFile()->window = NULL;
1131     }
1132 #endif // HAVE_LIBPCAP
1133 }
1134
1135 // Copied from ui/gtk/gui_utils.c
1136 void MainWindow::pipeTimeout() {
1137 #ifdef _WIN32
1138     HANDLE handle;
1139     DWORD avail = 0;
1140     gboolean result, result1;
1141     DWORD childstatus;
1142     gint iterations = 0;
1143
1144
1145     /* try to read data from the pipe only 5 times, to avoid blocking */
1146     while(iterations < 5) {
1147         /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
1148
1149         /* Oddly enough although Named pipes don't work on win9x,
1150            PeekNamedPipe does !!! */
1151         handle = (HANDLE) _get_osfhandle (pipe_source_);
1152         result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
1153
1154         /* Get the child process exit status */
1155         result1 = GetExitCodeProcess((HANDLE)*(pipe_child_process_),
1156                                      &childstatus);
1157
1158         /* If the Peek returned an error, or there are bytes to be read
1159            or the childwatcher thread has terminated then call the normal
1160            callback */
1161         if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
1162
1163             /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
1164
1165             /* And call the real handler */
1166             if (!pipe_input_cb_(pipe_source_, pipe_user_data_)) {
1167                 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
1168                 /* pipe closed, return false so that the old timer is not run again */
1169                 delete pipe_timer_;
1170                 return;
1171             }
1172         }
1173         else {
1174             /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
1175             /* No data, stop now */
1176             break;
1177         }
1178
1179         iterations++;
1180     }
1181 #endif // _WIN32
1182 }
1183
1184 void MainWindow::pipeActivated(int source) {
1185 #ifdef _WIN32
1186     Q_UNUSED(source)
1187 #else
1188     g_assert(source == pipe_source_);
1189
1190     pipe_notifier_->setEnabled(false);
1191     if (pipe_input_cb_(pipe_source_, pipe_user_data_)) {
1192         pipe_notifier_->setEnabled(true);
1193     } else {
1194         delete pipe_notifier_;
1195     }
1196 #endif // _WIN32
1197 }
1198
1199 void MainWindow::pipeNotifierDestroyed()
1200 {
1201     /* Pop the "<live capture in progress>" message off the status bar. */
1202     main_ui_->statusBar->setFileName(capture_file_);
1203
1204 #ifdef _WIN32
1205     pipe_timer_ = NULL;
1206 #else
1207     pipe_notifier_ = NULL;
1208 #endif // _WIN32
1209 }
1210
1211 void MainWindow::stopCapture() {
1212 //#ifdef HAVE_AIRPCAP
1213 //  if (airpcap_if_active)
1214 //    airpcap_set_toolbar_stop_capture(airpcap_if_active);
1215 //#endif
1216
1217 #ifdef HAVE_LIBPCAP
1218     capture_stop(&cap_session_);
1219 #endif // HAVE_LIBPCAP
1220
1221 }
1222
1223 // Keep focus rects from showing through the welcome screen. Primarily for
1224 // macOS.
1225 void MainWindow::mainStackChanged(int)
1226 {
1227     for (int i = 0; i < main_ui_->mainStack->count(); i++) {
1228         main_ui_->mainStack->widget(i)->setEnabled(i == main_ui_->mainStack->currentIndex());
1229     }
1230 }
1231
1232 // XXX - Copied from ui/gtk/menus.c
1233
1234 /**
1235  * Add the capture filename (with an absolute path) to the "Recent Files" menu.
1236  */
1237 // XXX - We should probably create a RecentFile class.
1238 void MainWindow::updateRecentCaptures() {
1239     QAction *ra;
1240     QMenu *recentMenu = main_ui_->menuOpenRecentCaptureFile;
1241     QString action_cf_name;
1242
1243     if (!recentMenu) {
1244         return;
1245     }
1246     recentMenu->clear();
1247
1248 // #if defined(QT_WINEXTRAS_LIB) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1249 //     QWinJumpList recent_jl(this);
1250 //     QWinJumpListCategory *recent_jlc = recent_jl.recent();
1251 //     if (recent_jlc) {
1252 //         recent_jlc->clear();
1253 //         recent_jlc->setVisible(true);
1254 //     }
1255 // #endif
1256 #if defined(Q_OS_MAC) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1257     if (!dock_menu_) {
1258         dock_menu_ = new QMenu();
1259         dock_menu_->setAsDockMenu();
1260     }
1261     dock_menu_->clear();
1262 #endif
1263
1264     /* Iterate through the actions in menuOpenRecentCaptureFile,
1265      * removing special items, a maybe duplicate entry and every item above count_max */
1266     int shortcut = Qt::Key_0;
1267     foreach (recent_item_status *ri, wsApp->recentItems()) {
1268         // Add the new item
1269         ra = new QAction(recentMenu);
1270         ra->setData(ri->filename);
1271         // XXX - Needs get_recent_item_status or equivalent
1272         ra->setEnabled(ri->accessible);
1273         recentMenu->insertAction(NULL, ra);
1274         action_cf_name = ra->data().toString();
1275         if (shortcut <= Qt::Key_9) {
1276             ra->setShortcut(Qt::META | shortcut);
1277             shortcut++;
1278         }
1279         ra->setText(action_cf_name);
1280         connect(ra, SIGNAL(triggered()), this, SLOT(recentActionTriggered()));
1281
1282 // This is slow, at least on my VM here. The added links also open Wireshark
1283 // in a new window. It might make more sense to add a recent item when we
1284 // open a capture file.
1285 // #if defined(QT_WINEXTRAS_LIB) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1286 //     if (recent_jlc) {
1287 //         QFileInfo fi(ri->filename);
1288 //         QWinJumpListItem *jli = recent_jlc->addLink(
1289 //             fi.fileName(),
1290 //             QApplication::applicationFilePath(),
1291 //             QStringList() << "-r" << ri->filename
1292 //         );
1293 //         // XXX set icon
1294 //         jli->setWorkingDirectory(QDir::toNativeSeparators(QApplication::applicationDirPath()));
1295 //     }
1296 // #endif
1297 #if defined(Q_OS_MAC) && QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
1298         QAction *rda = new QAction(dock_menu_);
1299         QFileInfo fi(ri->filename);
1300         rda->setText(fi.fileName());
1301         dock_menu_->insertAction(NULL, rda);
1302         connect(rda, SIGNAL(triggered()), ra, SLOT(trigger()));
1303 #endif
1304     }
1305
1306     if (recentMenu->actions().count() > 0) {
1307         // Separator + "Clear"
1308         // XXX - Do we really need this?
1309         ra = new QAction(recentMenu);
1310         ra->setSeparator(true);
1311         recentMenu->insertAction(NULL, ra);
1312
1313         ra = new QAction(recentMenu);
1314         ra->setText(tr("Clear Menu"));
1315         recentMenu->insertAction(NULL, ra);
1316         connect(ra, SIGNAL(triggered()), wsApp, SLOT(clearRecentCaptures()));
1317     } else {
1318         if (main_ui_->actionDummyNoFilesFound) {
1319             recentMenu->addAction(main_ui_->actionDummyNoFilesFound);
1320         }
1321     }
1322 }
1323
1324 void MainWindow::recentActionTriggered() {
1325     QAction *ra = qobject_cast<QAction*>(sender());
1326
1327     if (ra) {
1328         QString cfPath = ra->data().toString();
1329         openCaptureFile(cfPath);
1330     }
1331 }
1332
1333 void MainWindow::setMenusForSelectedPacket()
1334 {
1335     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;
1336
1337     /* Making the menu context-sensitive allows for easier selection of the
1338        desired item and has the added benefit, with large captures, of
1339        avoiding needless looping through huge lists for marked, ignored,
1340        or time-referenced packets. */
1341
1342     /* We have one or more items in the packet list */
1343     bool have_frames = false;
1344     /* A frame is selected */
1345     bool frame_selected = false;
1346     /* A visible packet comes after this one in the selection history */
1347     bool next_selection_history = false;
1348     /* A visible packet comes before this one in the selection history */
1349     bool previous_selection_history = false;
1350     /* We have marked frames.  (XXX - why check frame_selected?) */
1351     bool have_marked = false;
1352     /* We have a marked frame other than the current frame (i.e.,
1353        we have at least one marked frame, and either there's more
1354        than one marked frame or the current frame isn't marked). */
1355     bool another_is_marked = false;
1356     /* One or more frames are hidden by a display filter */
1357     bool have_filtered = false;
1358     /* One or more frames have been ignored */
1359     bool have_ignored = false;
1360     bool have_time_ref = false;
1361     /* We have a time reference frame other than the current frame (i.e.,
1362        we have at least one time reference frame, and either there's more
1363        than one time reference frame or the current frame isn't a
1364        time reference frame). (XXX - why check frame_selected?) */
1365     bool another_is_time_ref = false;
1366     /* We have a valid filter expression */
1367     bool have_filter_expr = false;
1368
1369     QList<QAction *> cc_actions = QList<QAction *>()
1370             << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1371             << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1372             << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1373             << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1374             << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1375
1376     if (capture_file_.capFile()) {
1377         frame_selected = capture_file_.capFile()->current_frame != NULL;
1378         next_selection_history = packet_list_->haveNextHistory();
1379         previous_selection_history = packet_list_->havePreviousHistory();
1380         have_frames = capture_file_.capFile()->count > 0;
1381         have_marked = frame_selected && capture_file_.capFile()->marked_count > 0;
1382         another_is_marked = have_marked &&
1383                 !(capture_file_.capFile()->marked_count == 1 && capture_file_.capFile()->current_frame->flags.marked);
1384         have_filtered = capture_file_.capFile()->displayed_count > 0 && capture_file_.capFile()->displayed_count != capture_file_.capFile()->count;
1385         have_ignored = capture_file_.capFile()->ignored_count > 0;
1386         have_time_ref = capture_file_.capFile()->ref_time_count > 0;
1387         another_is_time_ref = frame_selected && have_time_ref &&
1388                 !(capture_file_.capFile()->ref_time_count == 1 && capture_file_.capFile()->current_frame->flags.ref_time);
1389
1390         if (capture_file_.capFile()->edt)
1391         {
1392             proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers,
1393                                       &is_ip, &is_tcp, &is_udp, &is_sctp,
1394                                       &is_ssl, &is_rtp, &is_lte_rlc);
1395             is_http = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http");
1396         }
1397     }
1398
1399     have_filter_expr = !packet_list_->getFilterFromRowAndColumn().isEmpty();
1400
1401     main_ui_->actionEditMarkPacket->setEnabled(frame_selected);
1402     main_ui_->actionEditMarkAllDisplayed->setEnabled(have_frames);
1403     /* Unlike un-ignore, do not allow unmark of all frames when no frames are displayed  */
1404     main_ui_->actionEditUnmarkAllDisplayed->setEnabled(have_marked);
1405     main_ui_->actionEditNextMark->setEnabled(another_is_marked);
1406     main_ui_->actionEditPreviousMark->setEnabled(another_is_marked);
1407
1408     main_ui_->actionEditPacketComment->setEnabled(frame_selected && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET));
1409     main_ui_->actionDeleteAllPacketComments->setEnabled((capture_file_.capFile() != NULL) && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET));
1410
1411     main_ui_->actionEditIgnorePacket->setEnabled(frame_selected);
1412     main_ui_->actionEditIgnoreAllDisplayed->setEnabled(have_filtered);
1413     /* Allow un-ignore of all frames even with no frames currently displayed */
1414     main_ui_->actionEditUnignoreAllDisplayed->setEnabled(have_ignored);
1415
1416     main_ui_->actionEditSetTimeReference->setEnabled(frame_selected);
1417     main_ui_->actionEditUnsetAllTimeReferences->setEnabled(have_time_ref);
1418     main_ui_->actionEditNextTimeReference->setEnabled(another_is_time_ref);
1419     main_ui_->actionEditPreviousTimeReference->setEnabled(another_is_time_ref);
1420     main_ui_->actionEditTimeShift->setEnabled(have_frames);
1421
1422     main_ui_->actionGoGoToLinkedPacket->setEnabled(false);
1423     main_ui_->actionGoNextHistoryPacket->setEnabled(next_selection_history);
1424     main_ui_->actionGoPreviousHistoryPacket->setEnabled(previous_selection_history);
1425
1426     main_ui_->actionAnalyzeAAFSelected->setEnabled(have_filter_expr);
1427     main_ui_->actionAnalyzeAAFNotSelected->setEnabled(have_filter_expr);
1428     main_ui_->actionAnalyzeAAFAndSelected->setEnabled(have_filter_expr);
1429     main_ui_->actionAnalyzeAAFOrSelected->setEnabled(have_filter_expr);
1430     main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(have_filter_expr);
1431     main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(have_filter_expr);
1432
1433     main_ui_->actionAnalyzePAFSelected->setEnabled(have_filter_expr);
1434     main_ui_->actionAnalyzePAFNotSelected->setEnabled(have_filter_expr);
1435     main_ui_->actionAnalyzePAFAndSelected->setEnabled(have_filter_expr);
1436     main_ui_->actionAnalyzePAFOrSelected->setEnabled(have_filter_expr);
1437     main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(have_filter_expr);
1438     main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(have_filter_expr);
1439
1440     main_ui_->actionAnalyzeFollowTCPStream->setEnabled(is_tcp);
1441     main_ui_->actionAnalyzeFollowUDPStream->setEnabled(is_udp);
1442     main_ui_->actionAnalyzeFollowSSLStream->setEnabled(is_ssl);
1443     main_ui_->actionAnalyzeFollowHTTPStream->setEnabled(is_http);
1444
1445     foreach (QAction *cc_action, cc_actions) {
1446         cc_action->setEnabled(frame_selected);
1447     }
1448     main_ui_->actionViewColorizeNewColoringRule->setEnabled(frame_selected);
1449
1450     main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
1451
1452     main_ui_->actionViewShowPacketInNewWindow->setEnabled(frame_selected);
1453     main_ui_->actionViewEditResolvedName->setEnabled(frame_selected && is_ip);
1454
1455     emit packetInfoChanged(capture_file_.packetInfo());
1456
1457 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NameResolution/ResolveName",
1458 //                         frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1459 //                                            gbl_resolv_flags.transport_name));
1460
1461     main_ui_->actionToolsFirewallAclRules->setEnabled(frame_selected);
1462
1463     main_ui_->actionStatisticsTcpStreamRoundTripTime->setEnabled(is_tcp);
1464     main_ui_->actionStatisticsTcpStreamStevens->setEnabled(is_tcp);
1465     main_ui_->actionStatisticsTcpStreamTcptrace->setEnabled(is_tcp);
1466     main_ui_->actionStatisticsTcpStreamThroughput->setEnabled(is_tcp);
1467     main_ui_->actionStatisticsTcpStreamWindowScaling->setEnabled(is_tcp);
1468
1469     main_ui_->actionSCTPAnalyseThisAssociation->setEnabled(is_sctp);
1470     main_ui_->actionSCTPShowAllAssociations->setEnabled(is_sctp);
1471     main_ui_->actionSCTPFilterThisAssociation->setEnabled(is_sctp);
1472     main_ui_->actionTelephonyRTPStreamAnalysis->setEnabled(is_rtp);
1473     main_ui_->actionTelephonyLteRlcGraph->setEnabled(is_lte_rlc);
1474 }
1475
1476 void MainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) {
1477
1478     bool can_match_selected = false;
1479     bool is_framenum = false;
1480     bool have_field_info = false;
1481     bool have_subtree = false;
1482     bool can_open_url = false;
1483     bool have_packet_bytes = false;
1484     QByteArray field_filter;
1485     int field_id = -1;
1486
1487     field_info * fi = 0;
1488     if ( finfo )
1489         fi = finfo->fieldInfo();
1490
1491     if (capture_file_.capFile()) {
1492         capture_file_.capFile()->finfo_selected = fi;
1493
1494         if (fi && fi->tree_type != -1) {
1495             have_subtree = true;
1496         }
1497
1498         if (fi && fi->ds_tvb) {
1499             have_packet_bytes = true;
1500         }
1501     }
1502
1503     if (capture_file_.capFile() != NULL && fi != NULL) {
1504         header_field_info *hfinfo = fi->hfinfo;
1505         int linked_frame = -1;
1506
1507         have_field_info = true;
1508         can_match_selected = proto_can_match_selected(capture_file_.capFile()->finfo_selected, capture_file_.capFile()->edt);
1509         if (hfinfo && hfinfo->type == FT_FRAMENUM) {
1510             is_framenum = true;
1511             linked_frame = fvalue_get_uinteger(&fi->value);
1512         }
1513
1514         char *tmp_field = proto_construct_match_selected_string(fi, capture_file_.capFile()->edt);
1515         field_filter = tmp_field;
1516         wmem_free(NULL, tmp_field);
1517
1518         field_id = fi->hfinfo->id;
1519         /* if the selected field isn't a protocol, get its parent */
1520         if (!proto_registrar_is_protocol(field_id)) {
1521             field_id = proto_registrar_get_parent(fi->hfinfo->id);
1522         }
1523
1524         if (field_id >= 0) {
1525             can_open_url = true;
1526             main_ui_->actionContextWikiProtocolPage->setData(field_id);
1527             main_ui_->actionContextFilterFieldReference->setData(field_id);
1528         } else {
1529             main_ui_->actionContextWikiProtocolPage->setData(QVariant());
1530             main_ui_->actionContextFilterFieldReference->setData(QVariant());
1531         }
1532
1533         if (linked_frame > 0) {
1534             main_ui_->actionGoGoToLinkedPacket->setData(linked_frame);
1535         } else {
1536             main_ui_->actionGoGoToLinkedPacket->setData(QVariant());
1537         }
1538     }
1539
1540     // Always enable / disable the following items.
1541     main_ui_->actionFileExportPacketBytes->setEnabled(have_field_info);
1542
1543     main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL);
1544     main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected);
1545     main_ui_->actionEditCopyDescription->setEnabled(can_match_selected);
1546     main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected);
1547     main_ui_->actionEditCopyValue->setEnabled(can_match_selected);
1548     main_ui_->actionEditCopyAsFilter->setEnabled(can_match_selected);
1549
1550     main_ui_->actionAnalyzeShowPacketBytes->setEnabled(have_packet_bytes);
1551     main_ui_->actionFileExportPacketBytes->setEnabled(have_packet_bytes);
1552
1553     main_ui_->actionViewExpandSubtrees->setEnabled(have_subtree);
1554     main_ui_->actionViewCollapseSubtrees->setEnabled(have_subtree);
1555
1556     main_ui_->actionGoGoToLinkedPacket->setEnabled(is_framenum);
1557
1558     main_ui_->actionAnalyzeCreateAColumn->setEnabled(can_match_selected);
1559
1560     main_ui_->actionContextShowLinkedPacketInNewWindow->setEnabled(is_framenum);
1561
1562     main_ui_->actionContextWikiProtocolPage->setEnabled(can_open_url);
1563     main_ui_->actionContextFilterFieldReference->setEnabled(can_open_url);
1564
1565
1566     // Only enable / disable the following items if we have focus so that we
1567     // don't clobber anything we may have set in setMenusForSelectedPacket.
1568     if (!proto_tree_ || !proto_tree_->hasFocus()) return;
1569
1570     emit packetInfoChanged(capture_file_.packetInfo());
1571     emit fieldFilterChanged(field_filter);
1572
1573 //    set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ResolveName",
1574 //                         frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1575 //                                            gbl_resolv_flags.transport_name));
1576
1577     main_ui_->actionAnalyzeAAFSelected->setEnabled(can_match_selected);
1578     main_ui_->actionAnalyzeAAFNotSelected->setEnabled(can_match_selected);
1579     main_ui_->actionAnalyzeAAFAndSelected->setEnabled(can_match_selected);
1580     main_ui_->actionAnalyzeAAFOrSelected->setEnabled(can_match_selected);
1581     main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(can_match_selected);
1582     main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(can_match_selected);
1583
1584     main_ui_->actionAnalyzePAFSelected->setEnabled(can_match_selected);
1585     main_ui_->actionAnalyzePAFNotSelected->setEnabled(can_match_selected);
1586     main_ui_->actionAnalyzePAFAndSelected->setEnabled(can_match_selected);
1587     main_ui_->actionAnalyzePAFOrSelected->setEnabled(can_match_selected);
1588     main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(can_match_selected);
1589     main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(can_match_selected);
1590 }
1591
1592 void MainWindow::interfaceSelectionChanged()
1593 {
1594 #ifdef HAVE_LIBPCAP
1595     // XXX This doesn't disable the toolbar button when using
1596     // QtMacExtras.
1597     if (global_capture_opts.num_selected > 0 && capture_filter_valid_) {
1598         main_ui_->actionCaptureStart->setEnabled(true);
1599     } else {
1600         main_ui_->actionCaptureStart->setEnabled(false);
1601     }
1602 #endif // HAVE_LIBPCAP
1603 }
1604
1605 void MainWindow::captureFilterSyntaxChanged(bool valid)
1606 {
1607     capture_filter_valid_ = valid;
1608     interfaceSelectionChanged();
1609 }
1610
1611 void MainWindow::startInterfaceCapture(bool valid, const QString capture_filter)
1612 {
1613     capture_filter_valid_ = valid;
1614     main_welcome_->setCaptureFilter(capture_filter);
1615     // The interface tree will update the selected interfaces via its timer
1616     // so no need to do anything here.
1617     startCapture();
1618 }
1619
1620 void MainWindow::applyGlobalCommandLineOptions()
1621 {
1622     if (global_dissect_options.time_format != TS_NOT_SET) {
1623         foreach (QAction* tda, td_actions.keys()) {
1624             if (global_dissect_options.time_format == td_actions[tda]) {
1625                 tda->setChecked(true);
1626                 recent.gui_time_format = global_dissect_options.time_format;
1627                 timestamp_set_type(global_dissect_options.time_format);
1628                 break;
1629             }
1630         }
1631     }
1632     if (global_commandline_info.full_screen) {
1633         this->showFullScreen();
1634     }
1635 }
1636
1637 void MainWindow::redissectPackets()
1638 {
1639     if (capture_file_.capFile()) {
1640         cf_redissect_packets(capture_file_.capFile());
1641         main_ui_->statusBar->expertUpdate();
1642     }
1643
1644     proto_free_deregistered_fields();
1645 }
1646
1647 void MainWindow::checkDisplayFilter()
1648 {
1649     if (!df_combo_box_->checkDisplayFilter()) {
1650         g_free(CaptureFile::globalCapFile()->dfilter);
1651         CaptureFile::globalCapFile()->dfilter = NULL;
1652     }
1653 }
1654
1655 void MainWindow::fieldsChanged()
1656 {
1657     gchar *err_msg = NULL;
1658     if (!color_filters_reload(&err_msg, color_filter_add_cb)) {
1659         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
1660         g_free(err_msg);
1661     }
1662     tap_listeners_dfilter_recompile();
1663
1664     emit checkDisplayFilter();
1665
1666     if (have_custom_cols(&CaptureFile::globalCapFile()->cinfo)) {
1667         // Recreate packet list columns according to new/changed/deleted fields
1668         packet_list_->fieldsChanged(CaptureFile::globalCapFile());
1669     }
1670
1671     emit reloadFields();
1672 }
1673
1674 void MainWindow::reloadLuaPlugins()
1675 {
1676 #ifdef HAVE_LUA
1677     if (wsApp->isReloadingLua())
1678         return;
1679
1680     wsApp->setReloadingLua(true);
1681
1682     wslua_reload_plugins(NULL, NULL);
1683     funnel_statistics_reload_menus();
1684     reloadDynamicMenus();
1685     closePacketDialogs();
1686
1687     // Preferences may have been deleted so close all widgets using prefs
1688     proto_tree_->closeContextMenu();
1689     main_ui_->preferenceEditorFrame->animatedHide();
1690
1691     wsApp->readConfigurationFiles(true);
1692
1693     prefs_apply_all();
1694     fieldsChanged();
1695     redissectPackets();
1696
1697     wsApp->setReloadingLua(false);
1698     SimpleDialog::displayQueuedMessages();
1699 #endif
1700 }
1701
1702 void MainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle)
1703 {
1704     QList<AccordionFrame *>frame_list = QList<AccordionFrame *>()
1705             << main_ui_->goToFrame << main_ui_->searchFrame
1706             << main_ui_->addressEditorFrame << main_ui_->columnEditorFrame
1707             << main_ui_->preferenceEditorFrame << main_ui_->filterExpressionFrame;
1708
1709     frame_list.removeAll(show_frame);
1710     foreach (AccordionFrame *af, frame_list) af->animatedHide();
1711
1712     if (toggle) {
1713         if (show_frame->isVisible()) {
1714             show_frame->animatedHide();
1715             return;
1716         }
1717     }
1718     show_frame->animatedShow();
1719 }
1720
1721 void MainWindow::showColumnEditor(int column)
1722 {
1723     previous_focus_ = wsApp->focusWidget();
1724     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
1725     main_ui_->columnEditorFrame->editColumn(column);
1726     showAccordionFrame(main_ui_->columnEditorFrame);
1727 }
1728
1729 void MainWindow::showPreferenceEditor()
1730 {
1731     showAccordionFrame(main_ui_->preferenceEditorFrame);
1732 }
1733
1734 void MainWindow::initViewColorizeMenu()
1735 {
1736     QList<QAction *> cc_actions = QList<QAction *>()
1737             << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1738             << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1739             << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1740             << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1741             << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1742
1743     guint8 color_num = 1;
1744
1745     foreach (QAction *cc_action, cc_actions) {
1746         cc_action->setData(color_num);
1747         connect(cc_action, SIGNAL(triggered()), this, SLOT(colorizeConversation()));
1748
1749         const color_filter_t *colorf = color_filters_tmp_color(color_num);
1750         if (colorf) {
1751             QColor bg = ColorUtils::fromColorT(colorf->bg_color);
1752             QColor fg = ColorUtils::fromColorT(colorf->fg_color);
1753             cc_action->setIcon(StockIcon::colorIcon(bg.rgb(), fg.rgb(), QString::number(color_num)));
1754         }
1755         color_num++;
1756     }
1757
1758 #ifdef Q_OS_MAC
1759     // Spotlight uses Cmd+Space
1760     main_ui_->actionViewColorizeResetColorization->setShortcut(QKeySequence("Meta+Space"));
1761 #endif
1762 }
1763
1764 void MainWindow::addStatsPluginsToMenu() {
1765     GList          *cfg_list = stats_tree_get_cfg_list();
1766     GList          *iter = g_list_first(cfg_list);
1767     QAction        *stats_tree_action;
1768     QMenu          *parent_menu;
1769     bool            first_item = true;
1770
1771     while (iter) {
1772         stats_tree_cfg *cfg = (stats_tree_cfg*)iter->data;
1773         if (cfg->plugin) {
1774             if (first_item) {
1775                 main_ui_->menuStatistics->addSeparator();
1776                 first_item = false;
1777             }
1778
1779             parent_menu = main_ui_->menuStatistics;
1780             // gtk/main_menubar.c compresses double slashes, hence SkipEmptyParts
1781             QStringList cfg_name_parts = QString(cfg->name).split("/", QString::SkipEmptyParts);
1782             if (cfg_name_parts.isEmpty()) continue;
1783
1784             QString stat_name = cfg_name_parts.takeLast();
1785             if (!cfg_name_parts.isEmpty()) {
1786                 QString menu_name = cfg_name_parts.join("/");
1787                 parent_menu = findOrAddMenu(parent_menu, menu_name);
1788             }
1789
1790             stats_tree_action = new QAction(stat_name, this);
1791             stats_tree_action->setData(cfg->abbr);
1792             parent_menu->addAction(stats_tree_action);
1793             connect(stats_tree_action, SIGNAL(triggered()), this, SLOT(actionStatisticsPlugin_triggered()));
1794         }
1795         iter = g_list_next(iter);
1796     }
1797     g_list_free(cfg_list);
1798 }
1799
1800 void MainWindow::setFeaturesEnabled(bool enabled)
1801 {
1802     main_ui_->menuBar->setEnabled(enabled);
1803     main_ui_->mainToolBar->setEnabled(enabled);
1804     main_ui_->displayFilterToolBar->setEnabled(enabled);
1805     if(enabled)
1806     {
1807         main_ui_->statusBar->clearMessage();
1808 #ifdef HAVE_LIBPCAP
1809         main_ui_->actionGoAutoScroll->setChecked(auto_scroll_live);
1810 #endif
1811     }
1812     else
1813     {
1814         main_ui_->statusBar->showMessage(tr("Please wait while Wireshark is initializing" UTF8_HORIZONTAL_ELLIPSIS));
1815     }
1816 }
1817
1818 // Display Filter Toolbar
1819
1820 void MainWindow::on_actionDisplayFilterExpression_triggered()
1821 {
1822     DisplayFilterExpressionDialog *dfe_dialog = new DisplayFilterExpressionDialog(this);
1823
1824     connect(dfe_dialog, SIGNAL(insertDisplayFilter(QString)),
1825             df_combo_box_->lineEdit(), SLOT(insertFilter(const QString &)));
1826
1827     dfe_dialog->show();
1828 }
1829
1830 void MainWindow::on_actionNewDisplayFilterExpression_triggered()
1831 {
1832     main_ui_->filterExpressionFrame->addExpression(df_combo_box_->lineEdit()->text());
1833 }
1834
1835 // On Qt4 + macOS with unifiedTitleAndToolBarOnMac set it's possible to make
1836 // the main window obnoxiously wide.
1837
1838 void MainWindow::displayFilterButtonClicked()
1839 {
1840     QAction *dfb_action = qobject_cast<QAction*>(sender());
1841
1842     if (!dfb_action)
1843         return;
1844
1845     df_combo_box_->setDisplayFilter(dfb_action->data().toString());
1846     // Holding down the Shift key will only prepare filter.
1847     if (!(QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
1848         df_combo_box_->applyDisplayFilter();
1849     }
1850 }
1851
1852 void MainWindow::openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata)
1853 {
1854     QString slot = QString("statCommand%1").arg(menu_path);
1855     QMetaObject::invokeMethod(this, slot.toLatin1().constData(), Q_ARG(const char *, arg), Q_ARG(void *, userdata));
1856 }
1857
1858 void MainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata)
1859 {
1860     TapParameterDialog *tp_dialog = TapParameterDialog::showTapParameterStatistics(*this, capture_file_, cfg_str, arg, userdata);
1861     if (!tp_dialog) return;
1862
1863     connect(tp_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
1864             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
1865     connect(tp_dialog, SIGNAL(updateFilter(QString)),
1866             df_combo_box_->lineEdit(), SLOT(setText(QString)));
1867     tp_dialog->show();
1868 }
1869
1870 void MainWindow::openTapParameterDialog()
1871 {
1872     QAction *tpa = qobject_cast<QAction *>(QObject::sender());
1873     if (!tpa) return;
1874
1875     const QString cfg_str = tpa->data().toString();
1876     openTapParameterDialog(cfg_str, NULL, NULL);
1877 }
1878
1879 #ifdef HAVE_SOFTWARE_UPDATE
1880 void MainWindow::softwareUpdateRequested() {
1881     // We could call testCaptureFileClose here, but that would give us yet
1882     // another dialog. Just try again later.
1883     if (capture_file_.capFile() && capture_file_.capFile()->state != FILE_CLOSED) {
1884         wsApp->rejectSoftwareUpdate();
1885     }
1886 }
1887 #endif
1888
1889
1890 // File Menu
1891
1892 void MainWindow::on_actionFileOpen_triggered()
1893 {
1894     openCaptureFile();
1895 }
1896
1897 void MainWindow::on_actionFileMerge_triggered()
1898 {
1899     mergeCaptureFile();
1900 }
1901
1902 void MainWindow::on_actionFileImportFromHexDump_triggered()
1903 {
1904     importCaptureFile();
1905 }
1906
1907 void MainWindow::on_actionFileClose_triggered() {
1908     QString before_what(tr(" before closing the file"));
1909     if (testCaptureFileClose(before_what))
1910         main_ui_->mainStack->setCurrentWidget(main_welcome_);
1911 }
1912
1913 void MainWindow::on_actionFileSave_triggered()
1914 {
1915     saveCaptureFile(capture_file_.capFile(), false);
1916 }
1917
1918 void MainWindow::on_actionFileSaveAs_triggered()
1919 {
1920     saveAsCaptureFile(capture_file_.capFile());
1921 }
1922
1923 void MainWindow::on_actionFileSetListFiles_triggered()
1924 {
1925     file_set_dialog_->show();
1926 }
1927
1928 void MainWindow::on_actionFileSetNextFile_triggered()
1929 {
1930     fileset_entry *entry = fileset_get_next();
1931
1932     if (entry) {
1933         QString new_cf_path = entry->fullname;
1934         openCaptureFile(new_cf_path);
1935     }
1936 }
1937
1938 void MainWindow::on_actionFileSetPreviousFile_triggered()
1939 {
1940     fileset_entry *entry = fileset_get_previous();
1941
1942     if (entry) {
1943         QString new_cf_path = entry->fullname;
1944         openCaptureFile(new_cf_path);
1945     }
1946 }
1947
1948 void MainWindow::on_actionFileExportPackets_triggered()
1949 {
1950     exportSelectedPackets();
1951 }
1952
1953 void MainWindow::on_actionFileExportAsPlainText_triggered()
1954 {
1955     exportDissections(export_type_text);
1956 }
1957
1958 void MainWindow::on_actionFileExportAsCSV_triggered()
1959 {
1960     exportDissections(export_type_csv);
1961 }
1962
1963 void MainWindow::on_actionFileExportAsCArrays_triggered()
1964 {
1965     exportDissections(export_type_carrays);
1966 }
1967
1968 void MainWindow::on_actionFileExportAsPSML_triggered()
1969 {
1970     exportDissections(export_type_psml);
1971 }
1972
1973 void MainWindow::on_actionFileExportAsPDML_triggered()
1974 {
1975     exportDissections(export_type_pdml);
1976 }
1977
1978 void MainWindow::on_actionFileExportAsJSON_triggered()
1979 {
1980     exportDissections(export_type_json);
1981 }
1982
1983 void MainWindow::on_actionFileExportPacketBytes_triggered()
1984 {
1985     QString file_name;
1986
1987     if (!capture_file_.capFile() || !capture_file_.capFile()->finfo_selected) return;
1988
1989     file_name = QFileDialog::getSaveFileName(this,
1990                                              wsApp->windowTitleString(tr("Export Selected Packet Bytes")),
1991                                              wsApp->lastOpenDir().canonicalPath(),
1992                                              tr("Raw data (*.bin *.dat *.raw);;All Files (" ALL_FILES_WILDCARD ")")
1993                                              );
1994
1995     if (file_name.length() > 0) {
1996         const guint8 *data_p;
1997         int fd;
1998
1999         data_p = tvb_get_ptr(capture_file_.capFile()->finfo_selected->ds_tvb, 0, -1) +
2000                 capture_file_.capFile()->finfo_selected->start;
2001         fd = ws_open(qUtf8Printable(file_name), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
2002         if (fd == -1) {
2003             open_failure_alert_box(qUtf8Printable(file_name), errno, TRUE);
2004             return;
2005         }
2006         if (ws_write(fd, data_p, capture_file_.capFile()->finfo_selected->length) < 0) {
2007             write_failure_alert_box(qUtf8Printable(file_name), errno);
2008             ws_close(fd);
2009             return;
2010         }
2011         if (ws_close(fd) < 0) {
2012             write_failure_alert_box(qUtf8Printable(file_name), errno);
2013             return;
2014         }
2015
2016         /* Save the directory name for future file dialogs. */
2017         wsApp->setLastOpenDir(file_name);
2018     }
2019 }
2020
2021 void MainWindow::on_actionAnalyzeShowPacketBytes_triggered()
2022 {
2023     ShowPacketBytesDialog *spbd = new ShowPacketBytesDialog(*this, capture_file_);
2024     spbd->show();
2025 }
2026
2027 void MainWindow::on_actionFileExportPDU_triggered()
2028 {
2029     ExportPDUDialog *exportpdu_dialog = new ExportPDUDialog(this);
2030
2031     if (exportpdu_dialog->isMinimized() == true)
2032     {
2033         exportpdu_dialog->showNormal();
2034     }
2035     else
2036     {
2037         exportpdu_dialog->show();
2038     }
2039
2040     exportpdu_dialog->raise();
2041     exportpdu_dialog->activateWindow();
2042 }
2043
2044 void MainWindow::on_actionFileExportSSLSessionKeys_triggered()
2045 {
2046     QString file_name;
2047     QString save_title;
2048     int keylist_len;
2049
2050     keylist_len = ssl_session_key_count();
2051     /* don't show up the dialog, if no data has to be saved */
2052     if (keylist_len < 1) {
2053         /* shouldn't happen as the menu item should have been greyed out */
2054         QMessageBox::warning(
2055                     this,
2056                     tr("No Keys"),
2057                     tr("There are no SSL Session Keys to save."),
2058                     QMessageBox::Ok
2059                     );
2060         return;
2061     }
2062
2063     save_title.append(wsApp->windowTitleString(tr("Export SSL Session Keys (%Ln key(s))", "", keylist_len)));
2064     file_name = QFileDialog::getSaveFileName(this,
2065                                              save_title,
2066                                              wsApp->lastOpenDir().canonicalPath(),
2067                                              tr("SSL Session Keys (*.keys *.txt);;All Files (" ALL_FILES_WILDCARD ")")
2068                                              );
2069     if (file_name.length() > 0) {
2070         gchar *keylist;
2071         int fd;
2072
2073         keylist = ssl_export_sessions();
2074         fd = ws_open(qUtf8Printable(file_name), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
2075         if (fd == -1) {
2076             open_failure_alert_box(qUtf8Printable(file_name), errno, TRUE);
2077             g_free(keylist);
2078             return;
2079         }
2080         /*
2081          * Thanks, Microsoft, for not using size_t for the third argument to
2082          * _write().  Presumably this string will be <= 4GiB long....
2083          */
2084         if (ws_write(fd, keylist, (unsigned int)strlen(keylist)) < 0) {
2085             write_failure_alert_box(qUtf8Printable(file_name), errno);
2086             ws_close(fd);
2087             g_free(keylist);
2088             return;
2089         }
2090         if (ws_close(fd) < 0) {
2091             write_failure_alert_box(qUtf8Printable(file_name), errno);
2092             g_free(keylist);
2093             return;
2094         }
2095
2096         /* Save the directory name for future file dialogs. */
2097         wsApp->setLastOpenDir(file_name);
2098         g_free(keylist);
2099     }
2100 }
2101
2102 void MainWindow::on_actionStatisticsHpfeeds_triggered()
2103 {
2104     openStatisticsTreeDialog("hpfeeds");
2105 }
2106
2107 void MainWindow::on_actionFilePrint_triggered()
2108 {
2109     PrintDialog pdlg(this, capture_file_.capFile());
2110
2111     pdlg.exec();
2112 }
2113
2114 // Edit Menu
2115
2116 // XXX This should probably be somewhere else.
2117 void MainWindow::actionEditCopyTriggered(MainWindow::CopySelected selection_type)
2118 {
2119     char label_str[ITEM_LABEL_LENGTH];
2120     QString clip;
2121
2122     if (!capture_file_.capFile()) return;
2123
2124     field_info *finfo_selected = capture_file_.capFile()->finfo_selected;
2125
2126     switch(selection_type) {
2127     case CopySelectedDescription:
2128         if (finfo_selected && finfo_selected->rep
2129                 && strlen (finfo_selected->rep->representation) > 0) {
2130             clip.append(finfo_selected->rep->representation);
2131         }
2132         break;
2133     case CopySelectedFieldName:
2134         if (finfo_selected && finfo_selected->hfinfo->abbrev != 0) {
2135             clip.append(finfo_selected->hfinfo->abbrev);
2136         }
2137         break;
2138     case CopySelectedValue:
2139         if (finfo_selected && capture_file_.capFile()->edt != 0) {
2140             gchar* field_str = get_node_field_value(finfo_selected, capture_file_.capFile()->edt);
2141             clip.append(field_str);
2142             g_free(field_str);
2143         }
2144         break;
2145     case CopyAllVisibleItems:
2146         clip = proto_tree_->toString();
2147         break;
2148     case CopyAllVisibleSelectedTreeItems:
2149         if (proto_tree_->selectionModel()->hasSelection()) {
2150             clip = proto_tree_->toString(proto_tree_->selectionModel()->selectedIndexes().first());
2151         }
2152         break;
2153     }
2154
2155     if (clip.length() == 0) {
2156         /* If no representation then... Try to read the value */
2157         proto_item_fill_label(capture_file_.capFile()->finfo_selected, label_str);
2158         clip.append(label_str);
2159     }
2160
2161     if (clip.length()) {
2162         wsApp->clipboard()->setText(clip);
2163     } else {
2164         QString err = tr("Couldn't copy text. Try another item.");
2165         main_ui_->statusBar->pushTemporaryStatus(err);
2166     }
2167 }
2168
2169 void MainWindow::on_actionCopyAllVisibleItems_triggered()
2170 {
2171     actionEditCopyTriggered(CopyAllVisibleItems);
2172 }
2173
2174 void MainWindow::on_actionCopyAllVisibleSelectedTreeItems_triggered()
2175 {
2176     actionEditCopyTriggered(CopyAllVisibleSelectedTreeItems);
2177 }
2178
2179 void MainWindow::on_actionEditCopyDescription_triggered()
2180 {
2181     actionEditCopyTriggered(CopySelectedDescription);
2182 }
2183
2184 void MainWindow::on_actionEditCopyFieldName_triggered()
2185 {
2186     actionEditCopyTriggered(CopySelectedFieldName);
2187 }
2188
2189 void MainWindow::on_actionEditCopyValue_triggered()
2190 {
2191     actionEditCopyTriggered(CopySelectedValue);
2192 }
2193
2194 void MainWindow::on_actionEditCopyAsFilter_triggered()
2195 {
2196     matchFieldFilter(FilterAction::ActionCopy, FilterAction::ActionTypePlain);
2197 }
2198
2199 void MainWindow::on_actionEditFindPacket_triggered()
2200 {
2201     if (packet_list_->packetListModel()->rowCount() < 1) {
2202         return;
2203     }
2204     previous_focus_ = wsApp->focusWidget();
2205     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
2206     if (! main_ui_->searchFrame->isVisible()) {
2207         showAccordionFrame(main_ui_->searchFrame, true);
2208     }
2209     main_ui_->searchFrame->setFocus();
2210 }
2211
2212 void MainWindow::on_actionEditFindNext_triggered()
2213 {
2214     main_ui_->searchFrame->findNext();
2215 }
2216
2217 void MainWindow::on_actionEditFindPrevious_triggered()
2218 {
2219     main_ui_->searchFrame->findPrevious();
2220 }
2221
2222 void MainWindow::on_actionEditMarkPacket_triggered()
2223 {
2224     freeze();
2225     packet_list_->markFrame();
2226     thaw();
2227 }
2228
2229 void MainWindow::on_actionEditMarkAllDisplayed_triggered()
2230 {
2231     freeze();
2232     packet_list_->markAllDisplayedFrames(true);
2233     thaw();
2234 }
2235
2236 void MainWindow::on_actionEditUnmarkAllDisplayed_triggered()
2237 {
2238     freeze();
2239     packet_list_->markAllDisplayedFrames(false);
2240     thaw();
2241 }
2242
2243 void MainWindow::on_actionEditNextMark_triggered()
2244 {
2245     if (capture_file_.capFile())
2246         cf_find_packet_marked(capture_file_.capFile(), SD_FORWARD);
2247 }
2248
2249 void MainWindow::on_actionEditPreviousMark_triggered()
2250 {
2251     if (capture_file_.capFile())
2252         cf_find_packet_marked(capture_file_.capFile(), SD_BACKWARD);
2253 }
2254
2255 void MainWindow::on_actionEditIgnorePacket_triggered()
2256 {
2257     freeze();
2258     packet_list_->ignoreFrame();
2259     thaw();
2260 }
2261
2262 void MainWindow::on_actionEditIgnoreAllDisplayed_triggered()
2263 {
2264     freeze();
2265     packet_list_->ignoreAllDisplayedFrames(true);
2266     thaw();
2267 }
2268
2269 void MainWindow::on_actionEditUnignoreAllDisplayed_triggered()
2270 {
2271     freeze();
2272     packet_list_->ignoreAllDisplayedFrames(false);
2273     thaw();
2274 }
2275
2276 void MainWindow::on_actionEditSetTimeReference_triggered()
2277 {
2278     packet_list_->setTimeReference();
2279 }
2280
2281 void MainWindow::on_actionEditUnsetAllTimeReferences_triggered()
2282 {
2283     packet_list_->unsetAllTimeReferences();
2284 }
2285
2286 void MainWindow::on_actionEditNextTimeReference_triggered()
2287 {
2288     if (!capture_file_.capFile()) return;
2289     cf_find_packet_time_reference(capture_file_.capFile(), SD_FORWARD);
2290 }
2291
2292 void MainWindow::on_actionEditPreviousTimeReference_triggered()
2293 {
2294     if (!capture_file_.capFile()) return;
2295     cf_find_packet_time_reference(capture_file_.capFile(), SD_BACKWARD);
2296 }
2297
2298 void MainWindow::on_actionEditTimeShift_triggered()
2299 {
2300     TimeShiftDialog ts_dialog(this, capture_file_.capFile());
2301     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2302             &ts_dialog, SLOT(setCaptureFile(capture_file*)));
2303     connect(&ts_dialog, SIGNAL(timeShifted()), packet_list_, SLOT(applyTimeShift()));
2304     ts_dialog.exec();
2305 }
2306
2307 void MainWindow::on_actionEditPacketComment_triggered()
2308 {
2309     PacketCommentDialog pc_dialog(capture_file_.capFile()->current_frame->num, this, packet_list_->packetComment());
2310     if (pc_dialog.exec() == QDialog::Accepted) {
2311         packet_list_->setPacketComment(pc_dialog.text());
2312         updateForUnsavedChanges();
2313     }
2314 }
2315
2316 void MainWindow::on_actionDeleteAllPacketComments_triggered()
2317 {
2318     QMessageBox msg_dialog;
2319
2320     msg_dialog.setIcon(QMessageBox::Question);
2321     msg_dialog.setText(tr("Are you sure you want to remove all packet comments?"));
2322
2323     msg_dialog.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
2324     msg_dialog.setDefaultButton(QMessageBox::Ok);
2325
2326     if (msg_dialog.exec() == QMessageBox::Ok)
2327     {
2328         /* XXX Do we need a wait/hourglass for large files? */
2329         packet_list_->deleteAllPacketComments();
2330         updateForUnsavedChanges();
2331     }
2332 }
2333
2334 void MainWindow::on_actionEditConfigurationProfiles_triggered()
2335 {
2336     ProfileDialog cp_dialog;
2337
2338     cp_dialog.exec();
2339 }
2340
2341 void MainWindow::showPreferencesDialog(QString pane_name)
2342 {
2343     PreferencesDialog pref_dialog(this);
2344
2345     saveWindowGeometry();  // Save in case the layout panes are rearranged
2346
2347     pref_dialog.setPane(pane_name);
2348     pref_dialog.exec();
2349
2350     // Emitting PacketDissectionChanged directly from a QDialog can cause
2351     // problems on macOS.
2352     wsApp->flushAppSignals();
2353 }
2354
2355 void MainWindow::on_actionEditPreferences_triggered()
2356 {
2357     showPreferencesDialog(PrefsModel::APPEARANCE_PREFERENCE_TREE_NAME);
2358 }
2359
2360 // View Menu
2361
2362 void MainWindow::showHideMainWidgets(QAction *action)
2363 {
2364     if (!action) {
2365         return;
2366     }
2367     bool show = action->isChecked();
2368     QWidget *widget = action->data().value<QWidget*>();
2369
2370     // We may have come from the toolbar context menu, so check/uncheck each
2371     // action as well.
2372     if (widget == main_ui_->mainToolBar) {
2373         recent.main_toolbar_show = show;
2374         main_ui_->actionViewMainToolbar->setChecked(show);
2375     } else if (widget == main_ui_->displayFilterToolBar) {
2376         recent.filter_toolbar_show = show;
2377         main_ui_->actionViewFilterToolbar->setChecked(show);
2378      } else if (widget == main_ui_->wirelessToolBar) {
2379         recent.wireless_toolbar_show = show;
2380         main_ui_->actionViewWirelessToolbar->setChecked(show);
2381     } else if (widget == main_ui_->statusBar) {
2382         recent.statusbar_show = show;
2383         main_ui_->actionViewStatusBar->setChecked(show);
2384     } else if (widget == packet_list_) {
2385         recent.packet_list_show = show;
2386         main_ui_->actionViewPacketList->setChecked(show);
2387     } else if (widget == proto_tree_) {
2388         recent.tree_view_show = show;
2389         main_ui_->actionViewPacketDetails->setChecked(show);
2390     } else if (widget == byte_view_tab_) {
2391         recent.byte_view_show = show;
2392         main_ui_->actionViewPacketBytes->setChecked(show);
2393     } else {
2394         foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
2395             QToolBar *toolbar = action->data().value<QToolBar *>();
2396             if (widget == toolbar) {
2397                 GList *entry = g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp);
2398                 if (show && !entry) {
2399                     recent.interface_toolbars = g_list_append(recent.interface_toolbars, g_strdup(action->text().toUtf8()));
2400                 } else if (!show && entry) {
2401                     recent.interface_toolbars = g_list_remove(recent.interface_toolbars, entry->data);
2402                 }
2403                 action->setChecked(show);
2404             }
2405         }
2406
2407         ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data());
2408         if (toolbar) {
2409             GList *entry = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc) strcmp);
2410             if (show && !entry) {
2411                 recent.gui_additional_toolbars = g_list_append(recent.gui_additional_toolbars, g_strdup(toolbar->name));
2412             } else if (!show && entry) {
2413                 recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data);
2414             }
2415             action->setChecked(show);
2416
2417             QList<QToolBar *> toolbars = findChildren<QToolBar *>();
2418             foreach (QToolBar *bar, toolbars) {
2419                 AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
2420                 if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) {
2421                     iftoolbar->setVisible(show);
2422                 }
2423             }
2424         }
2425     }
2426
2427     if (widget) {
2428         widget->setVisible(show);
2429     }
2430 }
2431
2432 void MainWindow::setTimestampFormat(QAction *action)
2433 {
2434     if (!action) {
2435         return;
2436     }
2437     ts_type tsf = action->data().value<ts_type>();
2438     if (recent.gui_time_format != tsf) {
2439         timestamp_set_type(tsf);
2440         recent.gui_time_format = tsf;
2441
2442         if (packet_list_) {
2443             packet_list_->resetColumns();
2444         }
2445         if (capture_file_.capFile()) {
2446             /* This call adjusts column width */
2447             cf_timestamp_auto_precision(capture_file_.capFile());
2448         }
2449     }
2450 }
2451
2452 void MainWindow::setTimestampPrecision(QAction *action)
2453 {
2454     if (!action) {
2455         return;
2456     }
2457     ts_precision tsp = action->data().value<ts_precision>();
2458     if (recent.gui_time_precision != tsp) {
2459         /* the actual precision will be set in packet_list_queue_draw() below */
2460         timestamp_set_precision(tsp);
2461         recent.gui_time_precision = tsp;
2462
2463         if (packet_list_) {
2464             packet_list_->resetColumns();
2465         }
2466         if (capture_file_.capFile()) {
2467             /* This call adjusts column width */
2468             cf_timestamp_auto_precision(capture_file_.capFile());
2469         }
2470     }
2471 }
2472
2473 void MainWindow::on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked)
2474 {
2475     if (checked) {
2476         recent.gui_seconds_format = TS_SECONDS_HOUR_MIN_SEC;
2477     } else {
2478         recent.gui_seconds_format = TS_SECONDS_DEFAULT;
2479     }
2480     timestamp_set_seconds_type(recent.gui_seconds_format);
2481
2482     if (packet_list_) {
2483         packet_list_->resetColumns();
2484     }
2485     if (capture_file_.capFile()) {
2486         /* This call adjusts column width */
2487         cf_timestamp_auto_precision(capture_file_.capFile());
2488     }
2489 }
2490
2491 void MainWindow::on_actionViewEditResolvedName_triggered()
2492 {
2493 //    int column = packet_list_->selectedColumn();
2494     int column = -1;
2495
2496     if (packet_list_->currentIndex().isValid()) {
2497         column = packet_list_->currentIndex().column();
2498     }
2499
2500     main_ui_->addressEditorFrame->editAddresses(capture_file_, column);
2501     showAccordionFrame(main_ui_->addressEditorFrame);
2502 }
2503
2504 void MainWindow::setNameResolution()
2505 {
2506     gbl_resolv_flags.mac_name = main_ui_->actionViewNameResolutionPhysical->isChecked() ? TRUE : FALSE;
2507     gbl_resolv_flags.network_name = main_ui_->actionViewNameResolutionNetwork->isChecked() ? TRUE : FALSE;
2508     gbl_resolv_flags.transport_name = main_ui_->actionViewNameResolutionTransport->isChecked() ? TRUE : FALSE;
2509
2510     if (packet_list_) {
2511         packet_list_->resetColumns();
2512     }
2513     wsApp->emitAppSignal(WiresharkApplication::NameResolutionChanged);
2514 }
2515
2516 void MainWindow::on_actionViewNameResolutionPhysical_triggered()
2517 {
2518     setNameResolution();
2519 }
2520
2521 void MainWindow::on_actionViewNameResolutionNetwork_triggered()
2522 {
2523     setNameResolution();
2524 }
2525
2526 void MainWindow::on_actionViewNameResolutionTransport_triggered()
2527 {
2528     setNameResolution();
2529 }
2530
2531 void MainWindow::zoomText()
2532 {
2533     wsApp->zoomTextFont(recent.gui_zoom_level);
2534 }
2535
2536 void MainWindow::on_actionViewZoomIn_triggered()
2537 {
2538     recent.gui_zoom_level++;
2539     zoomText();
2540 }
2541
2542 void MainWindow::on_actionViewZoomOut_triggered()
2543 {
2544     recent.gui_zoom_level--;
2545     zoomText();
2546 }
2547
2548 void MainWindow::on_actionViewNormalSize_triggered()
2549 {
2550     recent.gui_zoom_level = 0;
2551     zoomText();
2552 }
2553
2554 void MainWindow::on_actionViewColorizePacketList_triggered(bool checked) {
2555     recent.packet_list_colorize = checked;
2556     packet_list_enable_color(checked);
2557     packet_list_->packetListModel()->resetColorized();
2558 }
2559
2560 void MainWindow::on_actionViewColoringRules_triggered()
2561 {
2562     ColoringRulesDialog coloring_rules_dialog(this);
2563     connect(&coloring_rules_dialog, SIGNAL(accepted()),
2564             packet_list_, SLOT(recolorPackets()));
2565     connect(&coloring_rules_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
2566             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
2567     coloring_rules_dialog.exec();
2568 }
2569
2570 // actionViewColorizeConversation1 - 10
2571 void MainWindow::colorizeConversation(bool create_rule)
2572 {
2573     QAction *colorize_action = qobject_cast<QAction *>(sender());
2574     if (!colorize_action) return;
2575
2576     if (capture_file_.capFile() && capture_file_.capFile()->current_frame) {
2577         packet_info *pi = capture_file_.packetInfo();
2578         guint8 cc_num = colorize_action->data().toUInt();
2579         gchar *filter = conversation_filter_from_packet(pi);
2580         if (filter == NULL) {
2581             main_ui_->statusBar->pushTemporaryStatus(tr("Unable to build conversation filter."));
2582             return;
2583         }
2584
2585         if (create_rule) {
2586             ColoringRulesDialog coloring_rules_dialog(this, filter);
2587             connect(&coloring_rules_dialog, SIGNAL(accepted()),
2588                     packet_list_, SLOT(recolorPackets()));
2589             connect(&coloring_rules_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
2590                     this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
2591             coloring_rules_dialog.exec();
2592         } else {
2593             gchar *err_msg = NULL;
2594             if (!color_filters_set_tmp(cc_num, filter, FALSE, &err_msg)) {
2595                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2596                 g_free(err_msg);
2597             }
2598             packet_list_->recolorPackets();
2599         }
2600     }
2601     setMenusForSelectedPacket();
2602 }
2603
2604 void MainWindow::colorizeActionTriggered()
2605 {
2606     QByteArray filter;
2607     int color_number = -1;
2608
2609     ConversationAction *conv_action = qobject_cast<ConversationAction *>(sender());
2610     if (conv_action) {
2611         filter = conv_action->filter();
2612         color_number = conv_action->colorNumber();
2613     } else {
2614         ColorizeAction *colorize_action = qobject_cast<ColorizeAction *>(sender());
2615         if (colorize_action) {
2616             filter = colorize_action->filter();
2617             color_number = colorize_action->colorNumber();
2618         }
2619     }
2620
2621     colorizeWithFilter(filter, color_number);
2622 }
2623
2624 void MainWindow::colorizeWithFilter(QByteArray filter, int color_number)
2625 {
2626     if (filter.isEmpty()) return;
2627
2628     if (color_number > 0) {
2629         // Assume "Color X"
2630         gchar *err_msg = NULL;
2631         if (!color_filters_set_tmp(color_number, filter.constData(), FALSE, &err_msg)) {
2632             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2633             g_free(err_msg);
2634         }
2635         packet_list_->recolorPackets();
2636     } else {
2637         // New coloring rule
2638         ColoringRulesDialog coloring_rules_dialog(window(), filter);
2639         connect(&coloring_rules_dialog, SIGNAL(accepted()),
2640                 packet_list_, SLOT(recolorPackets()));
2641         connect(&coloring_rules_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
2642                 this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
2643         coloring_rules_dialog.exec();
2644     }
2645     main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
2646 }
2647
2648 void MainWindow::on_actionViewColorizeResetColorization_triggered()
2649 {
2650     gchar *err_msg = NULL;
2651     if (!color_filters_reset_tmp(&err_msg)) {
2652         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2653         g_free(err_msg);
2654     }
2655     packet_list_->recolorPackets();
2656     setMenusForSelectedPacket();
2657 }
2658
2659 void MainWindow::on_actionViewColorizeNewColoringRule_triggered()
2660 {
2661     colorizeConversation(true);
2662 }
2663
2664 void MainWindow::on_actionViewResetLayout_triggered()
2665 {
2666     recent.gui_geometry_main_upper_pane = 0;
2667     recent.gui_geometry_main_lower_pane = 0;
2668
2669     applyRecentPaneGeometry();
2670 }
2671
2672 void MainWindow::on_actionViewResizeColumns_triggered()
2673 {
2674     for (int col = 0; col < packet_list_->packetListModel()->columnCount(); col++) {
2675         packet_list_->resizeColumnToContents(col);
2676         recent_set_column_width(col, packet_list_->columnWidth(col));
2677     }
2678 }
2679
2680 void MainWindow::openPacketDialog(bool from_reference)
2681 {
2682     frame_data * fdata;
2683
2684     /* Find the frame for which we're popping up a dialog */
2685     if(from_reference) {
2686         guint32 framenum = fvalue_get_uinteger(&(capture_file_.capFile()->finfo_selected->value));
2687         if (framenum == 0)
2688             return;
2689
2690         fdata = frame_data_sequence_find(capture_file_.capFile()->provider.frames, framenum);
2691     } else {
2692         fdata = capture_file_.capFile()->current_frame;
2693     }
2694
2695     /* If we have a frame, pop up the dialog */
2696     if (fdata) {
2697         PacketDialog *packet_dialog = new PacketDialog(*this, capture_file_, fdata);
2698
2699         connect(this, SIGNAL(closePacketDialogs()),
2700                 packet_dialog, SLOT(close()));
2701         zoomText(); // Emits wsApp->zoomMonospaceFont(QFont)
2702
2703         packet_dialog->show();
2704     }
2705 }
2706
2707 void MainWindow::on_actionViewInternalsConversationHashTables_triggered()
2708 {
2709     ConversationHashTablesDialog *conversation_hash_tables_dlg = new ConversationHashTablesDialog(this);
2710     conversation_hash_tables_dlg->show();
2711 }
2712
2713 void MainWindow::on_actionViewInternalsDissectorTables_triggered()
2714 {
2715     DissectorTablesDialog *dissector_tables_dlg = new DissectorTablesDialog(this);
2716     dissector_tables_dlg->show();
2717 }
2718
2719 void MainWindow::on_actionViewInternalsSupportedProtocols_triggered()
2720 {
2721     SupportedProtocolsDialog *supported_protocols_dlg = new SupportedProtocolsDialog(this);
2722     supported_protocols_dlg->show();
2723 }
2724
2725 void MainWindow::on_actionViewShowPacketInNewWindow_triggered()
2726 {
2727     openPacketDialog();
2728 }
2729
2730 // This is only used in ProtoTree. Defining it here makes more sense.
2731 void MainWindow::on_actionContextShowLinkedPacketInNewWindow_triggered()
2732 {
2733     openPacketDialog(true);
2734 }
2735
2736 void MainWindow::on_actionViewReload_triggered()
2737 {
2738     capture_file *cf = CaptureFile::globalCapFile();
2739
2740     if (cf->unsaved_changes) {
2741         QString before_what(tr(" before reloading the file"));
2742         if (!testCaptureFileClose(before_what, Reload))
2743             return;
2744     }
2745
2746     cf_reload(cf);
2747 }
2748
2749 void MainWindow::on_actionViewReload_as_File_Format_or_Capture_triggered()
2750 {
2751     capture_file *cf = CaptureFile::globalCapFile();
2752
2753     if (cf->unsaved_changes) {
2754         QString before_what(tr(" before reloading the file"));
2755         if (!testCaptureFileClose(before_what, Reload))
2756             return;
2757     }
2758
2759     if (cf->open_type == WTAP_TYPE_AUTO)
2760         cf->open_type = open_info_name_to_type("MIME Files Format");
2761     else /* TODO: This should be latest format chosen by user */
2762         cf->open_type = WTAP_TYPE_AUTO;
2763
2764     cf_reload(cf);
2765 }
2766
2767
2768 // Expand / collapse slots in proto_tree
2769
2770 // Go Menu
2771
2772 // Analyze Menu
2773
2774 void MainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type)
2775 {
2776     QString field_filter;
2777
2778     if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) {
2779         field_filter = packet_list_->getFilterFromRowAndColumn();
2780     } else if (capture_file_.capFile() && capture_file_.capFile()->finfo_selected) {
2781         char *tmp_field = proto_construct_match_selected_string(capture_file_.capFile()->finfo_selected,
2782                                                        capture_file_.capFile()->edt);
2783         field_filter = QString(tmp_field);
2784         wmem_free(NULL, tmp_field);
2785     }
2786
2787     if (field_filter.isEmpty()) {
2788         QString err = tr("No filter available. Try another ");
2789         err.append(packet_list_->contextMenuActive() ? "column" : "item");
2790         err.append(".");
2791         main_ui_->statusBar->pushTemporaryStatus(err);
2792         return;
2793     }
2794
2795     emit filterAction(field_filter, action, filter_type);
2796 }
2797
2798 void MainWindow::on_actionAnalyzeDisplayFilters_triggered()
2799 {
2800     if (!display_filter_dlg_) {
2801         display_filter_dlg_ = new FilterDialog(this, FilterDialog::DisplayFilter);
2802     }
2803     display_filter_dlg_->show();
2804     display_filter_dlg_->raise();
2805     display_filter_dlg_->activateWindow();
2806 }
2807
2808 struct epan_uat;
2809 void MainWindow::on_actionAnalyzeDisplayFilterMacros_triggered()
2810 {
2811     struct epan_uat* dfm_uat;
2812     dfilter_macro_get_uat(&dfm_uat);
2813     UatDialog uat_dlg(parentWidget(), dfm_uat);
2814
2815     uat_dlg.exec();
2816     // Emitting PacketDissectionChanged directly from a QDialog can cause
2817     // problems on macOS.
2818     wsApp->flushAppSignals();
2819 }
2820
2821 void MainWindow::on_actionAnalyzeCreateAColumn_triggered()
2822 {
2823     gint colnr = 0;
2824
2825     if (capture_file_.capFile() != 0 && capture_file_.capFile()->finfo_selected != 0) {
2826         colnr = column_prefs_add_custom(COL_CUSTOM, capture_file_.capFile()->finfo_selected->hfinfo->name,
2827                     capture_file_.capFile()->finfo_selected->hfinfo->abbrev,0);
2828
2829         packet_list_->columnsChanged();
2830         packet_list_->resizeColumnToContents(colnr);
2831
2832         prefs_main_write();
2833     }
2834 }
2835
2836 void MainWindow::applyConversationFilter()
2837 {
2838     ConversationAction *conv_action = qobject_cast<ConversationAction*>(sender());
2839     if (!conv_action) return;
2840
2841     packet_info *pinfo = capture_file_.packetInfo();
2842     if (!pinfo) return;
2843
2844     QByteArray conv_filter = conv_action->filter();
2845     if (conv_filter.isEmpty()) return;
2846
2847     if (conv_action->isFilterValid(pinfo)) {
2848
2849         df_combo_box_->lineEdit()->setText(conv_filter);
2850         df_combo_box_->applyDisplayFilter();
2851     }
2852 }
2853
2854 void MainWindow::applyExportObject()
2855 {
2856     ExportObjectAction *export_action = qobject_cast<ExportObjectAction*>(sender());
2857     if (!export_action)
2858         return;
2859
2860     ExportObjectDialog* export_dialog = new ExportObjectDialog(*this, capture_file_, export_action->exportObject());
2861
2862     connect(export_dialog->getExportObjectView(), SIGNAL(goToPacket(int)),
2863             packet_list_, SLOT(goToPacket(int)));
2864
2865 }
2866
2867 // XXX We could probably create the analyze and prepare actions
2868 // dynamically using FilterActions and consolidate the methods
2869 // below into one callback.
2870 void MainWindow::on_actionAnalyzeAAFSelected_triggered()
2871 {
2872     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypePlain);
2873 }
2874
2875 void MainWindow::on_actionAnalyzeAAFNotSelected_triggered()
2876 {
2877     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeNot);
2878 }
2879
2880 void MainWindow::on_actionAnalyzeAAFAndSelected_triggered()
2881 {
2882     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeAnd);
2883 }
2884
2885 void MainWindow::on_actionAnalyzeAAFOrSelected_triggered()
2886 {
2887     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeOr);
2888 }
2889
2890 void MainWindow::on_actionAnalyzeAAFAndNotSelected_triggered()
2891 {
2892     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeAndNot);
2893 }
2894
2895 void MainWindow::on_actionAnalyzeAAFOrNotSelected_triggered()
2896 {
2897     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeOrNot);
2898 }
2899
2900 void MainWindow::on_actionAnalyzePAFSelected_triggered()
2901 {
2902     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypePlain);
2903 }
2904
2905 void MainWindow::on_actionAnalyzePAFNotSelected_triggered()
2906 {
2907     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeNot);
2908 }
2909
2910 void MainWindow::on_actionAnalyzePAFAndSelected_triggered()
2911 {
2912     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeAnd);
2913 }
2914
2915 void MainWindow::on_actionAnalyzePAFOrSelected_triggered()
2916 {
2917     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeOr);
2918 }
2919
2920 void MainWindow::on_actionAnalyzePAFAndNotSelected_triggered()
2921 {
2922     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeAndNot);
2923 }
2924
2925 void MainWindow::on_actionAnalyzePAFOrNotSelected_triggered()
2926 {
2927     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeOrNot);
2928 }
2929
2930 void MainWindow::on_actionAnalyzeEnabledProtocols_triggered()
2931 {
2932     EnabledProtocolsDialog enable_proto_dialog(this);
2933     enable_proto_dialog.exec();
2934
2935     // Emitting PacketDissectionChanged directly from a QDialog can cause
2936     // problems on macOS.
2937     wsApp->flushAppSignals();
2938 }
2939
2940 void MainWindow::on_actionAnalyzeDecodeAs_triggered()
2941 {
2942     QAction *da_action = qobject_cast<QAction*>(sender());
2943     bool create_new = false;
2944     if (da_action && da_action->data().toBool() == true) {
2945         create_new = true;
2946     }
2947
2948     DecodeAsDialog da_dialog(this, capture_file_.capFile(), create_new);
2949     da_dialog.exec();
2950
2951     // Emitting PacketDissectionChanged directly from a QDialog can cause
2952     // problems on macOS.
2953     wsApp->flushAppSignals();
2954 }
2955
2956 void MainWindow::on_actionAnalyzeReloadLuaPlugins_triggered()
2957 {
2958     reloadLuaPlugins();
2959 }
2960
2961 void MainWindow::openFollowStreamDialog(follow_type_t type, int stream_num) {
2962     FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type);
2963     connect(fsd, SIGNAL(updateFilter(QString, bool)), this, SLOT(filterPackets(QString, bool)));
2964     connect(fsd, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
2965
2966     fsd->show();
2967     if (stream_num >= 0) {
2968         // If a specific conversation was requested, then ignore any previous
2969         // display filters and display all related packets.
2970         fsd->follow("", true, stream_num);
2971     } else {
2972         fsd->follow(getFilter());
2973     }
2974 }
2975
2976 void MainWindow::on_actionAnalyzeFollowTCPStream_triggered()
2977 {
2978     openFollowStreamDialog(FOLLOW_TCP);
2979 }
2980
2981 void MainWindow::on_actionAnalyzeFollowUDPStream_triggered()
2982 {
2983     openFollowStreamDialog(FOLLOW_UDP);
2984 }
2985
2986 void MainWindow::on_actionAnalyzeFollowSSLStream_triggered()
2987 {
2988     openFollowStreamDialog(FOLLOW_SSL);
2989 }
2990
2991 void MainWindow::on_actionAnalyzeFollowHTTPStream_triggered()
2992 {
2993     openFollowStreamDialog(FOLLOW_HTTP);
2994 }
2995
2996 void MainWindow::openSCTPAllAssocsDialog()
2997 {
2998     SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile());
2999     connect(sctp_dialog, SIGNAL(filterPackets(QString,bool)),
3000             this, SLOT(filterPackets(QString,bool)));
3001     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3002             sctp_dialog, SLOT(setCaptureFile(capture_file*)));
3003     sctp_dialog->fillTable();
3004
3005     if (sctp_dialog->isMinimized() == true)
3006     {
3007         sctp_dialog->showNormal();
3008     }
3009     else
3010     {
3011         sctp_dialog->show();
3012     }
3013
3014     sctp_dialog->raise();
3015     sctp_dialog->activateWindow();
3016 }
3017
3018 void MainWindow::on_actionSCTPShowAllAssociations_triggered()
3019 {
3020     openSCTPAllAssocsDialog();
3021 }
3022
3023 void MainWindow::on_actionSCTPAnalyseThisAssociation_triggered()
3024 {
3025     SCTPAssocAnalyseDialog *sctp_analyse = new SCTPAssocAnalyseDialog(this, NULL, capture_file_.capFile());
3026     connect(sctp_analyse, SIGNAL(filterPackets(QString,bool)),
3027             this, SLOT(filterPackets(QString,bool)));
3028
3029     if (sctp_analyse->isMinimized() == true)
3030     {
3031         sctp_analyse->showNormal();
3032     }
3033     else
3034     {
3035         sctp_analyse->show();
3036     }
3037
3038     sctp_analyse->raise();
3039     sctp_analyse->activateWindow();
3040 }
3041
3042 void MainWindow::on_actionSCTPFilterThisAssociation_triggered()
3043 {
3044     sctp_assoc_info_t* assoc = SCTPAssocAnalyseDialog::findAssocForPacket(capture_file_.capFile());
3045     if (assoc) {
3046         QString newFilter = QString("sctp.assoc_index==%1").arg(assoc->assoc_id);
3047         assoc = NULL;
3048         emit filterPackets(newFilter, false);
3049     }
3050 }
3051
3052 // -z wlan,stat
3053 void MainWindow::statCommandWlanStatistics(const char *arg, void *)
3054 {
3055     WlanStatisticsDialog *wlan_stats_dlg = new WlanStatisticsDialog(*this, capture_file_, arg);
3056     connect(wlan_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3057             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3058     wlan_stats_dlg->show();
3059 }
3060
3061 void MainWindow::on_actionWirelessWlanStatistics_triggered()
3062 {
3063     statCommandWlanStatistics(NULL, NULL);
3064 }
3065
3066 // -z expert
3067 void MainWindow::statCommandExpertInfo(const char *, void *)
3068 {
3069     ExpertInfoDialog *expert_dialog = new ExpertInfoDialog(*this, capture_file_);
3070     const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
3071
3072     expert_dialog->setDisplayFilter(df_edit->text());
3073
3074     connect(expert_dialog->getExpertInfoView(), SIGNAL(goToPacket(int, int)),
3075             packet_list_, SLOT(goToPacket(int, int)));
3076     connect(expert_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3077             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3078
3079     expert_dialog->show();
3080 }
3081
3082 void MainWindow::on_actionAnalyzeExpertInfo_triggered()
3083 {
3084     statCommandExpertInfo(NULL, NULL);
3085 }
3086
3087
3088 // Next / previous / first / last slots in packet_list
3089
3090 // Statistics Menu
3091
3092 void MainWindow::on_actionStatisticsFlowGraph_triggered()
3093 {
3094     SequenceDialog *sequence_dialog = new SequenceDialog(*this, capture_file_);
3095     sequence_dialog->show();
3096 }
3097
3098 void MainWindow::openTcpStreamDialog(int graph_type)
3099 {
3100     TCPStreamDialog *stream_dialog = new TCPStreamDialog(this, capture_file_.capFile(), (tcp_graph_type)graph_type);
3101     connect(stream_dialog, SIGNAL(goToPacket(int)),
3102             packet_list_, SLOT(goToPacket(int)));
3103     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3104             stream_dialog, SLOT(setCaptureFile(capture_file*)));
3105     if (stream_dialog->result() == QDialog::Accepted) {
3106         stream_dialog->show();
3107     }
3108 }
3109
3110 void MainWindow::on_actionStatisticsTcpStreamStevens_triggered()
3111 {
3112     openTcpStreamDialog(GRAPH_TSEQ_STEVENS);
3113 }
3114
3115 void MainWindow::on_actionStatisticsTcpStreamTcptrace_triggered()
3116 {
3117     openTcpStreamDialog(GRAPH_TSEQ_TCPTRACE);
3118 }
3119
3120 void MainWindow::on_actionStatisticsTcpStreamThroughput_triggered()
3121 {
3122     openTcpStreamDialog(GRAPH_THROUGHPUT);
3123 }
3124
3125 void MainWindow::on_actionStatisticsTcpStreamRoundTripTime_triggered()
3126 {
3127     openTcpStreamDialog(GRAPH_RTT);
3128 }
3129
3130 void MainWindow::on_actionStatisticsTcpStreamWindowScaling_triggered()
3131 {
3132     openTcpStreamDialog(GRAPH_WSCALE);
3133 }
3134
3135 // -z mcast,stat
3136 void MainWindow::statCommandMulticastStatistics(const char *arg, void *)
3137 {
3138     MulticastStatisticsDialog *mcast_stats_dlg = new MulticastStatisticsDialog(*this, capture_file_, arg);
3139     connect(mcast_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3140             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3141     mcast_stats_dlg->show();
3142 }
3143
3144 void MainWindow::on_actionStatisticsUdpMulticastStreams_triggered()
3145 {
3146     statCommandMulticastStatistics(NULL, NULL);
3147 }
3148
3149 void MainWindow::openStatisticsTreeDialog(const gchar *abbr)
3150 {
3151     StatsTreeDialog *st_dialog = new StatsTreeDialog(*this, capture_file_, abbr);
3152 //    connect(st_dialog, SIGNAL(goToPacket(int)),
3153 //            packet_list_, SLOT(goToPacket(int)));
3154     st_dialog->show();
3155 }
3156
3157 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered()
3158 {
3159     openStatisticsTreeDialog("lbmr_topic_ads_topic");
3160 }
3161
3162 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Source_triggered()
3163 {
3164     openStatisticsTreeDialog("lbmr_topic_ads_source");
3165 }
3166
3167 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered()
3168 {
3169     openStatisticsTreeDialog("lbmr_topic_ads_transport");
3170 }
3171
3172 void MainWindow::on_actionStatistics29WestTopics_Queries_by_Topic_triggered()
3173 {
3174     openStatisticsTreeDialog("lbmr_topic_queries_topic");
3175 }
3176
3177 void MainWindow::on_actionStatistics29WestTopics_Queries_by_Receiver_triggered()
3178 {
3179     openStatisticsTreeDialog("lbmr_topic_queries_receiver");
3180 }
3181
3182 void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered()
3183 {
3184     openStatisticsTreeDialog("lbmr_topic_queries_pattern");
3185 }
3186
3187 void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered()
3188 {
3189     openStatisticsTreeDialog("lbmr_topic_queries_pattern_receiver");
3190 }
3191
3192 void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered()
3193 {
3194     openStatisticsTreeDialog("lbmr_queue_ads_queue");
3195 }
3196
3197 void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Source_triggered()
3198 {
3199     openStatisticsTreeDialog("lbmr_queue_ads_source");
3200 }
3201
3202 void MainWindow::on_actionStatistics29WestQueues_Queries_by_Queue_triggered()
3203 {
3204     openStatisticsTreeDialog("lbmr_queue_queries_queue");
3205 }
3206
3207 void MainWindow::on_actionStatistics29WestQueues_Queries_by_Receiver_triggered()
3208 {
3209     openStatisticsTreeDialog("lbmr_queue_queries_receiver");
3210 }
3211
3212 void MainWindow::on_actionStatistics29WestUIM_Streams_triggered()
3213 {
3214     LBMStreamDialog *stream_dialog = new LBMStreamDialog(this, capture_file_.capFile());
3215 //    connect(stream_dialog, SIGNAL(goToPacket(int)),
3216 //            packet_list_, SLOT(goToPacket(int)));
3217     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3218             stream_dialog, SLOT(setCaptureFile(capture_file*)));
3219     stream_dialog->show();
3220 }
3221
3222 void MainWindow::on_actionStatistics29WestLBTRM_triggered()
3223 {
3224     LBMLBTRMTransportDialog * lbtrm_dialog = new LBMLBTRMTransportDialog(this, capture_file_.capFile());
3225     connect(lbtrm_dialog, SIGNAL(goToPacket(int)),
3226             packet_list_, SLOT(goToPacket(int)));
3227     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3228             lbtrm_dialog, SLOT(setCaptureFile(capture_file*)));
3229     lbtrm_dialog->show();
3230 }
3231 void MainWindow::on_actionStatistics29WestLBTRU_triggered()
3232 {
3233     LBMLBTRUTransportDialog * lbtru_dialog = new LBMLBTRUTransportDialog(this, capture_file_.capFile());
3234     connect(lbtru_dialog, SIGNAL(goToPacket(int)),
3235             packet_list_, SLOT(goToPacket(int)));
3236     connect(this, SIGNAL(setCaptureFile(capture_file*)),
3237             lbtru_dialog, SLOT(setCaptureFile(capture_file*)));
3238     lbtru_dialog->show();
3239 }
3240
3241 void MainWindow::on_actionStatisticsANCP_triggered()
3242 {
3243     openStatisticsTreeDialog("ancp");
3244 }
3245
3246 void MainWindow::on_actionStatisticsBACappInstanceId_triggered()
3247 {
3248     openStatisticsTreeDialog("bacapp_instanceid");
3249 }
3250
3251 void MainWindow::on_actionStatisticsBACappIP_triggered()
3252 {
3253     openStatisticsTreeDialog("bacapp_ip");
3254 }
3255
3256 void MainWindow::on_actionStatisticsBACappObjectId_triggered()
3257 {
3258     openStatisticsTreeDialog("bacapp_objectid");
3259 }
3260
3261 void MainWindow::on_actionStatisticsBACappService_triggered()
3262 {
3263     openStatisticsTreeDialog("bacapp_service");
3264 }
3265
3266 void MainWindow::on_actionStatisticsCollectd_triggered()
3267 {
3268     openStatisticsTreeDialog("collectd");
3269 }
3270
3271 // -z conv,...
3272 void MainWindow::statCommandConversations(const char *arg, void *userdata)
3273 {
3274     ConversationDialog *conv_dialog = new ConversationDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg);
3275     connect(conv_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3276             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3277     connect(conv_dialog, SIGNAL(openFollowStreamDialog(follow_type_t,int)),
3278             this, SLOT(openFollowStreamDialog(follow_type_t,int)));
3279     connect(conv_dialog, SIGNAL(openTcpStreamGraph(int)),
3280             this, SLOT(openTcpStreamDialog(int)));
3281     conv_dialog->show();
3282 }
3283
3284 void MainWindow::on_actionStatisticsConversations_triggered()
3285 {
3286     statCommandConversations(NULL, NULL);
3287 }
3288
3289 // -z endpoints,...
3290 void MainWindow::statCommandEndpoints(const char *arg, void *userdata)
3291 {
3292     EndpointDialog *endp_dialog = new EndpointDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg);
3293     connect(endp_dialog, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3294             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3295     connect(endp_dialog, SIGNAL(openFollowStreamDialog(follow_type_t)),
3296             this, SLOT(openFollowStreamDialog(follow_type_t)));
3297     connect(endp_dialog, SIGNAL(openTcpStreamGraph(int)),
3298             this, SLOT(openTcpStreamDialog(int)));
3299     endp_dialog->show();
3300 }
3301
3302 void MainWindow::on_actionStatisticsEndpoints_triggered()
3303 {
3304     statCommandEndpoints(NULL, NULL);
3305 }
3306
3307 void MainWindow::on_actionStatisticsHART_IP_triggered()
3308 {
3309     openStatisticsTreeDialog("hart_ip");
3310 }
3311
3312 void MainWindow::on_actionStatisticsHTTPPacketCounter_triggered()
3313 {
3314     openStatisticsTreeDialog("http");
3315 }
3316
3317 void MainWindow::on_actionStatisticsHTTPRequests_triggered()
3318 {
3319     openStatisticsTreeDialog("http_req");
3320 }
3321
3322 void MainWindow::on_actionStatisticsHTTPLoadDistribution_triggered()
3323 {
3324     openStatisticsTreeDialog("http_srv");
3325 }
3326
3327 void MainWindow::on_actionStatisticsHTTPRequestSequences_triggered()
3328 {
3329     openStatisticsTreeDialog("http_seq");
3330 }
3331
3332 void MainWindow::on_actionStatisticsPacketLengths_triggered()
3333 {
3334     openStatisticsTreeDialog("plen");
3335 }
3336
3337 // -z io,stat
3338 void MainWindow::statCommandIOGraph(const char *, void *)
3339 {
3340     IOGraphDialog *iog_dialog = new IOGraphDialog(*this, capture_file_);
3341     connect(iog_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
3342     connect(this, SIGNAL(reloadFields()), iog_dialog, SLOT(reloadFields()));
3343     iog_dialog->show();
3344 }
3345
3346 void MainWindow::on_actionStatisticsIOGraph_triggered()
3347 {
3348     statCommandIOGraph(NULL, NULL);
3349 }
3350
3351 void MainWindow::on_actionStatisticsSametime_triggered()
3352 {
3353     openStatisticsTreeDialog("sametime");
3354 }
3355
3356 void MainWindow::on_actionStatisticsDNS_triggered()
3357 {
3358     openStatisticsTreeDialog("dns");
3359 }
3360
3361 void MainWindow::actionStatisticsPlugin_triggered()
3362 {
3363     QAction* action = qobject_cast<QAction*>(sender());
3364     if(action) {
3365         openStatisticsTreeDialog(action->data().toString().toUtf8());
3366     }
3367 }
3368
3369 void MainWindow::on_actionStatisticsHTTP2_triggered()
3370 {
3371     openStatisticsTreeDialog("http2");
3372
3373 }
3374
3375 // Telephony Menu
3376
3377 void MainWindow::openVoipCallsDialog(bool all_flows)
3378 {
3379     VoipCallsDialog *voip_calls_dialog = new VoipCallsDialog(*this, capture_file_, all_flows);
3380     connect(voip_calls_dialog, SIGNAL(goToPacket(int)),
3381             packet_list_, SLOT(goToPacket(int)));
3382     connect(voip_calls_dialog, SIGNAL(updateFilter(QString, bool)),
3383             this, SLOT(filterPackets(QString, bool)));
3384     voip_calls_dialog->show();
3385 }
3386
3387 void MainWindow::on_actionTelephonyVoipCalls_triggered()
3388 {
3389     openVoipCallsDialog();
3390 }
3391
3392 void MainWindow::on_actionTelephonyGsmMapSummary_triggered()
3393 {
3394     GsmMapSummaryDialog *gms_dialog = new GsmMapSummaryDialog(*this, capture_file_);
3395     gms_dialog->show();
3396 }
3397
3398 void MainWindow::on_actionTelephonyIax2StreamAnalysis_triggered()
3399 {
3400     Iax2AnalysisDialog *iax2_analysis_dialog = new  Iax2AnalysisDialog(*this, capture_file_);
3401     connect(iax2_analysis_dialog, SIGNAL(goToPacket(int)),
3402             packet_list_, SLOT(goToPacket(int)));
3403     iax2_analysis_dialog->show();
3404 }
3405
3406 void MainWindow::on_actionTelephonyISUPMessages_triggered()
3407 {
3408     openStatisticsTreeDialog("isup_msg");
3409 }
3410
3411 // -z mac-lte,stat
3412 void MainWindow::statCommandLteMacStatistics(const char *arg, void *)
3413 {
3414     LteMacStatisticsDialog *lte_mac_stats_dlg = new LteMacStatisticsDialog(*this, capture_file_, arg);
3415     connect(lte_mac_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3416             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3417     lte_mac_stats_dlg->show();
3418 }
3419
3420 void MainWindow::on_actionTelephonyLteMacStatistics_triggered()
3421 {
3422     statCommandLteMacStatistics(NULL, NULL);
3423 }
3424
3425 void MainWindow::statCommandLteRlcStatistics(const char *arg, void *)
3426 {
3427     LteRlcStatisticsDialog *lte_rlc_stats_dlg = new LteRlcStatisticsDialog(*this, capture_file_, arg);
3428     connect(lte_rlc_stats_dlg, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3429             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3430     // N.B. It is necessary for the RLC Statistics window to launch the RLC graph in this way, to ensure
3431     // that the goToPacket() signal/slot connection gets set up...
3432     connect(lte_rlc_stats_dlg, SIGNAL(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8)),
3433             this, SLOT(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8)));
3434
3435     lte_rlc_stats_dlg->show();
3436 }
3437
3438 void MainWindow::on_actionTelephonyLteRlcStatistics_triggered()
3439 {
3440     statCommandLteRlcStatistics(NULL, NULL);
3441 }
3442
3443 void MainWindow::launchRLCGraph(bool channelKnown,
3444                                 guint16 ueid, guint8 rlcMode,
3445                                 guint16 channelType, guint16 channelId, guint8 direction)
3446 {
3447     LteRlcGraphDialog *lrg_dialog = new LteRlcGraphDialog(*this, capture_file_, channelKnown);
3448     connect(lrg_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
3449     // This is a bit messy, but wanted to hide these parameters from users of
3450     // on_actionTelephonyLteRlcGraph_triggered().
3451     if (channelKnown) {
3452         lrg_dialog->setChannelInfo(ueid, rlcMode, channelType, channelId, direction);
3453     }
3454     lrg_dialog->show();
3455 }
3456
3457 void MainWindow::on_actionTelephonyLteRlcGraph_triggered()
3458 {
3459     // We don't yet know the channel.
3460     launchRLCGraph(false, 0, 0, 0, 0, 0);
3461 }
3462
3463 void MainWindow::on_actionTelephonyMtp3Summary_triggered()
3464 {
3465     Mtp3SummaryDialog *mtp3s_dialog = new Mtp3SummaryDialog(*this, capture_file_);
3466     mtp3s_dialog->show();
3467 }
3468
3469 void MainWindow::on_actionTelephonyOsmuxPacketCounter_triggered()
3470 {
3471     openStatisticsTreeDialog("osmux");
3472 }
3473
3474 void MainWindow::on_actionTelephonyRTPStreams_triggered()
3475 {
3476     RtpStreamDialog *rtp_stream_dialog = new  RtpStreamDialog(*this, capture_file_);
3477     connect(rtp_stream_dialog, SIGNAL(packetsMarked()),
3478             packet_list_, SLOT(redrawVisiblePackets()));
3479     connect(rtp_stream_dialog, SIGNAL(goToPacket(int)),
3480             packet_list_, SLOT(goToPacket(int)));
3481     connect(rtp_stream_dialog, SIGNAL(updateFilter(QString, bool)),
3482             this, SLOT(filterPackets(QString, bool)));
3483     rtp_stream_dialog->show();
3484 }
3485
3486 void MainWindow::on_actionTelephonyRTPStreamAnalysis_triggered()
3487 {
3488     RtpAnalysisDialog *rtp_analysis_dialog = new  RtpAnalysisDialog(*this, capture_file_);
3489     connect(rtp_analysis_dialog, SIGNAL(goToPacket(int)),
3490             packet_list_, SLOT(goToPacket(int)));
3491     rtp_analysis_dialog->show();
3492 }
3493
3494 void MainWindow::on_actionTelephonyRTSPPacketCounter_triggered()
3495 {
3496     openStatisticsTreeDialog("rtsp");
3497 }
3498
3499 void MainWindow::on_actionTelephonySMPPOperations_triggered()
3500 {
3501     openStatisticsTreeDialog("smpp_commands");
3502 }
3503
3504 void MainWindow::on_actionTelephonyUCPMessages_triggered()
3505 {
3506     openStatisticsTreeDialog("ucp_messages");
3507 }
3508
3509 void MainWindow::on_actionTelephonySipFlows_triggered()
3510 {
3511     openVoipCallsDialog(true);
3512 }
3513
3514 // Wireless Menu
3515
3516 void MainWindow::on_actionBluetoothATT_Server_Attributes_triggered()
3517 {
3518     BluetoothAttServerAttributesDialog *bluetooth_att_sever_attributes_dialog = new BluetoothAttServerAttributesDialog(*this, capture_file_);
3519     connect(bluetooth_att_sever_attributes_dialog, SIGNAL(goToPacket(int)),
3520             packet_list_, SLOT(goToPacket(int)));
3521     connect(bluetooth_att_sever_attributes_dialog, SIGNAL(updateFilter(QString, bool)),
3522             this, SLOT(filterPackets(QString, bool)));
3523     bluetooth_att_sever_attributes_dialog->show();
3524 }
3525
3526 void MainWindow::on_actionBluetoothDevices_triggered()
3527 {
3528     BluetoothDevicesDialog *bluetooth_devices_dialog = new BluetoothDevicesDialog(*this, capture_file_, packet_list_);
3529     connect(bluetooth_devices_dialog, SIGNAL(goToPacket(int)),
3530             packet_list_, SLOT(goToPacket(int)));
3531     connect(bluetooth_devices_dialog, SIGNAL(updateFilter(QString, bool)),
3532             this, SLOT(filterPackets(QString, bool)));
3533     bluetooth_devices_dialog->show();
3534 }
3535
3536 void MainWindow::on_actionBluetoothHCI_Summary_triggered()
3537 {
3538     BluetoothHciSummaryDialog *bluetooth_hci_summary_dialog = new BluetoothHciSummaryDialog(*this, capture_file_);
3539     connect(bluetooth_hci_summary_dialog, SIGNAL(goToPacket(int)),
3540             packet_list_, SLOT(goToPacket(int)));
3541     connect(bluetooth_hci_summary_dialog, SIGNAL(updateFilter(QString, bool)),
3542             this, SLOT(filterPackets(QString, bool)));
3543     bluetooth_hci_summary_dialog->show();
3544 }
3545
3546 // Tools Menu
3547
3548 void MainWindow::on_actionToolsFirewallAclRules_triggered()
3549 {
3550     FirewallRulesDialog *firewall_rules_dialog = new FirewallRulesDialog(*this, capture_file_);
3551     firewall_rules_dialog->show();
3552 }
3553
3554
3555 // Help Menu
3556 void MainWindow::on_actionHelpContents_triggered() {
3557
3558     wsApp->helpTopicAction(HELP_CONTENT);
3559 }
3560
3561 void MainWindow::on_actionHelpMPWireshark_triggered() {
3562
3563     wsApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK);
3564 }
3565
3566 void MainWindow::on_actionHelpMPWireshark_Filter_triggered() {
3567     wsApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK_FILTER);
3568 }
3569
3570 void MainWindow::on_actionHelpMPCapinfos_triggered() {
3571     wsApp->helpTopicAction(LOCALPAGE_MAN_CAPINFOS);
3572 }
3573
3574 void MainWindow::on_actionHelpMPDumpcap_triggered() {
3575     wsApp->helpTopicAction(LOCALPAGE_MAN_DUMPCAP);
3576 }
3577
3578 void MainWindow::on_actionHelpMPEditcap_triggered() {
3579     wsApp->helpTopicAction(LOCALPAGE_MAN_EDITCAP);
3580 }
3581
3582 void MainWindow::on_actionHelpMPMergecap_triggered() {
3583     wsApp->helpTopicAction(LOCALPAGE_MAN_MERGECAP);
3584 }
3585
3586 void MainWindow::on_actionHelpMPRawShark_triggered() {
3587     wsApp->helpTopicAction(LOCALPAGE_MAN_RAWSHARK);
3588 }
3589
3590 void MainWindow::on_actionHelpMPReordercap_triggered() {
3591     wsApp->helpTopicAction(LOCALPAGE_MAN_REORDERCAP);
3592 }
3593
3594  void MainWindow::on_actionHelpMPText2cap_triggered() {
3595     wsApp->helpTopicAction(LOCALPAGE_MAN_TEXT2PCAP);
3596 }
3597
3598 void MainWindow::on_actionHelpMPTShark_triggered() {
3599     wsApp->helpTopicAction(LOCALPAGE_MAN_TSHARK);
3600 }
3601
3602 void MainWindow::on_actionHelpWebsite_triggered() {
3603
3604     wsApp->helpTopicAction(ONLINEPAGE_HOME);
3605 }
3606
3607 void MainWindow::on_actionHelpFAQ_triggered() {
3608
3609     wsApp->helpTopicAction(ONLINEPAGE_FAQ);
3610 }
3611
3612 void MainWindow::on_actionHelpAsk_triggered() {
3613
3614     wsApp->helpTopicAction(ONLINEPAGE_ASK);
3615 }
3616
3617 void MainWindow::on_actionHelpDownloads_triggered() {
3618
3619     wsApp->helpTopicAction(ONLINEPAGE_DOWNLOAD);
3620 }
3621
3622 void MainWindow::on_actionHelpWiki_triggered() {
3623
3624     wsApp->helpTopicAction(ONLINEPAGE_WIKI);
3625 }
3626
3627 void MainWindow::on_actionHelpSampleCaptures_triggered() {
3628
3629     wsApp->helpTopicAction(ONLINEPAGE_SAMPLE_FILES);
3630 }
3631
3632 #ifdef HAVE_SOFTWARE_UPDATE
3633 void MainWindow::checkForUpdates()
3634 {
3635     software_update_check();
3636 }
3637 #endif
3638
3639 void MainWindow::on_actionHelpAbout_triggered()
3640 {
3641     AboutDialog *about_dialog = new AboutDialog(this);
3642
3643     if (about_dialog->isMinimized() == true)
3644     {
3645         about_dialog->showNormal();
3646     }
3647     else
3648     {
3649         about_dialog->show();
3650     }
3651
3652     about_dialog->raise();
3653     about_dialog->activateWindow();
3654 }
3655
3656 void MainWindow::on_actionGoGoToPacket_triggered() {
3657     if (packet_list_->packetListModel()->rowCount() < 1) {
3658         return;
3659     }
3660     previous_focus_ = wsApp->focusWidget();
3661     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
3662
3663     showAccordionFrame(main_ui_->goToFrame, true);
3664     if (main_ui_->goToFrame->isVisible()) {
3665         main_ui_->goToLineEdit->clear();
3666         main_ui_->goToLineEdit->setFocus();
3667     }
3668 }
3669
3670 void MainWindow::on_actionGoGoToLinkedPacket_triggered()
3671 {
3672     QAction *gta = qobject_cast<QAction*>(sender());
3673     if (!gta) return;
3674
3675     bool ok = false;
3676     int packet_num = gta->data().toInt(&ok);
3677     if (!ok) return;
3678
3679     packet_list_->goToPacket(packet_num);
3680 }
3681
3682 // gtk/main_menubar.c:goto_conversation_frame
3683 void MainWindow::goToConversationFrame(bool go_next) {
3684     gchar     *filter       = NULL;
3685     dfilter_t *dfcode       = NULL;
3686     gboolean   found_packet = FALSE;
3687     packet_info *pi = &(capture_file_.capFile()->edt->pi);
3688
3689     /* Try to build a conversation
3690      * filter in the order TCP, UDP, IP, Ethernet and apply the
3691      * coloring */
3692     filter = conversation_filter_from_packet(pi);
3693     if (filter == NULL) {
3694         main_ui_->statusBar->pushTemporaryStatus(tr("Unable to build conversation filter."));
3695         g_free(filter);
3696         return;
3697     }
3698
3699     if (!dfilter_compile(filter, &dfcode, NULL)) {
3700         /* The attempt failed; report an error. */
3701         main_ui_->statusBar->pushTemporaryStatus(tr("Error compiling filter for this conversation."));
3702         g_free(filter);
3703         return;
3704     }
3705
3706     found_packet = cf_find_packet_dfilter(capture_file_.capFile(), dfcode, go_next ? SD_FORWARD : SD_BACKWARD);
3707
3708     if (!found_packet) {
3709         /* We didn't find a packet */
3710         main_ui_->statusBar->pushTemporaryStatus(tr("No previous/next packet in conversation."));
3711     }
3712
3713     dfilter_free(dfcode);
3714     g_free(filter);
3715 }
3716
3717 void MainWindow::on_actionGoNextConversationPacket_triggered()
3718 {
3719     goToConversationFrame(true);
3720 }
3721
3722 void MainWindow::on_actionGoPreviousConversationPacket_triggered()
3723 {
3724     goToConversationFrame(false);
3725 }
3726
3727 void MainWindow::on_actionGoAutoScroll_toggled(bool checked)
3728 {
3729     packet_list_->setVerticalAutoScroll(checked);
3730 }
3731
3732 void MainWindow::resetPreviousFocus() {
3733     previous_focus_ = NULL;
3734 }
3735
3736 void MainWindow::on_goToCancel_clicked()
3737 {
3738     main_ui_->goToFrame->animatedHide();
3739     if (previous_focus_) {
3740         disconnect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
3741         previous_focus_->setFocus();
3742         resetPreviousFocus();
3743     }
3744 }
3745
3746 void MainWindow::on_goToGo_clicked()
3747 {
3748     gotoFrame(main_ui_->goToLineEdit->text().toInt());
3749
3750     on_goToCancel_clicked();
3751 }
3752
3753 void MainWindow::on_goToLineEdit_returnPressed()
3754 {
3755     on_goToGo_clicked();
3756 }
3757
3758 void MainWindow::on_actionCaptureStart_triggered()
3759 {
3760 //#ifdef HAVE_AIRPCAP
3761 //  airpcap_if_active = airpcap_if_selected;
3762 //  if (airpcap_if_active)
3763 //    airpcap_set_toolbar_start_capture(airpcap_if_active);
3764 //#endif
3765
3766 //  if (cap_open_w) {
3767 //    /*
3768 //     * There's an options dialog; get the values from it and close it.
3769 //     */
3770 //    gboolean success;
3771
3772 //    /* Determine if "capture start" while building of the "capture options" window */
3773 //    /*  is in progress. If so, ignore the "capture start.                          */
3774 //    /* XXX: Would it be better/cleaner for the "capture options" window code to    */
3775 //    /*      disable the capture start button temporarily ?                         */
3776 //    if (cap_open_complete == FALSE) {
3777 //      return;  /* Building options window: ignore "capture start" */
3778 //    }
3779 //    success = capture_dlg_prep(cap_open_w);
3780 //    window_destroy(GTK_WIDGET(cap_open_w));
3781 //    if (!success)
3782 //      return;   /* error in options dialog */
3783 //  }
3784
3785 #ifdef HAVE_LIBPCAP
3786     if (global_capture_opts.num_selected == 0) {
3787         QString err_msg = tr("No Interface Selected");
3788         main_ui_->statusBar->pushTemporaryStatus(err_msg);
3789         main_ui_->actionCaptureStart->setChecked(false);
3790         return;
3791     }
3792
3793     /* XXX - will closing this remove a temporary file? */
3794     QString before_what(tr(" before starting a new capture"));
3795     if (testCaptureFileClose(before_what)) {
3796         startCapture();
3797     } else {
3798         // simply clicking the button sets it to 'checked' even though we've
3799         // decided to do nothing, so undo that
3800         main_ui_->actionCaptureStart->setChecked(false);
3801     }
3802 #endif // HAVE_LIBPCAP
3803 }
3804
3805 void MainWindow::on_actionCaptureStop_triggered()
3806 {
3807     stopCapture();
3808 }
3809
3810 void MainWindow::on_actionCaptureRestart_triggered()
3811 {
3812     QString before_what(tr(" before restarting the capture"));
3813     if (!testCaptureFileClose(before_what, Restart))
3814         return;
3815
3816 /* TODO: GTK use only this: capture_restart(&cap_session_); */
3817     startCapture();
3818 }
3819
3820 void MainWindow::on_actionCaptureCaptureFilters_triggered()
3821 {
3822     if (!capture_filter_dlg_) {
3823         capture_filter_dlg_ = new FilterDialog(this, FilterDialog::CaptureFilter);
3824     }
3825     capture_filter_dlg_->show();
3826     capture_filter_dlg_->raise();
3827     capture_filter_dlg_->activateWindow();
3828 }
3829
3830 void MainWindow::on_actionStatisticsCaptureFileProperties_triggered()
3831 {
3832     CaptureFilePropertiesDialog *capture_file_properties_dialog = new CaptureFilePropertiesDialog(*this, capture_file_);
3833     connect(capture_file_properties_dialog, SIGNAL(captureCommentChanged()),
3834             this, SLOT(updateForUnsavedChanges()));
3835     capture_file_properties_dialog->show();
3836 }
3837
3838 void MainWindow::on_actionStatisticsResolvedAddresses_triggered()
3839 {
3840     ResolvedAddressesDialog *resolved_addresses_dialog = new ResolvedAddressesDialog(this, &capture_file_);
3841     resolved_addresses_dialog->show();
3842 }
3843
3844 void MainWindow::on_actionStatisticsProtocolHierarchy_triggered()
3845 {
3846     ProtocolHierarchyDialog *phd = new ProtocolHierarchyDialog(*this, capture_file_);
3847     connect(phd, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
3848             this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
3849     phd->show();
3850 }
3851
3852 void MainWindow::on_actionCaptureOptions_triggered()
3853 {
3854 #ifdef HAVE_LIBPCAP
3855     if (!capture_interfaces_dialog_) {
3856         capture_interfaces_dialog_ = new CaptureInterfacesDialog(this);
3857
3858         connect(capture_interfaces_dialog_, SIGNAL(startCapture()), this, SLOT(startCapture()));
3859         connect(capture_interfaces_dialog_, SIGNAL(stopCapture()), this, SLOT(stopCapture()));
3860
3861         connect(capture_interfaces_dialog_, SIGNAL(getPoints(int,PointList*)),
3862                 this->main_welcome_->getInterfaceFrame(), SLOT(getPoints(int,PointList*)));
3863         connect(capture_interfaces_dialog_, SIGNAL(interfacesChanged()),
3864                 this->main_welcome_, SLOT(interfaceSelected()));
3865         connect(capture_interfaces_dialog_, SIGNAL(interfacesChanged()),
3866                 this->main_welcome_->getInterfaceFrame(), SLOT(updateSelectedInterfaces()));
3867         connect(capture_interfaces_dialog_, SIGNAL(interfaceListChanged()),
3868                 this->main_welcome_->getInterfaceFrame(), SLOT(interfaceListChanged()));
3869         connect(capture_interfaces_dialog_, SIGNAL(captureFilterTextEdited(QString)),
3870                 this->main_welcome_, SLOT(setCaptureFilterText(QString)));
3871         // Propagate selection changes from main UI to dialog.
3872         connect(this->main_welcome_, SIGNAL(interfacesChanged()),
3873                 capture_interfaces_dialog_, SLOT(interfaceSelected()));
3874
3875         connect(capture_interfaces_dialog_, SIGNAL(setFilterValid(bool, const QString)),
3876                 this, SLOT(startInterfaceCapture(bool, const QString)));
3877     }
3878     capture_interfaces_dialog_->setTab(0);
3879     capture_interfaces_dialog_->updateInterfaces();
3880
3881     if (capture_interfaces_dialog_->isMinimized()) {
3882         capture_interfaces_dialog_->showNormal();
3883     } else {
3884         capture_interfaces_dialog_->show();
3885     }
3886
3887     capture_interfaces_dialog_->raise();
3888     capture_interfaces_dialog_->activateWindow();
3889 #endif
3890 }
3891
3892 #ifdef HAVE_LIBPCAP
3893 void MainWindow::on_actionCaptureRefreshInterfaces_triggered()
3894 {
3895     main_ui_->actionCaptureRefreshInterfaces->setEnabled(false);
3896     wsApp->refreshLocalInterfaces();
3897     main_ui_->actionCaptureRefreshInterfaces->setEnabled(true);
3898 }
3899 #endif
3900
3901 void MainWindow::externalMenuItem_triggered()
3902 {
3903     QAction * triggerAction = NULL;
3904     QVariant v;
3905     ext_menubar_t * entry = NULL;
3906
3907     if (QObject::sender()) {
3908         triggerAction = (QAction *)QObject::sender();
3909         v = triggerAction->data();
3910
3911         if (v.canConvert<void *>()) {
3912             entry = (ext_menubar_t *)v.value<void *>();
3913
3914             if (entry->type == EXT_MENUBAR_ITEM) {
3915                 entry->callback(EXT_MENUBAR_QT_GUI, (gpointer) ((void *)main_ui_), entry->user_data);
3916             } else {
3917                 QDesktopServices::openUrl(QUrl(QString((gchar *)entry->user_data)));
3918             }
3919         }
3920     }
3921 }
3922
3923 void MainWindow::gotoFrame(int packet_num)
3924 {
3925     if (packet_num > 0) {
3926         packet_list_->goToPacket(packet_num);
3927     }
3928 }
3929
3930 void MainWindow::extcap_options_finished(int result)
3931 {
3932     if (result == QDialog::Accepted) {
3933         startCapture();
3934     }
3935     this->main_welcome_->getInterfaceFrame()->interfaceListChanged();
3936 }
3937
3938 void MainWindow::showExtcapOptionsDialog(QString &device_name)
3939 {
3940     ExtcapOptionsDialog * extcap_options_dialog = ExtcapOptionsDialog::createForDevice(device_name, this);
3941     extcap_options_dialog->setModal(true);
3942     /* The dialog returns null, if the given device name is not a valid extcap device */
3943     if (extcap_options_dialog) {
3944         connect(extcap_options_dialog, SIGNAL(finished(int)),
3945                 this, SLOT(extcap_options_finished(int)));
3946         extcap_options_dialog->show();
3947     }
3948 }
3949
3950 void MainWindow::on_actionContextWikiProtocolPage_triggered()
3951 {
3952     QAction *wa = qobject_cast<QAction*>(sender());
3953     if (!wa) return;
3954
3955     bool ok = false;
3956     int field_id = wa->data().toInt(&ok);
3957     if (!ok) return;
3958
3959     const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3960
3961     int ret = QMessageBox::question(this, wsApp->windowTitleString(tr("Wiki Page for %1").arg(proto_abbrev)),
3962                                    tr("<p>The Wireshark Wiki is maintained by the community.</p>"
3963                                       "<p>The page you are about to load might be wonderful, "
3964                                       "incomplete, wrong, or nonexistent.</p>"
3965                                       "<p>Proceed to the wiki?</p>"),
3966                                    QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
3967
3968     if (ret != QMessageBox::Yes) return;
3969
3970     QUrl wiki_url = QString("https://wiki.wireshark.org/Protocols/%1").arg(proto_abbrev);
3971     QDesktopServices::openUrl(wiki_url);
3972 }
3973
3974 void MainWindow::on_actionContextFilterFieldReference_triggered()
3975 {
3976     QAction *wa = qobject_cast<QAction*>(sender());
3977     if (!wa) return;
3978
3979     bool ok = false;
3980     int field_id = wa->data().toInt(&ok);
3981     if (!ok) return;
3982
3983     const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3984
3985     QUrl dfref_url = QString("https://www.wireshark.org/docs/dfref/%1/%2")
3986             .arg(proto_abbrev[0])
3987             .arg(proto_abbrev);
3988     QDesktopServices::openUrl(dfref_url);
3989 }
3990
3991 void MainWindow::on_actionViewFullScreen_triggered(bool checked)
3992 {
3993     if (checked) {
3994         // Save the state for future restore
3995         was_maximized_ = this->isMaximized();
3996         this->showFullScreen();
3997     } else {
3998         // Restore the previous state
3999         if (was_maximized_)
4000             this->showMaximized();
4001         else
4002             this->showNormal();
4003     }
4004 }
4005
4006 void MainWindow::activatePluginIFToolbar(bool)
4007 {
4008     QAction *sendingAction = dynamic_cast<QAction *>(sender());
4009     if (!sendingAction || !sendingAction->data().isValid())
4010         return;
4011
4012     ext_toolbar_t *toolbar = VariantPointer<ext_toolbar_t>::asPtr(sendingAction->data());
4013
4014     QList<QToolBar *> toolbars = findChildren<QToolBar *>();
4015     foreach (QToolBar *bar, toolbars) {
4016         AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
4017         if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) {
4018             if (iftoolbar->isVisible()) {
4019                 iftoolbar->setVisible(false);
4020                 sendingAction->setChecked(true);
4021             } else {
4022                 iftoolbar->setVisible(true);
4023                 sendingAction->setChecked(true);
4024             }
4025         }
4026     }
4027 }
4028
4029 void MainWindow::filterToolbarCustomMenuHandler(const QPoint& pos)
4030 {
4031     QAction * filterAction = filter_expression_toolbar_->actionAt(pos);
4032     if ( ! filterAction )
4033         return;
4034
4035     QMenu * filterMenu = new QMenu(this);
4036
4037     QAction *actFilter = filterMenu->addAction(tr("Filter Button Preferences..."));
4038     connect(actFilter, SIGNAL(triggered()), this, SLOT(filterToolbarShowPreferences()));
4039     actFilter->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4040     actFilter->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4041     actFilter->setData(filterAction->data());
4042     filterMenu->addSeparator();
4043     QAction * actEdit = filterMenu->addAction(tr("Edit"));
4044     connect(actEdit, SIGNAL(triggered()), this, SLOT(filterToolbarEditFilter()));
4045     actEdit->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4046     actEdit->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4047     actEdit->setData(filterAction->data());
4048     QAction * actDisable = filterMenu->addAction(tr("Disable"));
4049     connect(actDisable, SIGNAL(triggered()), this, SLOT(filterToolbarDisableFilter()));
4050     actDisable->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4051     actDisable->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4052     actDisable->setData(filterAction->data());
4053     QAction * actRemove = filterMenu->addAction(tr("Remove"));
4054     connect(actRemove, SIGNAL(triggered()), this, SLOT(filterToolbarRemoveFilter()));
4055     actRemove->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
4056     actRemove->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
4057     actRemove->setData(filterAction->data());
4058
4059     filterMenu->exec(filter_expression_toolbar_->mapToGlobal(pos));
4060 }
4061
4062 void MainWindow::filterToolbarShowPreferences()
4063 {
4064     emit showPreferencesDialog(PrefsModel::FILTER_BUTTONS_PREFERENCE_TREE_NAME);
4065 }
4066
4067 int MainWindow::uatRowIndexForFilterExpression(QString label, QString expression)
4068 {
4069     int result = -1;
4070
4071     if ( expression.length() == 0 )
4072         return result;
4073
4074     UatModel * uatModel = new UatModel(this, "Display expressions");
4075
4076     QModelIndex rowIndex;
4077
4078     if ( label.length() > 0 )
4079     {
4080         for ( int cnt = 0; cnt < uatModel->rowCount() && ! rowIndex.isValid(); cnt++ )
4081         {
4082             if ( uatModel->data(uatModel->index(cnt, 1), Qt::DisplayRole).toString().compare(label) == 0 &&
4083                     uatModel->data(uatModel->index(cnt, 2), Qt::DisplayRole).toString().compare(expression) == 0 )
4084             {
4085                 rowIndex = uatModel->index(cnt, 2);
4086             }
4087         }
4088     }
4089     else
4090     {
4091         rowIndex = uatModel->findRowForColumnContent(((QAction *)sender())->data(), 2);
4092     }
4093
4094     if ( rowIndex.isValid() )
4095         result = rowIndex.row();
4096
4097     delete uatModel;
4098
4099     return result;
4100 }
4101
4102 void MainWindow::filterToolbarEditFilter()
4103 {
4104     if ( ! sender() )
4105         return;
4106
4107     QString label = ((QAction *)sender())->property(dfe_property_label_).toString();
4108     QString expr = ((QAction *)sender())->property(dfe_property_expression_).toString();
4109
4110     int idx = uatRowIndexForFilterExpression(label, expr);
4111
4112     if ( idx > -1 )
4113         main_ui_->filterExpressionFrame->editExpression(idx);
4114 }
4115
4116 void MainWindow::filterDropped(QString description, QString filter)
4117 {
4118     gchar* err = NULL;
4119     if ( filter.length() == 0 )
4120         return;
4121
4122     filter_expression_new(qUtf8Printable(description),
4123             qUtf8Printable(filter), qUtf8Printable(description), TRUE);
4124
4125     uat_save(uat_get_table_by_name("Display expressions"), &err);
4126     g_free(err);
4127
4128     filterExpressionsChanged();
4129 }
4130
4131 void MainWindow::filterToolbarDisableFilter()
4132 {
4133     gchar* err = NULL;
4134
4135     QString label = ((QAction *)sender())->property(dfe_property_label_).toString();
4136     QString expr = ((QAction *)sender())->property(dfe_property_expression_).toString();
4137
4138     int idx = uatRowIndexForFilterExpression(label, expr);
4139     UatModel * uatModel = new UatModel(this, "Display expressions");
4140
4141     QModelIndex rowIndex = uatModel->index(idx, 0);
4142     if ( rowIndex.isValid() ) {
4143         uatModel->setData(rowIndex, QVariant::fromValue(false));
4144
4145         uat_save(uat_get_table_by_name("Display expressions"), &err);
4146         g_free(err);
4147         filterExpressionsChanged();
4148     }
4149 }
4150
4151 void MainWindow::filterToolbarRemoveFilter()
4152 {
4153     gchar* err = NULL;
4154     UatModel * uatModel = new UatModel(this, "Display expressions");
4155
4156     QString label = ((QAction *)sender())->property(dfe_property_label_).toString();
4157     QString expr = ((QAction *)sender())->property(dfe_property_expression_).toString();
4158
4159     int idx = uatRowIndexForFilterExpression(label, expr);
4160
4161     QModelIndex rowIndex = uatModel->index(idx, 0);
4162     if ( rowIndex.isValid() ) {
4163         uatModel->removeRow(rowIndex.row());
4164
4165         uat_save(uat_get_table_by_name("Display expressions"), &err);
4166         g_free(err);
4167         filterExpressionsChanged();
4168     }
4169 }
4170
4171 void MainWindow::filterToolbarActionMoved(QAction* action, int oldPos, int newPos)
4172 {
4173     gchar* err = NULL;
4174     if ( oldPos == newPos )
4175         return;
4176
4177     QString label = action->property(dfe_property_label_).toString();
4178     QString expr = action->property(dfe_property_expression_).toString();
4179
4180     int idx = uatRowIndexForFilterExpression(label, expr);
4181
4182     if ( idx > -1 && oldPos > -1 && newPos > -1 )
4183     {
4184         uat_t * table = uat_get_table_by_name("Display expressions");
4185         uat_move_index(table, oldPos, newPos);
4186         uat_save(table, &err);
4187
4188         g_free(err);
4189     }
4190 }
4191
4192 #ifdef _MSC_VER
4193 #pragma warning(pop)
4194 #endif
4195
4196 /*
4197  * Editor modelines
4198  *
4199  * Local Variables:
4200  * c-basic-offset: 4
4201  * tab-width: 8
4202  * indent-tabs-mode: nil
4203  * End:
4204  *
4205  * ex: set shiftwidth=4 tabstop=8 expandtab:
4206  * :indentSize=4:tabSize=8:noTabs=true:
4207  */