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