1 /* interface_toolbar.cpp
2 *
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "config.h"
11
12 #include <errno.h>
13
14 #include "interface_toolbar.h"
15 #include <ui/qt/widgets/interface_toolbar_lineedit.h>
16 #include "simple_dialog.h"
17 #include "wireshark_application.h"
18 #include <ui_interface_toolbar.h>
19
20 #include "capture_opts.h"
21 #include "ui/capture_globals.h"
22 #include "sync_pipe.h"
23 #include "wsutil/file_util.h"
24
25 #ifdef _WIN32
26 #include <wsutil/win32-utils.h>
27 #endif
28
29 #include <QCheckBox>
30 #include <QComboBox>
31 #include <QDesktopServices>
32 #include <QLineEdit>
33 #include <QPushButton>
34 #include <QThread>
35 #include <QUrl>
36
37 static const char *interface_type_property = "control_type";
38 static const char *interface_role_property = "control_role";
39
40 // From interface control protocol.
41 enum InterfaceControlCommand {
42 commandControlInitialized = 0,
43 commandControlSet = 1,
44 commandControlAdd = 2,
45 commandControlRemove = 3,
46 commandControlEnable = 4,
47 commandControlDisable = 5,
48 commandStatusMessage = 6,
49 commandInformationMessage = 7,
50 commandWarningMessage = 8,
51 commandErrorMessage = 9
52 };
53
54 // To do:
55 // - Move control pipe handling to extcap
56
InterfaceToolbar(QWidget * parent,const iface_toolbar * toolbar)57 InterfaceToolbar::InterfaceToolbar(QWidget *parent, const iface_toolbar *toolbar) :
58 QFrame(parent),
59 ui(new Ui::InterfaceToolbar),
60 help_link_(toolbar->help),
61 use_spacer_(true)
62 {
63 ui->setupUi(this);
64
65 // Fill inn interfaces list and initialize default interface values
66 for (GList *walker = toolbar->ifnames; walker; walker = walker->next)
67 {
68 QString ifname((gchar *)walker->data);
69 interface_[ifname].reader_thread = NULL;
70 interface_[ifname].out_fd = -1;
71 }
72
73 initializeControls(toolbar);
74
75 #ifdef Q_OS_MAC
76 foreach (QWidget *w, findChildren<QWidget *>())
77 {
78 w->setAttribute(Qt::WA_MacSmallSize, true);
79 }
80 #endif
81
82 if (!use_spacer_)
83 {
84 ui->horizontalSpacer->changeSize(0,0, QSizePolicy::Fixed, QSizePolicy::Fixed);
85 }
86
87 updateWidgets();
88 }
89
~InterfaceToolbar()90 InterfaceToolbar::~InterfaceToolbar()
91 {
92 foreach (QString ifname, interface_.keys())
93 {
94 foreach (int num, control_widget_.keys())
95 {
96 if (interface_[ifname].log_dialog.contains(num))
97 {
98 interface_[ifname].log_dialog[num]->close();
99 }
100 }
101 }
102
103 delete ui;
104 }
105
initializeControls(const iface_toolbar * toolbar)106 void InterfaceToolbar::initializeControls(const iface_toolbar *toolbar)
107 {
108 for (GList *walker = toolbar->controls; walker; walker = walker->next)
109 {
110 iface_toolbar_control *control = (iface_toolbar_control *)walker->data;
111
112 if (control_widget_.contains(control->num))
113 {
114 // Already have a widget with this number
115 continue;
116 }
117
118 QWidget *widget = NULL;
119 switch (control->ctrl_type)
120 {
121 case INTERFACE_TYPE_BOOLEAN:
122 widget = createCheckbox(control);
123 break;
124
125 case INTERFACE_TYPE_BUTTON:
126 widget = createButton(control);
127 break;
128
129 case INTERFACE_TYPE_SELECTOR:
130 widget = createSelector(control);
131 break;
132
133 case INTERFACE_TYPE_STRING:
134 widget = createString(control);
135 break;
136
137 default:
138 // Not supported
139 break;
140 }
141
142 if (widget)
143 {
144 widget->setProperty(interface_type_property, control->ctrl_type);
145 widget->setProperty(interface_role_property, control->ctrl_role);
146 control_widget_[control->num] = widget;
147 }
148 }
149 }
150
setDefaultValue(int num,const QByteArray & value)151 void InterfaceToolbar::setDefaultValue(int num, const QByteArray &value)
152 {
153 foreach (QString ifname, interface_.keys())
154 {
155 // Adding default value to all interfaces
156 interface_[ifname].value[num] = value;
157 }
158 default_value_[num] = value;
159 }
160
createCheckbox(iface_toolbar_control * control)161 QWidget *InterfaceToolbar::createCheckbox(iface_toolbar_control *control)
162 {
163 QCheckBox *checkbox = new QCheckBox(QString().fromUtf8(control->display));
164 checkbox->setToolTip(QString().fromUtf8(control->tooltip));
165
166 if (control->default_value.boolean)
167 {
168 checkbox->setCheckState(Qt::Checked);
169 QByteArray default_value(1, 1);
170 setDefaultValue(control->num, default_value);
171 }
172
173 connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(onCheckBoxChanged(int)));
174
175 ui->leftLayout->addWidget(checkbox);
176
177 return checkbox;
178 }
179
createButton(iface_toolbar_control * control)180 QWidget *InterfaceToolbar::createButton(iface_toolbar_control *control)
181 {
182 QPushButton *button = new QPushButton(QString().fromUtf8((gchar *)control->display));
183 button->setMaximumHeight(27);
184 button->setToolTip(QString().fromUtf8(control->tooltip));
185
186 switch (control->ctrl_role)
187 {
188 case INTERFACE_ROLE_CONTROL:
189 setDefaultValue(control->num, (gchar *)control->display);
190 connect(button, SIGNAL(clicked()), this, SLOT(onControlButtonClicked()));
191 break;
192
193 case INTERFACE_ROLE_HELP:
194 connect(button, SIGNAL(clicked()), this, SLOT(onHelpButtonClicked()));
195 if (help_link_.isEmpty())
196 {
197 // No help URL provided
198 button->hide();
199 }
200 break;
201
202 case INTERFACE_ROLE_LOGGER:
203 connect(button, SIGNAL(clicked()), this, SLOT(onLogButtonClicked()));
204 break;
205
206 case INTERFACE_ROLE_RESTORE:
207 connect(button, SIGNAL(clicked()), this, SLOT(onRestoreButtonClicked()));
208 break;
209
210 default:
211 // Not supported
212 break;
213 }
214
215 ui->rightLayout->addWidget(button);
216
217 return button;
218 }
219
createSelector(iface_toolbar_control * control)220 QWidget *InterfaceToolbar::createSelector(iface_toolbar_control *control)
221 {
222 QLabel *label = new QLabel(QString().fromUtf8(control->display));
223 label->setToolTip(QString().fromUtf8(control->tooltip));
224 QComboBox *combobox = new QComboBox();
225 combobox->setToolTip(QString().fromUtf8(control->tooltip));
226 combobox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
227
228 for (GList *walker = control->values; walker; walker = walker->next)
229 {
230 iface_toolbar_value *val = (iface_toolbar_value *)walker->data;
231 QString value = QString().fromUtf8((gchar *)val->value);
232 if (value.isEmpty())
233 {
234 // Invalid value
235 continue;
236 }
237 QString display = QString().fromUtf8((gchar *)val->display);
238 QByteArray interface_value;
239
240 interface_value.append(value.toUtf8());
241 if (display.isEmpty())
242 {
243 display = value;
244 }
245 else
246 {
247 interface_value.append(QString('\0' + display).toUtf8());
248 }
249 combobox->addItem(display, value);
250 if (val->is_default)
251 {
252 combobox->setCurrentText(display);
253 setDefaultValue(control->num, value.toUtf8());
254 }
255 foreach (QString ifname, interface_.keys())
256 {
257 // Adding values to all interfaces
258 interface_[ifname].list[control->num].append(interface_value);
259 }
260 default_list_[control->num].append(interface_value);
261 }
262
263 connect(combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxChanged(int)));
264
265 ui->leftLayout->addWidget(label);
266 ui->leftLayout->addWidget(combobox);
267 label_widget_[control->num] = label;
268
269 return combobox;
270 }
271
createString(iface_toolbar_control * control)272 QWidget *InterfaceToolbar::createString(iface_toolbar_control *control)
273 {
274 QLabel *label = new QLabel(QString().fromUtf8(control->display));
275 label->setToolTip(QString().fromUtf8(control->tooltip));
276 InterfaceToolbarLineEdit *lineedit = new InterfaceToolbarLineEdit(NULL, control->validation, control->is_required);
277 lineedit->setToolTip(QString().fromUtf8(control->tooltip));
278 lineedit->setPlaceholderText(QString().fromUtf8(control->placeholder));
279
280 if (control->default_value.string)
281 {
282 lineedit->setText(QString().fromUtf8(control->default_value.string));
283 setDefaultValue(control->num, control->default_value.string);
284 }
285
286 connect(lineedit, SIGNAL(editedTextApplied()), this, SLOT(onLineEditChanged()));
287
288 ui->leftLayout->addWidget(label);
289 ui->leftLayout->addWidget(lineedit);
290 label_widget_[control->num] = label;
291 use_spacer_ = false;
292
293 return lineedit;
294 }
295
setWidgetValue(QWidget * widget,int command,QByteArray payload)296 void InterfaceToolbar::setWidgetValue(QWidget *widget, int command, QByteArray payload)
297 {
298 if (QComboBox *combobox = qobject_cast<QComboBox *>(widget))
299 {
300 combobox->blockSignals(true);
301 switch (command)
302 {
303 case commandControlSet:
304 {
305 int idx = combobox->findData(payload);
306 if (idx != -1)
307 {
308 combobox->setCurrentIndex(idx);
309 }
310 break;
311 }
312
313 case commandControlAdd:
314 {
315 QString value;
316 QString display;
317 if (payload.contains('\0'))
318 {
319 // The payload contains "value\0display"
320 QList<QByteArray> values = payload.split('\0');
321 value = values[0];
322 display = values[1];
323 }
324 else
325 {
326 value = display = payload;
327 }
328
329 int idx = combobox->findData(value);
330 if (idx != -1)
331 {
332 // The value already exists, update item text
333 combobox->setItemText(idx, display);
334 }
335 else
336 {
337 combobox->addItem(display, value);
338 }
339 break;
340 }
341
342 case commandControlRemove:
343 {
344 if (payload.size() == 0)
345 {
346 combobox->clear();
347 }
348 else
349 {
350 int idx = combobox->findData(payload);
351 if (idx != -1)
352 {
353 combobox->removeItem(idx);
354 }
355 }
356 break;
357 }
358
359 default:
360 break;
361 }
362 combobox->blockSignals(false);
363 }
364 else if (InterfaceToolbarLineEdit *lineedit = qobject_cast<InterfaceToolbarLineEdit *>(widget))
365 {
366 // We don't block signals here because changes are applied with enter or apply button,
367 // and we want InterfaceToolbarLineEdit to always syntax check the text.
368 switch (command)
369 {
370 case commandControlSet:
371 lineedit->setText(payload);
372 lineedit->disableApplyButton();
373 break;
374
375 default:
376 break;
377 }
378 }
379 else if (QCheckBox *checkbox = qobject_cast<QCheckBox *>(widget))
380 {
381 checkbox->blockSignals(true);
382 switch (command)
383 {
384 case commandControlSet:
385 {
386 Qt::CheckState state = Qt::Unchecked;
387 if (payload.size() > 0 && payload.at(0) != 0)
388 {
389 state = Qt::Checked;
390 }
391 checkbox->setCheckState(state);
392 break;
393 }
394
395 default:
396 break;
397 }
398 checkbox->blockSignals(false);
399 }
400 else if (QPushButton *button = qobject_cast<QPushButton *>(widget))
401 {
402 if ((command == commandControlSet) &&
403 widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
404 {
405 button->setText(payload);
406 }
407 }
408 }
409
setInterfaceValue(QString ifname,QWidget * widget,int num,int command,QByteArray payload)410 void InterfaceToolbar::setInterfaceValue(QString ifname, QWidget *widget, int num, int command, QByteArray payload)
411 {
412 if (!widget) {
413 return;
414 }
415
416 if (qobject_cast<QComboBox *>(widget))
417 {
418 switch (command)
419 {
420 case commandControlSet:
421 if (interface_[ifname].value[num] != payload)
422 {
423 interface_[ifname].value_changed[num] = false;
424 }
425 foreach (QByteArray entry, interface_[ifname].list[num])
426 {
427 if (entry == payload || entry.startsWith(payload + '\0'))
428 {
429 interface_[ifname].value[num] = payload;
430 }
431 }
432 break;
433
434 case commandControlAdd:
435 interface_[ifname].list[num].append(payload);
436 break;
437
438 case commandControlRemove:
439 if (payload.size() == 0)
440 {
441 interface_[ifname].value[num].clear();
442 interface_[ifname].list[num].clear();
443 }
444 else
445 {
446 foreach (QByteArray entry, interface_[ifname].list[num])
447 {
448 if (entry == payload || entry.startsWith(payload + '\0'))
449 {
450 interface_[ifname].list[num].removeAll(entry);
451 }
452 }
453 }
454 break;
455
456 default:
457 break;
458 }
459 }
460 else if (qobject_cast<InterfaceToolbarLineEdit *>(widget))
461 {
462 switch (command)
463 {
464 case commandControlSet:
465 if (interface_[ifname].value[num] != payload)
466 {
467 interface_[ifname].value_changed[num] = false;
468 }
469 interface_[ifname].value[num] = payload;
470 break;
471
472 default:
473 break;
474 }
475 }
476 else if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
477 (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_LOGGER))
478 {
479 if (command == commandControlSet)
480 {
481 if (interface_[ifname].log_dialog.contains(num))
482 {
483 interface_[ifname].log_dialog[num]->clearText();
484 }
485 interface_[ifname].log_text.clear();
486 }
487 if (command == commandControlSet || command == commandControlAdd)
488 {
489 if (interface_[ifname].log_dialog.contains(num))
490 {
491 interface_[ifname].log_dialog[num]->appendText(payload);
492 }
493 interface_[ifname].log_text[num].append(payload);
494 }
495 }
496 else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
497 {
498 // QCheckBox or QPushButton
499 switch (command)
500 {
501 case commandControlSet:
502 if (interface_[ifname].value[num] != payload)
503 {
504 interface_[ifname].value_changed[num] = false;
505 }
506 interface_[ifname].value[num] = payload;
507 break;
508
509 default:
510 break;
511 }
512 }
513 }
514
controlReceived(QString ifname,int num,int command,QByteArray payload)515 void InterfaceToolbar::controlReceived(QString ifname, int num, int command, QByteArray payload)
516 {
517 switch (command)
518 {
519 case commandControlSet:
520 case commandControlAdd:
521 case commandControlRemove:
522 if (control_widget_.contains(num))
523 {
524 QWidget *widget = control_widget_[num];
525 setInterfaceValue(ifname, widget, num, command, payload);
526
527 if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
528 {
529 setWidgetValue(widget, command, payload);
530 }
531 }
532 break;
533
534 case commandControlEnable:
535 case commandControlDisable:
536 if (control_widget_.contains(num))
537 {
538 QWidget *widget = control_widget_[num];
539 if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
540 {
541 bool enable = (command == commandControlEnable ? true : false);
542 interface_[ifname].widget_disabled[num] = !enable;
543
544 if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
545 {
546 widget->setEnabled(enable);
547 if (label_widget_.contains(num))
548 {
549 label_widget_[num]->setEnabled(enable);
550 }
551 }
552 }
553 }
554 break;
555
556 case commandStatusMessage:
557 wsApp->pushStatus(WiresharkApplication::TemporaryStatus, payload);
558 break;
559
560 case commandInformationMessage:
561 simple_dialog_async(ESD_TYPE_INFO, ESD_BTN_OK, "%s", payload.data());
562 break;
563
564 case commandWarningMessage:
565 simple_dialog_async(ESD_TYPE_WARN, ESD_BTN_OK, "%s", payload.data());
566 break;
567
568 case commandErrorMessage:
569 simple_dialog_async(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", payload.data());
570 break;
571
572 default:
573 // Unknown commands are silently ignored
574 break;
575 }
576 }
577
controlSend(QString ifname,int num,int command,const QByteArray & payload=QByteArray ())578 void InterfaceToolbar::controlSend(QString ifname, int num, int command, const QByteArray &payload = QByteArray())
579 {
580 if (payload.length() > 65535)
581 {
582 // Not supported
583 return;
584 }
585
586 if (ifname.isEmpty() || interface_[ifname].out_fd == -1)
587 {
588 // Does not have a control out channel
589 return;
590 }
591
592 ssize_t payload_length = payload.length() + 2;
593 unsigned char high_nibble = (payload_length >> 16) & 0xFF;
594 unsigned char mid_nibble = (payload_length >> 8) & 0xFF;
595 unsigned char low_nibble = (payload_length >> 0) & 0xFF;
596
597 QByteArray ba;
598
599 ba.append(SP_TOOLBAR_CTRL);
600 ba.append(high_nibble);
601 ba.append(mid_nibble);
602 ba.append(low_nibble);
603 ba.append(num);
604 ba.append(command);
605 ba.append(payload);
606
607 if (ws_write(interface_[ifname].out_fd, ba.data(), ba.length()) != ba.length())
608 {
609 simple_dialog_async(ESD_TYPE_ERROR, ESD_BTN_OK,
610 "Unable to send control message:\n%s.",
611 g_strerror(errno));
612 }
613 }
614
onControlButtonClicked()615 void InterfaceToolbar::onControlButtonClicked()
616 {
617 const QString &ifname = ui->interfacesComboBox->currentText();
618 QPushButton *button = static_cast<QPushButton *>(sender());
619 int num = control_widget_.key(button);
620
621 controlSend(ifname, num, commandControlSet);
622 }
623
onCheckBoxChanged(int state)624 void InterfaceToolbar::onCheckBoxChanged(int state)
625 {
626 const QString &ifname = ui->interfacesComboBox->currentText();
627 QCheckBox *checkbox = static_cast<QCheckBox *>(sender());
628 int num = control_widget_.key(checkbox);
629
630 QByteArray payload(1, state == Qt::Unchecked ? 0 : 1);
631 controlSend(ifname, num, commandControlSet, payload);
632 interface_[ifname].value[num] = payload;
633 interface_[ifname].value_changed[num] = true;
634 }
635
onComboBoxChanged(int idx)636 void InterfaceToolbar::onComboBoxChanged(int idx)
637 {
638 const QString &ifname = ui->interfacesComboBox->currentText();
639 QComboBox *combobox = static_cast<QComboBox *>(sender());
640 int num = control_widget_.key(combobox);
641 QString value = combobox->itemData(idx).toString();
642
643 QByteArray payload(value.toUtf8());
644 controlSend(ifname, num, commandControlSet, payload);
645 interface_[ifname].value[num] = payload;
646 interface_[ifname].value_changed[num] = true;
647 }
648
onLineEditChanged()649 void InterfaceToolbar::onLineEditChanged()
650 {
651 const QString &ifname = ui->interfacesComboBox->currentText();
652 InterfaceToolbarLineEdit *lineedit = static_cast<InterfaceToolbarLineEdit *>(sender());
653 int num = control_widget_.key(lineedit);
654
655 QByteArray payload(lineedit->text().toUtf8());
656 controlSend(ifname, num, commandControlSet, payload);
657 interface_[ifname].value[num] = payload;
658 interface_[ifname].value_changed[num] = true;
659 }
660
onLogButtonClicked()661 void InterfaceToolbar::onLogButtonClicked()
662 {
663 const QString &ifname = ui->interfacesComboBox->currentText();
664 QPushButton *button = static_cast<QPushButton *>(sender());
665 int num = control_widget_.key(button);
666
667 if (!interface_[ifname].log_dialog.contains(num))
668 {
669 interface_[ifname].log_dialog[num] = new FunnelTextDialog(ifname + " " + button->text());
670 connect(interface_[ifname].log_dialog[num], SIGNAL(accepted()), this, SLOT(closeLog()));
671 connect(interface_[ifname].log_dialog[num], SIGNAL(rejected()), this, SLOT(closeLog()));
672
673 interface_[ifname].log_dialog[num]->setText(interface_[ifname].log_text[num]);
674 }
675
676 interface_[ifname].log_dialog[num]->show();
677 interface_[ifname].log_dialog[num]->raise();
678 interface_[ifname].log_dialog[num]->activateWindow();
679 }
680
onHelpButtonClicked()681 void InterfaceToolbar::onHelpButtonClicked()
682 {
683 QUrl help_url(help_link_);
684
685 if (help_url.scheme().compare("file") != 0)
686 {
687 QDesktopServices::openUrl(help_url);
688 }
689 }
690
closeLog()691 void InterfaceToolbar::closeLog()
692 {
693 FunnelTextDialog *log_dialog = static_cast<FunnelTextDialog *>(sender());
694
695 foreach (QString ifname, interface_.keys())
696 {
697 foreach (int num, control_widget_.keys())
698 {
699 if (interface_[ifname].log_dialog.value(num) == log_dialog)
700 {
701 interface_[ifname].log_dialog.remove(num);
702 }
703 }
704 }
705 }
706
707
startReaderThread(QString ifname,void * control_in)708 void InterfaceToolbar::startReaderThread(QString ifname, void *control_in)
709 {
710 QThread *thread = new QThread;
711 InterfaceToolbarReader *reader = new InterfaceToolbarReader(ifname, control_in);
712 reader->moveToThread(thread);
713
714 connect(thread, SIGNAL(started()), reader, SLOT(loop()));
715 connect(reader, SIGNAL(finished()), thread, SLOT(quit()));
716 connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater()));
717 connect(thread, SIGNAL(finished()), reader, SLOT(deleteLater()));
718 connect(reader, SIGNAL(received(QString, int, int, QByteArray)),
719 this, SLOT(controlReceived(QString, int, int, QByteArray)));
720
721 interface_[ifname].reader_thread = thread;
722
723 thread->start();
724 }
725
startCapture(GArray * ifaces)726 void InterfaceToolbar::startCapture(GArray *ifaces)
727 {
728 if (!ifaces || ifaces->len == 0)
729 return;
730
731 const QString &selected_ifname = ui->interfacesComboBox->currentText();
732 QString first_capturing_ifname;
733 bool selected_found = false;
734
735 for (guint i = 0; i < ifaces->len; i++)
736 {
737 interface_options *interface_opts = &g_array_index(ifaces, interface_options, i);
738 QString ifname(interface_opts->name);
739
740 if (!interface_.contains(ifname))
741 // This interface is not for us
742 continue;
743
744 if (first_capturing_ifname.isEmpty())
745 first_capturing_ifname = ifname;
746
747 if (ifname.compare(selected_ifname) == 0)
748 selected_found = true;
749
750 if (interface_[ifname].out_fd != -1)
751 // Already have control channels for this interface
752 continue;
753
754 // Open control out channel
755 #ifdef _WIN32
756 startReaderThread(ifname, interface_opts->extcap_control_in_h);
757 // Duplicate control out handle and pass the duplicate handle to _open_osfhandle().
758 // This allows the C run-time file descriptor (out_fd) and the extcap_control_out_h to be closed independently.
759 // The duplicated handle will get closed at the same time the file descriptor is closed.
760 // The control out pipe will close when both out_fd and extcap_control_out_h are closed.
761 HANDLE duplicate_out_handle = INVALID_HANDLE_VALUE;
762 if (!DuplicateHandle(GetCurrentProcess(), interface_opts->extcap_control_out_h,
763 GetCurrentProcess(), &duplicate_out_handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
764 {
765 simple_dialog_async(ESD_TYPE_ERROR, ESD_BTN_OK,
766 "Failed to duplicate extcap control out handle: %s\n.",
767 win32strerror(GetLastError()));
768 }
769 else
770 {
771 interface_[ifname].out_fd = _open_osfhandle((intptr_t)duplicate_out_handle, O_APPEND | O_BINARY);
772 }
773 #else
774 startReaderThread(ifname, interface_opts->extcap_control_in);
775 interface_[ifname].out_fd = ws_open(interface_opts->extcap_control_out, O_WRONLY | O_BINARY, 0);
776 #endif
777 sendChangedValues(ifname);
778 controlSend(ifname, 0, commandControlInitialized);
779 }
780
781 if (!selected_found && !first_capturing_ifname.isEmpty())
782 {
783 ui->interfacesComboBox->setCurrentText(first_capturing_ifname);
784 }
785 else
786 {
787 updateWidgets();
788 }
789 }
790
stopCapture()791 void InterfaceToolbar::stopCapture()
792 {
793 foreach (QString ifname, interface_.keys())
794 {
795 if (interface_[ifname].reader_thread)
796 {
797 if (!interface_[ifname].reader_thread->isFinished())
798 {
799 interface_[ifname].reader_thread->requestInterruption();
800 }
801 interface_[ifname].reader_thread = NULL;
802 }
803
804 if (interface_[ifname].out_fd != -1)
805 {
806 ws_close (interface_[ifname].out_fd);
807 interface_[ifname].out_fd = -1;
808 }
809
810 foreach (int num, control_widget_.keys())
811 {
812 // Reset disabled property for all widgets
813 interface_[ifname].widget_disabled[num] = false;
814
815 QWidget *widget = control_widget_[num];
816 if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
817 (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
818 {
819 // Reset default value for control buttons
820 interface_[ifname].value[num] = default_value_[num];
821
822 if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
823 {
824 setWidgetValue(widget, commandControlSet, default_value_[num]);
825 }
826 }
827 }
828 }
829
830 updateWidgets();
831 }
832
sendChangedValues(QString ifname)833 void InterfaceToolbar::sendChangedValues(QString ifname)
834 {
835 // Send all values which has changed
836 foreach (int num, control_widget_.keys())
837 {
838 QWidget *widget = control_widget_[num];
839 if ((interface_[ifname].value_changed[num]) &&
840 (widget->property(interface_type_property).toInt() != INTERFACE_TYPE_BUTTON) &&
841 (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
842 {
843 controlSend(ifname, num, commandControlSet, interface_[ifname].value[num]);
844 }
845 }
846 }
847
onRestoreButtonClicked()848 void InterfaceToolbar::onRestoreButtonClicked()
849 {
850 const QString &ifname = ui->interfacesComboBox->currentText();
851
852 // Set default values to all widgets and interfaces
853 foreach (int num, control_widget_.keys())
854 {
855 QWidget *widget = control_widget_[num];
856 if (default_list_[num].size() > 0)
857 {
858 // This is a QComboBox. Clear list and add new entries.
859 setWidgetValue(widget, commandControlRemove, QByteArray());
860 interface_[ifname].list[num].clear();
861
862 foreach (QByteArray value, default_list_[num])
863 {
864 setWidgetValue(widget, commandControlAdd, value);
865 interface_[ifname].list[num].append(value);
866 }
867 }
868
869 switch (widget->property(interface_role_property).toInt())
870 {
871 case INTERFACE_ROLE_CONTROL:
872 setWidgetValue(widget, commandControlSet, default_value_[num]);
873 interface_[ifname].value[num] = default_value_[num];
874 interface_[ifname].value_changed[num] = false;
875 break;
876
877 case INTERFACE_ROLE_LOGGER:
878 if (interface_[ifname].log_dialog.contains(num))
879 {
880 interface_[ifname].log_dialog[num]->clearText();
881 }
882 interface_[ifname].log_text[num].clear();
883 break;
884
885 default:
886 break;
887 }
888 }
889 }
890
hasInterface(QString ifname)891 bool InterfaceToolbar::hasInterface(QString ifname)
892 {
893 return interface_.contains(ifname);
894 }
895
updateWidgets()896 void InterfaceToolbar::updateWidgets()
897 {
898 const QString &ifname = ui->interfacesComboBox->currentText();
899 bool is_capturing = (interface_[ifname].out_fd == -1 ? false : true);
900
901 foreach (int num, control_widget_.keys())
902 {
903 QWidget *widget = control_widget_[num];
904 bool widget_enabled = true;
905
906 if (ifname.isEmpty() &&
907 (widget->property(interface_role_property).toInt() != INTERFACE_ROLE_HELP))
908 {
909 // No interface selected, disable all but Help button
910 widget_enabled = false;
911 }
912 else if (!is_capturing &&
913 (widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
914 (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
915 {
916 widget_enabled = false;
917 }
918 else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
919 {
920 widget_enabled = !interface_[ifname].widget_disabled[num];
921 }
922
923 widget->setEnabled(widget_enabled);
924 if (label_widget_.contains(num))
925 {
926 label_widget_[num]->setEnabled(widget_enabled);
927 }
928 }
929
930 foreach (int num, control_widget_.keys())
931 {
932 QWidget *widget = control_widget_[num];
933 if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
934 (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_RESTORE))
935 {
936 widget->setEnabled(!is_capturing);
937 }
938 }
939 }
940
interfaceListChanged()941 void InterfaceToolbar::interfaceListChanged()
942 {
943 #ifdef HAVE_LIBPCAP
944 const QString &selected_ifname = ui->interfacesComboBox->currentText();
945 bool keep_selected = false;
946
947 ui->interfacesComboBox->blockSignals(true);
948 ui->interfacesComboBox->clear();
949
950 for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++)
951 {
952 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
953 if (device->hidden)
954 continue;
955
956 if (interface_.keys().contains(device->name))
957 {
958 ui->interfacesComboBox->addItem(device->name);
959 if (selected_ifname.compare(device->name) == 0)
960 {
961 // Keep selected interface
962 ui->interfacesComboBox->setCurrentText(device->name);
963 keep_selected = true;
964 }
965 }
966 }
967
968 ui->interfacesComboBox->blockSignals(false);
969
970 if (!keep_selected)
971 {
972 // Select the first interface
973 on_interfacesComboBox_currentIndexChanged(ui->interfacesComboBox->currentText());
974 }
975
976 updateWidgets();
977 #endif
978 }
979
on_interfacesComboBox_currentIndexChanged(const QString & ifname)980 void InterfaceToolbar::on_interfacesComboBox_currentIndexChanged(const QString &ifname)
981 {
982 foreach (int num, control_widget_.keys())
983 {
984 QWidget *widget = control_widget_[num];
985 if (interface_[ifname].list[num].size() > 0)
986 {
987 // This is a QComboBox. Clear list and add new entries.
988 setWidgetValue(widget, commandControlRemove, QByteArray());
989
990 foreach (QByteArray value, interface_[ifname].list[num])
991 {
992 setWidgetValue(widget, commandControlAdd, value);
993 }
994 }
995
996 if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
997 {
998 setWidgetValue(widget, commandControlSet, interface_[ifname].value[num]);
999 }
1000 }
1001
1002 updateWidgets();
1003 }
1004