1 /* extcap_options_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 <extcap_options_dialog.h>
27 #include <ui_extcap_options_dialog.h>
29 #include <wireshark_application.h>
32 #include <QMessageBox>
34 #include <QHBoxLayout>
35 #include <QVBoxLayout>
36 #include <QGridLayout>
38 #include <QDesktopServices>
40 #include "ringbuffer.h"
41 #include "ui/capture_ui_utils.h"
42 #include "ui/capture_globals.h"
43 #include "ui/iface_lists.h"
44 #include "ui/last_open_dir.h"
46 #include "ui/ws_ui_util.h"
48 #include <wsutil/utf8_entities.h>
51 #include <epan/addr_resolv.h>
52 #include <wsutil/filesystem.h>
55 #include <extcap_parser.h>
57 #include <ui/qt/utils/qt_ui_utils.h>
59 #include <epan/prefs.h>
60 #include <ui/preference_utils.h>
62 #include <ui/qt/wireshark_application.h>
63 #include <ui/qt/utils/variant_pointer.h>
65 #include <ui/qt/extcap_argument.h>
66 #include <ui/qt/extcap_argument_file.h>
67 #include <ui/qt/extcap_argument_multiselect.h>
69 ExtcapOptionsDialog::ExtcapOptionsDialog(QWidget *parent) :
71 ui(new Ui::ExtcapOptionsDialog),
77 setWindowTitle(wsApp->windowTitleString(tr("Interface Options")));
79 ui->checkSaveOnStart->setCheckState(prefs.extcap_save_on_start ? Qt::Checked : Qt::Unchecked);
81 ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Start"));
84 ExtcapOptionsDialog * ExtcapOptionsDialog::createForDevice(QString &dev_name, QWidget *parent)
87 ExtcapOptionsDialog * resultDialog = NULL;
88 bool dev_found = false;
91 if ( dev_name.length() == 0 )
94 for (if_idx = 0; if_idx < global_capture_opts.all_ifaces->len; if_idx++)
96 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, if_idx);
97 if (dev_name.compare(QString(device->name)) == 0 && device->if_info.type == IF_EXTCAP)
107 resultDialog = new ExtcapOptionsDialog(parent);
108 resultDialog->device_name = QString(dev_name);
109 resultDialog->device_idx = if_idx;
111 resultDialog->setWindowTitle(wsApp->windowTitleString(tr("Interface Options") + ": " + device->display_name));
113 resultDialog->updateWidgets();
115 /* mark required fields */
116 resultDialog->anyValueChanged();
122 ExtcapOptionsDialog::~ExtcapOptionsDialog()
127 void ExtcapOptionsDialog::on_buttonBox_accepted()
129 if (saveOptionToCaptureInfo()) {
130 /* Starting a new capture with those values */
131 prefs.extcap_save_on_start = ui->checkSaveOnStart->checkState() == Qt::Checked;
133 if ( prefs.extcap_save_on_start )
140 void ExtcapOptionsDialog::anyValueChanged()
142 bool allowStart = true;
144 ExtcapArgumentList::const_iterator iter;
146 /* All arguments are being iterated, to ensure, that any error handling catches all arguments */
147 for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd(); ++iter)
149 /* The dynamic casts are necessary, because we come here using the Signal/Slot system
150 * of Qt, and -in short- Q_OBJECT classes cannot be multiple inherited. Another possibility
151 * would be to use Q_INTERFACE, but this causes way more nightmares, and we really just
152 * need here an explicit cast for the check functionality */
153 if ( dynamic_cast<ExtArgBool *>((*iter)) != NULL)
155 if ( ! ((ExtArgBool *)*iter)->isValid() )
158 else if ( dynamic_cast<ExtArgRadio *>((*iter)) != NULL)
160 if ( ! ((ExtArgRadio *)*iter)->isValid() )
163 else if ( dynamic_cast<ExtArgSelector *>((*iter)) != NULL)
165 if ( ! ((ExtArgSelector *)*iter)->isValid() )
168 else if ( dynamic_cast<ExtArgMultiSelect *>((*iter)) != NULL)
170 if ( ! ((ExtArgMultiSelect *)*iter)->isValid() )
173 else if ( dynamic_cast<ExtcapArgumentFileSelection *>((*iter)) != NULL)
175 if ( ! ((ExtcapArgumentFileSelection *)*iter)->isValid() )
178 else if ( dynamic_cast<ExtArgNumber *>((*iter)) != NULL)
180 if ( ! ((ExtArgNumber *)*iter)->isValid() )
183 else if ( dynamic_cast<ExtArgText *>((*iter)) != NULL)
185 if ( ! ((ExtArgText *)*iter)->isValid() )
188 else if ( dynamic_cast<ExtArgTimestamp *>((*iter)) != NULL)
190 if ( ! ((ExtArgTimestamp *)*iter)->isValid() )
194 if ( ! (*iter)->isValid() )
198 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowStart);
201 void ExtcapOptionsDialog::loadArguments()
203 GList * arguments = NULL, * walker = NULL, * item = NULL;
204 ExtcapArgument * argument = NULL;
206 if ( device_name.length() == 0 )
209 extcapArguments.clear();
211 arguments = g_list_first(extcap_get_if_configuration((const char *)( device_name.toStdString().c_str() ) ));
213 ExtcapArgumentList required;
214 ExtcapArgumentList optional;
217 while ( walker != NULL )
219 item = g_list_first((GList *)(walker->data));
220 while ( item != NULL )
222 argument = ExtcapArgument::create((extcap_arg *)(item->data));
223 if ( argument != NULL )
225 if ( argument->isRequired() )
226 required << argument;
228 optional << argument;
233 walker = g_list_next(walker);
236 if ( required.length() > 0 )
237 extcapArguments << required;
239 if ( optional.length() > 0 )
240 extcapArguments << optional;
242 /* argument items are now owned by ExtcapArgument. Only free the lists */
243 extcap_free_if_configuration(arguments, FALSE);
246 void ExtcapOptionsDialog::updateWidgets()
248 QWidget * lblWidget = NULL, *editWidget = NULL;
249 ExtcapArgument * argument = NULL;
250 bool allowStart = true;
252 unsigned int counter = 0;
254 if ( device_name.length() == 0 )
257 /* find existing layout */
258 if (ui->verticalLayout->children().count() > 0)
260 QGridLayout * layout = (QGridLayout *)ui->verticalLayout->itemAt(0);
261 ui->verticalLayout->removeItem(layout);
262 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
265 QGridLayout * layout = new QGridLayout();
267 /* Load all extcap arguments */
271 ExtcapArgumentList::iterator iter = extcapArguments.begin();
272 while ( iter != extcapArguments.end() )
274 argument = (ExtcapArgument *)(*iter);
275 lblWidget = argument->createLabel((QWidget *)this);
276 if ( lblWidget != NULL )
278 layout->addWidget(lblWidget, counter, 0, Qt::AlignVCenter);
279 editWidget = argument->createEditor((QWidget *) this);
280 if ( editWidget != NULL )
282 editWidget->setProperty(QString("extcap").toLocal8Bit(), VariantPointer<ExtcapArgument>::asQVariant(argument));
283 layout->addWidget(editWidget, counter, 1, Qt::AlignVCenter);
286 if ( argument->isRequired() && ! argument->isValid() )
289 connect(argument, SIGNAL(valueChanged()), this, SLOT(anyValueChanged()));
298 setStyleSheet ( "QLabel[isRequired=\"true\"] { font-weight: bold; } ");
300 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowStart);
302 ui->verticalLayout->addLayout(layout);
303 ui->verticalLayout->addSpacerItem(new QSpacerItem(20, 100, QSizePolicy::Minimum, QSizePolicy::Expanding));
311 // Not sure why we have to do this manually.
312 void ExtcapOptionsDialog::on_buttonBox_rejected()
317 void ExtcapOptionsDialog::on_buttonBox_helpRequested()
320 QString interface_help = NULL;
322 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
323 interface_help = QString(extcap_get_help_for_ifname(device->name));
324 /* The extcap interface didn't provide an help. Let's go with the default */
325 if (interface_help.isEmpty()) {
326 wsApp->helpTopicAction(HELP_EXTCAP_OPTIONS_DIALOG);
330 QUrl help_url(interface_help);
332 /* The help is not a local file, open it and exit */
333 if (help_url.scheme().compare("file") != 0) {
334 QDesktopServices::openUrl(help_url);
338 /* The help information is a file url and has been provided as-is by the extcap.
339 Before attempting to open the it, check if it actually exists.
341 QFileInfo help_file(help_url.path());
342 if ( !help_file.exists() )
344 QMessageBox::warning(this, tr("Extcap Help cannot be found"),
345 QString(tr("The help for the extcap interface %1 cannot be found. Given file: %2"))
346 .arg(device->name).arg(help_url.path()),
352 bool ExtcapOptionsDialog::saveOptionToCaptureInfo()
354 GHashTable * ret_args;
357 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
358 ret_args = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
360 ExtcapArgumentList::const_iterator iter;
362 for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd(); ++iter)
364 QString call = (*iter)->call();
365 QString value = (*iter)->value();
367 if ((*iter)->argument()->arg_type != EXTCAP_ARG_BOOLFLAG && value.length() == 0)
370 if ( call.length() <= 0 )
373 if ( value.compare((*iter)->defaultValue()) == 0 )
376 gchar * call_string = g_strdup(call.toStdString().c_str());
377 gchar * value_string = g_strdup(value.toStdString().c_str());
379 g_hash_table_insert(ret_args, call_string, value_string );
382 if (device->external_cap_args_settings != NULL)
383 g_hash_table_unref(device->external_cap_args_settings);
384 device->external_cap_args_settings = ret_args;
388 void ExtcapOptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
390 /* Only the save button has the ActionRole */
391 if ( ui->buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole )
395 void ExtcapOptionsDialog::resetValues()
397 ExtcapArgumentList::const_iterator iter;
400 if (ui->verticalLayout->children().count() > 0)
402 QGridLayout * layout = (QGridLayout *)ui->verticalLayout->findChild<QGridLayout *>();
404 for ( int row = 0; row < layout->rowCount(); row++ )
406 QWidget * child = layout->itemAtPosition(row, 1)->widget();
410 /* Don't need labels, the edit widget contains the extcapargument property value */
411 ExtcapArgument * arg = 0;
412 QVariant prop = child->property(QString("extcap").toLocal8Bit());
414 if ( prop.isValid() )
416 arg = VariantPointer<ExtcapArgument>::asPtr(prop);
418 /* value<> can fail */
423 /* replacing the edit widget after resetting will lead to default value */
424 layout->removeItem(layout->itemAtPosition(row, 1));
425 QWidget * editWidget = arg->createEditor((QWidget *) this);
426 if ( editWidget != NULL )
428 editWidget->setProperty(QString("extcap").toLocal8Bit(), VariantPointer<ExtcapArgument>::asQVariant(arg));
429 layout->addWidget(editWidget, row, 1, Qt::AlignVCenter);
436 /* this stores all values to the preferences */
441 void ExtcapOptionsDialog::storeValues()
443 GHashTable * entries = g_hash_table_new(g_str_hash, g_str_equal);
444 ExtcapArgumentList::const_iterator iter;
448 /* All arguments are being iterated, to ensure, that any error handling catches all arguments */
449 for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd(); ++iter)
451 ExtcapArgument * argument = (ExtcapArgument *)(*iter);
453 /* The dynamic casts are necessary, because we come here using the Signal/Slot system
454 * of Qt, and -in short- Q_OBJECT classes cannot be multiple inherited. Another possibility
455 * would be to use Q_INTERFACE, but this causes way more nightmares, and we really just
456 * need here an explicit cast for the check functionality */
457 if ( dynamic_cast<ExtArgBool *>((*iter)) != NULL)
459 value = ((ExtArgBool *)*iter)->prefValue();
461 else if ( dynamic_cast<ExtArgRadio *>((*iter)) != NULL)
463 value = ((ExtArgRadio *)*iter)->prefValue();
465 else if ( dynamic_cast<ExtArgSelector *>((*iter)) != NULL)
467 value = ((ExtArgSelector *)*iter)->prefValue();
469 else if ( dynamic_cast<ExtArgMultiSelect *>((*iter)) != NULL)
471 value = ((ExtArgMultiSelect *)*iter)->prefValue();
473 else if ( dynamic_cast<ExtcapArgumentFileSelection *>((*iter)) != NULL)
475 value = ((ExtcapArgumentFileSelection *)*iter)->prefValue();
477 else if ( dynamic_cast<ExtArgNumber *>((*iter)) != NULL)
479 value = ((ExtArgNumber *)*iter)->prefValue();
481 else if ( dynamic_cast<ExtArgText *>((*iter)) != NULL)
483 value = ((ExtArgText *)*iter)->prefValue();
485 else if ( dynamic_cast<ExtArgTimestamp *>((*iter)) != NULL)
487 value = ((ExtArgTimestamp *)*iter)->prefValue();
490 value = (*iter)->prefValue();
492 QString key = argument->prefKey(device_name);
493 if (key.length() > 0)
495 gchar * val = g_strdup(value.length() == 0 ? " " : value.toStdString().c_str());
497 g_hash_table_insert(entries, g_strdup(key.toStdString().c_str()), val);
501 if ( g_hash_table_size(entries) > 0 )
503 if ( prefs_store_ext_multiple("extcap", entries) )
504 wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
510 #endif /* HAVE_LIBPCAP */
518 * indent-tabs-mode: nil
521 * ex: set shiftwidth=4 tabstop=8 expandtab:
522 * :indentSize=4:tabSize=8:noTabs=true: