extcap: Add regular expression validation support
authorRoland Knall <roland.knall@br-automation.com>
Tue, 29 Dec 2015 14:35:43 +0000 (15:35 +0100)
committerStig Bjørlykke <stig@bjorlykke.org>
Tue, 5 Jan 2016 14:41:12 +0000 (14:41 +0000)
 Regular expressions follow the Qt Regex syntax, which is
 formulated after the Perl Regex syntax. A more detailed
 overview of the possible rules can be found at:
 http://doc.qt.io/qt-4.8/qregexp.html

 If a required option is present, even the double-click on
 the interface will first start the options dialog (Qt only)

 Required fields are marked bold and put first in the dialog.
 Additionally if validation failes (which it will if a required
 field is kept empty, but also if a non-required textfield is
 violating the defined regex), the label of the field is marked
 with red.

Change-Id: If04a1146d0dfa778332ab2a39122c7a6ee1e93d2
Reviewed-on: https://code.wireshark.org/review/12914
Petri-Dish: Stig Bjørlykke <stig@bjorlykke.org>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org>
13 files changed:
doc/extcap_example.py
extcap.c
extcap.h
extcap_parser.c
extcap_parser.h
ui/qt/extcap_argument.cpp
ui/qt/extcap_argument.h
ui/qt/extcap_argument_file.cpp
ui/qt/extcap_argument_multiselect.cpp
ui/qt/extcap_argument_multiselect.h
ui/qt/extcap_options_dialog.cpp
ui/qt/interface_tree.cpp
ui/qt/main_welcome.cpp

index 1eab8d39e40fcf94ff587777f41473eb1e0976d4..13c079d0ec39ad9933aa9b7adede1c949f4ff367 100755 (executable)
@@ -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('<H', int ( '0000', 16) )) # Checksum
-       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)
index 0a5e19ba3c4b0055416450d488ed2054546bddf9..6d66ad167cec9a269f2b1636cf804f8a4ea9dcb6 100644 (file)
--- 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);
index 47c6511dc5733fc02b2d35cab84e4cb6dc558068..813d4bd740a631fe135faeca4c9dcb70503c2018 100644 (file)
--- 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
index ef683f1a40c59c09b140b86ced3509c0ac61bc89..d884298a3a8d736272010cdb5a50f2e37163c531 100644 (file)
@@ -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');
index a730d200bc484cdd927e9b469122426aad20b02f..158838c16f9afe39ebb765468923dd1827baef40 100644 (file)
@@ -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;
index 0150446ae510c0f8e9a6e00edd56c0ee5f46aad9..2ae543660f82013bf25fc76e0e214fb611e24bb7 100644 (file)
 #include <QStandardItem>
 #include <QStandardItemModel>
 #include <QItemSelectionModel>
-#include <QTreeView>
+
+#include <epan/prefs.h>
+#include <color_utils.h>
 
 #include <extcap_parser.h>
 #include <extcap_argument_file.h>
 #include <extcap_argument_multiselect.h>
 
-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)
-    {
-        int counter = 0;
-        int selected = -1;
+    boxSelection = new QComboBox(parent);
 
-        boxSelection = new QComboBox(parent);
+    if ( values.length() > 0 )
+    {
+        ExtcapValueList::const_iterator iter = values.constBegin();
 
-        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;
+        }
 
-                counter++;
-                ++iter;
-            }
+        if ( selected > -1 && selected < boxSelection->count() )
+            boxSelection->setCurrentIndex(selected);
+    }
 
-            if ( selected > -1 && selected < boxSelection->count() )
-                boxSelection->setCurrentIndex(selected);
-        }
+    connect ( boxSelection, SIGNAL(currentIndexChanged(int)), SLOT(onIntChanged(int)) );
 
-        connect ( boxSelection, SIGNAL(currentIndexChanged(int)), SLOT(onIntChanged(int)) );
+    return boxSelection;
+}
 
-        return boxSelection;
-    }
+bool ExtArgSelector::isValid()
+{
+    bool valid = true;
 
-    virtual QString value()
-    {
-        if ( boxSelection == 0 )
-            return QString();
+    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();
-    }
-
-private:
+    return data.toString();
+}
 
-    QComboBox * boxSelection;
-};
+ExtArgRadio::ExtArgRadio(extcap_arg * argument) :
+        ExtcapArgument(argument), selectorGroup(0), callStrings(0) {}
 
