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/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 "qt_ui_utils.h"
59 #include <epan/prefs.h>
60 #include <ui/preference_utils.h>
62 #include <ui/qt/wireshark_application.h>
64 #include <ui/qt/extcap_argument.h>
65 #include <ui/qt/extcap_argument_file.h>
66 #include <ui/qt/extcap_argument_multiselect.h>
68 ExtcapOptionsDialog::ExtcapOptionsDialog(QWidget *parent) :
70 ui(new Ui::ExtcapOptionsDialog),
76 setWindowTitle(wsApp->windowTitleString(tr("Extcap Interface Options")));
78 ui->checkSaveOnStart->setCheckState(prefs.extcap_save_on_start ? Qt::Checked : Qt::Unchecked);
80 ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Start"));
83 ExtcapOptionsDialog * ExtcapOptionsDialog::createForDevice(QString &dev_name, QWidget *parent)
86 ExtcapOptionsDialog * resultDialog = NULL;
87 bool dev_found = false;
90 if ( dev_name.length() == 0 )
93 for (if_idx = 0; if_idx < global_capture_opts.all_ifaces->len; if_idx++)
95 device = g_array_index(global_capture_opts.all_ifaces, interface_t, if_idx);
96 if (dev_name.compare(QString(device.name)) == 0 && device.if_info.type == IF_EXTCAP)
106 resultDialog = new ExtcapOptionsDialog(parent);
107 resultDialog->device_name = QString(dev_name);
108 resultDialog->device_idx = if_idx;
110 resultDialog->setWindowTitle(wsApp->windowTitleString(tr("Extcap Interface Options") + ": " + device.display_name));
112 resultDialog->updateWidgets();
114 /* mark required fields */
115 resultDialog->anyValueChanged();
121 ExtcapOptionsDialog::~ExtcapOptionsDialog()
126 void ExtcapOptionsDialog::on_buttonBox_accepted()
128 if (saveOptionToCaptureInfo()) {
129 /* Starting a new capture with those values */
130 prefs.extcap_save_on_start = ui->checkSaveOnStart->checkState() == Qt::Checked;
132 if ( prefs.extcap_save_on_start )
139 void ExtcapOptionsDialog::anyValueChanged()
141 bool allowStart = true;
143 ExtcapArgumentList::const_iterator iter;
145 /* All arguments are being iterated, to ensure, that any error handling catches all arguments */
146 for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd(); ++iter)
148 /* The dynamic casts are necessary, because we come here using the Signal/Slot system
149 * of Qt, and -in short- Q_OBJECT classes cannot be multiple inherited. Another possibility
150 * would be to use Q_INTERFACE, but this causes way more nightmares, and we really just
151 * need here an explicit cast for the check functionality */
152 if ( dynamic_cast<ExtArgBool *>((*iter)) != NULL)
154 if ( ! ((ExtArgBool *)*iter)->isValid() )
157 else if ( dynamic_cast<ExtArgRadio *>((*iter)) != NULL)
159 if ( ! ((ExtArgRadio *)*iter)->isValid() )
162 else if ( dynamic_cast<ExtArgSelector *>((*iter)) != NULL)
164 if ( ! ((ExtArgSelector *)*iter)->isValid() )
167 else if ( dynamic_cast<ExtArgMultiSelect *>((*iter)) != NULL)
169 if ( ! ((ExtArgMultiSelect *)*iter)->isValid() )
172 else if ( dynamic_cast<ExtcapArgumentFileSelection *>((*iter)) != NULL)
174 if ( ! ((ExtcapArgumentFileSelection *)*iter)->isValid() )
177 else if ( dynamic_cast<ExtArgNumber *>((*iter)) != NULL)
179 if ( ! ((ExtArgNumber *)*iter)->isValid() )
182 else if ( dynamic_cast<ExtArgText *>((*iter)) != NULL)
184 if ( ! ((ExtArgText *)*iter)->isValid() )
188 if ( ! (*iter)->isValid() )
192 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowStart);
195 void ExtcapOptionsDialog::loadArguments()
197 GList * arguments = NULL, * walker = NULL, * item = NULL;
198 ExtcapArgument * argument = NULL;
200 if ( device_name.length() == 0 )
203 extcapArguments.clear();
205 arguments = g_list_first(extcap_get_if_configuration((const char *)( device_name.toStdString().c_str() ) ));
207 ExtcapArgumentList required;
208 ExtcapArgumentList optional;
211 while ( walker != NULL )
213 item = g_list_first((GList *)(walker->data));
214 while ( item != NULL )
216 argument = ExtcapArgument::create((extcap_arg *)(item->data));
217 if ( argument != NULL )
219 if ( argument->isRequired() )
220 required << argument;
222 optional << argument;
227 walker = g_list_next(walker);
230 if ( required.length() > 0 )
231 extcapArguments << required;
233 if ( optional.length() > 0 )
234 extcapArguments << optional;
236 /* argument items are now owned by ExtcapArgument. Only free the lists */
237 extcap_free_if_configuration(arguments, FALSE);
240 void ExtcapOptionsDialog::updateWidgets()
242 QWidget * lblWidget = NULL, *editWidget = NULL;
243 ExtcapArgument * argument = NULL;
244 bool allowStart = true;
246 unsigned int counter = 0;
248 if ( device_name.length() == 0 )
251 /* find existing layout */
252 if (ui->verticalLayout->children().count() > 0)
254 QGridLayout * layout = (QGridLayout *)ui->verticalLayout->itemAt(0);
255 ui->verticalLayout->removeItem(layout);
256 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
259 QGridLayout * layout = new QGridLayout();
261 /* Load all extcap arguments */
265 ExtcapArgumentList::iterator iter = extcapArguments.begin();
266 while ( iter != extcapArguments.end() )
268 argument = (ExtcapArgument *)(*iter);
269 lblWidget = argument->createLabel((QWidget *)this);
270 if ( lblWidget != NULL )
272 layout->addWidget(lblWidget, counter, 0, Qt::AlignVCenter);
273 editWidget = argument->createEditor((QWidget *) this);
274 if ( editWidget != NULL )
276 editWidget->setProperty(QString("extcap").toLocal8Bit(), QVariant::fromValue(argument));
277 layout->addWidget(editWidget, counter, 1, Qt::AlignVCenter);
280 if ( argument->isRequired() && ! argument->isValid() )
283 connect(argument, SIGNAL(valueChanged()), this, SLOT(anyValueChanged()));
292 setStyleSheet ( "QLabel[isRequired=\"true\"] { font-weight: bold; } ");
294 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowStart);
296 ui->verticalLayout->addLayout(layout);
297 ui->verticalLayout->addSpacerItem(new QSpacerItem(20, 100, QSizePolicy::Minimum, QSizePolicy::Expanding));
305 // Not sure why we have to do this manually.
306 void ExtcapOptionsDialog::on_buttonBox_rejected()
311 void ExtcapOptionsDialog::on_buttonBox_helpRequested()
314 gchar * interface_help = NULL;
316 device = g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
317 interface_help = extcap_get_help_for_ifname(device.name);
321 QUrl help_url = QString(interface_help);
322 QDesktopServices::openUrl(help_url);
326 wsApp->helpTopicAction(HELP_EXTCAP_OPTIONS_DIALOG);
330 bool ExtcapOptionsDialog::saveOptionToCaptureInfo()
332 GHashTable * ret_args;
335 device = g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
336 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, device_idx);
338 ret_args = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
340 ExtcapArgumentList::const_iterator iter;
342 for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd(); ++iter)
344 QString call = (*iter)->call();
345 QString value = (*iter)->value();
347 if ((*iter)->argument()->arg_type != EXTCAP_ARG_BOOLFLAG && value.length() == 0)
350 if ( call.length() <= 0 )
353 if ( value.compare((*iter)->defaultValue()) == 0 )
356 gchar * call_string = g_strdup(call.toStdString().c_str());
357 gchar * value_string = g_strdup(value.toStdString().c_str());
359 g_hash_table_insert(ret_args, call_string, value_string );
362 if (device.external_cap_args_settings != NULL)
363 g_hash_table_unref(device.external_cap_args_settings);
364 device.external_cap_args_settings = ret_args;
366 g_array_insert_val(global_capture_opts.all_ifaces, device_idx, device);
371 void ExtcapOptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
373 /* Only the save button has the ActionRole */
374 if ( ui->buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole )
378 void ExtcapOptionsDialog::resetValues()
380 ExtcapArgumentList::const_iterator iter;
383 if (ui->verticalLayout->children().count() > 0)
385 QGridLayout * layout = (QGridLayout *)ui->verticalLayout->findChild<QGridLayout *>();
387 for ( int row = 0; row < layout->rowCount(); row++ )
389 QWidget * child = layout->itemAtPosition(row, 1)->widget();
393 /* Don't need labels, the edit widget contains the extcapargument property value */
394 ExtcapArgument * arg = 0;
395 QVariant prop = child->property(QString("extcap").toLocal8Bit());
397 if ( prop.isValid() && prop.canConvert<ExtcapArgument *>())
399 arg = prop.value<ExtcapArgument *>();
401 /* value<> can fail */
406 /* replacing the edit widget after resetting will lead to default value */
407 layout->removeItem(layout->itemAtPosition(row, 1));
408 QWidget * editWidget = arg->createEditor((QWidget *) this);
409 if ( editWidget != NULL )
411 editWidget->setProperty(QString("extcap").toLocal8Bit(), QVariant::fromValue(arg));
412 layout->addWidget(editWidget, row, 1, Qt::AlignVCenter);
419 /* this stores all values to the preferences */
424 void ExtcapOptionsDialog::storeValues()
426 GHashTable * entries = g_hash_table_new(g_str_hash, g_str_equal);
427 ExtcapArgumentList::const_iterator iter;
431 /* All arguments are being iterated, to ensure, that any error handling catches all arguments */
432 for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd(); ++iter)
434 ExtcapArgument * argument = (ExtcapArgument *)(*iter);
436 /* The dynamic casts are necessary, because we come here using the Signal/Slot system
437 * of Qt, and -in short- Q_OBJECT classes cannot be multiple inherited. Another possibility
438 * would be to use Q_INTERFACE, but this causes way more nightmares, and we really just
439 * need here an explicit cast for the check functionality */
440 if ( dynamic_cast<ExtArgBool *>((*iter)) != NULL)
442 value = ((ExtArgBool *)*iter)->prefValue();
444 else if ( dynamic_cast<ExtArgRadio *>((*iter)) != NULL)
446 value = ((ExtArgRadio *)*iter)->prefValue();
448 else if ( dynamic_cast<ExtArgSelector *>((*iter)) != NULL)
450 value = ((ExtArgSelector *)*iter)->prefValue();
452 else if ( dynamic_cast<ExtArgMultiSelect *>((*iter)) != NULL)
454 value = ((ExtArgMultiSelect *)*iter)->prefValue();
456 else if ( dynamic_cast<ExtcapArgumentFileSelection *>((*iter)) != NULL)
458 value = ((ExtcapArgumentFileSelection *)*iter)->prefValue();
460 else if ( dynamic_cast<ExtArgNumber *>((*iter)) != NULL)
462 value = ((ExtArgNumber *)*iter)->prefValue();
464 else if ( dynamic_cast<ExtArgText *>((*iter)) != NULL)
466 value = ((ExtArgText *)*iter)->prefValue();
469 value = (*iter)->prefValue();
471 QString key = argument->prefKey(device_name);
472 if (key.length() > 0)
474 gchar * val = g_strdup(value.length() == 0 ? " " : value.toStdString().c_str());
476 /* Setting the internally stored value for the preference to the new value */
477 extcap_pref_store((*iter)->argument(), val);
479 g_hash_table_insert(entries, g_strdup(key.toStdString().c_str()), val);
483 if ( g_hash_table_size(entries) > 0 )
485 if ( prefs_store_ext_multiple("extcap", entries) )
486 wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
492 #endif /* HAVE_LIBPCAP */
500 * indent-tabs-mode: nil
503 * ex: set shiftwidth=4 tabstop=8 expandtab:
504 * :indentSize=4:tabSize=8:noTabs=true: