diff --git a/doc/extcap_example.py b/doc/extcap_example.py index 1eab8d39e4..13c079d0ec 100755 --- a/doc/extcap_example.py +++ b/doc/extcap_example.py @@ -74,9 +74,10 @@ def extcap_config(interface): values = [] args.append ( (0, '--delay', 'Time delay', 'Time delay between packages', 'integer', '{range=1,15}') ) - args.append ( (1, '--message', 'Message', 'Package message content', 'string', '') ) + args.append ( (1, '--message', 'Message', 'Package message content', 'string', '{required=true}') ) args.append ( (2, '--verify', 'Verify', 'Verify package content', 'boolflag', '') ) args.append ( (3, '--remote', 'Remote Channel', 'Remote Channel Selector', 'selector', '')) + args.append ( (4, '--fake_ip', 'Fake IP Address', 'Use this ip address as sender', 'string', '{validation=\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b}')) values.append ( (3, "if1", "Remote1", "true" ) ) values.append ( (3, "if2", "Remote2", "false" ) ) @@ -140,7 +141,7 @@ def ip_checksum(iph): csum = csum & 0xFFFF ^ 0xFFFF return csum -def pcap_fake_package ( message ): +def pcap_fake_package ( message, fake_ip ): pcap = bytearray() #length = 14 bytes [ eth ] + 20 bytes [ ip ] + messagelength @@ -172,13 +173,16 @@ def pcap_fake_package ( message ): pcap = append_bytes(pcap, struct.pack('b', int ( '40', 16) )) pcap = append_bytes(pcap, struct.pack('B', 0xFE )) # Protocol (2 = unspecified) pcap = append_bytes(pcap, struct.pack('L', int ( '7F000001', 16) )) # Source IP + + parts = fake_ip.split('.') + ipadr = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3]) + pcap = append_bytes(pcap, struct.pack('>L', ipadr )) # Source IP pcap = append_bytes(pcap, struct.pack('>L', int ( '7F000001', 16) )) # Dest IP pcap = append_bytes(pcap, message) return pcap -def extcap_capture(interface, fifo, delay, verify, message, remote): +def extcap_capture(interface, fifo, delay, verify, message, remote, fake_ip): global doExit signal.signal(signal.SIGINT, signalHandler) @@ -198,7 +202,7 @@ def extcap_capture(interface, fifo, delay, verify, message, remote): while doExit == False: out = str( "%s|%04X%s|%s" % ( remote.strip(), len(message), message, verify ) ) try: - fh.write (pcap_fake_package(out)) + fh.write (pcap_fake_package(out, fake_ip)) time.sleep(tdelay) except IOError: doExit = True @@ -216,6 +220,7 @@ if __name__ == '__main__': # Capture options delay = 0 message = "" + fake_ip = "" parser = argparse.ArgumentParser( prog="Extcap Example", @@ -236,6 +241,7 @@ if __name__ == '__main__': parser.add_argument("--delay", help="Demonstrates an integer variable", type=int, default=0, choices=[0, 1, 2, 3, 4, 5] ) parser.add_argument("--remote", help="Demonstrates a selector choice", default="if1", choices=["if1", "if2"] ) parser.add_argument("--message", help="Demonstrates string variable", nargs='?', default="" ) + parser.add_argument("--fake_ip", help="Add a fake sender IP adress", nargs='?', default="127.0.0.1" ) args, unknown = parser.parse_known_args() if ( len(sys.argv) <= 1 ): @@ -260,6 +266,10 @@ if __name__ == '__main__': if ( args.message == None or len(args.message) == 0 ): message = "Extcap Test" + fake_ip = args.fake_ip + if ( args.fake_ip == None or len(args.fake_ip) < 7 or len(args.fake_ip.split('.')) != 4 ): + fake_ip = "127.0.0.1" + if args.extcap_config: extcap_config(interface) elif args.extcap_dlts: @@ -267,7 +277,7 @@ if __name__ == '__main__': elif args.capture: if args.fifo is None: sys.exit(ERROR_FIFO) - extcap_capture(interface, args.fifo, args.delay, args.verify, message, args.remote) + extcap_capture(interface, args.fifo, args.delay, args.verify, message, args.remote, fake_ip) else: usage() sys.exit(ERROR_USAGE) diff --git a/extcap.c b/extcap.c index 0a5e19ba3c..6d66ad167c 100644 --- a/extcap.c +++ b/extcap.c @@ -440,7 +440,7 @@ extcap_get_if_configuration(const char * ifname) { } gboolean -extcap_has_configuration(const char * ifname) { +extcap_has_configuration(const char * ifname, gboolean is_required) { GList * arguments = 0; GList * walker = 0, * item = 0; @@ -455,7 +455,11 @@ extcap_has_configuration(const char * ifname) { while ( item != NULL && ! found ) { if ( (extcap_arg *)(item->data) != NULL ) - found = TRUE; + { + /* Should required options be present, or any kind of options */ + if ( ! is_required || ((extcap_arg *)(item->data))->is_required ) + found = TRUE; + } item = item->next; } @@ -869,7 +873,7 @@ void extcap_debug_arguments ( extcap_arg *arg_iter ) for ( walker = g_list_first ( arg_iter->value_list ); walker; walker = walker->next ) { v = (extcap_value *)walker->data; - if (v->is_default == TRUE) + if (v->is_default) printf("*"); printf("\tcall=\"%p\" display=\"%p\"\n", v->call, v->display); printf("\tcall=\"%s\" display=\"%s\"\n", v->call, v->display); diff --git a/extcap.h b/extcap.h index 47c6511dc5..813d4bd740 100644 --- a/extcap.h +++ b/extcap.h @@ -67,7 +67,7 @@ GList * extcap_get_if_configuration(const char * ifname); gboolean -extcap_has_configuration(const char * ifname); +extcap_has_configuration(const char * ifname, gboolean is_required); #ifdef WIN32 HANDLE diff --git a/extcap_parser.c b/extcap_parser.c index ef683f1a40..d884298a3a 100644 --- a/extcap_parser.c +++ b/extcap_parser.c @@ -300,6 +300,21 @@ extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) { return NULL ; } + /* caught a regex quantifier end bracket and not the end of the line. + * let's find the correct end bracket */ + if ( *(e+1) != '{' && strlen ( e ) > 1 ) { + gchar *f = (e + 1); + + while ( ( f = g_strstr_len(f, -1, "}") ) != NULL) { + if ( strlen ( f ) <= 1 || *(f+1) == '{' ) + break; + f++; + } + + if ( f != NULL ) + e = f; + } + if ((eq = g_strstr_len(b, -1, "=")) == NULL) { /* printf("debug - tokenizer - invalid, missing =\n"); */ extcap_free_tokenized_sentence(rs); @@ -349,6 +364,8 @@ extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) { tv->param_type = EXTCAP_PARAM_PARENT; } else if (g_ascii_strcasecmp(tv->arg, "required") == 0) { tv->param_type = EXTCAP_PARAM_REQUIRED; + } else if (g_ascii_strcasecmp(tv->arg, "validation") == 0) { + tv->param_type = EXTCAP_PARAM_VALIDATION; } else { tv->param_type = EXTCAP_PARAM_UNKNOWN; } @@ -480,6 +497,7 @@ extcap_arg *extcap_new_arg(void) { r->default_complex = NULL; r->fileexists = FALSE; r->fileextension = NULL; + r->regexp = NULL; r->is_required = FALSE; r->values = NULL; @@ -509,6 +527,9 @@ void extcap_free_arg(extcap_arg *a) { if (a->fileextension != NULL) g_free(a->fileextension); + if (a->regexp != NULL) + g_free(a->regexp); + if (a->range_start != NULL) extcap_free_complex(a->range_start); @@ -605,6 +626,11 @@ extcap_arg *extcap_parse_arg_sentence(GList * args, extcap_token_sentence *s) { target_arg->fileextension = g_strdup(v->value); } + if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_VALIDATION)) + != NULL) { + target_arg->regexp = g_strdup(v->value); + } + if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_REQUIRED)) != NULL) { target_arg->is_required = (v->value[0] == 't' || v->value[0] == 'T'); diff --git a/extcap_parser.h b/extcap_parser.h index a730d200bc..158838c16f 100644 --- a/extcap_parser.h +++ b/extcap_parser.h @@ -69,7 +69,8 @@ typedef enum { EXTCAP_PARAM_FILE_MUSTEXIST, EXTCAP_PARAM_FILE_EXTENSION, EXTCAP_PARAM_PARENT, - EXTCAP_PARAM_REQUIRED + EXTCAP_PARAM_REQUIRED, + EXTCAP_PARAM_VALIDATION } extcap_param_type; /* Values for a given sentence; values are all stored as a call @@ -112,6 +113,8 @@ typedef struct _extcap_arg { gboolean is_required; + gchar * regexp; + extcap_arg_type arg_type; extcap_complex *range_start; diff --git a/ui/qt/extcap_argument.cpp b/ui/qt/extcap_argument.cpp index 0150446ae5..2ae543660f 100644 --- a/ui/qt/extcap_argument.cpp +++ b/ui/qt/extcap_argument.cpp @@ -40,338 +40,364 @@ #include #include #include -#include + +#include +#include #include #include #include -class ExtArgSelector : public ExtcapArgument +ExtArgSelector::ExtArgSelector(extcap_arg * argument) : + ExtcapArgument(argument), boxSelection(0) {} + +QWidget * ExtArgSelector::createEditor(QWidget * parent) { -public: - ExtArgSelector(extcap_arg * argument) : - ExtcapArgument(argument), boxSelection(0) {}; + int counter = 0; + int selected = -1; - virtual QWidget * createEditor(QWidget * parent) + boxSelection = new QComboBox(parent); + + if ( values.length() > 0 ) { - int counter = 0; - int selected = -1; + ExtcapValueList::const_iterator iter = values.constBegin(); - boxSelection = new QComboBox(parent); - - if ( values.length() > 0 ) + while ( iter != values.constEnd() ) { - ExtcapValueList::const_iterator iter = values.constBegin(); + boxSelection->addItem((*iter).value(), (*iter).call()); + if ( (*iter).isDefault() ) + selected = counter; - while ( iter != values.constEnd() ) - { - boxSelection->addItem((*iter).value(), (*iter).call()); - if ( (*iter).isDefault() ) - selected = counter; - - counter++; - ++iter; - } - - if ( selected > -1 && selected < boxSelection->count() ) - boxSelection->setCurrentIndex(selected); + counter++; + ++iter; } - connect ( boxSelection, SIGNAL(currentIndexChanged(int)), SLOT(onIntChanged(int)) ); - - return boxSelection; + if ( selected > -1 && selected < boxSelection->count() ) + boxSelection->setCurrentIndex(selected); } - virtual QString value() - { - if ( boxSelection == 0 ) - return QString(); + connect ( boxSelection, SIGNAL(currentIndexChanged(int)), SLOT(onIntChanged(int)) ); + + return boxSelection; +} + +bool ExtArgSelector::isValid() +{ + bool valid = true; + + if ( value().length() == 0 && isRequired() ) + valid = false; + + QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name(); + QString cmbBoxStyle("QComboBox { background-color: %1; } "); + boxSelection->setStyleSheet( cmbBoxStyle.arg(valid ? QString("") : lblInvalidColor) ); + + return valid; +} + +QString ExtArgSelector::value() +{ + if ( boxSelection == 0 ) + return QString(); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) - QVariant data = boxSelection->currentData(); + QVariant data = boxSelection->currentData(); #else - QVariant data = boxSelection->itemData(boxSelection->currentIndex()); + QVariant data = boxSelection->itemData(boxSelection->currentIndex()); #endif - return data.toString(); - } + return data.toString(); +} -private: +ExtArgRadio::ExtArgRadio(extcap_arg * argument) : + ExtcapArgument(argument), selectorGroup(0), callStrings(0) {} - QComboBox * boxSelection; -}; - -class ExtArgRadio : public ExtcapArgument +QWidget * ExtArgRadio::createEditor(QWidget * parent) { -public: - ExtArgRadio(extcap_arg * argument) : - ExtcapArgument(argument), selectorGroup(0), callStrings(0) + + int count = 0; + bool anyChecked = false; + + selectorGroup = new QButtonGroup(parent); + QWidget * radioButtons = new QWidget; + QVBoxLayout * vrLayout = new QVBoxLayout(); + QMargins margins = vrLayout->contentsMargins(); + vrLayout->setContentsMargins(0, 0, 0, margins.bottom()); + if ( callStrings != 0 ) + delete callStrings; + + callStrings = new QList(); + + if ( values.length() > 0 ) { - }; + ExtcapValueList::const_iterator iter = values.constBegin(); - virtual QWidget * createEditor(QWidget * parent) - { + while ( iter != values.constEnd() ) + { + QRadioButton * radio = new QRadioButton((*iter).value()); + QString callString = (*iter).call(); + callStrings->append(callString); - int count = 0; - bool anyChecked = false; - - selectorGroup = new QButtonGroup(parent); - QWidget * radioButtons = new QWidget; - QVBoxLayout * vrLayout = new QVBoxLayout(); - QMargins margins = vrLayout->contentsMargins(); - vrLayout->setContentsMargins(0, 0, 0, margins.bottom()); - if ( callStrings != 0 ) - delete callStrings; - - callStrings = new QList(); - - if ( values.length() > 0 ) - { - ExtcapValueList::const_iterator iter = values.constBegin(); - - while ( iter != values.constEnd() ) - { - QRadioButton * radio = new QRadioButton((*iter).value()); - QString callString = (*iter).call(); - callStrings->append(callString); - - if ( _default != NULL && (*iter).isDefault() ) + if ( _default != NULL && (*iter).isDefault() ) + { + radio->setChecked(true); + anyChecked = true; + } + else if (_default != NULL) + { + if ( callString.compare(_default->toString()) == 0 ) { radio->setChecked(true); anyChecked = true; } - else if (_default != NULL) - { - if ( callString.compare(_default->toString()) == 0 ) - { - radio->setChecked(true); - anyChecked = true; - } - } - - connect(radio, SIGNAL(clicked(bool)), SLOT(onBoolChanged(bool))); - selectorGroup->addButton(radio, count); - - vrLayout->addWidget(radio); - count++; - - ++iter; } + + connect(radio, SIGNAL(clicked(bool)), SLOT(onBoolChanged(bool))); + selectorGroup->addButton(radio, count); + + vrLayout->addWidget(radio); + count++; + + ++iter; } - - /* No default was provided, and not saved value exists */ - if ( anyChecked == false && count > 0 ) - ((QRadioButton*)(selectorGroup->button(0)))->setChecked(true); - - radioButtons->setLayout(vrLayout); - - return radioButtons; } - virtual QString value() + /* No default was provided, and not saved value exists */ + if ( anyChecked == false && count > 0 ) + ((QRadioButton*)(selectorGroup->button(0)))->setChecked(true); + + radioButtons->setLayout(vrLayout); + + return radioButtons; +} + +QString ExtArgRadio::value() +{ + int idx = 0; + if ( selectorGroup == 0 || callStrings == 0 ) + return QString(); + + idx = selectorGroup->checkedId(); + if ( idx > -1 && callStrings->length() > idx ) + return callStrings->takeAt(idx); + + return QString(); +} + +bool ExtArgRadio::isValid() +{ + bool valid = true; + int idx = 0; + + if ( isRequired() ) { - int idx = 0; if ( selectorGroup == 0 || callStrings == 0 ) - return QString(); + valid = false; + else + { + idx = selectorGroup->checkedId(); + if ( idx == -1 || callStrings->length() <= idx ) + valid = false; + } + } - idx = selectorGroup->checkedId(); - if ( idx > -1 && callStrings->length() > idx ) - return callStrings->takeAt(idx); + /* If nothing is selected, but a selection is required, the only thing that + * can be marked is the label */ + QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name(); + _label->setStyleSheet ( label_style.arg(valid ? QString("") : lblInvalidColor) ); + return valid; +} + +ExtArgBool::ExtArgBool(extcap_arg * argument) : + ExtcapArgument(argument), boolBox(0) {} + +QWidget * ExtArgBool::createLabel(QWidget * parent) +{ + return new QWidget(parent); +} + +QWidget * ExtArgBool::createEditor(QWidget * parent) +{ + boolBox = new QCheckBox(QString().fromUtf8(_argument->display), parent); + if ( _argument->tooltip != NULL ) + boolBox->setToolTip(QString().fromUtf8(_argument->tooltip)); + + if ( _argument->default_complex != NULL ) + if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE ) + boolBox->setCheckState(Qt::Checked); + + if ( _default != NULL ) + { + if ( _default->toString().compare("true") ) + boolBox->setCheckState(Qt::Checked); + } + + connect (boolBox, SIGNAL(stateChanged(int)), SLOT(onIntChanged(int))); + + return boolBox; +} + +QString ExtArgBool::call() +{ + if ( boolBox == NULL ) + return QString(""); + + if ( _argument->arg_type == EXTCAP_ARG_BOOLEAN ) + return ExtcapArgument::call(); + + return QString(boolBox->checkState() == Qt::Checked ? _argument->call : ""); +} + +QString ExtArgBool::value() +{ + if ( boolBox == NULL || _argument->arg_type == EXTCAP_ARG_BOOLFLAG ) return QString(); - } + return QString(boolBox->checkState() == Qt::Checked ? "true" : "false"); +} -private: - - QButtonGroup * selectorGroup; - QList * callStrings; -}; - -class ExtArgBool : public ExtcapArgument +bool ExtArgBool::isValid() { -public: - ExtArgBool(extcap_arg * argument) : - ExtcapArgument(argument), boolBox(0) {}; + /* A bool is allways valid, but the base function checks on string length, + * which will fail with boolflags */ + return true; +} - virtual QWidget * createLabel(QWidget * parent) - { - return new QWidget(parent); - } - - virtual QWidget * createEditor(QWidget * parent) - { - boolBox = new QCheckBox(QString().fromUtf8(_argument->display), parent); - if ( _argument->tooltip != NULL ) - boolBox->setToolTip(QString().fromUtf8(_argument->tooltip)); - - if ( _argument->default_complex != NULL ) - if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE ) - boolBox->setCheckState(Qt::Checked); - - if ( _default != NULL ) - { - if ( _default->toString().compare("true") ) - boolBox->setCheckState(Qt::Checked); - } - - connect (boolBox, SIGNAL(stateChanged(int)), SLOT(onIntChanged(int))); - - return boolBox; - } - - virtual QString call() - { - if ( boolBox == NULL ) - return QString(""); - - if ( _argument->arg_type == EXTCAP_ARG_BOOLEAN ) - return ExtcapArgument::call(); - - return QString(boolBox->checkState() == Qt::Checked ? _argument->call : ""); - } - - virtual QString value() - { - if ( boolBox == NULL || _argument->arg_type == EXTCAP_ARG_BOOLFLAG ) - return QString(); - return QString(boolBox->checkState() == Qt::Checked ? "true" : "false"); - } - - virtual QString defaultValue() - { - if ( _argument != 0 && _argument->default_complex != NULL ) - if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE ) - return QString("true"); - - return QString("false"); - } - -private: - - QCheckBox * boolBox; -}; - -class ExtArgText : public ExtcapArgument +QString ExtArgBool::defaultValue() { + if ( _argument != 0 && _argument->default_complex != NULL ) + if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE ) + return QString("true"); -public: - ExtArgText(extcap_arg * argument) : - ExtcapArgument(argument), textBox(0) - { - _default = new QVariant(QString("")); - }; + return QString("false"); +} - virtual QWidget * createEditor(QWidget * parent) - { - textBox = new QLineEdit(_default->toString(), parent); +ExtArgText::ExtArgText(extcap_arg * argument) : + ExtcapArgument(argument), textBox(0) +{ + _default = new QVariant(QString("")); +} - textBox->setText(defaultValue()); +QWidget * ExtArgText::createEditor(QWidget * parent) +{ + textBox = new QLineEdit(_default->toString(), parent); - if ( _argument->tooltip != NULL ) - textBox->setToolTip(QString().fromUtf8(_argument->tooltip)); + textBox->setText(defaultValue()); - connect(textBox , SIGNAL(textChanged(QString)), SLOT(onStringChanged(QString))); + if ( _argument->tooltip != NULL ) + textBox->setToolTip(QString().fromUtf8(_argument->tooltip)); - return textBox; - } + connect(textBox , SIGNAL(textChanged(QString)), SLOT(onStringChanged(QString))); - virtual QString value() - { - if ( textBox == 0 ) - return QString(); - - return textBox->text(); - } - - virtual bool isValid() - { - if ( isRequired() && value().length() == 0 ) - return false; - - return true; - } - - virtual QString defaultValue() - { - if ( _argument != 0 && _argument->default_complex != 0) - { - gchar * str = extcap_get_complex_as_string(_argument->default_complex); - if ( str != 0 ) - return QString(str); - } + return textBox; +} +QString ExtArgText::value() +{ + if ( textBox == 0 ) return QString(); - } -protected: + return textBox->text(); +} - QLineEdit * textBox; -}; - -class ExtArgNumber : public ExtArgText +bool ExtArgText::isValid() { -public: - ExtArgNumber(extcap_arg * argument) : - ExtArgText(argument) {}; + bool valid = true; - virtual QWidget * createEditor(QWidget * parent) + if ( isRequired() && value().length() == 0 ) + valid = false; + + /* validation should only be checked if there is a value. if the argument + * must be present (isRequired) the check above will handle that */ + if ( valid && _argument->regexp != NULL && value().length() > 0) { - textBox = (QLineEdit *)ExtArgText::createEditor(parent); - textBox->disconnect(SIGNAL(textChanged(QString))); - - if ( _argument->arg_type == EXTCAP_ARG_INTEGER || _argument->arg_type == EXTCAP_ARG_UNSIGNED ) + QString regexp = QString().fromUtf8(_argument->regexp); + if ( regexp.length() > 0 ) { - QIntValidator * textValidator = new QIntValidator(parent); - if ( _argument->range_start != NULL ) - textValidator->setBottom(extcap_complex_get_int(_argument->range_start)); - - if ( _argument->arg_type == EXTCAP_ARG_UNSIGNED && textValidator->bottom() < 0 ) - textValidator->setBottom(0); - - if ( _argument->range_end != NULL ) - textValidator->setTop(extcap_complex_get_int(_argument->range_end)); - textBox->setValidator(textValidator); + QRegExp expr(regexp); + if ( ! expr.isValid() || expr.indexIn(value(), 0) == -1 ) + valid = false; } - else if ( _argument->arg_type == EXTCAP_ARG_DOUBLE ) - { - QDoubleValidator * textValidator = new QDoubleValidator(parent); - if ( _argument->range_start != NULL ) - textValidator->setBottom(extcap_complex_get_double(_argument->range_start)); - if ( _argument->range_end != NULL ) - textValidator->setTop(extcap_complex_get_double(_argument->range_end)); - - textBox->setValidator(textValidator); - } - - textBox->setText(defaultValue()); - - connect(textBox, SIGNAL(textChanged(QString)), SLOT(onStringChanged(QString))); - - return textBox; - }; - - virtual QString defaultValue() - { - QString result; - - if ( _argument != 0 && _argument->default_complex != NULL ) - { - if ( _argument->arg_type == EXTCAP_ARG_DOUBLE ) - result = QString::number(extcap_complex_get_double(_argument->default_complex)); - else if ( _argument->arg_type == EXTCAP_ARG_INTEGER ) - result = QString::number(extcap_complex_get_int(_argument->default_complex)); - else if ( _argument->arg_type == EXTCAP_ARG_UNSIGNED ) - result = QString::number(extcap_complex_get_uint(_argument->default_complex)); - else if ( _argument->arg_type == EXTCAP_ARG_LONG ) - result = QString::number(extcap_complex_get_long(_argument->default_complex)); - else - result = QString(); - } - - return result; } -}; + QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name(); + QString txtStyle("QLineEdit { background-color: %1; } "); + textBox->setStyleSheet( txtStyle.arg(valid ? QString("") : lblInvalidColor) ); + + return valid; +} + +QString ExtArgText::defaultValue() +{ + if ( _argument != 0 && _argument->default_complex != 0) + { + gchar * str = extcap_get_complex_as_string(_argument->default_complex); + if ( str != 0 ) + return QString(str); + } + + return QString(); +} + +ExtArgNumber::ExtArgNumber(extcap_arg * argument) : + ExtArgText(argument) {} + +QWidget * ExtArgNumber::createEditor(QWidget * parent) +{ + textBox = (QLineEdit *)ExtArgText::createEditor(parent); + textBox->disconnect(SIGNAL(textChanged(QString))); + + if ( _argument->arg_type == EXTCAP_ARG_INTEGER || _argument->arg_type == EXTCAP_ARG_UNSIGNED ) + { + QIntValidator * textValidator = new QIntValidator(parent); + if ( _argument->range_start != NULL ) + textValidator->setBottom(extcap_complex_get_int(_argument->range_start)); + + if ( _argument->arg_type == EXTCAP_ARG_UNSIGNED && textValidator->bottom() < 0 ) + textValidator->setBottom(0); + + if ( _argument->range_end != NULL ) + textValidator->setTop(extcap_complex_get_int(_argument->range_end)); + textBox->setValidator(textValidator); + } + else if ( _argument->arg_type == EXTCAP_ARG_DOUBLE ) + { + QDoubleValidator * textValidator = new QDoubleValidator(parent); + if ( _argument->range_start != NULL ) + textValidator->setBottom(extcap_complex_get_double(_argument->range_start)); + if ( _argument->range_end != NULL ) + textValidator->setTop(extcap_complex_get_double(_argument->range_end)); + + textBox->setValidator(textValidator); + } + + textBox->setText(defaultValue()); + + connect(textBox, SIGNAL(textChanged(QString)), SLOT(onStringChanged(QString))); + + return textBox; +} + +QString ExtArgNumber::defaultValue() +{ + QString result; + + if ( _argument != 0 && _argument->default_complex != NULL ) + { + if ( _argument->arg_type == EXTCAP_ARG_DOUBLE ) + result = QString::number(extcap_complex_get_double(_argument->default_complex)); + else if ( _argument->arg_type == EXTCAP_ARG_INTEGER ) + result = QString::number(extcap_complex_get_int(_argument->default_complex)); + else if ( _argument->arg_type == EXTCAP_ARG_UNSIGNED ) + result = QString::number(extcap_complex_get_uint(_argument->default_complex)); + else if ( _argument->arg_type == EXTCAP_ARG_LONG ) + result = QString::number(extcap_complex_get_long(_argument->default_complex)); + else + result = QString(); + } + + return result; +} ExtcapValue::~ExtcapValue() {} @@ -388,7 +414,8 @@ void ExtcapValue::setChildren(ExtcapValueList children) } ExtcapArgument::ExtcapArgument(extcap_arg * argument, QObject *parent) : - QObject(parent), _argument(argument), _default(0) + QObject(parent), _argument(argument), _default(0), _label(0), + label_style(QString("QLabel { color: %1; }")) { if ( _argument->values != 0 ) { @@ -441,13 +468,20 @@ QWidget * ExtcapArgument::createLabel(QWidget * parent) if ( _argument == 0 || _argument->display == 0 ) return 0; + QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name(); + QString text = QString().fromUtf8(_argument->display); - QLabel * label = new QLabel(text, parent); - if ( _argument->tooltip != 0 ) - label->setToolTip(QString().fromUtf8(_argument->tooltip)); + _label = new QLabel(text, parent); - return label; + _label->setProperty("isRequired", QString(isRequired() ? "true" : "false")); + + _label->setStyleSheet ( label_style.arg(QString("")) ); + + if ( _argument->tooltip != 0 ) + _label->setToolTip(QString().fromUtf8(_argument->tooltip)); + + return _label; } QWidget * ExtcapArgument::createEditor(QWidget *) @@ -468,6 +502,11 @@ QString ExtcapArgument::value() bool ExtcapArgument::isValid() { + /* Unrequired arguments are always valid, except if validity checks fail, + * which must be checked in an derived class, not here */ + if ( ! isRequired() ) + return true; + return value().length() > 0; } diff --git a/ui/qt/extcap_argument.h b/ui/qt/extcap_argument.h index 9287628a7c..017a163378 100644 --- a/ui/qt/extcap_argument.h +++ b/ui/qt/extcap_argument.h @@ -27,9 +27,16 @@ #include #include #include +#include +#include +#include +#include #include +#define EXTCAP_GUI_BLANK_LABEL "QLabel { color : ; }" +#define EXTCAP_GUI_ERROR_LABEL "QLabel { color : red; }" + class ExtcapValue; typedef QList ExtcapValueList; @@ -108,6 +115,9 @@ protected: extcap_arg * _argument; QVariant * _default; + QWidget * _label; + + const QString label_style; private Q_SLOTS: @@ -117,6 +127,78 @@ private Q_SLOTS: }; +class ExtArgText : public ExtcapArgument +{ + +public: + ExtArgText(extcap_arg * argument); + + virtual QWidget * createEditor(QWidget * parent); + virtual QString value(); + virtual bool isValid(); + virtual QString defaultValue(); + +protected: + + QLineEdit * textBox; +}; + +class ExtArgNumber : public ExtArgText +{ +public: + ExtArgNumber(extcap_arg * argument); + + virtual QWidget * createEditor(QWidget * parent); + virtual QString defaultValue(); +}; + +class ExtArgSelector : public ExtcapArgument +{ +public: + ExtArgSelector(extcap_arg * argument); + + virtual QWidget * createEditor(QWidget * parent); + virtual QString value(); + virtual bool isValid(); + +private: + + QComboBox * boxSelection; +}; + +class ExtArgRadio : public ExtcapArgument +{ +public: + ExtArgRadio(extcap_arg * argument); + + virtual QWidget * createEditor(QWidget * parent); + virtual QString value(); + virtual bool isValid(); + +private: + + QButtonGroup * selectorGroup; + QList * callStrings; +}; + +class ExtArgBool : public ExtcapArgument +{ +public: + ExtArgBool(extcap_arg * argument); + + virtual QWidget * createLabel(QWidget * parent); + virtual QWidget * createEditor(QWidget * parent); + + virtual QString call(); + virtual QString value(); + virtual bool isValid(); + virtual QString defaultValue(); + +private: + + QCheckBox * boolBox; +}; + #endif /* UI_QT_EXTCAP_ARGUMENT_H_ */ /* diff --git a/ui/qt/extcap_argument_file.cpp b/ui/qt/extcap_argument_file.cpp index f0115ceda4..b93e889ef6 100644 --- a/ui/qt/extcap_argument_file.cpp +++ b/ui/qt/extcap_argument_file.cpp @@ -35,8 +35,10 @@ #include #include -#include +#include +#include +#include ExtcapArgumentFileSelection::ExtcapArgumentFileSelection (extcap_arg * argument) : ExtcapArgument(argument), textBox(0) @@ -118,9 +120,16 @@ void ExtcapArgumentFileSelection::openFileDialog() bool ExtcapArgumentFileSelection::isValid() { - if ( textBox->text().length() > 0 ) - return true; - return false; + bool valid = false; + + if ( textBox->text().length() > 0 || ! isRequired() ) + valid = true; + + QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name(); + QString txtStyle("QLineEdit { background-color: %1; } "); + textBox->setStyleSheet( txtStyle.arg(valid ? QString("") : lblInvalidColor) ); + + return valid; } /* diff --git a/ui/qt/extcap_argument_multiselect.cpp b/ui/qt/extcap_argument_multiselect.cpp index b99a75379d..fc01dfb351 100644 --- a/ui/qt/extcap_argument_multiselect.cpp +++ b/ui/qt/extcap_argument_multiselect.cpp @@ -32,11 +32,14 @@ #include #include +#include +#include + #include #include ExtArgMultiSelect::ExtArgMultiSelect(extcap_arg * argument) : - ExtcapArgument(argument), treeView(0), viewModel(0) {}; + ExtcapArgument(argument), treeView(0), viewModel(0) {} ExtArgMultiSelect::~ExtArgMultiSelect() { @@ -187,6 +190,31 @@ void ExtArgMultiSelect::selectionChanged(const QItemSelection &, const QItemSele emit valueChanged(); } +bool ExtArgMultiSelect::isValid() +{ + bool valid = true; + + if ( isRequired() ) + { + if ( viewModel == 0 ) + valid = false; + else + { + QStringList result; + QModelIndexList selected = treeView->selectionModel()->selectedIndexes(); + + if ( selected.size() <= 0 ) + valid = false; + } + } + + QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name(); + QString txtStyle("QTreeView { background-color: %1; } "); + treeView->setStyleSheet( txtStyle.arg(valid ? QString("") : lblInvalidColor) ); + + return valid; +} + /* * Editor modelines diff --git a/ui/qt/extcap_argument_multiselect.h b/ui/qt/extcap_argument_multiselect.h index 9b9dcd6480..9e72faeca2 100644 --- a/ui/qt/extcap_argument_multiselect.h +++ b/ui/qt/extcap_argument_multiselect.h @@ -41,6 +41,7 @@ public: virtual QString value(); virtual QString defaultValue(); + virtual bool isValid(); protected: virtual QList valueWalker(ExtcapValueList list, QStringList &defaults); diff --git a/ui/qt/extcap_options_dialog.cpp b/ui/qt/extcap_options_dialog.cpp index 229c5e5843..e2b5c165ca 100644 --- a/ui/qt/extcap_options_dialog.cpp +++ b/ui/qt/extcap_options_dialog.cpp @@ -56,6 +56,7 @@ #include #include +#include ExtcapOptionsDialog::ExtcapOptionsDialog(QWidget *parent) : QDialog(parent), @@ -104,6 +105,9 @@ ExtcapOptionsDialog * ExtcapOptionsDialog::createForDevice(QString &dev_name, QW resultDialog->updateWidgets(); + /* mark required fields */ + resultDialog->anyValueChanged(); + return resultDialog; } @@ -122,18 +126,55 @@ void ExtcapOptionsDialog::on_buttonBox_accepted() void ExtcapOptionsDialog::anyValueChanged() { - /* Guard, that only extcap arguments are given, which should be the case anyway */ - if ( dynamic_cast(QObject::sender()) == NULL ) - return; - bool allowStart = true; ExtcapArgumentList::const_iterator iter; - for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd() && allowStart; ++iter) + /* All arguments are being iterated, to ensure, that any error handling catches all arguments */ + for(iter = extcapArguments.constBegin(); iter != extcapArguments.constEnd(); ++iter) { - if ( (*iter)->isRequired() && ! (*iter)->isValid() ) - allowStart = false; + /* The dynamic casts are necessary, because we come here using the Signal/Slot system + * of Qt, and -in short- Q_OBJECT classes cannot be multiple inherited. Another possibility + * would be to use Q_INTERFACE, but this causes way more nightmares, and we really just + * need here an explicit cast for the check functionality */ + if ( dynamic_cast((*iter)) != NULL) + { + if ( ! ((ExtArgBool *)*iter)->isValid() ) + allowStart = false; + } + else if ( dynamic_cast((*iter)) != NULL) + { + if ( ! ((ExtArgRadio *)*iter)->isValid() ) + allowStart = false; + } + else if ( dynamic_cast((*iter)) != NULL) + { + if ( ! ((ExtArgSelector *)*iter)->isValid() ) + allowStart = false; + } + else if ( dynamic_cast((*iter)) != NULL) + { + if ( ! ((ExtArgMultiSelect *)*iter)->isValid() ) + allowStart = false; + } + else if ( dynamic_cast((*iter)) != NULL) + { + if ( ! ((ExtcapArgumentFileSelection *)*iter)->isValid() ) + allowStart = false; + } + else if ( dynamic_cast((*iter)) != NULL) + { + if ( ! ((ExtArgNumber *)*iter)->isValid() ) + allowStart = false; + } + else if ( dynamic_cast((*iter)) != NULL) + { + if ( ! ((ExtArgText *)*iter)->isValid() ) + allowStart = false; + } + else + if ( ! (*iter)->isValid() ) + allowStart = false; } ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowStart); @@ -156,6 +197,9 @@ void ExtcapOptionsDialog::updateWidgets() QGridLayout * layout = new QGridLayout(); + ExtcapArgumentList required; + ExtcapArgumentList optional; + while ( walker != NULL ) { item = g_list_first((GList *)(walker->data)); @@ -164,34 +208,50 @@ void ExtcapOptionsDialog::updateWidgets() argument = ExtcapArgument::create((extcap_arg *)(item->data), device_defaults); if ( argument != NULL ) { - extcapArguments << argument; + if ( argument->isRequired() ) + required << argument; + else + optional << argument; - lblWidget = argument->createLabel((QWidget *)this); - if ( lblWidget != NULL ) - { - layout->addWidget(lblWidget, counter, 0, Qt::AlignVCenter); - editWidget = argument->createEditor((QWidget *) this); - if ( editWidget != NULL ) - { - layout->addWidget(editWidget, counter, 1, Qt::AlignVCenter); - } - - if ( argument->isRequired() && ! argument->isValid() ) - allowStart = false; - - connect(argument, SIGNAL(valueChanged()), this, SLOT(anyValueChanged())); - - counter++; - } } - item = item->next; } walker = walker->next; } + if ( required.length() > 0 ) + extcapArguments << required; + + if ( optional.length() > 0 ) + extcapArguments << optional; + + ExtcapArgumentList::iterator iter = extcapArguments.begin(); + while ( iter != extcapArguments.end() ) + { + lblWidget = (*iter)->createLabel((QWidget *)this); + if ( lblWidget != NULL ) + { + layout->addWidget(lblWidget, counter, 0, Qt::AlignVCenter); + editWidget = (*iter)->createEditor((QWidget *) this); + if ( editWidget != NULL ) + { + layout->addWidget(editWidget, counter, 1, Qt::AlignVCenter); + } + + if ( (*iter)->isRequired() && ! (*iter)->isValid() ) + allowStart = false; + + connect((*iter), SIGNAL(valueChanged()), this, SLOT(anyValueChanged())); + + counter++; + } + ++iter; + } + if ( counter > 0 ) { + setStyleSheet ( "QLabel[isRequired=\"true\"] { font-weight: bold; } "); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowStart); ui->verticalLayout->addLayout(layout); diff --git a/ui/qt/interface_tree.cpp b/ui/qt/interface_tree.cpp index a506e13376..5d4839c80f 100644 --- a/ui/qt/interface_tree.cpp +++ b/ui/qt/interface_tree.cpp @@ -189,7 +189,7 @@ void InterfaceTree::display() #if HAVE_EXTCAP if ( device.if_info.type == IF_EXTCAP ) { - if ( extcap_has_configuration((const char *)(device.name)) ) + if ( extcap_has_configuration((const char *)(device.name), FALSE) ) { ti->setIcon(IFTREE_COL_EXTCAP, extcap_icon); ti->setData(IFTREE_COL_EXTCAP, Qt::UserRole, QString(device.if_info.extcap)); diff --git a/ui/qt/main_welcome.cpp b/ui/qt/main_welcome.cpp index 521c2aa6a9..667fbf582a 100644 --- a/ui/qt/main_welcome.cpp +++ b/ui/qt/main_welcome.cpp @@ -53,6 +53,10 @@ #define VERSION_FLAVOR "" #endif +#if HAVE_EXTCAP +#include +#endif + MainWelcome::MainWelcome(QWidget *parent) : QFrame(parent), welcome_ui_(new Ui::MainWelcome), @@ -230,6 +234,19 @@ void MainWelcome::appInitialized() void MainWelcome::interfaceDoubleClicked(QTreeWidgetItem *item, int) { if (item) { +#if HAVE_EXTCAP + QString extcap_string = QVariant(item->data(IFTREE_COL_EXTCAP, Qt::UserRole)).toString(); + /* We trust the string here. If this interface is really extcap, the string is + * being checked immediatly before the dialog is being generated */ + if ( extcap_string.length() > 0 ) { + QString device_name = QVariant(item->data(IFTREE_COL_NAME, Qt::UserRole)).toString(); + /* this checks if configuration is required and not yet provided or saved via prefs */ + if ( extcap_has_configuration((const char *)(device_name.toStdString().c_str()), TRUE ) ) { + emit showExtcapOptions(device_name); + return; + } + } +#endif emit startCapture(); } }