-class ExtArgRadio : public ExtcapArgument
+QWidget * ExtArgRadio::createEditor(QWidget * parent)
 {
-public:
-    ExtArgRadio(extcap_arg * argument) :
-        ExtcapArgument(argument), selectorGroup(0), callStrings(0)
-    {
-    };
 
-    virtual QWidget * createEditor(QWidget * parent)
-    {
-
-        int count = 0;
-        bool anyChecked = false;
+    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;
+    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<QString>();
+    callStrings = new QList<QString>();
 
-        if ( values.length() > 0  )
-        {
-            ExtcapValueList::const_iterator iter = values.constBegin();
+    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);
+        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;
             }
-        }
 
-        /* No default was provided, and not saved value exists */
-        if ( anyChecked == false && count > 0 )
-            ((QRadioButton*)(selectorGroup->button(0)))->setChecked(true);
+            connect(radio, SIGNAL(clicked(bool)), SLOT(onBoolChanged(bool)));
+            selectorGroup->addButton(radio, count);
 
-        radioButtons->setLayout(vrLayout);
+            vrLayout->addWidget(radio);
+            count++;
 
-        return radioButtons;
+            ++iter;
+        }
     }
 
-    virtual QString value()
-    {
-        int idx = 0;
-        if ( selectorGroup == 0 || callStrings == 0 )
-            return QString();
+    /* No default was provided, and not saved value exists */
+    if ( anyChecked == false && count > 0 )
+        ((QRadioButton*)(selectorGroup->button(0)))->setChecked(true);
+
+    radioButtons->setLayout(vrLayout);
 
-        idx = selectorGroup->checkedId();
-        if ( idx > -1 && callStrings->length() > idx )
-            return callStrings->takeAt(idx);
+    return radioButtons;
+}
 
+QString ExtArgRadio::value()
+{
+    int idx = 0;
+    if ( selectorGroup == 0 || callStrings == 0 )
         return QString();
-    }
 
-private:
+    idx = selectorGroup->checkedId();
+    if ( idx > -1 && callStrings->length() > idx )
+        return callStrings->takeAt(idx);
 
-    QButtonGroup * selectorGroup;
-    QList<QString> * callStrings;
-};
+    return QString();
+}
 
-class ExtArgBool : public ExtcapArgument
+bool ExtArgRadio::isValid()
 {
-public:
-    ExtArgBool(extcap_arg * argument) :
-        ExtcapArgument(argument), boolBox(0) {};
+    bool valid = true;
+    int idx = 0;
 
-    virtual QWidget * createLabel(QWidget * parent)
+    if ( isRequired() )
     {
-        return new QWidget(parent);
+        if ( selectorGroup == 0 || callStrings == 0 )
+            valid = false;
+        else
+        {
+            idx = selectorGroup->checkedId();
+            if ( idx == -1 || callStrings->length() <= idx )
+                valid = false;
+        }
     }
 
-    virtual QWidget * createEditor(QWidget * parent)
-    {
-        boolBox = new QCheckBox(QString().fromUtf8(_argument->display), parent);
-        if ( _argument->tooltip != NULL )
-            boolBox->setToolTip(QString().fromUtf8(_argument->tooltip));
+    /* 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) );
 
-        if ( _argument->default_complex != NULL )
-            if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE )
-                boolBox->setCheckState(Qt::Checked);
+    return valid;
+}
 
-        if ( _default != NULL )
-        {
-            if ( _default->toString().compare("true") )
-                boolBox->setCheckState(Qt::Checked);
-        }
+ExtArgBool::ExtArgBool(extcap_arg * argument) :
+        ExtcapArgument(argument), boolBox(0) {}
 
-        connect (boolBox, SIGNAL(stateChanged(int)), SLOT(onIntChanged(int)));
+QWidget * ExtArgBool::createLabel(QWidget * parent)
+{
+    return new QWidget(parent);
+}
 
-        return boolBox;
-    }
+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);
 
-    virtual QString call()
+    if ( _default != NULL )
     {
-        if ( boolBox == NULL )
-            return QString("");
+        if ( _default->toString().compare("true") )
+            boolBox->setCheckState(Qt::Checked);
+    }
 
-        if ( _argument->arg_type == EXTCAP_ARG_BOOLEAN )
-            return ExtcapArgument::call();
+    connect (boolBox, SIGNAL(stateChanged(int)), SLOT(onIntChanged(int)));
 
-        return QString(boolBox->checkState() == Qt::Checked ? _argument->call : "");
-    }
+    return boolBox;
+}
 
-    virtual QString value()
-    {
-        if ( boolBox == NULL || _argument->arg_type == EXTCAP_ARG_BOOLFLAG )
-            return QString();
-        return QString(boolBox->checkState() == Qt::Checked ? "true" : "false");
-    }
+QString ExtArgBool::call()
+{
+    if ( boolBox == NULL )
+        return QString("");
 
-    virtual QString defaultValue()
-    {
-        if ( _argument != 0 && _argument->default_complex != NULL )
-            if ( extcap_complex_get_bool(_argument->default_complex) == (gboolean)TRUE )
-                return QString("true");
+    if ( _argument->arg_type == EXTCAP_ARG_BOOLEAN )
+        return ExtcapArgument::call();
 
-        return QString("false");
-    }
+    return QString(boolBox->checkState() == Qt::Checked ? _argument->call : "");
+}
 
-private:
+QString ExtArgBool::value()
+{
+    if ( boolBox == NULL || _argument->arg_type == EXTCAP_ARG_BOOLFLAG )
+        return QString();
+    return QString(boolBox->checkState() == Qt::Checked ? "true" : "false");
+}
 
-    QCheckBox * boolBox;
-};
+bool ExtArgBool::isValid()
+{
+    /* A bool is allways valid, but the base function checks on string length,
+     * which will fail with boolflags */
+    return true;
+}
 
-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;
+}
 
