Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / qt / capture_options_dialog.cpp
blobbd109fa3b379a4066dd00377bbd89146f859afa2
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"
23 #include "capture_opts.h"
25 #ifdef HAVE_LIBPCAP
27 #include <QAbstractItemModel>
28 #include <QMessageBox>
29 #include <QTimer>
31 #include "ringbuffer.h"
32 #include "ui/capture_ui_utils.h"
33 #include "ui/capture_globals.h"
34 #include "ui/iface_lists.h"
35 #include "ui/file_dialog.h"
37 #include "ui/ws_ui_util.h"
38 #include "ui/util.h"
39 #include <wsutil/utf8_entities.h>
40 #include "ui/preference_utils.h"
41 #include "ui/recent.h"
43 #include <cstdio>
44 #include <epan/prefs.h>
45 #include <epan/prefs-int.h>
46 #include <epan/addr_resolv.h>
47 #include <wsutil/filesystem.h>
49 #include <wiretap/wtap.h>
51 #include <ui/qt/utils/qt_ui_utils.h>
52 #include <ui/qt/utils/stock_icon.h>
53 #include <ui/qt/models/sparkline_delegate.h>
54 #include "ui/qt/widgets/wireshark_file_dialog.h"
56 // To do:
57 // - Set a size hint for item delegates.
58 // - Make promiscuous and monitor mode checkboxes.
59 // - Fix InterfaceTreeDelegate method names.
60 // - You can edit filters via the main CaptureFilterCombo and via each
61 // individual interface row. We should probably do one or the other.
62 // - There might be a point in having the separate combo boxes in the
63 // individual interface row, if their CaptureFilterCombos actually
64 // called recent_get_cfilter_list with the interface name to get the
65 // separate list of recent capture filters for that interface, but
66 // they don't.
68 const int stat_update_interval_ = 1000; // ms
70 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
71 #define SHOW_BUFFER_COLUMN 1
72 #endif
74 #if defined(HAVE_PCAP_CREATE)
75 #define SHOW_MONITOR_COLUMN 1
76 #endif
79 * Symbolic names for column indices.
81 enum
83 col_extcap_ = 0,
84 col_interface_,
85 col_traffic_,
86 col_link_,
87 col_pmode_,
88 col_snaplen_,
89 col_buffer_,
90 col_monitor_,
91 col_filter_,
92 col_num_columns_
95 static interface_t *find_device_by_if_name(const QString &interface_name)
97 interface_t *device;
98 unsigned i;
99 for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
100 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
101 if (!interface_name.compare(device->display_name) && !device->hidden && device->if_info.type != IF_PIPE) {
102 return device;
105 return NULL;
108 class InterfaceTreeWidgetItem : public QTreeWidgetItem
110 public:
111 InterfaceTreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
112 bool operator< (const QTreeWidgetItem &other) const;
113 QVariant data(int column, int role) const;
114 void setData(int column, int role, const QVariant &value);
115 QList<int> points;
117 void updateInterfaceColumns(interface_t *device)
119 if (!device) return;
121 // Prevent infinite recursive signal loop
122 // itemChanged->interfaceItemChanged->updateInterfaceColumns
123 treeWidget()->blockSignals(true);
124 QString default_str = QObject::tr("default");
126 // XXX - this is duplicated in InterfaceTreeModel::data;
127 // it should be done in common code somewhere.
128 QString linkname;
129 if (device->active_dlt == -1)
130 linkname = "Unknown";
131 else {
132 linkname = QObject::tr("DLT %1").arg(device->active_dlt);
133 for (GList *list = device->links; list != NULL; list = gxx_list_next(list)) {
134 link_row *linkr = gxx_list_data(link_row *, list);
135 if (linkr->dlt == device->active_dlt) {
136 linkname = linkr->name;
137 break;
141 setText(col_link_, linkname);
143 if (device->if_info.type == IF_EXTCAP) {
144 /* extcap interfaces does not have this settings */
145 setApplicable(col_pmode_, false);
147 setApplicable(col_snaplen_, false);
148 #ifdef SHOW_BUFFER_COLUMN
149 setApplicable(col_buffer_, false);
150 #endif
151 } else {
152 setApplicable(col_pmode_, true);
153 setCheckState(col_pmode_, device->pmode ? Qt::Checked : Qt::Unchecked);
155 QString snaplen_string = device->has_snaplen ? QString::number(device->snaplen) : default_str;
156 setText(col_snaplen_, snaplen_string);
157 #ifdef SHOW_BUFFER_COLUMN
158 setText(col_buffer_, QString::number(device->buffer));
159 #endif
161 setText(col_filter_, device->cfilter);
163 #ifdef SHOW_MONITOR_COLUMN
164 if (device->monitor_mode_supported) {
165 setApplicable(col_monitor_, true);
166 setCheckState(col_monitor_, device->monitor_mode_enabled ? Qt::Checked : Qt::Unchecked);
167 } else {
168 setApplicable(col_monitor_, false);
170 #endif
171 treeWidget()->blockSignals(false);
174 void setApplicable(int column, bool applicable = false) {
175 QPalette palette = mainApp->palette();
177 if (applicable) {
178 setText(column, QString());
179 } else {
180 setData(column, Qt::CheckStateRole, QVariant());
181 palette.setCurrentColorGroup(QPalette::Disabled);
182 setText(column, UTF8_EM_DASH);
184 setForeground(column, palette.text().color());
189 CaptureOptionsDialog::CaptureOptionsDialog(QWidget *parent) :
190 GeometryStateDialog(parent),
191 ui(new Ui::CaptureOptionsDialog)
193 ui->setupUi(this);
194 loadGeometry();
195 setWindowTitle(mainApp->windowTitleString(tr("Capture Options")));
197 stat_timer_ = NULL;
198 stat_cache_ = NULL;
200 ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Start"));
202 // Start out with the list *not* sorted, so they show up in the order
203 // in which they were provided
204 ui->interfaceTree->sortByColumn(-1, Qt::AscendingOrder);
205 ui->interfaceTree->setItemDelegateForColumn(col_extcap_, &interface_item_delegate_);
206 ui->interfaceTree->setItemDelegateForColumn(col_interface_, &interface_item_delegate_);
207 ui->interfaceTree->setItemDelegateForColumn(col_traffic_, new SparkLineDelegate(this));
208 ui->interfaceTree->setItemDelegateForColumn(col_link_, &interface_item_delegate_);
210 ui->interfaceTree->setItemDelegateForColumn(col_snaplen_, &interface_item_delegate_);
211 #ifdef SHOW_BUFFER_COLUMN
212 ui->interfaceTree->setItemDelegateForColumn(col_buffer_, &interface_item_delegate_);
213 #else
214 ui->interfaceTree->setColumnHidden(col_buffer_, true);
215 #endif
216 #ifndef SHOW_MONITOR_COLUMN
217 ui->interfaceTree->setColumnHidden(col_monitor_, true);
218 ui->captureMonitorModeCheckBox->setVisible(false);
219 #endif
220 ui->interfaceTree->setItemDelegateForColumn(col_filter_, &interface_item_delegate_);
222 interface_item_delegate_.setTree(ui->interfaceTree);
224 ui->filenameLineEdit->setPlaceholderText(tr("Leave blank to use a temporary file"));
226 ui->rbCompressionNone->setChecked(true);
227 ui->rbTimeNum->setChecked(true);
229 ui->tempDirLineEdit->setPlaceholderText(g_get_tmp_dir());
230 ui->tempDirLineEdit->setText(global_capture_opts.temp_dir);
232 // Changes in interface selections or capture filters should be propagated
233 // to the main welcome screen where they will be applied to the global
234 // capture options.
235 connect(this, SIGNAL(interfacesChanged()), ui->captureFilterComboBox, SIGNAL(interfacesChanged()));
236 connect(ui->captureFilterComboBox, SIGNAL(captureFilterSyntaxChanged(bool)), this, SLOT(updateWidgets()));
237 connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)),
238 this, SLOT(filterEdited()));
239 connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)),
240 this, SIGNAL(captureFilterTextEdited(QString)));
241 connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)),
242 ui->captureFilterComboBox->lineEdit(), SLOT(setText(QString)));
243 connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)),
244 this, SIGNAL(captureFilterTextEdited(QString)));
245 connect(this, SIGNAL(ifsChanged()), this, SLOT(refreshInterfaceList()));
246 connect(mainApp, SIGNAL(localInterfaceListChanged()), this, SLOT(updateLocalInterfaces()));
247 connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
248 connect(ui->interfaceTree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(itemClicked(QTreeWidgetItem*,int)));
249 connect(ui->interfaceTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem*,int)));
250 connect(ui->tempDirBrowseButton, SIGNAL(clicked()), this, SLOT(tempDirBrowseButtonClicked()));
252 // Ring buffer minimums (all 1 except # of files)
253 ui->PktSpinBox->setMinimum(1);
254 ui->MBSpinBox->setMinimum(1);
255 ui->SecsSpinBox->setMinimum(1);
256 ui->IntervalSecsSpinBox->setMinimum(1);
257 ui->RbSpinBox->setMinimum(2);
259 // Autostop minimums
260 ui->stopPktSpinBox->setMinimum(1);
261 ui->stopFilesSpinBox->setMinimum(1);
262 ui->stopMBSpinBox->setMinimum(1);
263 ui->stopSecsSpinBox->setMinimum(1);
265 // Capture size maximum depends on units. Initial unit is kB.
266 ui->MBSpinBox->setMaximum(2000000000);
267 ui->stopMBSpinBox->setMaximum(2000000000);
269 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
270 connect(ui->MBComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CaptureOptionsDialog::MBComboBoxIndexChanged);
271 connect(ui->stopMBComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CaptureOptionsDialog::stopMBComboBoxIndexChanged);
272 #else
273 connect(ui->MBComboBox, &QComboBox::currentIndexChanged, this, &CaptureOptionsDialog::MBComboBoxIndexChanged);
274 connect(ui->stopMBComboBox, &QComboBox::currentIndexChanged, this, &CaptureOptionsDialog::stopMBComboBoxIndexChanged);
275 #endif
277 ui->tabWidget->setCurrentIndex(0);
279 updateWidgets();
282 CaptureOptionsDialog::~CaptureOptionsDialog()
284 delete ui;
287 /* Update global device selections based on the TreeWidget selection. */
288 void CaptureOptionsDialog::updateGlobalDeviceSelections()
290 #ifdef HAVE_LIBPCAP
291 QTreeWidgetItemIterator iter(ui->interfaceTree);
293 global_capture_opts.num_selected = 0;
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 ((*iter)->isSelected()) {
301 device->selected = true;
302 global_capture_opts.num_selected++;
303 } else {
304 device->selected = false;
306 break;
309 ++iter;
311 #endif
314 /* Update TreeWidget selection based on global device selections. */
315 void CaptureOptionsDialog::updateFromGlobalDeviceSelections()
317 #ifdef HAVE_LIBPCAP
318 QTreeWidgetItemIterator iter(ui->interfaceTree);
320 // Prevent recursive interface interfaceSelected signals
321 ui->interfaceTree->blockSignals(true);
323 while (*iter) {
324 QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value<QString>();
325 for (unsigned i = 0; i < global_capture_opts.all_ifaces->len; i++) {
326 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
327 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
328 if ((bool)device->selected != (*iter)->isSelected()) {
329 (*iter)->setSelected(device->selected);
331 break;
334 ++iter;
337 ui->interfaceTree->blockSignals(false);
338 #endif
341 void CaptureOptionsDialog::interfaceSelected()
343 if (sender() == ui->interfaceTree) {
344 // Local changes, propagate our changes
345 updateGlobalDeviceSelections();
346 emit interfacesChanged();
347 } else {
348 // Changes from the welcome screen, adjust to its state.
349 updateFromGlobalDeviceSelections();
352 updateSelectedFilter();
354 updateWidgets();
357 void CaptureOptionsDialog::filterEdited()
359 QList<QTreeWidgetItem*> si = ui->interfaceTree->selectedItems();
361 foreach (QTreeWidgetItem *ti, si) {
362 ti->setText(col_filter_, ui->captureFilterComboBox->lineEdit()->text());
365 if (si.count() > 0) {
366 QModelIndex col_filter_idx = ui->interfaceTree->model()->index(ui->interfaceTree->indexOfTopLevelItem(si[0]), col_filter_);
367 ui->interfaceTree->scrollTo(col_filter_idx);
371 void CaptureOptionsDialog::updateWidgets()
373 SyntaxLineEdit *sle = qobject_cast<SyntaxLineEdit *>(ui->captureFilterComboBox->lineEdit());
374 if (!sle) {
375 return;
378 bool can_capture = false;
380 if (ui->interfaceTree->selectedItems().count() > 0 && sle->syntaxState() != SyntaxLineEdit::Invalid) {
381 can_capture = true;
384 ui->compileBPF->setEnabled(can_capture);
385 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(can_capture);
388 void CaptureOptionsDialog::on_capturePromModeCheckBox_toggled(bool checked)
390 interface_t *device;
391 prefs.capture_prom_mode = checked;
392 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
393 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->topLevelItem(row));
394 if (!ti) continue;
396 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
397 device = getDeviceByName(device_name);
398 if (!device) continue;
399 device->pmode = checked;
400 ti->updateInterfaceColumns(device);
404 void CaptureOptionsDialog::on_captureMonitorModeCheckBox_toggled(bool checked)
406 interface_t *device;
407 prefs.capture_monitor_mode = checked;
408 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
409 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->topLevelItem(row));
410 if (!ti) continue;
412 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
413 device = getDeviceByName(device_name);
414 if (!device) continue;
415 if (device->monitor_mode_supported) {
416 device->monitor_mode_enabled = checked;
417 ti->updateInterfaceColumns(device);
422 void CaptureOptionsDialog::browseButtonClicked()
424 QString file_name = WiresharkFileDialog::getSaveFileName(this, tr("Specify a Capture File"), get_open_dialog_initial_dir());
425 ui->filenameLineEdit->setText(file_name);
428 void CaptureOptionsDialog::tempDirBrowseButtonClicked()
430 QString specified_dir = WiresharkFileDialog::getExistingDirectory(this, tr("Specify temporary directory"));
431 ui->tempDirLineEdit->setText(specified_dir);
434 void CaptureOptionsDialog::interfaceItemChanged(QTreeWidgetItem *item, int column)
436 QWidget* editor = ui->interfaceTree->indexWidget(ui->interfaceTree->currentIndex());
437 if (editor) {
438 ui->interfaceTree->closePersistentEditor(item, ui->interfaceTree->currentColumn());
441 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
442 if (!ti) return;
444 interface_t *device;
445 QString interface_name = ti->text(col_interface_);
446 device = find_device_by_if_name(interface_name);
447 if (!device) return;
449 switch(column) {
451 case col_pmode_:
452 device->pmode = item->checkState(col_pmode_) == Qt::Checked ? true : false;
453 ti->updateInterfaceColumns(device);
454 break;
456 #ifdef SHOW_MONITOR_COLUMN
457 case col_monitor_:
459 bool monitor_mode = false;
460 if (ti->checkState(col_monitor_) == Qt::Checked) monitor_mode = true;
462 if_capabilities_t *caps;
463 char *auth_str = NULL;
464 QString active_dlt_name;
466 set_active_dlt(device, global_capture_opts.default_options.linktype);
468 #ifdef HAVE_PCAP_REMOTE
469 if (device->remote_opts.remote_host_opts.auth_type == CAPTURE_AUTH_PWD) {
470 auth_str = ws_strdup_printf("%s:%s", device->remote_opts.remote_host_opts.auth_username,
471 device->remote_opts.remote_host_opts.auth_password);
473 #endif
474 caps = capture_get_if_capabilities(device->name, monitor_mode, auth_str, NULL, NULL, main_window_update);
475 g_free(auth_str);
477 if (caps != Q_NULLPTR) {
479 #if GLIB_CHECK_VERSION(2, 68, 0)
480 g_list_free_full(g_steal_pointer(&device->links), capture_opts_free_link_row);
481 #else
482 g_list_free_full((GList*)g_steal_pointer(&device->links), capture_opts_free_link_row);
483 #endif
484 device->active_dlt = -1;
485 device->monitor_mode_supported = caps->can_set_rfmon;
486 device->monitor_mode_enabled = monitor_mode && caps->can_set_rfmon;
487 GList *lt_list = device->monitor_mode_enabled ? caps->data_link_types_rfmon : caps->data_link_types;
489 for (GList *lt_entry = lt_list; lt_entry != Q_NULLPTR; lt_entry = gxx_list_next(lt_entry)) {
490 link_row *linkr = g_new(link_row, 1);
491 data_link_info_t *data_link_info = gxx_list_data(data_link_info_t *, lt_entry);
493 * For link-layer types libpcap/WinPcap/Npcap doesn't know
494 * about, the name will be "DLT n", and the description will
495 * be null.
496 * We mark those as unsupported, and don't allow them to be
497 * used - capture filters won't work on them, for example.
499 if (data_link_info->description != Q_NULLPTR) {
500 linkr->dlt = data_link_info->dlt;
501 if (active_dlt_name.isEmpty()) {
502 device->active_dlt = data_link_info->dlt;
503 active_dlt_name = data_link_info->description;
505 linkr->name = g_strdup(data_link_info->description);
506 } else {
507 char *str;
508 /* XXX - should we just omit them? */
509 str = ws_strdup_printf("%s (not supported)", data_link_info->name);
510 linkr->dlt = -1;
511 linkr->name = g_strdup(str);
512 g_free(str);
514 device->links = g_list_append(device->links, linkr);
516 free_if_capabilities(caps);
517 } else {
518 /* We don't know whether this supports monitor mode or not;
519 don't ask for monitor mode. */
520 device->monitor_mode_enabled = false;
521 device->monitor_mode_supported = false;
524 ti->updateInterfaceColumns(device);
526 break;
528 #endif // SHOW_MONITOR_COLUMN
529 default:
530 break;
534 void CaptureOptionsDialog::itemClicked(QTreeWidgetItem *item, int column)
536 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
537 if (!ti) return;
539 #ifdef HAVE_LIBPCAP
540 interface_t *device;
541 QString interface_name = ti->text(col_interface_);
542 device = find_device_by_if_name(interface_name);
543 if (!device) return;
545 switch(column) {
547 case col_extcap_:
548 if (device->if_info.type == IF_EXTCAP) {
549 /* this checks if configuration is required and not yet provided or saved via prefs */
550 QString device_name = ti->data(col_extcap_, Qt::UserRole).value<QString>();
551 if (extcap_has_configuration((const char *)(device_name.toStdString().c_str())))
553 emit showExtcapOptions(device_name, false);
554 return;
557 break;
559 default:
560 break;
562 #endif /* HAVE_LIBPCAP */
565 void CaptureOptionsDialog::itemDoubleClicked(QTreeWidgetItem *item, int column)
567 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
568 if (!ti) return;
570 switch(column) {
572 // Double click starts capture just on columns which are not editable
573 case col_interface_:
574 case col_traffic_:
576 #ifdef HAVE_LIBPCAP
577 interface_t *device;
578 QString interface_name = ti->text(col_interface_);
579 device = find_device_by_if_name(interface_name);
580 if (!device) return;
582 if (device->if_info.type == IF_EXTCAP) {
583 /* this checks if configuration is required and not yet provided or saved via prefs */
584 QString device_name = ti->data(col_extcap_, Qt::UserRole).value<QString>();
585 if (extcap_requires_configuration((const char *)(device_name.toStdString().c_str())))
587 emit showExtcapOptions(device_name, true);
588 return;
591 #endif /* HAVE_LIBPCAP */
592 emit startCapture();
593 close();
594 break;
597 default:
598 break;
602 void CaptureOptionsDialog::MBComboBoxIndexChanged(int index)
604 switch (index) {
605 case 0: // kilobytes
606 ui->MBSpinBox->setMaximum(2000000000);
607 break;
608 case 1: // megabytes
609 ui->MBSpinBox->setMaximum(2000000);
610 break;
611 case 2: // gigabytes
612 ui->MBSpinBox->setMaximum(2000);
613 break;
617 void CaptureOptionsDialog::stopMBComboBoxIndexChanged(int index)
619 switch (index) {
620 case 0: // kilobytes
621 ui->stopMBSpinBox->setMaximum(2000000000);
622 break;
623 case 1: // megabytes
624 ui->stopMBSpinBox->setMaximum(2000000);
625 break;
626 case 2: // gigabytes
627 ui->stopMBSpinBox->setMaximum(2000);
628 break;
632 void CaptureOptionsDialog::on_gbStopCaptureAuto_toggled(bool checked)
634 global_capture_opts.has_file_interval = checked;
637 void CaptureOptionsDialog::on_gbNewFileAuto_toggled(bool checked)
639 global_capture_opts.multi_files_on = checked;
640 ui->stopMBCheckBox->setEnabled(checked?false:true);
641 ui->stopMBSpinBox->setEnabled(checked?false:true);
642 ui->stopMBComboBox->setEnabled(checked?false:true);
643 ui->gbCompression->setEnabled(checked);
644 ui->rbCompressionNone->setEnabled(checked);
645 #if defined(HAVE_ZLIB) || defined(HAVE_ZLIBNG)
646 ui->rbCompressionGzip->setEnabled(checked);
647 #else
648 ui->rbCompressionGzip->setEnabled(false);
649 #endif
652 void CaptureOptionsDialog::on_cbUpdatePacketsRT_toggled(bool checked)
654 global_capture_opts.real_time_mode = checked;
657 void CaptureOptionsDialog::on_cbAutoScroll_toggled(bool checked)
659 recent.capture_auto_scroll = checked;
662 void CaptureOptionsDialog::on_cbExtraCaptureInfo_toggled(bool checked)
664 global_capture_opts.show_info = checked;
667 void CaptureOptionsDialog::on_cbResolveMacAddresses_toggled(bool checked)
669 gbl_resolv_flags.mac_name = checked;
672 void CaptureOptionsDialog::on_cbResolveNetworkNames_toggled(bool checked)
674 gbl_resolv_flags.network_name = checked;
677 void CaptureOptionsDialog::on_cbResolveTransportNames_toggled(bool checked)
679 gbl_resolv_flags.transport_name = checked;
682 void CaptureOptionsDialog::on_buttonBox_accepted()
684 if (saveOptionsToPreferences()) {
686 #ifdef HAVE_LIBPCAP
687 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->currentItem());
688 if (ti) {
689 interface_t *device;
691 QString interface_name = ti->text(col_interface_);
692 device = find_device_by_if_name(interface_name);
693 if (device && device->if_info.type == IF_EXTCAP) {
694 /* this checks if configuration is required and not yet provided or saved via prefs */
695 QString device_name = ti->data(col_extcap_, Qt::UserRole).value<QString>();
696 if (extcap_requires_configuration((const char *)(device_name.toStdString().c_str())))
698 emit showExtcapOptions(device_name, true);
699 return;
703 #endif /* HAVE_LIBPCAP */
705 emit setFilterValid(true, ui->captureFilterComboBox->lineEdit()->text());
706 accept();
710 // Not sure why we have to do this manually.
711 void CaptureOptionsDialog::on_buttonBox_rejected()
713 if (saveOptionsToPreferences()) {
714 reject();
718 void CaptureOptionsDialog::on_buttonBox_helpRequested()
720 // Probably the wrong URL.
721 mainApp->helpTopicAction(HELP_CAPTURE_OPTIONS_DIALOG);
724 void CaptureOptionsDialog::updateInterfaces()
726 if (prefs.capture_pcap_ng) {
727 ui->rbPcapng->setChecked(true);
728 } else {
729 ui->rbPcap->setChecked(true);
731 ui->capturePromModeCheckBox->setChecked(prefs.capture_prom_mode);
732 ui->captureMonitorModeCheckBox->setChecked(prefs.capture_monitor_mode);
733 ui->captureMonitorModeCheckBox->setEnabled(false);
735 if (global_capture_opts.saving_to_file) {
736 ui->filenameLineEdit->setText(QString(global_capture_opts.orig_save_file));
739 ui->gbNewFileAuto->setChecked(global_capture_opts.multi_files_on);
740 ui->PktCheckBox->setChecked(global_capture_opts.has_file_packets);
741 if (global_capture_opts.has_file_packets) {
742 ui->PktSpinBox->setValue(global_capture_opts.file_packets);
744 ui->MBCheckBox->setChecked(global_capture_opts.has_autostop_filesize);
745 if (global_capture_opts.has_autostop_filesize) {
746 int value = global_capture_opts.autostop_filesize;
747 if (value > 1000000) {
748 if (global_capture_opts.multi_files_on) {
749 ui->MBSpinBox->setValue(value / 1000000);
750 ui->MBComboBox->setCurrentIndex(2);
751 } else {
752 ui->stopMBCheckBox->setChecked(true);
753 ui->stopMBSpinBox->setValue(value / 1000000);
754 ui->stopMBComboBox->setCurrentIndex(2);
756 } else if (value > 1000 && value % 1000 == 0) {
757 if (global_capture_opts.multi_files_on) {
758 ui->MBSpinBox->setValue(value / 1000);
759 ui->MBComboBox->setCurrentIndex(1);
760 } else {
761 ui->stopMBCheckBox->setChecked(true);
762 ui->stopMBSpinBox->setValue(value / 1000);
763 ui->stopMBComboBox->setCurrentIndex(1);
765 } else {
766 if (global_capture_opts.multi_files_on) {
767 ui->MBSpinBox->setValue(value);
768 ui->MBComboBox->setCurrentIndex(0);
769 } else {
770 ui->stopMBCheckBox->setChecked(true);
771 ui->stopMBSpinBox->setValue(value);
772 ui->stopMBComboBox->setCurrentIndex(0);
777 ui->SecsCheckBox->setChecked(global_capture_opts.has_file_duration);
778 if (global_capture_opts.has_file_duration) {
779 int value = global_capture_opts.file_duration;
780 if (value > 3600 && value % 3600 == 0) {
781 ui->SecsSpinBox->setValue(value / 3600);
782 ui->SecsComboBox->setCurrentIndex(2);
783 } else if (value > 60 && value % 60 == 0) {
784 ui->SecsSpinBox->setValue(value / 60);
785 ui->SecsComboBox->setCurrentIndex(1);
786 } else {
787 ui->SecsSpinBox->setValue(value);
788 ui->SecsComboBox->setCurrentIndex(0);
792 ui->IntervalSecsCheckBox->setChecked(global_capture_opts.has_file_interval);
793 if (global_capture_opts.has_file_interval) {
794 int value = global_capture_opts.file_interval;
795 if (value > 3600 && value % 3600 == 0) {
796 ui->IntervalSecsSpinBox->setValue(value / 3600);
797 ui->IntervalSecsComboBox->setCurrentIndex(2);
798 } else if (value > 60 && value % 60 == 0) {
799 ui->IntervalSecsSpinBox->setValue(value / 60);
800 ui->IntervalSecsComboBox->setCurrentIndex(1);
801 } else {
802 ui->IntervalSecsSpinBox->setValue(value);
803 ui->IntervalSecsComboBox->setCurrentIndex(0);
807 if (global_capture_opts.has_ring_num_files) {
808 ui->RbSpinBox->setValue(global_capture_opts.ring_num_files);
809 ui->RbCheckBox->setCheckState(Qt::Checked);
812 if (global_capture_opts.has_autostop_duration) {
813 ui->stopSecsCheckBox->setChecked(true);
814 int value = global_capture_opts.autostop_duration;
815 if (value > 3600 && value % 3600 == 0) {
816 ui->stopSecsSpinBox->setValue(value / 3600);
817 ui->stopSecsComboBox->setCurrentIndex(2);
818 } else if (value > 60 && value % 60 == 0) {
819 ui->stopSecsSpinBox->setValue(value / 60);
820 ui->stopSecsComboBox->setCurrentIndex(1);
821 } else {
822 ui->stopSecsSpinBox->setValue(value);
823 ui->stopSecsComboBox->setCurrentIndex(0);
827 if (global_capture_opts.has_autostop_packets) {
828 ui->stopPktCheckBox->setChecked(true);
829 ui->stopPktSpinBox->setValue(global_capture_opts.autostop_packets);
832 if (global_capture_opts.has_autostop_files) {
833 ui->stopFilesCheckBox->setChecked(true);
834 ui->stopFilesSpinBox->setValue(global_capture_opts.autostop_files);
837 ui->cbUpdatePacketsRT->setChecked(global_capture_opts.real_time_mode);
838 ui->cbAutoScroll->setChecked(recent.capture_auto_scroll);
839 ui->cbExtraCaptureInfo->setChecked(global_capture_opts.show_info);
841 ui->cbResolveMacAddresses->setChecked(gbl_resolv_flags.mac_name);
842 ui->cbResolveNetworkNames->setChecked(gbl_resolv_flags.network_name);
843 ui->cbResolveTransportNames->setChecked(gbl_resolv_flags.transport_name);
845 // Rebuild the interface list without disturbing the main welcome screen.
846 disconnect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
847 ui->interfaceTree->clear();
849 #ifdef SHOW_BUFFER_COLUMN
850 int buffer;
851 #endif
852 int snaplen;
853 bool hassnap, pmode;
854 QList<QTreeWidgetItem *> selected_interfaces;
856 disconnect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
858 if (global_capture_opts.all_ifaces->len > 0) {
859 interface_t *device;
861 for (unsigned device_idx = 0; device_idx < global_capture_opts.all_ifaces->len; device_idx++) {
862 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
864 /* Continue if capture device is hidden */
865 if (device->hidden) {
866 continue;
869 // Traffic sparklines
870 InterfaceTreeWidgetItem *ti = new InterfaceTreeWidgetItem(ui->interfaceTree);
871 ti->setFlags(ti->flags() | Qt::ItemIsEditable);
873 if (device->if_info.type == IF_EXTCAP) {
874 ti->setIcon(col_extcap_, QIcon(StockIcon("x-capture-options")));
875 ti->setData(col_extcap_, Qt::UserRole, QString(device->if_info.name));
876 ti->setToolTip(col_extcap_, QStringLiteral("Extcap interface settings"));
879 ti->setText(col_interface_, device->display_name);
880 ti->setData(col_interface_, Qt::UserRole, QString(device->name));
881 if (device->if_info.type != IF_EXTCAP)
882 ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(ti->points));
884 if (device->no_addresses > 0) {
885 QString addr_str = tr("%1: %2").arg(device->no_addresses > 1 ? tr("Addresses") : tr("Address")).arg(device->addresses);
886 QTreeWidgetItem *addr_ti = new QTreeWidgetItem(ti);
888 addr_str.replace('\n', ", ");
889 addr_ti->setText(0, addr_str);
890 addr_ti->setFlags(addr_ti->flags() ^ Qt::ItemIsSelectable);
891 addr_ti->setFirstColumnSpanned(true);
892 addr_ti->setToolTip(col_interface_, QStringLiteral("<span>%1</span>").arg(addr_str));
893 ti->setToolTip(col_interface_, QStringLiteral("<span>%1</span>").arg(addr_str));
894 } else {
895 ti->setToolTip(col_interface_, tr("no addresses"));
898 if (capture_dev_user_pmode_find(device->name, &pmode)) {
899 device->pmode = pmode;
901 if (capture_dev_user_snaplen_find(device->name, &hassnap, &snaplen)) {
902 /* Default snap length set in preferences */
903 device->snaplen = snaplen;
904 device->has_snaplen = snaplen == WTAP_MAX_PACKET_SIZE_STANDARD ? false : hassnap;
905 } else {
906 /* No preferences set yet, use default values */
907 device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD;
908 device->has_snaplen = false;
911 #ifdef SHOW_BUFFER_COLUMN
912 if (capture_dev_user_buffersize_find(device->name) != -1) {
913 buffer = capture_dev_user_buffersize_find(device->name);
914 device->buffer = buffer;
915 } else {
916 device->buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
918 #endif
919 #ifdef SHOW_MONITOR_COLUMN
920 if (device->monitor_mode_supported) {
921 ui->captureMonitorModeCheckBox->setEnabled(true);
923 #endif
924 ti->updateInterfaceColumns(device);
926 if (device->selected) {
927 selected_interfaces << ti;
932 connect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
934 foreach (QTreeWidgetItem *ti, selected_interfaces) {
935 ti->setSelected(true);
937 connect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
938 updateSelectedFilter();
940 // Manually or automatically size some columns as needed.
941 int one_em = fontMetrics().height();
942 for (int col = 0; col < ui->interfaceTree->topLevelItemCount(); col++) {
943 switch (col) {
944 case col_pmode_:
945 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
946 break;
947 case col_snaplen_:
948 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
949 break;
950 case col_buffer_:
951 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
952 break;
953 case col_monitor_:
954 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
955 break;
956 default:
957 ui->interfaceTree->resizeColumnToContents(col);
962 updateWidgets();
964 if (!stat_timer_) {
965 updateStatistics();
966 stat_timer_ = new QTimer(this);
967 connect(stat_timer_, SIGNAL(timeout()), this, SLOT(updateStatistics()));
968 stat_timer_->start(stat_update_interval_);
972 void CaptureOptionsDialog::showEvent(QShowEvent *)
974 updateInterfaces();
977 void CaptureOptionsDialog::refreshInterfaceList()
979 updateInterfaces();
980 emit interfaceListChanged();
983 void CaptureOptionsDialog::updateLocalInterfaces()
985 updateInterfaces();
988 void CaptureOptionsDialog::updateStatistics(void)
990 interface_t *device;
992 disconnect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
993 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
995 for (unsigned if_idx = 0; if_idx < global_capture_opts.all_ifaces->len; if_idx++) {
996 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
997 if (!ti) {
998 continue;
1000 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, if_idx);
1001 QString device_name = ti->text(col_interface_);
1002 if (device_name.compare(device->display_name) || device->hidden || device->if_info.type == IF_PIPE) {
1003 continue;
1005 QList<int> points = ti->data(col_traffic_, Qt::UserRole).value<QList<int> >();
1006 points.append(device->packet_diff);
1007 ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(points));
1010 connect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
1011 ui->interfaceTree->viewport()->update();
1014 void CaptureOptionsDialog::on_compileBPF_clicked()
1016 QList<InterfaceFilter> interfaces;
1017 foreach (QTreeWidgetItem *ti, ui->interfaceTree->selectedItems()) {
1018 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1019 interfaces.emplaceBack(ti->text(col_interface_), ti->text(col_filter_));
1020 #else
1021 interfaces.append(InterfaceFilter(ti->text(col_interface_), ti->text(col_filter_)));
1022 #endif
1025 QString filter = ui->captureFilterComboBox->currentText();
1026 CompiledFilterOutput *cfo = new CompiledFilterOutput(this, interfaces);
1028 cfo->show();
1031 bool CaptureOptionsDialog::saveOptionsToPreferences()
1033 if (ui->rbPcapng->isChecked()) {
1034 global_capture_opts.use_pcapng = true;
1035 prefs.capture_pcap_ng = true;
1036 } else {
1037 global_capture_opts.use_pcapng = false;
1038 prefs.capture_pcap_ng = false;
1041 g_free(global_capture_opts.save_file);
1042 g_free(global_capture_opts.orig_save_file);
1044 QString filename = ui->filenameLineEdit->text();
1045 if (filename.length() > 0) {
1046 /* User specified a file to which the capture should be written. */
1047 global_capture_opts.saving_to_file = true;
1048 global_capture_opts.save_file = qstring_strdup(filename);
1049 global_capture_opts.orig_save_file = qstring_strdup(filename);
1050 /* Save the directory name for future file dialogs. */
1051 set_last_open_dir(get_dirname(filename.toUtf8().data()));
1052 } else {
1053 /* User didn't specify a file; save to a temporary file. */
1054 global_capture_opts.saving_to_file = false;
1055 global_capture_opts.save_file = NULL;
1056 global_capture_opts.orig_save_file = NULL;
1059 QString tempdir = ui->tempDirLineEdit->text();
1060 if (tempdir.length() > 0) {
1061 global_capture_opts.temp_dir = qstring_strdup(tempdir);
1063 else {
1064 global_capture_opts.temp_dir = NULL;
1067 global_capture_opts.has_ring_num_files = ui->RbCheckBox->isChecked();
1069 if (global_capture_opts.has_ring_num_files) {
1070 global_capture_opts.ring_num_files = ui->RbSpinBox->value();
1071 if (global_capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
1072 global_capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
1073 #if RINGBUFFER_MIN_NUM_FILES > 0
1074 else if (global_capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
1075 global_capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
1076 #endif
1078 global_capture_opts.multi_files_on = ui->gbNewFileAuto->isChecked();
1079 if (global_capture_opts.multi_files_on) {
1080 global_capture_opts.has_file_duration = ui->SecsCheckBox->isChecked();
1081 if (global_capture_opts.has_file_duration) {
1082 global_capture_opts.file_duration = ui->SecsSpinBox->value();
1083 int index = ui->SecsComboBox->currentIndex();
1084 switch (index) {
1085 case 1: global_capture_opts.file_duration *= 60;
1086 break;
1087 case 2: global_capture_opts.file_duration *= 3600;
1088 break;
1091 global_capture_opts.has_file_interval = ui->IntervalSecsCheckBox->isChecked();
1092 if (global_capture_opts.has_file_interval) {
1093 global_capture_opts.file_interval = ui->IntervalSecsSpinBox->value();
1094 int index = ui->IntervalSecsComboBox->currentIndex();
1095 switch (index) {
1096 case 1: global_capture_opts.file_interval *= 60;
1097 break;
1098 case 2: global_capture_opts.file_interval *= 3600;
1099 break;
1102 global_capture_opts.has_file_packets = ui->PktCheckBox->isChecked();
1103 if (global_capture_opts.has_file_packets) {
1104 global_capture_opts.file_packets = ui->PktSpinBox->value();
1106 global_capture_opts.has_autostop_filesize = ui->MBCheckBox->isChecked();
1107 if (global_capture_opts.has_autostop_filesize) {
1108 global_capture_opts.autostop_filesize = ui->MBSpinBox->value();
1109 int index = ui->MBComboBox->currentIndex();
1110 switch (index) {
1111 case 1: if (global_capture_opts.autostop_filesize > 2000000) {
1112 QMessageBox::warning(this, tr("Error"),
1113 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1114 return false;
1115 } else {
1116 global_capture_opts.autostop_filesize *= 1000;
1118 break;
1119 case 2: if (global_capture_opts.autostop_filesize > 2000) {
1120 QMessageBox::warning(this, tr("Error"),
1121 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1122 return false;
1123 } else {
1124 global_capture_opts.autostop_filesize *= 1000000;
1126 break;
1129 /* test if the settings are ok for a ringbuffer */
1130 if (global_capture_opts.save_file == NULL) {
1131 QMessageBox::warning(this, tr("Error"),
1132 tr("Multiple files: No capture file name given. You must specify a filename if you want to use multiple files."));
1133 return false;
1134 } else if (!global_capture_opts.has_autostop_filesize &&
1135 !global_capture_opts.has_file_interval &&
1136 !global_capture_opts.has_file_duration &&
1137 !global_capture_opts.has_file_packets) {
1138 QMessageBox::warning(this, tr("Error"),
1139 tr("Multiple files: No file limit given. You must specify a file size, interval, or number of packets for each file."));
1140 g_free(global_capture_opts.save_file);
1141 global_capture_opts.save_file = NULL;
1142 return false;
1144 } else {
1145 global_capture_opts.has_autostop_filesize = ui->stopMBCheckBox->isChecked();
1146 if (global_capture_opts.has_autostop_filesize) {
1147 global_capture_opts.autostop_filesize = ui->stopMBSpinBox->value();
1148 int index = ui->stopMBComboBox->currentIndex();
1149 switch (index) {
1150 case 1: if (global_capture_opts.autostop_filesize > 2000000) {
1151 QMessageBox::warning(this, tr("Error"),
1152 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1153 return false;
1154 } else {
1155 global_capture_opts.autostop_filesize *= 1000;
1157 break;
1158 case 2: if (global_capture_opts.autostop_filesize > 2000) {
1159 QMessageBox::warning(this, tr("Error"),
1160 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 TB."));
1161 return false;
1162 } else {
1163 global_capture_opts.autostop_filesize *= 1000000;
1165 break;
1170 global_capture_opts.has_autostop_duration = ui->stopSecsCheckBox->isChecked();
1171 if (global_capture_opts.has_autostop_duration) {
1172 global_capture_opts.autostop_duration = ui->stopSecsSpinBox->value();
1173 int index = ui->stopSecsComboBox->currentIndex();
1174 switch (index) {
1175 case 1: global_capture_opts.autostop_duration *= 60;
1176 break;
1177 case 2: global_capture_opts.autostop_duration *= 3600;
1178 break;
1182 global_capture_opts.has_autostop_packets = ui->stopPktCheckBox->isChecked();
1183 if (global_capture_opts.has_autostop_packets) {
1184 global_capture_opts.autostop_packets = ui->stopPktSpinBox->value();
1187 global_capture_opts.has_autostop_files = ui->stopFilesCheckBox->isChecked();
1188 if (global_capture_opts.has_autostop_files) {
1189 global_capture_opts.autostop_files = ui->stopFilesSpinBox->value();
1192 interface_t *device;
1194 for (int col = col_link_; col <= col_filter_; col++) {
1195 if (ui->interfaceTree->isColumnHidden(col)) {
1196 continue;
1198 /* All entries are separated by comma. There is also one before the first interface to be able to identify
1199 word boundaries. As 'lo' is part of 'nflog' an exact match is necessary. */
1200 switch (col) {
1201 case col_link_:
1203 QStringList link_list;
1205 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1206 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1207 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1208 device = getDeviceByName(device_name);
1209 if (!device || device->active_dlt == -1) {
1210 continue;
1212 link_list << QStringLiteral("%1(%2)").arg(device->name).arg(device->active_dlt);
1214 g_free(prefs.capture_devices_linktypes);
1215 prefs.capture_devices_linktypes = qstring_strdup(link_list.join(","));
1216 break;
1218 #ifdef SHOW_BUFFER_COLUMN
1219 case col_buffer_:
1221 QStringList buffer_size_list;
1223 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1224 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1225 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1226 device = getDeviceByName(device_name);
1227 if (!device || device->buffer == -1) {
1228 continue;
1230 buffer_size_list << QStringLiteral("%1(%2)").arg(device->name).arg(device->buffer);
1232 g_free(prefs.capture_devices_buffersize);
1233 prefs.capture_devices_buffersize = qstring_strdup(buffer_size_list.join(","));
1234 break;
1236 #endif // HAVE_BUFFER_SETTING
1237 case col_snaplen_:
1239 QStringList snaplen_list;
1241 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1242 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1243 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1244 device = getDeviceByName(device_name);
1245 if (!device) continue;
1246 snaplen_list << QStringLiteral("%1:%2(%3)")
1247 .arg(device->name)
1248 .arg(device->has_snaplen)
1249 .arg(device->has_snaplen ? device->snaplen : WTAP_MAX_PACKET_SIZE_STANDARD);
1251 g_free(prefs.capture_devices_snaplen);
1252 prefs.capture_devices_snaplen = qstring_strdup(snaplen_list.join(","));
1253 break;
1255 case col_pmode_:
1257 QStringList pmode_list;
1259 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1260 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1261 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1262 device = getDeviceByName(device_name);
1263 if (!device || !device->pmode) {
1264 continue;
1266 pmode_list << QStringLiteral("%1(%2)").arg(device->name).arg(device->pmode);
1268 g_free(prefs.capture_devices_pmode);
1269 prefs.capture_devices_pmode = qstring_strdup(pmode_list.join(","));
1270 break;
1273 #ifdef SHOW_MONITOR_COLUMN
1274 case col_monitor_:
1276 QStringList monitor_list;
1278 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1279 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1280 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1281 device = getDeviceByName(device_name);
1282 if (!device || !device->monitor_mode_supported || (device->monitor_mode_supported && !device->monitor_mode_enabled)) {
1283 continue;
1285 monitor_list << device->name;
1287 g_free(prefs.capture_devices_monitor_mode);
1288 prefs.capture_devices_monitor_mode = qstring_strdup(monitor_list.join(","));
1289 break;
1291 #endif // HAVE_MONITOR_SETTING
1293 #if 0
1294 // The device cfilter should have been applied at this point.
1295 // We shouldn't change it here.
1296 case col_filter_:
1298 // XXX Update selected interfaces only?
1299 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1300 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1301 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1302 device = getDeviceByName(device_name);
1303 if (!device) continue;
1304 g_free(device->cfilter);
1305 if (ti->text(col_filter_).isEmpty()) {
1306 device->cfilter = NULL;
1307 } else {
1308 device->cfilter = qstring_strdup(ti->text(col_filter_));
1312 #endif
1316 g_free(global_capture_opts.compress_type);
1318 if (ui->rbCompressionNone->isChecked() ) {
1319 global_capture_opts.compress_type = NULL;
1320 } else if (ui->rbCompressionGzip->isChecked() ) {
1321 global_capture_opts.compress_type = qstring_strdup("gzip");
1322 } else {
1323 global_capture_opts.compress_type = NULL;
1326 if (ui->rbTimeNum->isChecked() ) {
1327 global_capture_opts.has_nametimenum = true;
1328 } else if (ui->rbNumTime->isChecked() ) {
1329 global_capture_opts.has_nametimenum = false;
1330 } else {
1331 global_capture_opts.has_nametimenum = false;
1334 prefs_main_write();
1335 return true;
1338 void CaptureOptionsDialog::updateSelectedFilter()
1340 // Should match MainWelcome::interfaceSelected.
1341 QPair <const QString, bool> sf_pair = CaptureFilterEdit::getSelectedFilter();
1342 const QString user_filter = sf_pair.first;
1343 bool conflict = sf_pair.second;
1345 if (conflict) {
1346 ui->captureFilterComboBox->lineEdit()->clear();
1347 ui->captureFilterComboBox->setConflict(true);
1348 } else {
1349 ui->captureFilterComboBox->lineEdit()->setText(user_filter);
1353 void CaptureOptionsDialog::on_manageButton_clicked()
1355 if (saveOptionsToPreferences()) {
1356 ManageInterfacesDialog *dlg = new ManageInterfacesDialog(this);
1357 dlg->show();
1361 void CaptureOptionsDialog::changeEvent(QEvent* event)
1363 if (0 != event)
1365 switch (event->type())
1367 case QEvent::LanguageChange:
1368 ui->retranslateUi(this);
1369 break;
1370 default:
1371 break;
1374 QDialog::changeEvent(event);
1377 interface_t *CaptureOptionsDialog::getDeviceByName(const QString device_name)
1379 for (unsigned i = 0; i < global_capture_opts.all_ifaces->len; i++) {
1380 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
1381 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
1382 return device;
1385 return NULL;
1389 // InterfaceTreeItem
1391 bool InterfaceTreeWidgetItem::operator< (const QTreeWidgetItem &other) const {
1392 if (treeWidget()->sortColumn() == col_traffic_) {
1393 QList<int> points = data(col_traffic_, Qt::UserRole).value<QList<int> >();
1394 QList<int> other_points = other.data(col_traffic_, Qt::UserRole).value<QList<int> >();
1395 double avg = 0, other_avg = 0;
1396 foreach (int point, points) {
1397 avg += (double) point / points.length();
1399 foreach (int point, other_points) {
1400 other_avg += (double) point / other_points.length();
1402 return avg < other_avg;
1404 return QTreeWidgetItem::operator<(other);
1407 QVariant InterfaceTreeWidgetItem::data(int column, int role) const
1409 // See setData for the special col_traffic_ treatment.
1410 if (column == col_traffic_ && role == Qt::UserRole) {
1411 return QVariant::fromValue(points);
1414 if (column == col_snaplen_ && role == Qt::DisplayRole) {
1415 QVariant data = QTreeWidgetItem::data(column, role);
1416 if (data.toInt() == WTAP_MAX_PACKET_SIZE_STANDARD || data.toInt() == 0) {
1417 return InterfaceTreeDelegate::tr("default");
1419 return data;
1421 return QTreeWidgetItem::data(column, role);
1424 void InterfaceTreeWidgetItem::setData(int column, int role, const QVariant &value)
1426 // Workaround for closing editors on updates to the points list: normally
1427 // QTreeWidgetItem::setData emits dataChanged when the value (list) changes.
1428 // We could store a pointer to the list, or just have this hack that does
1429 // not emit dataChanged.
1430 if (column == col_traffic_ && role == Qt::UserRole) {
1431 points = value.value<QList<int> >();
1432 return;
1435 QTreeWidgetItem::setData(column, role, value);
1439 // InterfaceTreeDelegate
1442 #include <QComboBox>
1444 InterfaceTreeDelegate::InterfaceTreeDelegate(QObject *parent)
1445 : QStyledItemDelegate(parent), tree_(NULL)
1450 InterfaceTreeDelegate::~InterfaceTreeDelegate()
1455 QWidget* InterfaceTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &idx) const
1457 QWidget *w = NULL;
1458 #ifdef SHOW_BUFFER_COLUMN
1459 int buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
1460 #endif
1461 unsigned snap = WTAP_MAX_PACKET_SIZE_STANDARD;
1462 GList *links = NULL;
1464 if (idx.column() > 1 && idx.data().toString().compare(UTF8_EM_DASH)) {
1465 QTreeWidgetItem *ti = tree_->topLevelItem(idx.row());
1466 QString interface_name = ti->text(col_interface_);
1467 interface_t *device = find_device_by_if_name(interface_name);
1469 if (device) {
1470 #ifdef SHOW_BUFFER_COLUMN
1471 buffer = device->buffer;
1472 #endif
1473 snap = device->snaplen;
1474 links = device->links;
1476 switch (idx.column()) {
1477 case col_extcap_:
1478 case col_interface_:
1479 case col_traffic_:
1480 break;
1481 case col_link_:
1483 GList *list;
1484 link_row *linkr;
1485 QStringList valid_link_types;
1487 // XXX The GTK+ UI fills in all link types, valid or not. We add
1488 // only the valid ones. If we *do* wish to include invalid link
1489 // types we'll have to jump through the hoops necessary to disable
1490 // QComboBox items.
1492 for (list = links; list != Q_NULLPTR; list = gxx_list_next(list)) {
1493 linkr = gxx_list_data(link_row*, list);
1494 if (linkr->dlt >= 0) {
1495 valid_link_types << linkr->name;
1499 if (valid_link_types.size() < 2) {
1500 break;
1502 QComboBox *cb = new QComboBox(parent);
1503 cb->addItems(valid_link_types);
1505 connect(cb, &QComboBox::currentTextChanged, this, &InterfaceTreeDelegate::linkTypeChanged);
1506 w = (QWidget*) cb;
1507 break;
1509 case col_snaplen_:
1511 QSpinBox *sb = new QSpinBox(parent);
1512 sb->setRange(0, WTAP_MAX_PACKET_SIZE_STANDARD);
1513 sb->setValue(snap);
1514 sb->setWrapping(true);
1515 sb->setSpecialValueText(tr("default"));
1516 connect(sb, SIGNAL(valueChanged(int)), this, SLOT(snapshotLengthChanged(int)));
1517 w = (QWidget*) sb;
1518 break;
1520 #ifdef SHOW_BUFFER_COLUMN
1521 case col_buffer_:
1523 QSpinBox *sb = new QSpinBox(parent);
1524 sb->setRange(1, WTAP_MAX_PACKET_SIZE_STANDARD);
1525 sb->setValue(buffer);
1526 sb->setWrapping(true);
1527 connect(sb, SIGNAL(valueChanged(int)), this, SLOT(bufferSizeChanged(int)));
1528 w = (QWidget*) sb;
1529 break;
1531 #endif
1532 case col_filter_:
1534 // XXX: Should this take the interface name, so that the history
1535 // list is taken from the interface-specific recent cfilter list?
1536 CaptureFilterCombo *cf = new CaptureFilterCombo(parent, true);
1537 connect(cf->lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString)));
1538 w = (QWidget*) cf;
1540 default:
1541 break;
1544 if (w)
1545 w->setAutoFillBackground(true);
1546 return w;
1549 bool InterfaceTreeDelegate::eventFilter(QObject *object, QEvent *event)
1551 QComboBox * comboBox = dynamic_cast<QComboBox*>(object);
1552 if (comboBox) {
1553 if (event->type() == QEvent::MouseButtonRelease) {
1554 comboBox->showPopup();
1555 return true;
1557 } else {
1558 return QStyledItemDelegate::eventFilter(object, event);
1560 return false;
1563 void InterfaceTreeDelegate::linkTypeChanged(const QString selected_link_type)
1565 GList *list;
1566 link_row *temp;
1567 interface_t *device;
1569 QTreeWidgetItem *ti = tree_->currentItem();
1570 if (!ti) {
1571 return;
1573 QString interface_name = ti->text(col_interface_);
1574 device = find_device_by_if_name(interface_name);
1575 if (!device) {
1576 return;
1578 for (list = device->links; list != Q_NULLPTR; list = gxx_list_next(list)) {
1579 temp = gxx_list_data(link_row*, list);
1580 if (!selected_link_type.compare(temp->name)) {
1581 device->active_dlt = temp->dlt;
1584 // XXX We might want to verify that active_dlt is valid at this point.
1587 void InterfaceTreeDelegate::snapshotLengthChanged(int value)
1589 interface_t *device;
1590 QTreeWidgetItem *ti = tree_->currentItem();
1591 if (!ti) {
1592 return;
1594 QString interface_name = ti->text(col_interface_);
1595 device = find_device_by_if_name(interface_name);
1596 if (!device) {
1597 return;
1599 if (value != WTAP_MAX_PACKET_SIZE_STANDARD && value != 0) {
1600 device->has_snaplen = true;
1601 device->snaplen = value;
1602 } else {
1603 device->has_snaplen = false;
1604 device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD;
1608 #ifdef SHOW_BUFFER_COLUMN
1609 void InterfaceTreeDelegate::bufferSizeChanged(int value)
1611 interface_t *device;
1612 QTreeWidgetItem *ti = tree_->currentItem();
1613 if (!ti) {
1614 return;
1616 QString interface_name = ti->text(col_interface_);
1617 device = find_device_by_if_name(interface_name);
1618 if (!device) {
1619 return;
1621 device->buffer = value;
1623 #endif
1625 #endif /* HAVE_LIBPCAP */