1 /* capture_interfaces_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "capture_interfaces_dialog.h"
27 #include "capture_filter_combo.h"
28 #include <ui_capture_interfaces_dialog.h>
29 #include "compiled_filter_output.h"
30 #include "manage_interfaces_dialog.h"
32 #include "wireshark_application.h"
36 #include <QAbstractItemModel>
37 #include <QFileDialog>
38 #include <QMessageBox>
41 #include "ringbuffer.h"
42 #include "ui/capture_ui_utils.h"
43 #include "ui/capture_globals.h"
44 #include "ui/iface_lists.h"
45 #include "ui/last_open_dir.h"
47 #include "ui/ui_util.h"
49 #include <wsutil/utf8_entities.h>
50 #include "ui/preference_utils.h"
53 #include <epan/prefs.h>
54 #include <epan/prefs-int.h>
55 #include <epan/addr_resolv.h>
56 #include <wsutil/filesystem.h>
58 #include "qt_ui_utils.h"
59 #include "sparkline_delegate.h"
62 // - Set a size hint for item delegates.
63 // - Make promiscuous and monitor mode checkboxes.
64 // - Fix InterfaceTreeDelegate method names.
65 // - You can edit filters via the main CaptureFilterCombo and via each
66 // individual interface row. We should probably do one or the other.
68 const int stat_update_interval_ = 1000; // ms
70 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
71 #define SHOW_BUFFER_COLUMN 1
74 #if defined(HAVE_PCAP_CREATE)
75 #define SHOW_MONITOR_COLUMN 1
79 * Symbolic names for column indices.
94 static interface_t *find_device_by_if_name(const QString &interface_name)
98 for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
99 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
100 if (!interface_name.compare(device->display_name) && !device->hidden && device->type != IF_PIPE) {
107 class InterfaceTreeWidgetItem : public QTreeWidgetItem
110 InterfaceTreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
111 bool operator< (const QTreeWidgetItem &other) const;
114 void updateInterfaceColumns(interface_t *device)
118 QString default_str = QObject::tr("default");
120 QString linkname = QObject::tr("DLT %1").arg(device->active_dlt);
121 for (GList *list = device->links; list != NULL; list = g_list_next(list)) {
122 link_row *linkr = (link_row*)(list->data);
123 // XXX ...and if they're both -1?
124 if (linkr->dlt == device->active_dlt) {
125 linkname = linkr->name;
129 setText(col_link_, linkname);
132 if (device->if_info.type == IF_EXTCAP) {
133 /* extcap interfaces does not have this settings */
134 setApplicable(col_pmode_, false);
136 setApplicable(col_snaplen_, false);
137 #ifdef SHOW_BUFFER_COLUMN
138 setApplicable(col_buffer_, false);
142 setApplicable(col_pmode_, true);
143 setCheckState(col_pmode_, device->pmode ? Qt::Checked : Qt::Unchecked);
145 QString snaplen_string = device->has_snaplen ? QString::number(device->snaplen) : default_str;
146 setText(col_snaplen_, snaplen_string);
147 #ifdef SHOW_BUFFER_COLUMN
148 setText(col_buffer_, QString::number(device->buffer));
153 setText(col_filter_, device->cfilter);
155 #ifdef SHOW_MONITOR_COLUMN
156 if (device->monitor_mode_supported) {
157 setApplicable(col_monitor_, true);
158 setCheckState(col_monitor_, device->monitor_mode_enabled ? Qt::Checked : Qt::Unchecked);
160 setApplicable(col_monitor_, false);
165 void setApplicable(int column, bool applicable = false) {
166 QPalette palette = wsApp->palette();
169 setText(column, QString());
171 setData(column, Qt::CheckStateRole, QVariant());
172 palette.setCurrentColorGroup(QPalette::Disabled);
173 setText(column, UTF8_EM_DASH);
175 setTextColor(column, palette.text().color());
180 CaptureInterfacesDialog::CaptureInterfacesDialog(QWidget *parent) :
181 GeometryStateDialog(parent),
182 ui(new Ui::CaptureInterfacesDialog)
186 setWindowTitle(wsApp->windowTitleString(tr("Capture Interfaces")));
191 // XXX - Enable / disable as needed
192 ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Start"));
194 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled((global_capture_opts.num_selected > 0)? true: false);
196 // Start out with the list *not* sorted, so they show up in the order
197 // in which they were provided
198 ui->interfaceTree->sortByColumn(-1, Qt::AscendingOrder);
199 ui->interfaceTree->setItemDelegateForColumn(col_interface_, &interface_item_delegate_);
200 ui->interfaceTree->setItemDelegateForColumn(col_traffic_, new SparkLineDelegate());
201 ui->interfaceTree->setItemDelegateForColumn(col_link_, &interface_item_delegate_);
203 ui->interfaceTree->setItemDelegateForColumn(col_snaplen_, &interface_item_delegate_);
204 #ifdef SHOW_BUFFER_COLUMN
205 ui->interfaceTree->setItemDelegateForColumn(col_buffer_, &interface_item_delegate_);
207 ui->interfaceTree->setColumnHidden(col_buffer_, true);
209 #ifndef SHOW_MONITOR_COLUMN
210 ui->interfaceTree->setColumnHidden(col_monitor_, true);
212 ui->interfaceTree->setItemDelegateForColumn(col_filter_, &interface_item_delegate_);
214 interface_item_delegate_.setTree(ui->interfaceTree);
216 ui->filenameLineEdit->setPlaceholderText(tr("Leave blank to use a temporary file"));
218 // Changes in interface selections or capture filters should be propagated
219 // to the main welcome screen where they will be applied to the global
221 connect(this, SIGNAL(interfacesChanged()), ui->captureFilterComboBox, SIGNAL(interfacesChanged()));
222 connect(ui->captureFilterComboBox, SIGNAL(captureFilterSyntaxChanged(bool)), this, SLOT(updateWidgets()));
223 connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)),
224 this, SLOT(filterEdited()));
225 connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)),
226 this, SIGNAL(captureFilterTextEdited(QString)));
227 connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)),
228 ui->captureFilterComboBox->lineEdit(), SLOT(setText(QString)));
229 connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)),
230 this, SIGNAL(captureFilterTextEdited(QString)));
231 connect(this, SIGNAL(ifsChanged()), this, SLOT(refreshInterfaceList()));
232 connect(wsApp, SIGNAL(localInterfaceListChanged()), this, SLOT(updateLocalInterfaces()));
233 connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
236 /* Update global device selections based on the TreeWidget selection. */
237 void CaptureInterfacesDialog::updateGlobalDeviceSelections()
240 QTreeWidgetItemIterator iter(ui->interfaceTree);
242 global_capture_opts.num_selected = 0;
245 QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value<QString>();
246 for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
247 interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
248 if (device_name.compare(QString().fromUtf8(device.name)) == 0) {
249 if (!device.locked) {
250 if ((*iter)->isSelected()) {
251 device.selected = TRUE;
252 global_capture_opts.num_selected++;
254 device.selected = FALSE;
256 device.locked = TRUE;
257 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
258 g_array_insert_val(global_capture_opts.all_ifaces, i, device);
260 device.locked = FALSE;
261 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
262 g_array_insert_val(global_capture_opts.all_ifaces, i, device);
272 void CaptureInterfacesDialog::interfaceSelected()
274 updateGlobalDeviceSelections();
276 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled((global_capture_opts.num_selected > 0) ? true: false);
278 emit interfacesChanged();
280 updateSelectedFilter();
285 void CaptureInterfacesDialog::filterEdited()
287 QList<QTreeWidgetItem*> si = ui->interfaceTree->selectedItems();
289 foreach (QTreeWidgetItem *ti, si) {
290 ti->setText(col_filter_, ui->captureFilterComboBox->lineEdit()->text());
293 if (si.count() > 0) {
294 QModelIndex col_filter_idx = ui->interfaceTree->model()->index(ui->interfaceTree->indexOfTopLevelItem(si[0]), col_filter_);
295 ui->interfaceTree->scrollTo(col_filter_idx);
299 void CaptureInterfacesDialog::updateWidgets()
301 SyntaxLineEdit *sle = qobject_cast<SyntaxLineEdit *>(ui->captureFilterComboBox->lineEdit());
306 bool can_capture = false;
308 if (ui->interfaceTree->selectedItems().count() > 0 && sle->syntaxState() != SyntaxLineEdit::Invalid) {
312 ui->compileBPF->setEnabled(can_capture);
313 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(can_capture);
316 CaptureInterfacesDialog::~CaptureInterfacesDialog()
321 void CaptureInterfacesDialog::setTab(int idx)
323 ui->tabWidget->setCurrentIndex(idx);
326 void CaptureInterfacesDialog::on_capturePromModeCheckBox_toggled(bool checked)
329 prefs.capture_prom_mode = checked;
330 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
331 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->topLevelItem(row));
334 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
335 device = getDeviceByName(device_name);
336 if (!device) continue;
337 device->pmode = checked;
338 ti->updateInterfaceColumns(device);
342 void CaptureInterfacesDialog::browseButtonClicked()
344 char *open_dir = NULL;
346 switch (prefs.gui_fileopen_style) {
348 case FO_STYLE_LAST_OPENED:
349 open_dir = get_last_open_dir();
352 case FO_STYLE_SPECIFIED:
353 if (prefs.gui_fileopen_dir[0] != '\0')
354 open_dir = prefs.gui_fileopen_dir;
357 QString file_name = QFileDialog::getSaveFileName(this, tr("Specify a Capture File"), open_dir);
358 ui->filenameLineEdit->setText(file_name);
361 void CaptureInterfacesDialog::interfaceItemChanged(QTreeWidgetItem *item, int column)
363 QWidget* editor = ui->interfaceTree->indexWidget(ui->interfaceTree->currentIndex());
365 ui->interfaceTree->closePersistentEditor(item, ui->interfaceTree->currentColumn());
368 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
372 QString interface_name = ti->text(col_interface_);
373 device = find_device_by_if_name(interface_name);
379 device->pmode = item->checkState(col_pmode_) == Qt::Checked ? TRUE : FALSE;
380 ti->updateInterfaceColumns(device);
383 #ifdef SHOW_MONITOR_COLUMN
386 gboolean monitor_mode = FALSE;
387 if (ti->checkState(col_monitor_) == Qt::Checked) monitor_mode = TRUE;
389 if_capabilities_t *caps;
390 char *auth_str = NULL;
391 QString active_dlt_name;
393 set_active_dlt(device, global_capture_opts.default_options.linktype);
395 #ifdef HAVE_PCAP_REMOTE
396 if (device->remote_opts.remote_host_opts.auth_type == CAPTURE_AUTH_PWD) {
397 auth_str = g_strdup_printf("%s:%s", device->remote_opts.remote_host_opts.auth_username,
398 device->remote_opts.remote_host_opts.auth_password);
401 caps = capture_get_if_capabilities(device->name, monitor_mode, auth_str, NULL, main_window_update);
406 for (int i = (gint)g_list_length(device->links)-1; i >= 0; i--) {
407 GList* rem = g_list_nth(device->links, i);
408 device->links = g_list_remove_link(device->links, rem);
411 device->active_dlt = -1;
412 device->monitor_mode_supported = caps->can_set_rfmon;
413 device->monitor_mode_enabled = monitor_mode;
415 for (GList *lt_entry = caps->data_link_types; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
416 link_row *linkr = (link_row *)g_malloc(sizeof(link_row));
417 data_link_info_t *data_link_info = (data_link_info_t *)lt_entry->data;
419 * For link-layer types libpcap/WinPcap doesn't know about, the
420 * name will be "DLT n", and the description will be null.
421 * We mark those as unsupported, and don't allow them to be
422 * used - capture filters won't work on them, for example.
424 if (data_link_info->description != NULL) {
425 linkr->dlt = data_link_info->dlt;
426 if (active_dlt_name.isEmpty()) {
427 device->active_dlt = data_link_info->dlt;
428 active_dlt_name = data_link_info->description;
430 linkr->name = g_strdup(data_link_info->description);
433 /* XXX - should we just omit them? */
434 str = g_strdup_printf("%s (not supported)", data_link_info->name);
436 linkr->name = g_strdup(str);
439 device->links = g_list_append(device->links, linkr);
441 free_if_capabilities(caps);
443 /* We don't know whether this supports monitor mode or not;
444 don't ask for monitor mode. */
445 device->monitor_mode_enabled = FALSE;
446 device->monitor_mode_supported = FALSE;
449 ti->updateInterfaceColumns(device);
453 #endif // SHOW_MONITOR_COLUMN
459 void CaptureInterfacesDialog::on_gbStopCaptureAuto_toggled(bool checked)
461 global_capture_opts.has_file_duration = checked;
464 void CaptureInterfacesDialog::on_gbNewFileAuto_toggled(bool checked)
466 global_capture_opts.multi_files_on = checked;
467 ui->stopMBCheckBox->setEnabled(checked?false:true);
468 ui->stopMBSpinBox->setEnabled(checked?false:true);
469 ui->stopMBComboBox->setEnabled(checked?false:true);
472 void CaptureInterfacesDialog::on_cbUpdatePacketsRT_toggled(bool checked)
474 global_capture_opts.real_time_mode = checked;
477 void CaptureInterfacesDialog::on_cbAutoScroll_toggled(bool checked)
479 auto_scroll_live = checked;
482 void CaptureInterfacesDialog::on_cbExtraCaptureInfo_toggled(bool checked)
484 global_capture_opts.show_info = checked;
487 void CaptureInterfacesDialog::on_cbResolveMacAddresses_toggled(bool checked)
489 gbl_resolv_flags.mac_name = checked;
492 void CaptureInterfacesDialog::on_cbResolveNetworkNames_toggled(bool checked)
494 gbl_resolv_flags.network_name = checked;
497 void CaptureInterfacesDialog::on_cbResolveTransportNames_toggled(bool checked)
499 gbl_resolv_flags.transport_name = checked;
502 void CaptureInterfacesDialog::on_buttonBox_accepted()
504 if (saveOptionsToPreferences()) {
505 emit setFilterValid(true, ui->captureFilterComboBox->lineEdit()->text());
510 // Not sure why we have to do this manually.
511 void CaptureInterfacesDialog::on_buttonBox_rejected()
513 if (saveOptionsToPreferences()) {
518 void CaptureInterfacesDialog::on_buttonBox_helpRequested()
520 // Probably the wrong URL.
521 wsApp->helpTopicAction(HELP_CAPTURE_INTERFACES_DIALOG);
524 void CaptureInterfacesDialog::updateInterfaces()
526 if(prefs.capture_pcap_ng) {
527 ui->rbPcapng->setChecked(true);
529 ui->rbPcap->setChecked(true);
531 ui->capturePromModeCheckBox->setChecked(prefs.capture_prom_mode);
533 if (global_capture_opts.saving_to_file) {
534 ui->filenameLineEdit->setText(QString(global_capture_opts.orig_save_file));
537 ui->gbNewFileAuto->setChecked(global_capture_opts.multi_files_on);
538 ui->MBCheckBox->setChecked(global_capture_opts.has_autostop_filesize);
539 ui->SecsCheckBox->setChecked(global_capture_opts.has_file_duration);
540 if (global_capture_opts.has_autostop_filesize) {
541 int value = global_capture_opts.autostop_filesize;
542 if (value > 1000000) {
543 if (global_capture_opts.multi_files_on) {
544 ui->MBSpinBox->setValue(value / 1000000);
545 ui->MBComboBox->setCurrentIndex(2);
547 ui->stopMBCheckBox->setChecked(true);
548 ui->stopMBSpinBox->setValue(value / 1000000);
549 ui->stopMBComboBox->setCurrentIndex(2);
551 } else if (value > 1000 && value % 1000 == 0) {
552 if (global_capture_opts.multi_files_on) {
553 ui->MBSpinBox->setValue(value / 1000);
554 ui->MBComboBox->setCurrentIndex(1);
556 ui->stopMBCheckBox->setChecked(true);
557 ui->stopMBSpinBox->setValue(value / 1000);
558 ui->stopMBComboBox->setCurrentIndex(1);
561 if (global_capture_opts.multi_files_on) {
562 ui->MBSpinBox->setValue(value);
563 ui->MBComboBox->setCurrentIndex(0);
565 ui->stopMBCheckBox->setChecked(true);
566 ui->stopMBSpinBox->setValue(value);
567 ui->stopMBComboBox->setCurrentIndex(0);
571 if (global_capture_opts.has_file_duration) {
572 int value = global_capture_opts.file_duration;
573 if (value > 3600 && value % 3600 == 0) {
574 ui->SecsSpinBox->setValue(value / 3600);
575 ui->SecsComboBox->setCurrentIndex(2);
576 } else if (value > 60 && value % 60 == 0) {
577 ui->SecsSpinBox->setValue(value / 60);
578 ui->SecsComboBox->setCurrentIndex(1);
580 ui->SecsSpinBox->setValue(value);
581 ui->SecsComboBox->setCurrentIndex(0);
585 if (global_capture_opts.has_ring_num_files) {
586 ui->RbSpinBox->setValue(global_capture_opts.ring_num_files);
587 ui->RbCheckBox->setCheckState(Qt::Checked);
590 if (global_capture_opts.has_autostop_duration) {
591 ui->stopSecsCheckBox->setChecked(true);
592 int value = global_capture_opts.file_duration;
593 if (value > 3600 && value % 3600 == 0) {
594 ui->stopSecsSpinBox->setValue(value / 3600);
595 ui->stopSecsComboBox->setCurrentIndex(2);
596 } else if (value > 60 && value % 60 == 0) {
597 ui->stopSecsSpinBox->setValue(value / 60);
598 ui->stopSecsComboBox->setCurrentIndex(1);
600 ui->stopSecsSpinBox->setValue(value);
601 ui->stopSecsComboBox->setCurrentIndex(0);
605 if (global_capture_opts.has_autostop_packets) {
606 ui->stopPktCheckBox->setChecked(true);
607 ui->stopPktSpinBox->setValue(global_capture_opts.autostop_packets);
610 if (global_capture_opts.has_autostop_files) {
611 ui->stopFilesCheckBox->setChecked(true);
612 ui->stopFilesSpinBox->setValue(global_capture_opts.autostop_files);
615 ui->cbUpdatePacketsRT->setChecked(global_capture_opts.real_time_mode);
616 ui->cbAutoScroll->setChecked(true);
617 ui->cbExtraCaptureInfo->setChecked(global_capture_opts.show_info);
619 ui->cbResolveMacAddresses->setChecked(gbl_resolv_flags.mac_name);
620 ui->cbResolveNetworkNames->setChecked(gbl_resolv_flags.network_name);
621 ui->cbResolveTransportNames->setChecked(gbl_resolv_flags.transport_name);
623 // Rebuild the interface list without disturbing the main welcome screen.
624 disconnect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
625 ui->interfaceTree->clear();
627 #ifdef SHOW_BUFFER_COLUMN
631 gboolean hassnap, pmode;
632 QList<QTreeWidgetItem *> selected_interfaces;
634 disconnect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
636 if (global_capture_opts.all_ifaces->len > 0) {
639 for (guint device_idx = 0; device_idx < global_capture_opts.all_ifaces->len; device_idx++) {
640 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
642 /* Continue if capture device is hidden */
643 if (device->hidden) {
647 // Traffic sparklines
648 InterfaceTreeWidgetItem *ti = new InterfaceTreeWidgetItem(ui->interfaceTree);
649 ti->setFlags(ti->flags() | Qt::ItemIsEditable);
650 ti->setData(col_interface_, Qt::UserRole, QString(device->name));
651 ti->setData(col_traffic_, Qt::UserRole, qVariantFromValue(ti->points));
653 ti->setText(col_interface_, device->display_name);
654 if (device->no_addresses > 0) {
655 QString addr_str = tr("%1: %2").arg(device->no_addresses > 1 ? tr("Addresses") : tr("Address")).arg(device->addresses);
656 QTreeWidgetItem *addr_ti = new QTreeWidgetItem(ti);
658 addr_str.replace('\n', ", ");
659 addr_ti->setText(0, addr_str);
660 addr_ti->setFlags(addr_ti->flags() ^ Qt::ItemIsSelectable);
661 addr_ti->setFirstColumnSpanned(true);
662 addr_ti->setToolTip(col_interface_, QString("<span>%1</span>").arg(addr_str));
663 ti->setToolTip(col_interface_, QString("<span>%1</span>").arg(addr_str));
665 ti->setToolTip(col_interface_, tr("no addresses"));
668 if (capture_dev_user_pmode_find(device->name, &pmode)) {
669 device->pmode = pmode;
671 if (capture_dev_user_snaplen_find(device->name, &hassnap, &snaplen)) {
672 /* Default snap length set in preferences */
673 device->snaplen = snaplen;
674 device->has_snaplen = hassnap;
676 /* No preferences set yet, use default values */
677 device->snaplen = WTAP_MAX_PACKET_SIZE;
678 device->has_snaplen = FALSE;
681 #ifdef SHOW_BUFFER_COLUMN
682 if (capture_dev_user_buffersize_find(device->name) != -1) {
683 buffer = capture_dev_user_buffersize_find(device->name);
684 device->buffer = buffer;
686 device->buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
689 ti->updateInterfaceColumns(device);
691 if (device->selected) {
692 selected_interfaces << ti;
697 connect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
699 foreach (QTreeWidgetItem *ti, selected_interfaces) {
700 ti->setSelected(true);
702 connect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
703 updateSelectedFilter();
705 // Manually or automatically size some columns as needed.
706 int one_em = fontMetrics().height();
707 for (int col = 0; col < ui->interfaceTree->topLevelItemCount(); col++) {
710 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
713 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
716 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
719 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
722 ui->interfaceTree->resizeColumnToContents(col);
727 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled((global_capture_opts.num_selected > 0)? true: false);
731 stat_timer_ = new QTimer(this);
732 connect(stat_timer_, SIGNAL(timeout()), this, SLOT(updateStatistics()));
733 stat_timer_->start(stat_update_interval_);
737 void CaptureInterfacesDialog::showEvent(QShowEvent *)
742 void CaptureInterfacesDialog::refreshInterfaceList()
745 emit interfaceListChanged();
748 void CaptureInterfacesDialog::updateLocalInterfaces()
753 void CaptureInterfacesDialog::updateStatistics(void)
757 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
759 for (guint if_idx = 0; if_idx < global_capture_opts.all_ifaces->len; if_idx++) {
760 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
764 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, if_idx);
765 QString device_name = ti->text(col_interface_);
766 if (device_name.compare(device->display_name) || device->hidden || device->type == IF_PIPE) {
769 QList<int> points = ti->data(col_traffic_, Qt::UserRole).value<QList<int> >();
770 points.append(device->packet_diff);
771 ti->setData(col_traffic_, Qt::UserRole, qVariantFromValue(points));
774 ui->interfaceTree->viewport()->update();
777 void CaptureInterfacesDialog::on_compileBPF_clicked()
779 QStringList interfaces;
780 foreach (QTreeWidgetItem *ti, ui->interfaceTree->selectedItems()) {
781 interfaces.append(ti->text(col_interface_));
784 QString filter = ui->captureFilterComboBox->currentText();
785 CompiledFilterOutput *cfo = new CompiledFilterOutput(this, interfaces, filter);
790 bool CaptureInterfacesDialog::saveOptionsToPreferences()
792 if (ui->rbPcapng->isChecked()) {
793 global_capture_opts.use_pcapng = true;
794 prefs.capture_pcap_ng = true;
796 global_capture_opts.use_pcapng = false;
797 prefs.capture_pcap_ng = false;
800 QString filename = ui->filenameLineEdit->text();
801 if (filename.length() > 0) {
802 /* User specified a file to which the capture should be written. */
803 global_capture_opts.saving_to_file = true;
804 global_capture_opts.save_file = qstring_strdup(filename);
805 global_capture_opts.orig_save_file = qstring_strdup(filename);
806 /* Save the directory name for future file dialogs. */
807 set_last_open_dir(get_dirname(filename.toUtf8().data()));
809 /* User didn't specify a file; save to a temporary file. */
810 global_capture_opts.save_file = NULL;
813 global_capture_opts.has_ring_num_files = ui->RbCheckBox->isChecked();
815 if (global_capture_opts.has_ring_num_files) {
816 global_capture_opts.ring_num_files = ui->RbSpinBox->value();
817 if (global_capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
818 global_capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
819 #if RINGBUFFER_MIN_NUM_FILES > 0
820 else if (global_capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
821 global_capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
824 global_capture_opts.multi_files_on = ui->gbNewFileAuto->isChecked();
825 if (global_capture_opts.multi_files_on) {
826 global_capture_opts.has_file_duration = ui->SecsCheckBox->isChecked();
827 if (global_capture_opts.has_file_duration) {
828 global_capture_opts.file_duration = ui->SecsSpinBox->value();
829 int index = ui->SecsComboBox->currentIndex();
831 case 1: global_capture_opts.file_duration *= 60;
833 case 2: global_capture_opts.file_duration *= 3600;
837 global_capture_opts.has_autostop_filesize = ui->MBCheckBox->isChecked();
838 if (global_capture_opts.has_autostop_filesize) {
839 global_capture_opts.autostop_filesize = ui->MBSpinBox->value();
840 int index = ui->MBComboBox->currentIndex();
842 case 1: if (global_capture_opts.autostop_filesize > 2000) {
843 QMessageBox::warning(this, tr("Error"),
844 tr("Multiple files: Requested filesize too large! The filesize cannot be greater than 2 GiB."));
847 global_capture_opts.autostop_filesize *= 1000;
850 case 2: if (global_capture_opts.autostop_filesize > 2) {
851 QMessageBox::warning(this, tr("Error"),
852 tr("Multiple files: Requested filesize too large! The filesize cannot be greater than 2 GiB."));
855 global_capture_opts.autostop_filesize *= 1000000;
860 /* test if the settings are ok for a ringbuffer */
861 if (global_capture_opts.save_file == NULL) {
862 QMessageBox::warning(this, tr("Error"),
863 tr("Multiple files: No capture file name given! You must specify a filename if you want to use multiple files."));
865 } else if (!global_capture_opts.has_autostop_filesize && !global_capture_opts.has_file_duration) {
866 QMessageBox::warning(this, tr("Error"),
867 tr("Multiple files: No file limit given! You must specify a file size or duration at which is switched to the next capture file\n if you want to use multiple files."));
868 g_free(global_capture_opts.save_file);
869 global_capture_opts.save_file = NULL;
873 global_capture_opts.has_autostop_filesize = ui->stopMBCheckBox->isChecked();
874 if (global_capture_opts.has_autostop_filesize) {
875 global_capture_opts.autostop_filesize = ui->stopMBSpinBox->value();
876 int index = ui->stopMBComboBox->currentIndex();
878 case 1: if (global_capture_opts.autostop_filesize > 2000) {
879 QMessageBox::warning(this, tr("Error"),
880 tr("Multiple files: Requested filesize too large! The filesize cannot be greater than 2 GiB."));
883 global_capture_opts.autostop_filesize *= 1000;
886 case 2: if (global_capture_opts.autostop_filesize > 2) {
887 QMessageBox::warning(this, tr("Error"),
888 tr("Multiple files: Requested filesize too large! The filesize cannot be greater than 2 GiB."));
891 global_capture_opts.autostop_filesize *= 1000000;
898 global_capture_opts.has_autostop_duration = ui->stopSecsCheckBox->isChecked();
899 if (global_capture_opts.has_autostop_duration) {
900 global_capture_opts.autostop_duration = ui->stopSecsSpinBox->value();
901 int index = ui->stopSecsComboBox->currentIndex();
903 case 1: global_capture_opts.autostop_duration *= 60;
905 case 2: global_capture_opts.autostop_duration *= 3600;
910 global_capture_opts.has_autostop_packets = ui->stopPktCheckBox->isChecked();
911 if (global_capture_opts.has_autostop_packets) {
912 global_capture_opts.autostop_packets = ui->stopPktSpinBox->value();
915 global_capture_opts.has_autostop_files = ui->stopFilesCheckBox->isChecked();
916 if (global_capture_opts.has_autostop_files) {
917 global_capture_opts.autostop_files = ui->stopFilesSpinBox->value();
922 for (int col = col_link_; col <= col_filter_; col++) {
923 if (ui->interfaceTree->isColumnHidden(col)) {
926 /* All entries are separated by comma. There is also one before the first interface to be able to identify
927 word boundaries. As 'lo' is part of 'nflog' an exact match is necessary. */
931 QStringList link_list;
933 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
934 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
935 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
936 device = getDeviceByName(device_name);
937 if (!device || device->active_dlt == -1) {
940 link_list << QString("%1(%2)").arg(device->name).arg(device->active_dlt);
942 g_free(prefs.capture_devices_linktypes);
943 prefs.capture_devices_linktypes = qstring_strdup(link_list.join(","));
946 #ifdef SHOW_BUFFER_COLUMN
949 QStringList buffer_size_list;
951 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
952 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
953 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
954 device = getDeviceByName(device_name);
955 if (!device || device->buffer == -1) {
958 buffer_size_list << QString("%1(%2)").arg(device->name).arg(device->buffer);
960 g_free(prefs.capture_devices_buffersize);
961 prefs.capture_devices_buffersize = qstring_strdup(buffer_size_list.join(","));
964 #endif // HAVE_BUFFER_SETTING
967 QStringList snaplen_list;
969 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
970 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
971 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
972 device = getDeviceByName(device_name);
973 if (!device) continue;
974 snaplen_list << QString("%1:%2(%3)")
976 .arg(device->has_snaplen)
977 .arg(device->has_snaplen ? device->snaplen : WTAP_MAX_PACKET_SIZE);
979 g_free(prefs.capture_devices_snaplen);
980 prefs.capture_devices_snaplen = qstring_strdup(snaplen_list.join(","));
985 QStringList pmode_list;
987 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
988 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
989 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
990 device = getDeviceByName(device_name);
991 if (!device || device->pmode == -1) {
994 pmode_list << QString("%1(%2)").arg(device->name).arg(device->pmode);
996 g_free(prefs.capture_devices_pmode);
997 prefs.capture_devices_pmode = qstring_strdup(pmode_list.join(","));
1001 #ifdef SHOW_MONITOR_COLUMN
1004 QStringList monitor_list;
1006 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1007 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1008 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1009 device = getDeviceByName(device_name);
1010 if (!device || !device->monitor_mode_supported || (device->monitor_mode_supported && !device->monitor_mode_enabled)) {
1013 monitor_list << device->name;
1015 g_free(prefs.capture_devices_monitor_mode);
1016 prefs.capture_devices_monitor_mode = qstring_strdup(monitor_list.join(","));
1019 #endif // HAVE_MONITOR_SETTING
1022 // The device cfilter should have been applied at this point.
1023 // We shouldn't change it here.
1026 // XXX Update selected interfaces only?
1027 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1028 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1029 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1030 device = getDeviceByName(device_name);
1031 if (!device) continue;
1032 g_free(device->cfilter);
1033 if (ti->text(col_filter_).isEmpty()) {
1034 device->cfilter = NULL;
1036 device->cfilter = qstring_strdup(ti->text(col_filter_));
1043 if (!prefs.gui_use_pref_save) {
1049 void CaptureInterfacesDialog::updateSelectedFilter()
1051 // Should match MainWelcome::interfaceSelected.
1052 QPair <const QString, bool> sf_pair = CaptureFilterEdit::getSelectedFilter();
1053 const QString user_filter = sf_pair.first;
1054 bool conflict = sf_pair.second;
1057 ui->captureFilterComboBox->lineEdit()->clear();
1058 ui->captureFilterComboBox->setConflict(true);
1060 ui->captureFilterComboBox->lineEdit()->setText(user_filter);
1064 void CaptureInterfacesDialog::on_manageButton_clicked()
1066 if (saveOptionsToPreferences()) {
1067 ManageInterfacesDialog *dlg = new ManageInterfacesDialog(this);
1072 void CaptureInterfacesDialog::changeEvent(QEvent* event)
1076 switch (event->type())
1078 case QEvent::LanguageChange:
1079 ui->retranslateUi(this);
1085 QDialog::changeEvent(event);
1088 interface_t *CaptureInterfacesDialog::getDeviceByName(const QString device_name)
1090 for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
1091 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
1092 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
1100 // InterfaceTreeItem
1102 bool InterfaceTreeWidgetItem::operator< (const QTreeWidgetItem &other) const {
1103 if (treeWidget()->sortColumn() == col_traffic_) {
1104 QList<int> points = data(col_traffic_, Qt::UserRole).value<QList<int> >();
1105 QList<int> other_points = other.data(col_traffic_, Qt::UserRole).value<QList<int> >();
1106 double avg = 0, other_avg = 0;
1107 foreach (int point, points) {
1108 avg += (double) point / points.length();
1110 foreach (int point, other_points) {
1111 other_avg += (double) point / other_points.length();
1113 return avg < other_avg;
1115 return QTreeWidgetItem::operator<(other);
1120 // InterfaceTreeDelegate
1123 #include <QComboBox>
1125 InterfaceTreeDelegate::InterfaceTreeDelegate(QObject *parent)
1126 : QStyledItemDelegate(parent), tree_(NULL)
1131 InterfaceTreeDelegate::~InterfaceTreeDelegate()
1136 QWidget* InterfaceTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &idx) const
1139 #ifdef SHOW_BUFFER_COLUMN
1140 gint buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
1142 guint snap = WTAP_MAX_PACKET_SIZE;
1143 GList *links = NULL;
1145 if (idx.column() > 1 && idx.data().toString().compare(UTF8_EM_DASH)) {
1146 QTreeWidgetItem *ti = tree_->topLevelItem(idx.row());
1147 QString interface_name = ti->text(col_interface_);
1148 interface_t *device = find_device_by_if_name(interface_name);
1151 #ifdef SHOW_BUFFER_COLUMN
1152 buffer = device->buffer;
1154 snap = device->snaplen;
1155 links = device->links;
1157 switch (idx.column()) {
1158 case col_interface_:
1165 QStringList valid_link_types;
1167 // XXX The GTK+ UI fills in all link types, valid or not. We add
1168 // only the valid ones. If we *do* wish to include invalid link
1169 // types we'll have to jump through the hoops necessary to disable
1172 for (list = links; list != NULL; list = g_list_next(list)) {
1173 linkr = (link_row*)(list->data);
1174 if (linkr->dlt >= 0) {
1175 valid_link_types << linkr->name;
1179 if (valid_link_types.size() < 2) {
1182 QComboBox *cb = new QComboBox(parent);
1183 cb->addItems(valid_link_types);
1185 connect(cb, SIGNAL(currentIndexChanged(QString)), this, SLOT(linkTypeChanged(QString)));
1191 QSpinBox *sb = new QSpinBox(parent);
1192 sb->setRange(1, 65535);
1194 sb->setWrapping(true);
1195 connect(sb, SIGNAL(valueChanged(int)), this, SLOT(snapshotLengthChanged(int)));
1199 #ifdef SHOW_BUFFER_COLUMN
1202 QSpinBox *sb = new QSpinBox(parent);
1203 sb->setRange(1, 65535);
1204 sb->setValue(buffer);
1205 sb->setWrapping(true);
1206 connect(sb, SIGNAL(valueChanged(int)), this, SLOT(bufferSizeChanged(int)));
1213 CaptureFilterCombo *cf = new CaptureFilterCombo(parent, true);
1214 connect(cf->lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString)));
1221 // ti->setSizeHint(index.column(), w->sizeHint());
1227 bool InterfaceTreeDelegate::eventFilter(QObject *object, QEvent *event)
1229 QComboBox * comboBox = dynamic_cast<QComboBox*>(object);
1231 if (event->type() == QEvent::MouseButtonRelease) {
1232 comboBox->showPopup();
1236 return QStyledItemDelegate::eventFilter(object, event);
1241 void InterfaceTreeDelegate::linkTypeChanged(QString selected_link_type)
1245 interface_t *device;
1247 QTreeWidgetItem *ti = tree_->currentItem();
1251 QString interface_name = ti->text(col_interface_);
1252 device = find_device_by_if_name(interface_name);
1256 for (list = device->links; list != NULL; list = g_list_next(list)) {
1257 temp = (link_row*) (list->data);
1258 if (!selected_link_type.compare(temp->name)) {
1259 device->active_dlt = temp->dlt;
1262 // XXX We might want to verify that active_dlt is valid at this point.
1265 void InterfaceTreeDelegate::snapshotLengthChanged(int value)
1267 interface_t *device;
1268 QTreeWidgetItem *ti = tree_->currentItem();
1272 QString interface_name = ti->text(col_interface_);
1273 device = find_device_by_if_name(interface_name);
1277 if (value != WTAP_MAX_PACKET_SIZE) {
1278 device->has_snaplen = true;
1279 device->snaplen = value;
1281 device->has_snaplen = false;
1282 device->snaplen = WTAP_MAX_PACKET_SIZE;
1286 void InterfaceTreeDelegate::bufferSizeChanged(int value)
1288 #ifdef SHOW_BUFFER_COLUMN
1289 interface_t *device;
1290 QTreeWidgetItem *ti = tree_->currentItem();
1294 QString interface_name = ti->text(col_interface_);
1295 device = find_device_by_if_name(interface_name);
1299 device->buffer = value;
1305 #endif /* HAVE_LIBPCAP */
1313 * indent-tabs-mode: nil
1316 * ex: set shiftwidth=4 tabstop=8 expandtab:
1317 * :indentSize=4:tabSize=8:noTabs=true: