File indexing completed on 2024-05-05 17:42:44

0001 /*
0002     SPDX-FileCopyrightText: 2009 Paul Marchouk <pmarchouk@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "simpleipv4addressvalidator.h"
0008 
0009 #include <QStringList>
0010 #include <QVector>
0011 
0012 SimpleIpV4AddressValidator::SimpleIpV4AddressValidator(AddressStyle style, QObject *parent)
0013     : QValidator(parent)
0014     , m_addressStyle(style)
0015 {
0016     switch (style) {
0017     case Base:
0018         m_validator.setRegularExpression(QRegularExpression(QStringLiteral("[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}")));
0019         break;
0020     case WithCidr:
0021         m_validator.setRegularExpression(QRegularExpression(QStringLiteral("([0-9]{1,3}\\.){3,3}[0-9]{1,3}/[0-9]{1,2}")));
0022         break;
0023     case WithPort:
0024         m_validator.setRegularExpression(QRegularExpression(QStringLiteral("([0-9]{1,3}\\.){3,3}[0-9]{1,3}:[0-9]{1,5}")));
0025         break;
0026     }
0027 }
0028 
0029 SimpleIpV4AddressValidator::~SimpleIpV4AddressValidator() = default;
0030 
0031 QValidator::State SimpleIpV4AddressValidator::validate(QString &address, int &pos) const
0032 {
0033     QValidator::State maskResult = checkWithInputMask(address, pos);
0034     if (QValidator::Invalid == maskResult) {
0035         return QValidator::Invalid;
0036     }
0037 
0038     // this list will be filled with tetrad values. It can be used to make
0039     // some additional correctness checks on the last validation step.
0040     QList<int> tetrads;
0041 
0042     QValidator::State tetradResult = checkTetradsRanges(address, tetrads);
0043     if (QValidator::Invalid == tetradResult)
0044         return QValidator::Invalid;
0045     else if (QValidator::Intermediate == tetradResult || QValidator::Intermediate == maskResult)
0046         return QValidator::Intermediate;
0047     else
0048         return QValidator::Acceptable;
0049 }
0050 
0051 QValidator::State SimpleIpV4AddressValidator::checkWithInputMask(QString &value, int &pos) const
0052 {
0053     return m_validator.validate(value, pos);
0054 }
0055 
0056 QValidator::State SimpleIpV4AddressValidator::checkTetradsRanges(QString &value, QList<int> &tetrads) const
0057 {
0058     QStringList temp;
0059 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0060     QVector<QStringRef> addrParts;
0061 #else
0062     QVector<QStringView> addrParts;
0063 #endif
0064     QStringList cidrParts;
0065     QStringList portParts;
0066 
0067     switch (m_addressStyle) {
0068     case Base:
0069 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0070         addrParts = value.splitRef(QLatin1Char('.'));
0071 #else
0072         addrParts = QStringView(value).split(QLatin1Char('.'));
0073 #endif
0074         break;
0075 
0076     case WithCidr:
0077         cidrParts = value.split(QLatin1Char('/'));
0078 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0079         addrParts = cidrParts[0].splitRef(QLatin1Char('.'));
0080 #else
0081         addrParts = QStringView(cidrParts[0]).split(QLatin1Char('.'));
0082 #endif
0083         break;
0084 
0085     case WithPort:
0086         portParts = value.split(QLatin1Char(':'));
0087 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0088         addrParts = portParts[0].splitRef(QLatin1Char('.'));
0089 #else
0090         addrParts = QStringView(portParts[0]).split(QLatin1Char('.'));
0091 #endif
0092         break;
0093     }
0094 
0095     int i = 0;
0096     // fill in the list with invalid values
0097     tetrads << -1 << -1 << -1 << -1;
0098 
0099     // lets check address parts
0100 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0101     for (const QStringRef &part : std::as_const(addrParts)) {
0102 #else
0103     for (const QStringView &part : std::as_const(addrParts)) {
0104 #endif
0105         if (part.isEmpty()) {
0106             if (i != (addrParts.size() - 1)) {
0107                 // qCDebug(PLASMA_NM_EDITOR_LOG) << "part.isEmpty()";
0108                 return QValidator::Invalid;
0109             }
0110             // the last tetrad can be empty, continue...
0111             return QValidator::Intermediate;
0112         }
0113 
0114         tetrads[i] = part.toInt();
0115 
0116         if (tetrads[i] > 255) {
0117             // qCDebug(PLASMA_NM_EDITOR_LOG) << "tetrads[i] > 255";
0118             return QValidator::Invalid;
0119         }
0120 
0121         // correct tetrad value: for example, 001 -> 1
0122         temp.append(QString::number(tetrads[i]));
0123 
0124         i++;
0125     }
0126 
0127     // replace input string with the corrected version
0128     value = temp.join(QLatin1String("."));
0129 
0130     if (i < 4) {
0131         // not all tetrads are filled... continue
0132         // qCDebug(PLASMA_NM_EDITOR_LOG) << "QValidator::Intermediate";
0133         return QValidator::Intermediate;
0134     } else {
0135         if (m_addressStyle == WithCidr) {
0136             if (cidrParts.size() > 1) {
0137                 value += QLatin1String("/");
0138                 if (!cidrParts[1].isEmpty()) {
0139                     int cidrValue = cidrParts[1].toInt();
0140                     if (cidrValue > 32) {
0141                         return QValidator::Invalid;
0142                     } else {
0143                         value += cidrParts[1];
0144                         return QValidator::Acceptable;
0145                     }
0146                 } else {
0147                     return QValidator::Intermediate;
0148                 }
0149             }
0150         } else if (m_addressStyle == WithPort) {
0151             if (portParts.size() > 1) {
0152                 value += QLatin1String(":");
0153                 if (!portParts[1].isEmpty()) {
0154                     int portValue = portParts[1].toInt();
0155                     if (portValue > 65535) {
0156                         return QValidator::Invalid;
0157                     } else {
0158                         value += portParts[1];
0159                         return QValidator::Acceptable;
0160                     }
0161                 } else {
0162                     return QValidator::Intermediate;
0163                 }
0164             }
0165         }
0166 
0167         // qCDebug(PLASMA_NM_EDITOR_LOG) << "QValidator::Acceptable";
0168         return QValidator::Acceptable;
0169     }
0170 }