Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / ui / qt / capture_options_dialog.cpp
blob55d0da79fbf4103386390d76d2d344c5522b18ec
1 /* capture_options_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include "config.h"
12 #include <wireshark.h>
14 #include "capture_options_dialog.h"
15 #include <ui/qt/widgets/capture_filter_combo.h>
16 #include <ui_capture_options_dialog.h>
17 #include "compiled_filter_output.h"
18 #include "manage_interfaces_dialog.h"
20 #include "main_application.h"
22 #include "extcap.h"
24 #ifdef HAVE_LIBPCAP
26 #include <QAbstractItemModel>
27 #include <QMessageBox>
28 #include <QTimer>
30 #include "ringbuffer.h"
31 #include "ui/capture_opts.h"
32 #include "ui/capture_ui_utils.h"
33 #include "ui/capture_globals.h"
35 #include "ui/ws_ui_util.h"
36 #include "ui/util.h"
37 #include <wsutil/utf8_entities.h>
38 #include "ui/preference_utils.h"
39 #include "ui/recent.h"
41 #include <cstdio>
42 #include <epan/prefs.h>
43 #include <epan/prefs-int.h>
44 #include <epan/addr_resolv.h>
45 #include <wsutil/filesystem.h>
47 #include <wiretap/wtap.h>
49 #include <ui/qt/utils/qt_ui_utils.h>
50 #include <ui/qt/utils/stock_icon.h>
51 #include <ui/qt/models/sparkline_delegate.h>
52 #include "ui/qt/widgets/wireshark_file_dialog.h"
54 // To do:
55 // - Set a size hint for item delegates.
56 // - Make promiscuous and monitor mode checkboxes.
57 // - Fix InterfaceTreeDelegate method names.
58 // - You can edit filters via the main CaptureFilterCombo and via each
59 // individual interface row. We should probably do one or the other.
60 // - There might be a point in having the separate combo boxes in the
61 // individual interface row, if their CaptureFilterCombos actually
62 // called recent_get_cfilter_list with the interface name to get the
63 // separate list of recent capture filters for that interface, but
64 // they don't.
66 const int stat_update_interval_ = 1000; // ms
69 * Symbolic names for column indices.
71 enum
73 col_extcap_ = 0,
74 col_interface_,
75 col_traffic_,
76 col_link_,
77 col_pmode_,
78 col_snaplen_,
79 col_buffer_,
80 col_monitor_,
81 col_filter_,
82 col_num_columns_
85 static interface_t *find_device_by_if_name(const QString &interface_name)
87 interface_t *device;
88 unsigned i;
89 for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
90 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
91 if (!interface_name.compare(device->display_name) && !device->hidden && device->if_info.type != IF_PIPE) {
92 return device;
95 return NULL;
98 class InterfaceTreeWidgetItem : public QTreeWidgetItem
100 public:
101 InterfaceTreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
102 bool operator< (const QTreeWidgetItem &other) const;
103 QVariant data(int column, int role) const;
104 void setData(int column, int role, const QVariant &value);
105 QList<int> points;
107 void updateInterfaceColumns(interface_t *device)
109 if (!device) return;
111 // Prevent infinite recursive signal loop
112 // itemChanged->interfaceItemChanged->updateInterfaceColumns
113 treeWidget()->blockSignals(true);
114 QString default_str = QObject::tr("default");
116 // XXX - this is duplicated in InterfaceTreeModel::data;
117 // it should be done in common code somewhere.
118 QString linkname;
119 if (device->active_dlt == -1)
120 linkname = "Unknown";
121 else {
122 linkname = QObject::tr("DLT %1").arg(device->active_dlt);
123 for (GList *list = device->links; list != NULL; list = gxx_list_next(list)) {
124 link_row *linkr = gxx_list_data(link_row *, list);
125 if (linkr->dlt == device->active_dlt) {
126 linkname = linkr->name;
127 break;
131 setText(col_link_, linkname);
133 if (device->if_info.type == IF_EXTCAP) {
134 /* extcap interfaces does not have this settings */
135 setApplicable(col_pmode_, false);
137 setApplicable(col_snaplen_, false);
138 setApplicable(col_buffer_, false);
139 } else {
140 setApplicable(col_pmode_, true);
141 setCheckState(col_pmode_, device->pmode ? Qt::Checked : Qt::Unchecked);
143 QString snaplen_string = device->has_snaplen ? QString::number(device->snaplen) : default_str;
144 setText(col_snaplen_, snaplen_string);
145 setText(col_buffer_, QString::number(device->buffer));
147 setText(col_filter_, device->cfilter);
149 if (device->monitor_mode_supported) {
150 setApplicable(col_monitor_, true);
151 setCheckState(col_monitor_, device->monitor_mode_enabled ? Qt::Checked : Qt::Unchecked);
152 } else {
153 setApplicable(col_monitor_, false);
155 treeWidget()->blockSignals(false);
158 void setApplicable(int column, bool applicable = false) {
159 QPalette palette = mainApp->palette();
161 if (applicable) {
162 setText(column, QString());
163 } else {
164 setData(column, Qt::CheckStateRole, QVariant());
165 palette.setCurrentColorGroup(QPalette::Disabled);
166 setText(column, UTF8_EM_DASH);
168 setForeground(column, palette.text().color());
173 CaptureOptionsDialog::CaptureOptionsDialog(QWidget *parent) :
174 GeometryStateDialog(parent),
175 ui(new Ui::CaptureOptionsDialog)
177 ui->setupUi(this);
178 loadGeometry();
179 setWindowTitle(mainApp->windowTitleString(tr("Capture Options")));
181 stat_timer_ = NULL;
182 stat_cache_ = NULL;
184 ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Start"));
186 // Start out with the list *not* sorted, so they show up in the order
187 // in which they were provided
188 ui->interfaceTree->sortByColumn(-1, Qt::AscendingOrder);
189 ui->interfaceTree->setItemDelegateForColumn(col_extcap_, &interface_item_delegate_);
190 ui->interfaceTree->setItemDelegateForColumn(col_interface_, &interface_item_delegate_);
191 ui->interfaceTree->setItemDelegateForColumn(col_traffic_, new SparkLineDelegate(this));
192 ui->interfaceTree->setItemDelegateForColumn(col_link_, &interface_item_delegate_);
194 ui->interfaceTree->setItemDelegateForColumn(col_snaplen_, &interface_item_delegate_);
195 ui->interfaceTree->setItemDelegateForColumn(col_buffer_, &interface_item_delegate_);
196 ui->interfaceTree->setItemDelegateForColumn(col_filter_, &interface_item_delegate_);
198 interface_item_delegate_.setTree(ui->interfaceTree);
200 ui->filenameLineEdit->setPlaceholderText(tr("Leave blank to use a temporary file"));
202 ui->rbCompressionNone->setChecked(true);
203 ui->rbTimeNum->setChecked(true);
205 ui->tempDirLineEdit->setPlaceholderText(g_get_tmp_dir());
206 ui->tempDirLineEdit->setText(global_capture_opts.temp_dir);
208 // Changes in interface selections or capture filters should be propagated
209 // to the main welcome screen where they will be applied to the global
210 // capture options.
211 connect(this, &CaptureOptionsDialog::interfacesChanged, ui->captureFilterComboBox, &CaptureFilterCombo::interfacesChanged);
212 connect(ui->captureFilterComboBox, &CaptureFilterCombo::captureFilterSyntaxChanged, this, &CaptureOptionsDialog::updateWidgets);
213 connect(ui->captureFilterComboBox->lineEdit(), &QLineEdit::textEdited, this, &CaptureOptionsDialog::filterEdited);
214 connect(ui->captureFilterComboBox->lineEdit(), &QLineEdit::textEdited, this, &CaptureOptionsDialog::captureFilterTextEdited);
215 connect(&interface_item_delegate_, &InterfaceTreeDelegate::filterChanged, ui->captureFilterComboBox->lineEdit(), &QLineEdit::setText);
216 connect(&interface_item_delegate_, &InterfaceTreeDelegate::filterChanged, this, &CaptureOptionsDialog::captureFilterTextEdited);
217 connect(this, &CaptureOptionsDialog::ifsChanged, this, &CaptureOptionsDialog::refreshInterfaceList);
218 connect(mainApp, &MainApplication::localInterfaceListChanged, this, &CaptureOptionsDialog::updateLocalInterfaces);
219 connect(ui->browseButton, &QPushButton::clicked, this, &CaptureOptionsDialog::browseButtonClicked);
220 connect(ui->interfaceTree, &QTreeWidget::itemClicked, this, &CaptureOptionsDialog::itemClicked);
221 connect(ui->interfaceTree, &QTreeWidget::itemDoubleClicked, this, &CaptureOptionsDialog::itemDoubleClicked);
222 connect(ui->tempDirBrowseButton, &QPushButton::clicked, this, &CaptureOptionsDialog::tempDirBrowseButtonClicked);
224 // Ring buffer minimums (all 1 except # of files)
225 ui->PktSpinBox->setMinimum(1);
226 ui->MBSpinBox->setMinimum(1);
227 ui->SecsSpinBox->setMinimum(1);
228 ui->IntervalSecsSpinBox->setMinimum(1);
229 ui->RbSpinBox->setMinimum(2);
231 // Autostop minimums
232 ui->stopPktSpinBox->setMinimum(1);
233 ui->stopFilesSpinBox->setMinimum(1);
234 ui->stopMBSpinBox->setMinimum(1);
235 ui->stopSecsSpinBox->setMinimum(1);
237 // Capture size maximum depends on units. Initial unit is kB.
238 ui->MBSpinBox->setMaximum(2000000000);
239 ui->stopMBSpinBox->setMaximum(2000000000);
241 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
242 connect(ui->MBComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CaptureOptionsDialog::MBComboBoxIndexChanged);
243 connect(ui->stopMBComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CaptureOptionsDialog::stopMBComboBoxIndexChanged);
244 #else
245 connect(ui->MBComboBox, &QComboBox::currentIndexChanged, this, &CaptureOptionsDialog::MBComboBoxIndexChanged);
246 connect(ui->stopMBComboBox, &QComboBox::currentIndexChanged, this, &CaptureOptionsDialog::stopMBComboBoxIndexChanged);
247 #endif
249 ui->tabWidget->setCurrentIndex(0);
251 updateWidgets();
254 CaptureOptionsDialog::~CaptureOptionsDialog()
256 delete ui;
259 /* Update global device selections based on the TreeWidget selection. */
260 void CaptureOptionsDialog::updateGlobalDeviceSelections()
262 #ifdef HAVE_LIBPCAP
263 QTreeWidgetItemIterator iter(ui->interfaceTree);
265 global_capture_opts.num_selected = 0;
267 while (*iter) {
268 QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value<QString>();
269 for (unsigned i = 0; i < global_capture_opts.all_ifaces->len; i++) {
270 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
271 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
272 if ((*iter)->isSelected()) {
273 device->selected = true;
274 global_capture_opts.num_selected++;
275 } else {
276 device->selected = false;
278 break;
281 ++iter;
283 #endif
286 /* Update TreeWidget selection based on global device selections. */
287 void CaptureOptionsDialog::updateFromGlobalDeviceSelections()
289 #ifdef HAVE_LIBPCAP
290 QTreeWidgetItemIterator iter(ui->interfaceTree);
292 // Prevent recursive interface interfaceSelected signals
293 ui->interfaceTree->blockSignals(true);
295 while (*iter) {
296 QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value<QString>();
297 for (unsigned i = 0; i < global_capture_opts.all_ifaces->len; i++) {
298 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
299 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
300 if ((bool)device->selected != (*iter)->isSelected()) {
301 (*iter)->setSelected(device->selected);
303 break;
306 ++iter;
309 ui->interfaceTree->blockSignals(false);
310 #endif
313 void CaptureOptionsDialog::interfaceSelected()
315 if (sender() == ui->interfaceTree) {
316 // Local changes, propagate our changes
317 updateGlobalDeviceSelections();
318 emit interfacesChanged();
319 } else {
320 // Changes from the welcome screen, adjust to its state.
321 updateFromGlobalDeviceSelections();
324 updateSelectedFilter();
326 updateWidgets();
329 void CaptureOptionsDialog::filterEdited()
331 QList<QTreeWidgetItem*> si = ui->interfaceTree->selectedItems();
333 foreach (QTreeWidgetItem *ti, si) {
334 ti->setText(col_filter_, ui->captureFilterComboBox->lineEdit()->text());
337 if (si.count() > 0) {
338 QModelIndex col_filter_idx = ui->interfaceTree->model()->index(ui->interfaceTree->indexOfTopLevelItem(si[0]), col_filter_);
339 ui->interfaceTree->scrollTo(col_filter_idx);
343 void CaptureOptionsDialog::updateWidgets()
345 SyntaxLineEdit *sle = qobject_cast<SyntaxLineEdit *>(ui->captureFilterComboBox->lineEdit());
346 if (!sle) {
347 return;
350 bool can_capture = false;
352 if (ui->interfaceTree->selectedItems().count() > 0 && sle->syntaxState() != SyntaxLineEdit::Invalid) {
353 can_capture = true;
356 ui->compileBPF->setEnabled(can_capture);
357 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(can_capture);
360 void CaptureOptionsDialog::on_capturePromModeCheckBox_toggled(bool checked)
362 interface_t *device;
363 prefs.capture_prom_mode = checked;
364 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
365 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->topLevelItem(row));
366 if (!ti) continue;
368 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
369 device = getDeviceByName(device_name);
370 if (!device) continue;
371 device->pmode = checked;
372 ti->updateInterfaceColumns(device);
376 void CaptureOptionsDialog::on_captureMonitorModeCheckBox_toggled(bool checked)
378 interface_t *device;
379 prefs.capture_monitor_mode = checked;
380 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
381 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->topLevelItem(row));
382 if (!ti) continue;
384 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
385 device = getDeviceByName(device_name);
386 if (!device) continue;
387 if (device->monitor_mode_supported) {
388 device->monitor_mode_enabled = checked;
389 ti->updateInterfaceColumns(device);
394 void CaptureOptionsDialog::browseButtonClicked()
396 QString file_name = WiresharkFileDialog::getSaveFileName(this, tr("Specify a Capture File"), get_open_dialog_initial_dir());
397 ui->filenameLineEdit->setText(file_name);
400 void CaptureOptionsDialog::tempDirBrowseButtonClicked()
402 QString specified_dir = WiresharkFileDialog::getExistingDirectory(this, tr("Specify temporary directory"));
403 ui->tempDirLineEdit->setText(specified_dir);
406 void CaptureOptionsDialog::interfaceItemChanged(QTreeWidgetItem *item, int column)
408 QWidget* editor = ui->interfaceTree->indexWidget(ui->interfaceTree->currentIndex());
409 if (editor) {
410 ui->interfaceTree->closePersistentEditor(item, ui->interfaceTree->currentColumn());
413 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
414 if (!ti) return;
416 interface_t *device;
417 QString interface_name = ti->text(col_interface_);
418 device = find_device_by_if_name(interface_name);
419 if (!device) return;
421 switch(column) {
423 case col_pmode_:
424 device->pmode = item->checkState(col_pmode_) == Qt::Checked ? true : false;
425 ti->updateInterfaceColumns(device);
426 break;
428 case col_monitor_:
430 bool monitor_mode = false;
431 if (ti->checkState(col_monitor_) == Qt::Checked) monitor_mode = true;
433 if_capabilities_t *caps;
434 char *auth_str = NULL;
435 QString active_dlt_name;
437 set_active_dlt(device, global_capture_opts.default_options.linktype);
439 #ifdef HAVE_PCAP_REMOTE
440 if (device->remote_opts.remote_host_opts.auth_type == CAPTURE_AUTH_PWD) {
441 auth_str = ws_strdup_printf("%s:%s", device->remote_opts.remote_host_opts.auth_username,
442 device->remote_opts.remote_host_opts.auth_password);
444 #endif
445 caps = capture_get_if_capabilities(device->name, monitor_mode, auth_str, NULL, NULL, main_window_update);
446 g_free(auth_str);
448 if (caps != Q_NULLPTR) {
450 #if GLIB_CHECK_VERSION(2, 68, 0)
451 g_list_free_full(g_steal_pointer(&device->links), capture_opts_free_link_row);
452 #else
453 g_list_free_full((GList*)g_steal_pointer(&device->links), capture_opts_free_link_row);
454 #endif
455 device->active_dlt = -1;
456 device->monitor_mode_supported = caps->can_set_rfmon;
457 device->monitor_mode_enabled = monitor_mode && caps->can_set_rfmon;
458 GList *lt_list = device->monitor_mode_enabled ? caps->data_link_types_rfmon : caps->data_link_types;
460 for (GList *lt_entry = lt_list; lt_entry != Q_NULLPTR; lt_entry = gxx_list_next(lt_entry)) {
461 link_row *linkr = g_new(link_row, 1);
462 data_link_info_t *data_link_info = gxx_list_data(data_link_info_t *, lt_entry);
464 * For link-layer types libpcap/Npcap doesn't know
465 * about, the name will be "DLT n", and the description will
466 * be null.
467 * We mark those as unsupported, and don't allow them to be
468 * used - capture filters won't work on them, for example.
470 if (data_link_info->description != Q_NULLPTR) {
471 linkr->dlt = data_link_info->dlt;
472 if (active_dlt_name.isEmpty()) {
473 device->active_dlt = data_link_info->dlt;
474 active_dlt_name = data_link_info->description;
476 linkr->name = g_strdup(data_link_info->description);
477 } else {
478 char *str;
479 /* XXX - should we just omit them? */
480 str = ws_strdup_printf("%s (not supported)", data_link_info->name);
481 linkr->dlt = -1;
482 linkr->name = g_strdup(str);
483 g_free(str);
485 device->links = g_list_append(device->links, linkr);
487 free_if_capabilities(caps);
488 } else {
489 /* We don't know whether this supports monitor mode or not;
490 don't ask for monitor mode. */
491 device->monitor_mode_enabled = false;
492 device->monitor_mode_supported = false;
495 ti->updateInterfaceColumns(device);
497 break;
499 default:
500 break;
504 void CaptureOptionsDialog::itemClicked(QTreeWidgetItem *item, int column)
506 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
507 if (!ti) return;
509 #ifdef HAVE_LIBPCAP
510 interface_t *device;
511 QString interface_name = ti->text(col_interface_);
512 device = find_device_by_if_name(interface_name);
513 if (!device) return;
515 switch(column) {
517 case col_extcap_:
518 if (device->if_info.type == IF_EXTCAP) {
519 /* this checks if configuration is required and not yet provided or saved via prefs */
520 QString device_name = ti->data(col_extcap_, Qt::UserRole).value<QString>();
521 if (extcap_has_configuration((const char *)(device_name.toStdString().c_str())))
523 emit showExtcapOptions(device_name, false);
524 return;
527 break;
529 default:
530 break;
532 #endif /* HAVE_LIBPCAP */
535 void CaptureOptionsDialog::itemDoubleClicked(QTreeWidgetItem *item, int column)
537 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
538 if (!ti) return;
540 switch(column) {
542 // Double click starts capture just on columns which are not editable
543 case col_interface_:
544 case col_traffic_:
546 #ifdef HAVE_LIBPCAP
547 interface_t *device;
548 QString interface_name = ti->text(col_interface_);
549 device = find_device_by_if_name(interface_name);
550 if (!device) return;
552 if (device->if_info.type == IF_EXTCAP) {
553 /* this checks if configuration is required and not yet provided or saved via prefs */
554 QString device_name = ti->data(col_extcap_, Qt::UserRole).value<QString>();
555 if (extcap_requires_configuration((const char *)(device_name.toStdString().c_str())))
557 emit showExtcapOptions(device_name, true);
558 return;
561 #endif /* HAVE_LIBPCAP */
562 emit startCapture();
563 close();
564 break;
567 default:
568 break;
572 void CaptureOptionsDialog::MBComboBoxIndexChanged(int index)
574 switch (index) {
575 case 0: // kilobytes
576 ui->MBSpinBox->setMaximum(2000000000);
577 break;
578 case 1: // megabytes
579 ui->MBSpinBox->setMaximum(2000000);
580 break;
581 case 2: // gigabytes
582 ui->MBSpinBox->setMaximum(2000);
583 break;
587 void CaptureOptionsDialog::stopMBComboBoxIndexChanged(int index)
589 switch (index) {
590 case 0: // kilobytes
591 ui->stopMBSpinBox->setMaximum(2000000000);
592 break;
593 case 1: // megabytes
594 ui->stopMBSpinBox->setMaximum(2000000);
595 break;
596 case 2: // gigabytes
597 ui->stopMBSpinBox->setMaximum(2000);
598 break;
602 void CaptureOptionsDialog::on_gbStopCaptureAuto_toggled(bool checked)
604 global_capture_opts.has_file_interval = checked;
607 void CaptureOptionsDialog::on_gbNewFileAuto_toggled(bool checked)
609 global_capture_opts.multi_files_on = checked;
610 ui->stopMBCheckBox->setEnabled(checked?false:true);
611 ui->stopMBSpinBox->setEnabled(checked?false:true);
612 ui->stopMBComboBox->setEnabled(checked?false:true);
613 ui->gbCompression->setEnabled(checked);
614 ui->rbCompressionNone->setEnabled(checked);
615 #if defined(HAVE_ZLIB) || defined(HAVE_ZLIBNG)
616 ui->rbCompressionGzip->setEnabled(checked);
617 #else
618 ui->rbCompressionGzip->setEnabled(false);
619 #endif
622 void CaptureOptionsDialog::on_cbUpdatePacketsRT_toggled(bool checked)
624 global_capture_opts.real_time_mode = checked;
627 void CaptureOptionsDialog::on_cbAutoScroll_toggled(bool checked)
629 recent.capture_auto_scroll = checked;
632 void CaptureOptionsDialog::on_cbExtraCaptureInfo_toggled(bool checked)
634 global_capture_opts.show_info = checked;
637 void CaptureOptionsDialog::on_cbResolveMacAddresses_toggled(bool checked)
639 gbl_resolv_flags.mac_name = checked;
642 void CaptureOptionsDialog::on_cbResolveNetworkNames_toggled(bool checked)
644 gbl_resolv_flags.network_name = checked;
647 void CaptureOptionsDialog::on_cbResolveTransportNames_toggled(bool checked)
649 gbl_resolv_flags.transport_name = checked;
652 void CaptureOptionsDialog::on_buttonBox_accepted()
654 if (saveOptionsToPreferences()) {
656 #ifdef HAVE_LIBPCAP
657 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->currentItem());
658 if (ti) {
659 interface_t *device;
661 QString interface_name = ti->text(col_interface_);
662 device = find_device_by_if_name(interface_name);
663 if (device && device->if_info.type == IF_EXTCAP) {
664 /* this checks if configuration is required and not yet provided or saved via prefs */
665 QString device_name = ti->data(col_extcap_, Qt::UserRole).value<QString>();
666 if (extcap_requires_configuration((const char *)(device_name.toStdString().c_str())))
668 emit showExtcapOptions(device_name, true);
669 return;
673 #endif /* HAVE_LIBPCAP */
675 emit setFilterValid(true, ui->captureFilterComboBox->lineEdit()->text());
676 accept();
680 // Not sure why we have to do this manually.
681 void CaptureOptionsDialog::on_buttonBox_rejected()
683 if (saveOptionsToPreferences()) {
684 reject();
688 void CaptureOptionsDialog::on_buttonBox_helpRequested()
690 // Probably the wrong URL.
691 mainApp->helpTopicAction(HELP_CAPTURE_OPTIONS_DIALOG);
694 void CaptureOptionsDialog::updateInterfaces()
696 if (prefs.capture_pcap_ng) {
697 ui->rbPcapng->setChecked(true);
698 } else {
699 ui->rbPcap->setChecked(true);
701 ui->capturePromModeCheckBox->setChecked(prefs.capture_prom_mode);
702 ui->captureMonitorModeCheckBox->setChecked(prefs.capture_monitor_mode);
703 ui->captureMonitorModeCheckBox->setEnabled(false);
705 if (global_capture_opts.saving_to_file) {
706 ui->filenameLineEdit->setText(QString(global_capture_opts.orig_save_file));
709 ui->gbNewFileAuto->setChecked(global_capture_opts.multi_files_on);
710 ui->PktCheckBox->setChecked(global_capture_opts.has_file_packets);
711 if (global_capture_opts.has_file_packets) {
712 ui->PktSpinBox->setValue(global_capture_opts.file_packets);
714 ui->MBCheckBox->setChecked(global_capture_opts.has_autostop_filesize);
715 if (global_capture_opts.has_autostop_filesize) {
716 int value = global_capture_opts.autostop_filesize;
717 if (value > 1000000) {
718 if (global_capture_opts.multi_files_on) {
719 ui->MBSpinBox->setValue(value / 1000000);
720 ui->MBComboBox->setCurrentIndex(2);
721 } else {
722 ui->stopMBCheckBox->setChecked(true);
723 ui->stopMBSpinBox->setValue(value / 1000000);
724 ui->stopMBComboBox->setCurrentIndex(2);
726 } else if (value > 1000 && value % 1000 == 0) {
727 if (global_capture_opts.multi_files_on) {
728 ui->MBSpinBox->setValue(value / 1000);
729 ui->MBComboBox->setCurrentIndex(1);
730 } else {
731 ui->stopMBCheckBox->setChecked(true);
732 ui->stopMBSpinBox->setValue(value / 1000);
733 ui->stopMBComboBox->setCurrentIndex(1);
735 } else {
736 if (global_capture_opts.multi_files_on) {
737 ui->MBSpinBox->setValue(value);
738 ui->MBComboBox->setCurrentIndex(0);
739 } else {
740 ui->stopMBCheckBox->setChecked(true);
741 ui->stopMBSpinBox->setValue(value);
742 ui->stopMBComboBox->setCurrentIndex(0);
747 ui->SecsCheckBox->setChecked(global_capture_opts.has_file_duration);
748 if (global_capture_opts.has_file_duration) {
749 int value = global_capture_opts.file_duration;
750 if (value > 3600 && value % 3600 == 0) {
751 ui->SecsSpinBox->setValue(value / 3600);
752 ui->SecsComboBox->setCurrentIndex(2);
753 } else if (value > 60 && value % 60 == 0) {
754 ui->SecsSpinBox->setValue(value / 60);
755 ui->SecsComboBox->setCurrentIndex(1);
756 } else {
757 ui->SecsSpinBox->setValue(value);
758 ui->SecsComboBox->setCurrentIndex(0);
762 ui->IntervalSecsCheckBox->setChecked(global_capture_opts.has_file_interval);
763 if (global_capture_opts.has_file_interval) {
764 int value = global_capture_opts.file_interval;
765 if (value > 3600 && value % 3600 == 0) {
766 ui->IntervalSecsSpinBox->setValue(value / 3600);
767 ui->IntervalSecsComboBox->setCurrentIndex(2);
768 } else if (value > 60 && value % 60 == 0) {
769 ui->IntervalSecsSpinBox->setValue(value / 60);
770 ui->IntervalSecsComboBox->setCurrentIndex(1);
771 } else {
772 ui->IntervalSecsSpinBox->setValue(value);
773 ui->IntervalSecsComboBox->setCurrentIndex(0);
777 if (global_capture_opts.has_ring_num_files) {
778 ui->RbSpinBox->setValue(global_capture_opts.ring_num_files);
779 ui->RbCheckBox->setCheckState(Qt::Checked);
782 if (global_capture_opts.has_autostop_duration) {
783 ui->stopSecsCheckBox->setChecked(true);
784 int value = global_capture_opts.autostop_duration;
785 if (value > 3600 && value % 3600 == 0) {
786 ui->stopSecsSpinBox->setValue(value / 3600);
787 ui->stopSecsComboBox->setCurrentIndex(2);
788 } else if (value > 60 && value % 60 == 0) {
789 ui->stopSecsSpinBox->setValue(value / 60);
790 ui->stopSecsComboBox->setCurrentIndex(1);
791 } else {
792 ui->stopSecsSpinBox->setValue(value);
793 ui->stopSecsComboBox->setCurrentIndex(0);
797 if (global_capture_opts.has_autostop_packets) {
798 ui->stopPktCheckBox->setChecked(true);
799 ui->stopPktSpinBox->setValue(global_capture_opts.autostop_packets);
802 if (global_capture_opts.has_autostop_files) {
803 ui->stopFilesCheckBox->setChecked(true);
804 ui->stopFilesSpinBox->setValue(global_capture_opts.autostop_files);
807 ui->cbUpdatePacketsRT->setChecked(global_capture_opts.real_time_mode);
808 ui->cbAutoScroll->setChecked(recent.capture_auto_scroll);
809 ui->cbExtraCaptureInfo->setChecked(global_capture_opts.show_info);
811 ui->cbResolveMacAddresses->setChecked(gbl_resolv_flags.mac_name);
812 ui->cbResolveNetworkNames->setChecked(gbl_resolv_flags.network_name);
813 ui->cbResolveTransportNames->setChecked(gbl_resolv_flags.transport_name);
815 // Rebuild the interface list without disturbing the main welcome screen.
816 disconnect(ui->interfaceTree, &QTreeWidget::itemSelectionChanged, this, &CaptureOptionsDialog::interfaceSelected);
817 ui->interfaceTree->clear();
819 int buffer;
820 int snaplen;
821 bool hassnap, pmode;
822 QList<QTreeWidgetItem *> selected_interfaces;
824 disconnect(ui->interfaceTree, &QTreeWidget::itemChanged, this, &CaptureOptionsDialog::interfaceItemChanged);
826 if (global_capture_opts.all_ifaces->len > 0) {
827 interface_t *device;
829 for (unsigned device_idx = 0; device_idx < global_capture_opts.all_ifaces->len; device_idx++) {
830 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
832 /* Continue if capture device is hidden */
833 if (device->hidden) {
834 continue;
837 // Traffic sparklines
838 InterfaceTreeWidgetItem *ti = new InterfaceTreeWidgetItem(ui->interfaceTree);
839 ti->setFlags(ti->flags() | Qt::ItemIsEditable);
841 if (device->if_info.type == IF_EXTCAP) {
842 ti->setIcon(col_extcap_, QIcon(StockIcon("x-capture-options")));
843 ti->setData(col_extcap_, Qt::UserRole, QString(device->if_info.name));
844 ti->setToolTip(col_extcap_, QStringLiteral("Extcap interface settings"));
847 ti->setText(col_interface_, device->display_name);
848 ti->setData(col_interface_, Qt::UserRole, QString(device->name));
849 if (device->if_info.type != IF_EXTCAP)
850 ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(ti->points));
852 if (device->no_addresses > 0) {
853 QString addr_str = tr("%1: %2").arg(device->no_addresses > 1 ? tr("Addresses") : tr("Address")).arg(device->addresses);
854 QTreeWidgetItem *addr_ti = new QTreeWidgetItem(ti);
856 addr_str.replace('\n', ", ");
857 addr_ti->setText(0, addr_str);
858 addr_ti->setFlags(addr_ti->flags() ^ Qt::ItemIsSelectable);
859 addr_ti->setFirstColumnSpanned(true);
860 addr_ti->setToolTip(col_interface_, QStringLiteral("<span>%1</span>").arg(addr_str));
861 ti->setToolTip(col_interface_, QStringLiteral("<span>%1</span>").arg(addr_str));
862 } else {
863 ti->setToolTip(col_interface_, tr("no addresses"));
866 if (capture_dev_user_pmode_find(device->name, &pmode)) {
867 device->pmode = pmode;
869 if (capture_dev_user_snaplen_find(device->name, &hassnap, &snaplen)) {
870 /* Default snap length set in preferences */
871 device->snaplen = snaplen;
872 device->has_snaplen = snaplen == WTAP_MAX_PACKET_SIZE_STANDARD ? false : hassnap;
873 } else {
874 /* No preferences set yet, use default values */
875 device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD;
876 device->has_snaplen = false;
879 if (capture_dev_user_buffersize_find(device->name) != -1) {
880 buffer = capture_dev_user_buffersize_find(device->name);
881 device->buffer = buffer;
882 } else {
883 device->buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
885 if (device->monitor_mode_supported) {
886 ui->captureMonitorModeCheckBox->setEnabled(true);
888 ti->updateInterfaceColumns(device);
890 if (device->selected) {
891 selected_interfaces << ti;
896 connect(ui->interfaceTree, &QTreeWidget::itemChanged, this, &CaptureOptionsDialog::interfaceItemChanged);
898 foreach (QTreeWidgetItem *ti, selected_interfaces) {
899 ti->setSelected(true);
901 connect(ui->interfaceTree, &QTreeWidget::itemSelectionChanged, this, &CaptureOptionsDialog::interfaceSelected);
902 updateSelectedFilter();
904 // Manually or automatically size some columns as needed.
905 int one_em = fontMetrics().height();
906 for (int col = 0; col < ui->interfaceTree->topLevelItemCount(); col++) {
907 switch (col) {
908 case col_pmode_:
909 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
910 break;
911 case col_snaplen_:
912 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
913 break;
914 case col_buffer_:
915 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
916 break;
917 case col_monitor_:
918 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
919 break;
920 default:
921 ui->interfaceTree->resizeColumnToContents(col);
926 updateWidgets();
928 if (!stat_timer_) {
929 updateStatistics();
930 stat_timer_ = new QTimer(this);
931 connect(stat_timer_, &QTimer::timeout, this, &CaptureOptionsDialog::updateStatistics);
932 stat_timer_->start(stat_update_interval_);
936 void CaptureOptionsDialog::showEvent(QShowEvent *)
938 updateInterfaces();
941 void CaptureOptionsDialog::refreshInterfaceList()
943 updateInterfaces();
944 emit interfaceListChanged();
947 void CaptureOptionsDialog::updateLocalInterfaces()
949 updateInterfaces();
952 void CaptureOptionsDialog::updateStatistics(void)
954 interface_t *device;
956 disconnect(ui->interfaceTree, &QTreeWidget::itemChanged, this, &CaptureOptionsDialog::interfaceItemChanged);
957 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
959 for (unsigned if_idx = 0; if_idx < global_capture_opts.all_ifaces->len; if_idx++) {
960 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
961 if (!ti) {
962 continue;
964 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, if_idx);
965 QString device_name = ti->text(col_interface_);
966 if (device_name.compare(device->display_name) || device->hidden || device->if_info.type == IF_PIPE) {
967 continue;
969 QList<int> points = ti->data(col_traffic_, Qt::UserRole).value<QList<int> >();
970 points.append(device->packet_diff);
971 ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(points));
974 connect(ui->interfaceTree, &QTreeWidget::itemChanged, this, &CaptureOptionsDialog::interfaceItemChanged);
975 ui->interfaceTree->viewport()->update();
978 void CaptureOptionsDialog::on_compileBPF_clicked()
980 QList<InterfaceFilter> interfaces;
981 foreach (QTreeWidgetItem *ti, ui->interfaceTree->selectedItems()) {
982 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
983 interfaces.emplaceBack(ti->text(col_interface_), ti->text(col_filter_));
984 #else
985 interfaces.append(InterfaceFilter(ti->text(col_interface_), ti->text(col_filter_)));
986 #endif
989 CompiledFilterOutput *cfo = new CompiledFilterOutput(this, interfaces);
991 cfo->show();
994 bool CaptureOptionsDialog::saveOptionsToPreferences()
996 if (ui->rbPcapng->isChecked()) {
997 global_capture_opts.use_pcapng = true;
998 prefs.capture_pcap_ng = true;
999 } else {
1000 global_capture_opts.use_pcapng = false;
1001 prefs.capture_pcap_ng = false;
1004 g_free(global_capture_opts.save_file);
1005 g_free(global_capture_opts.orig_save_file);
1007 QString filename = ui->filenameLineEdit->text();
1008 if (filename.length() > 0) {
1009 /* User specified a file to which the capture should be written. */
1010 global_capture_opts.saving_to_file = true;
1011 global_capture_opts.save_file = qstring_strdup(filename);
1012 global_capture_opts.orig_save_file = qstring_strdup(filename);
1013 /* Save the directory name for future file dialogs. */
1014 set_last_open_dir(get_dirname(filename.toUtf8().data()));
1015 } else {
1016 /* User didn't specify a file; save to a temporary file. */
1017 global_capture_opts.saving_to_file = false;
1018 global_capture_opts.save_file = NULL;
1019 global_capture_opts.orig_save_file = NULL;
1022 QString tempdir = ui->tempDirLineEdit->text();
1023 if (tempdir.length() > 0) {
1024 global_capture_opts.temp_dir = qstring_strdup(tempdir);
1026 else {
1027 global_capture_opts.temp_dir = NULL;
1030 global_capture_opts.has_ring_num_files = ui->RbCheckBox->isChecked();
1032 if (global_capture_opts.has_ring_num_files) {
1033 global_capture_opts.ring_num_files = ui->RbSpinBox->value();
1034 if (global_capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
1035 global_capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
1036 #if RINGBUFFER_MIN_NUM_FILES > 0
1037 else if (global_capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
1038 global_capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
1039 #endif
1041 global_capture_opts.multi_files_on = ui->gbNewFileAuto->isChecked();
1042 if (global_capture_opts.multi_files_on) {
1043 global_capture_opts.has_file_duration = ui->SecsCheckBox->isChecked();
1044 if (global_capture_opts.has_file_duration) {
1045 global_capture_opts.file_duration = ui->SecsSpinBox->value();
1046 int index = ui->SecsComboBox->currentIndex();
1047 switch (index) {
1048 case 1: global_capture_opts.file_duration *= 60;
1049 break;
1050 case 2: global_capture_opts.file_duration *= 3600;
1051 break;
1054 global_capture_opts.has_file_interval = ui->IntervalSecsCheckBox->isChecked();
1055 if (global_capture_opts.has_file_interval) {
1056 global_capture_opts.file_interval = ui->IntervalSecsSpinBox->value();
1057 int index = ui->IntervalSecsComboBox->currentIndex();
1058 switch (index) {
1059 case 1: global_capture_opts.file_interval *= 60;
1060 break;
1061 case 2: global_capture_opts.file_interval *= 3600;
1062 break;
1065 global_capture_opts.has_file_packets = ui->PktCheckBox->isChecked();
1066 if (global_capture_opts.has_file_packets) {
1067 global_capture_opts.file_packets = ui->PktSpinBox->value();
1069 global_capture_opts.has_autostop_filesize = ui->MBCheckBox->isChecked();
1070 if (global_capture_opts.has_autostop_filesize) {
1071 global_capture_opts.autostop_filesize = ui->MBSpinBox->value();
1072 int index = ui->MBComboBox->currentIndex();
1073 switch (index) {
1074 case 1: if (global_capture_opts.autostop_filesize > 2000000) {
1075 QMessageBox::warning(this, tr("Error"),
1076 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1077 return false;
1078 } else {
1079 global_capture_opts.autostop_filesize *= 1000;
1081 break;
1082 case 2: if (global_capture_opts.autostop_filesize > 2000) {
1083 QMessageBox::warning(this, tr("Error"),
1084 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1085 return false;
1086 } else {
1087 global_capture_opts.autostop_filesize *= 1000000;
1089 break;
1092 /* test if the settings are ok for a ringbuffer */
1093 if (global_capture_opts.save_file == NULL) {
1094 QMessageBox::warning(this, tr("Error"),
1095 tr("Multiple files: No capture file name given. You must specify a filename if you want to use multiple files."));
1096 return false;
1097 } else if (!global_capture_opts.has_autostop_filesize &&
1098 !global_capture_opts.has_file_interval &&
1099 !global_capture_opts.has_file_duration &&
1100 !global_capture_opts.has_file_packets) {
1101 QMessageBox::warning(this, tr("Error"),
1102 tr("Multiple files: No file limit given. You must specify a file size, interval, or number of packets for each file."));
1103 g_free(global_capture_opts.save_file);
1104 global_capture_opts.save_file = NULL;
1105 return false;
1107 } else {
1108 global_capture_opts.has_autostop_filesize = ui->stopMBCheckBox->isChecked();
1109 if (global_capture_opts.has_autostop_filesize) {
1110 global_capture_opts.autostop_filesize = ui->stopMBSpinBox->value();
1111 int index = ui->stopMBComboBox->currentIndex();
1112 switch (index) {
1113 case 1: if (global_capture_opts.autostop_filesize > 2000000) {
1114 QMessageBox::warning(this, tr("Error"),
1115 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1116 return false;
1117 } else {
1118 global_capture_opts.autostop_filesize *= 1000;
1120 break;
1121 case 2: if (global_capture_opts.autostop_filesize > 2000) {
1122 QMessageBox::warning(this, tr("Error"),
1123 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1124 return false;
1125 } else {
1126 global_capture_opts.autostop_filesize *= 1000000;
1128 break;
1133 global_capture_opts.has_autostop_duration = ui->stopSecsCheckBox->isChecked();
1134 if (global_capture_opts.has_autostop_duration) {
1135 global_capture_opts.autostop_duration = ui->stopSecsSpinBox->value();
1136 int index = ui->stopSecsComboBox->currentIndex();
1137 switch (index) {
1138 case 1: global_capture_opts.autostop_duration *= 60;
1139 break;
1140 case 2: global_capture_opts.autostop_duration *= 3600;
1141 break;
1145 global_capture_opts.has_autostop_packets = ui->stopPktCheckBox->isChecked();
1146 if (global_capture_opts.has_autostop_packets) {
1147 global_capture_opts.autostop_packets = ui->stopPktSpinBox->value();
1150 global_capture_opts.has_autostop_files = ui->stopFilesCheckBox->isChecked();
1151 if (global_capture_opts.has_autostop_files) {
1152 global_capture_opts.autostop_files = ui->stopFilesSpinBox->value();
1155 interface_t *device;
1157 for (int col = col_link_; col <= col_filter_; col++) {
1158 if (ui->interfaceTree->isColumnHidden(col)) {
1159 continue;
1161 /* All entries are separated by comma. There is also one before the first interface to be able to identify
1162 word boundaries. As 'lo' is part of 'nflog' an exact match is necessary. */
1163 switch (col) {
1164 case col_link_:
1166 QStringList link_list;
1168 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1169 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1170 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1171 device = getDeviceByName(device_name);
1172 if (!device || device->active_dlt == -1) {
1173 continue;
1175 link_list << QStringLiteral("%1(%2)").arg(device->name).arg(device->active_dlt);
1177 g_free(prefs.capture_devices_linktypes);
1178 prefs.capture_devices_linktypes = qstring_strdup(link_list.join(","));
1179 break;
1181 case col_buffer_:
1183 QStringList buffer_size_list;
1185 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1186 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1187 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1188 device = getDeviceByName(device_name);
1189 if (!device || device->buffer == -1) {
1190 continue;
1192 buffer_size_list << QStringLiteral("%1(%2)").arg(device->name).arg(device->buffer);
1194 g_free(prefs.capture_devices_buffersize);
1195 prefs.capture_devices_buffersize = qstring_strdup(buffer_size_list.join(","));
1196 break;
1198 case col_snaplen_:
1200 QStringList snaplen_list;
1202 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1203 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1204 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1205 device = getDeviceByName(device_name);
1206 if (!device) continue;
1207 snaplen_list << QStringLiteral("%1:%2(%3)")
1208 .arg(device->name)
1209 .arg(device->has_snaplen)
1210 .arg(device->has_snaplen ? device->snaplen : WTAP_MAX_PACKET_SIZE_STANDARD);
1212 g_free(prefs.capture_devices_snaplen);
1213 prefs.capture_devices_snaplen = qstring_strdup(snaplen_list.join(","));
1214 break;
1216 case col_pmode_:
1218 QStringList pmode_list;
1220 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1221 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1222 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1223 device = getDeviceByName(device_name);
1224 if (!device || !device->pmode) {
1225 continue;
1227 pmode_list << QStringLiteral("%1(%2)").arg(device->name).arg(device->pmode);
1229 g_free(prefs.capture_devices_pmode);
1230 prefs.capture_devices_pmode = qstring_strdup(pmode_list.join(","));
1231 break;
1234 case col_monitor_:
1236 QStringList monitor_list;
1238 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1239 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1240 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1241 device = getDeviceByName(device_name);
1242 if (!device || !device->monitor_mode_supported || (device->monitor_mode_supported && !device->monitor_mode_enabled)) {
1243 continue;
1245 monitor_list << device->name;
1247 g_free(prefs.capture_devices_monitor_mode);
1248 prefs.capture_devices_monitor_mode = qstring_strdup(monitor_list.join(","));
1249 break;
1252 #if 0
1253 // The device cfilter should have been applied at this point.
1254 // We shouldn't change it here.
1255 case col_filter_:
1257 // XXX Update selected interfaces only?
1258 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1259 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1260 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1261 device = getDeviceByName(device_name);
1262 if (!device) continue;
1263 g_free(device->cfilter);
1264 if (ti->text(col_filter_).isEmpty()) {
1265 device->cfilter = NULL;
1266 } else {
1267 device->cfilter = qstring_strdup(ti->text(col_filter_));
1271 #endif
1275 g_free(global_capture_opts.compress_type);
1277 if (ui->rbCompressionNone->isChecked() ) {
1278 global_capture_opts.compress_type = NULL;
1279 } else if (ui->rbCompressionGzip->isChecked() ) {
1280 global_capture_opts.compress_type = qstring_strdup("gzip");
1281 } else {
1282 global_capture_opts.compress_type = NULL;
1285 if (ui->rbTimeNum->isChecked() ) {
1286 global_capture_opts.has_nametimenum = true;
1287 } else if (ui->rbNumTime->isChecked() ) {
1288 global_capture_opts.has_nametimenum = false;
1289 } else {
1290 global_capture_opts.has_nametimenum = false;
1293 prefs_main_write();
1294 return true;
1297 void CaptureOptionsDialog::updateSelectedFilter()
1299 // Should match MainWelcome::interfaceSelected.
1300 QPair <const QString, bool> sf_pair = CaptureFilterEdit::getSelectedFilter();
1301 const QString user_filter = sf_pair.first;
1302 bool conflict = sf_pair.second;
1304 if (conflict) {
1305 ui->captureFilterComboBox->lineEdit()->clear();
1306 ui->captureFilterComboBox->setConflict(true);
1307 } else {
1308 ui->captureFilterComboBox->lineEdit()->setText(user_filter);
1312 void CaptureOptionsDialog::on_manageButton_clicked()
1314 if (saveOptionsToPreferences()) {
1315 ManageInterfacesDialog *dlg = new ManageInterfacesDialog(this);
1316 dlg->show();
1320 void CaptureOptionsDialog::changeEvent(QEvent* event)
1322 if (0 != event)
1324 switch (event->type())
1326 case QEvent::LanguageChange:
1327 ui->retranslateUi(this);
1328 break;
1329 default:
1330 break;
1333 QDialog::changeEvent(event);
1336 interface_t *CaptureOptionsDialog::getDeviceByName(const QString device_name)
1338 for (unsigned i = 0; i < global_capture_opts.all_ifaces->len; i++) {
1339 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
1340 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
1341 return device;
1344 return NULL;
1348 // InterfaceTreeItem
1350 bool InterfaceTreeWidgetItem::operator< (const QTreeWidgetItem &other) const {
1351 if (treeWidget()->sortColumn() == col_traffic_) {
1352 QList<int> points = data(col_traffic_, Qt::UserRole).value<QList<int> >();
1353 QList<int> other_points = other.data(col_traffic_, Qt::UserRole).value<QList<int> >();
1354 double avg = 0, other_avg = 0;
1355 foreach (int point, points) {
1356 avg += (double) point / points.length();
1358 foreach (int point, other_points) {
1359 other_avg += (double) point / other_points.length();
1361 return avg < other_avg;
1363 return QTreeWidgetItem::operator<(other);
1366 QVariant InterfaceTreeWidgetItem::data(int column, int role) const
1368 // See setData for the special col_traffic_ treatment.
1369 if (column == col_traffic_ && role == Qt::UserRole) {
1370 return QVariant::fromValue(points);
1373 if (column == col_snaplen_ && role == Qt::DisplayRole) {
1374 QVariant data = QTreeWidgetItem::data(column, role);
1375 if (data.toInt() == WTAP_MAX_PACKET_SIZE_STANDARD || data.toInt() == 0) {
1376 return InterfaceTreeDelegate::tr("default");
1378 return data;
1380 return QTreeWidgetItem::data(column, role);
1383 void InterfaceTreeWidgetItem::setData(int column, int role, const QVariant &value)
1385 // Workaround for closing editors on updates to the points list: normally
1386 // QTreeWidgetItem::setData emits dataChanged when the value (list) changes.
1387 // We could store a pointer to the list, or just have this hack that does
1388 // not emit dataChanged.
1389 if (column == col_traffic_ && role == Qt::UserRole) {
1390 points = value.value<QList<int> >();
1391 return;
1394 QTreeWidgetItem::setData(column, role, value);
1398 // InterfaceTreeDelegate
1401 #include <QComboBox>
1403 InterfaceTreeDelegate::InterfaceTreeDelegate(QObject *parent)
1404 : QStyledItemDelegate(parent), tree_(NULL)
1409 InterfaceTreeDelegate::~InterfaceTreeDelegate()
1414 QWidget* InterfaceTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &idx) const
1416 QWidget *w = NULL;
1417 int buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
1418 unsigned snap = WTAP_MAX_PACKET_SIZE_STANDARD;
1419 GList *links = NULL;
1421 if (idx.column() > 1 && idx.data().toString().compare(UTF8_EM_DASH)) {
1422 QTreeWidgetItem *ti = tree_->topLevelItem(idx.row());
1423 QString interface_name = ti->text(col_interface_);
1424 interface_t *device = find_device_by_if_name(interface_name);
1426 if (device) {
1427 buffer = device->buffer;
1428 snap = device->snaplen;
1429 links = device->links;
1431 switch (idx.column()) {
1432 case col_extcap_:
1433 case col_interface_:
1434 case col_traffic_:
1435 break;
1436 case col_link_:
1438 GList *list;
1439 link_row *linkr;
1440 QStringList valid_link_types;
1442 // XXX The GTK+ UI fills in all link types, valid or not. We add
1443 // only the valid ones. If we *do* wish to include invalid link
1444 // types we'll have to jump through the hoops necessary to disable
1445 // QComboBox items.
1447 for (list = links; list != Q_NULLPTR; list = gxx_list_next(list)) {
1448 linkr = gxx_list_data(link_row*, list);
1449 if (linkr->dlt >= 0) {
1450 valid_link_types << linkr->name;
1454 if (valid_link_types.size() < 2) {
1455 break;
1457 QComboBox *cb = new QComboBox(parent);
1458 cb->addItems(valid_link_types);
1460 connect(cb, &QComboBox::currentTextChanged, this, &InterfaceTreeDelegate::linkTypeChanged);
1461 w = (QWidget*) cb;
1462 break;
1464 case col_snaplen_:
1466 QSpinBox *sb = new QSpinBox(parent);
1467 sb->setRange(0, WTAP_MAX_PACKET_SIZE_STANDARD);
1468 sb->setValue(snap);
1469 sb->setWrapping(true);
1470 sb->setSpecialValueText(tr("default"));
1471 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1472 connect(sb, &QSpinBox::valueChanged, this, &InterfaceTreeDelegate::snapshotLengthChanged);
1473 #else
1474 connect(sb, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &InterfaceTreeDelegate::snapshotLengthChanged);
1475 #endif
1476 w = (QWidget*) sb;
1477 break;
1479 case col_buffer_:
1481 QSpinBox *sb = new QSpinBox(parent);
1482 sb->setRange(1, WTAP_MAX_PACKET_SIZE_STANDARD);
1483 sb->setValue(buffer);
1484 sb->setWrapping(true);
1485 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1486 connect(sb, &QSpinBox::valueChanged, this, &InterfaceTreeDelegate::bufferSizeChanged);
1487 #else
1488 connect(sb, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &InterfaceTreeDelegate::bufferSizeChanged);
1489 #endif
1490 w = (QWidget*) sb;
1491 break;
1493 case col_filter_:
1495 // XXX: Should this take the interface name, so that the history
1496 // list is taken from the interface-specific recent cfilter list?
1497 CaptureFilterCombo *cf = new CaptureFilterCombo(parent, true);
1498 connect(cf->lineEdit(), &QLineEdit::textEdited, this, &InterfaceTreeDelegate::filterChanged);
1499 w = (QWidget*) cf;
1501 default:
1502 break;
1505 if (w)
1506 w->setAutoFillBackground(true);
1507 return w;
1510 bool InterfaceTreeDelegate::eventFilter(QObject *object, QEvent *event)
1512 QComboBox * comboBox = dynamic_cast<QComboBox*>(object);
1513 if (comboBox) {
1514 if (event->type() == QEvent::MouseButtonRelease) {
1515 comboBox->showPopup();
1516 return true;
1518 } else {
1519 return QStyledItemDelegate::eventFilter(object, event);
1521 return false;
1524 void InterfaceTreeDelegate::linkTypeChanged(const QString selected_link_type)
1526 GList *list;
1527 link_row *temp;
1528 interface_t *device;
1530 QTreeWidgetItem *ti = tree_->currentItem();
1531 if (!ti) {
1532 return;
1534 QString interface_name = ti->text(col_interface_);
1535 device = find_device_by_if_name(interface_name);
1536 if (!device) {
1537 return;
1539 for (list = device->links; list != Q_NULLPTR; list = gxx_list_next(list)) {
1540 temp = gxx_list_data(link_row*, list);
1541 if (!selected_link_type.compare(temp->name)) {
1542 device->active_dlt = temp->dlt;
1545 // XXX We might want to verify that active_dlt is valid at this point.
1548 void InterfaceTreeDelegate::snapshotLengthChanged(int value)
1550 interface_t *device;
1551 QTreeWidgetItem *ti = tree_->currentItem();
1552 if (!ti) {
1553 return;
1555 QString interface_name = ti->text(col_interface_);
1556 device = find_device_by_if_name(interface_name);
1557 if (!device) {
1558 return;
1560 if (value != WTAP_MAX_PACKET_SIZE_STANDARD && value != 0) {
1561 device->has_snaplen = true;
1562 device->snaplen = value;
1563 } else {
1564 device->has_snaplen = false;
1565 device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD;
1569 void InterfaceTreeDelegate::bufferSizeChanged(int value)
1571 interface_t *device;
1572 QTreeWidgetItem *ti = tree_->currentItem();
1573 if (!ti) {
1574 return;
1576 QString interface_name = ti->text(col_interface_);
1577 device = find_device_by_if_name(interface_name);
1578 if (!device) {
1579 return;
1581 device->buffer = value;
1584 #endif /* HAVE_LIBPCAP */