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