-        return textBox->text();
-    }
+QString ExtArgText::value()
+{
+    if ( textBox == 0 )
+        return QString();
 
-    virtual bool isValid()
-    {
-        if ( isRequired() && value().length() == 0 )
-            return false;
+    return textBox->text();
+}
 
-        return true;
-    }
+bool ExtArgText::isValid()
+{
+    bool valid = true;
+
+    if ( isRequired() && value().length() == 0 )
+        valid = false;
 
-    virtual QString defaultValue()
+    /* 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)
     {
-        if ( _argument != 0 && _argument->default_complex != 0)
+        QString regexp = QString().fromUtf8(_argument->regexp);
+        if ( regexp.length() > 0 )
         {
-            gchar * str = extcap_get_complex_as_string(_argument->default_complex);
-            if ( str != 0 )
-                return QString(str);
+            QRegExp expr(regexp);
+            if ( ! expr.isValid() || expr.indexIn(value(), 0) == -1 )
+                valid = false;
         }
+    }
 
-        return QString();
+    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);
     }
 
-protected:
+    return QString();
+}
 
-    QLineEdit * textBox;
-};
+ExtArgNumber::ExtArgNumber(extcap_arg * argument) :
+        ExtArgText(argument) {}
 
-class ExtArgNumber : public ExtArgText
+QWidget * ExtArgNumber::createEditor(QWidget * parent)
 {
-public:
-    ExtArgNumber(extcap_arg * argument) :
-        ExtArgText(argument) {};
+    textBox = (QLineEdit *)ExtArgText::createEditor(parent);
+    textBox->disconnect(SIGNAL(textChanged(QString)));
 
-    virtual QWidget * createEditor(QWidget * parent)
+    if ( _argument->arg_type == EXTCAP_ARG_INTEGER || _argument->arg_type == EXTCAP_ARG_UNSIGNED )
     {
-        textBox = (QLineEdit *)ExtArgText::createEditor(parent);
-        textBox->disconnect(SIGNAL(textChanged(QString)));
+        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_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->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));
 
-            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->setValidator(textValidator);
-        }
+    textBox->setText(defaultValue());
 
-        textBox->setText(defaultValue());
+    connect(textBox, SIGNAL(textChanged(QString)), SLOT(onStringChanged(QString)));
 
-        connect(textBox, SIGNAL(textChanged(QString)), SLOT(onStringChanged(QString)));
+    return textBox;
+}
 
-        return textBox;
-    };
+QString ExtArgNumber::defaultValue()
+{
+    QString result;
 
-    virtual QString defaultValue()
+    if ( _argument != 0 && _argument->default_complex != NULL )
     {
-        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;
+        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);
+    _label = new QLabel(text, parent);
+
+    _label->setProperty("isRequired", QString(isRequired() ? "true" : "false"));
+
+    _label->setStyleSheet ( label_style.arg(QString("")) );
+
     if ( _argument->tooltip != 0 )
-        label->setToolTip(QString().fromUtf8(_argument->tooltip));
+        _label->setToolTip(QString().fromUtf8(_argument->tooltip));
 
-    return label;
+    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;
 }
 
index 9287628a7cc433944a10a3416defa70ed799f53e..017a163378b5a7725771e8b5045b6507681dda6e 100644 (file)
 #include <QLabel>
 #include <QVariant>
 #include <QList>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QButtonGroup>
+#include <QCheckBox>
 
 #include <extcap_parser.h>
 
+#define EXTCAP_GUI_BLANK_LABEL "QLabel { color : ; }"
+#define EXTCAP_GUI_ERROR_LABEL "QLabel { color : red; }"
+
 class ExtcapValue;
 
 typedef QList<ExtcapValue> 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<QString> * 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_ */
 
 /*
index f0115ceda441a0960f3faf757956bd5a753a8bad..b93e889ef6a14f1569085c40b98f1ebc631c5229 100644 (file)
 #include <QFileInfo>
 #include <QVariant>
 
-#include <extcap_parser.h>
+#include <epan/prefs.h>
+#include <color_utils.h>
 
+#include <extcap_parser.h>
 
 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;
 }
 
 /*
index b99a75379d101e29e5b65a3f88404f5e5d30fd0f..fc01dfb351be634a7dab5916e9a62d1e7053b4be 100644 (file)
 #include <QPushButton>
 #include <QVariant>
 
+#include <epan/prefs.h>
+#include <color_utils.h>
+
 #include <extcap_parser.h>
 #include <extcap_argument_multiselect.h>
 
 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
index 9b9dcd6480f5a8d3cae46ef7db37cd94d85395e5..9e72faeca2dec87f49975469e6c51cb9fc793d9f 100644 (file)
@@ -41,6 +41,7 @@ public:
 
     virtual QString value();
     virtual QString defaultValue();
+    virtual bool isValid();
 
 protected:
     virtual QList<QStandardItem *> valueWalker(ExtcapValueList list, QStringList &defaults);
index 229c5e58436211a15731a27e9249a118ef5c8375..e2b5c165ca9663b5a5a83f204075459eda9c80f4 100644 (file)
@@ -56,6 +56,7 @@
 
 #include <ui/qt/extcap_argument.h>
 #include <ui/qt/extcap_argument_file.h>
+#include <ui/qt/extcap_argument_multiselect.h>
 
 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<ExtcapArgument *>(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<ExtArgBool *>((*iter)) != NULL)
+        {
+            if ( ! ((ExtArgBool *)*iter)->isValid() )
+                allowStart = false;
+        }
+        else if ( dynamic_cast<ExtArgRadio *>((*iter)) != NULL)
+        {
+            if ( ! ((ExtArgRadio *)*iter)->isValid() )
+                allowStart = false;
+        }
+        else if ( dynamic_cast<ExtArgSelector *>((*iter)) != NULL)
+        {
+            if ( ! ((ExtArgSelector *)*iter)->isValid() )
+                allowStart = false;
+        }
+        else if ( dynamic_cast<ExtArgMultiSelect *>((*iter)) != NULL)
+        {
+            if ( ! ((ExtArgMultiSelect *)*iter)->isValid() )
+                allowStart = false;
+        }
+        else if ( dynamic_cast<ExtcapArgumentFileSelection *>((*iter)) != NULL)
+        {
+            if ( ! ((ExtcapArgumentFileSelection *)*iter)->isValid() )
+                allowStart = false;
+        }
+        else if ( dynamic_cast<ExtArgNumber *>((*iter)) != NULL)
+        {
+            if ( ! ((ExtArgNumber *)*iter)->isValid() )
+                allowStart = false;
+        }
+        else if ( dynamic_cast<ExtArgText *>((*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);
-                    }
+            }
+            item = item->next;
+        }
+        walker = walker->next;
+    }
 
-                    if ( argument->isRequired() && ! argument->isValid() )
-                        allowStart = false;
+    if ( required.length() > 0 )
+        extcapArguments << required;
 
-                    connect(argument, SIGNAL(valueChanged()), this, SLOT(anyValueChanged()));
+    if ( optional.length() > 0 )
+        extcapArguments << optional;
 
-                    counter++;
-                }
+    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);
             }
 
-            item = item->next;
+            if ( (*iter)->isRequired() && ! (*iter)->isValid() )
+                allowStart = false;
+
+            connect((*iter), SIGNAL(valueChanged()), this, SLOT(anyValueChanged()));
+
+            counter++;
         }
-        walker = walker->next;
+        ++iter;
     }
 
     if ( counter > 0 )
     {
+        setStyleSheet ( "QLabel[isRequired=\"true\"] { font-weight: bold; } ");
+
         ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowStart);
 
         ui->verticalLayout->addLayout(layout);
index a506e13376e21b0464c8ba199cd578d07e43ce76..5d4839c80f93aa4d6abf5e3ca57a6f6e1efd54db 100644 (file)
@@ -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));
index 521c2aa6a93321b2b4ac4b288f92d761442a11f7..667fbf582a0c1e121f9a37d25dfbe9b1ba9ebdf9 100644 (file)
 #define VERSION_FLAVOR ""
 #endif
 
+#if HAVE_EXTCAP
+#include <extcap.h>
+#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();
     }
 }