6#include "validatoremail_p.h"
18const QRegularExpression ValidatorEmailPrivate::ipv4Regex{
19 u
"\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25["
20 "0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"_qs};
21const QRegularExpression ValidatorEmailPrivate::ipv6PartRegex{u
"^[0-9A-Fa-f]{0,4}$"_qs};
22const QString ValidatorEmailPrivate::stringSpecials{u
"()<>[]:;@\\,.\""_qs};
28 const QString &defValKey)
29 :
ValidatorRule(*new ValidatorEmailPrivate(field, threshold, options, messages, defValKey))
39 const QString v =
value(params);
69 ValidatorEmailDiagnoseStruct diag;
71 if (ValidatorEmailPrivate::checkEmail(v, d->options, d->threshold, &diag)) {
72 if (!diag.literal.isEmpty()) {
73 result.
value.setValue<QString>(diag.localpart + QLatin1Char(
'@') + diag.literal);
75 result.
value.setValue<QString>(diag.localpart + QLatin1Char(
'@') + diag.domain);
82 result.
extra = QVariant::fromValue<QList<Diagnose>>(diag.returnStatus);
100bool ValidatorEmailPrivate::checkEmail(
const QString &address,
101 ValidatorEmail::Options options,
103 ValidatorEmailDiagnoseStruct *diagnoseStruct)
107 EmailPart context = ComponentLocalpart;
108 QList<EmailPart> contextStack{context};
109 EmailPart contextPrior = ComponentLocalpart;
114 QString parseLocalPart;
116 QString parseLiteral;
117 QMap<int, QString> atomListLocalPart;
118 QMap<int, QString> atomListDomain;
119 int elementCount = 0;
121 bool hypenFlag =
false;
122 bool endOrDie =
false;
130 const qsizetype atPos = address.lastIndexOf(QLatin1Char(
'@'));
133 const QString local = address.left(atPos);
134 const QString domain = address.mid(atPos + 1);
135 bool asciiDomain =
true;
136 for (
const QChar &ch : domain) {
137 const ushort &uc = ch.unicode();
138 if (uc > ValidatorEmailPrivate::asciiEnd) {
147 email = local + QLatin1Char(
'@') + QString::fromLatin1(QUrl::toAce(domain));
156 const qsizetype rawLength = email.length();
158 for (
int i = 0; i < rawLength; i++) {
165 case ComponentLocalpart:
184 if (token == QLatin1Char(
'(')) {
185 if (elementLen == 0) {
195 contextStack.push_back(context);
196 context = ContextComment;
197 }
else if (token == QLatin1Char(
'.')) {
198 if (elementLen == 0) {
200 returnStatus.push_back((elementCount == 0)
215 parseLocalPart += token;
216 atomListLocalPart[elementCount] = QString();
217 }
else if (token == QLatin1Char(
'"')) {
218 if (elementLen == 0) {
221 returnStatus.push_back((elementCount == 0)
225 parseLocalPart += token;
226 atomListLocalPart[elementCount] += token;
229 contextStack.push_back(context);
230 context = ContextQuotedString;
234 }
else if ((token == QChar(QChar::CarriageReturn)) || (token == QChar(QChar::Space)) ||
235 (token == QChar(QChar::Tabulation))) {
236 if ((token == QChar(QChar::CarriageReturn)) &&
237 ((++i == rawLength) || (email[i] != QChar(QChar::LineFeed)))) {
242 if (elementLen == 0) {
250 contextStack.push_back(context);
251 context = ContextFWS;
253 }
else if (token == QLatin1Char(
'@')) {
255 if (contextStack.size() != 1) {
257 qCCritical(C_VALIDATOR) <<
"ValidatorEmail: Unexpected item on context stack";
261 if (parseLocalPart.isEmpty()) {
263 }
else if (elementLen == 0) {
265 }
else if (parseLocalPart.size() > ValidatorEmailPrivate::maxLocalPartLength) {
270 }
else if ((contextPrior == ContextComment) || (contextPrior == ContextFWS)) {
284 context = ComponentDomain;
285 contextStack.clear();
286 contextStack.push_back(context);
305 switch (contextPrior) {
310 case ContextQuotedString:
315 qCCritical(C_VALIDATOR)
316 <<
"ValidatorEmail: More atext found where none is allowed, "
317 "but unrecognizes prior context";
321 contextPrior = context;
322 const char16_t uni = token.unicode();
324 if (!allowUtf8Local) {
325 if ((uni < ValidatorEmailPrivate::asciiExclamationMark) ||
326 (uni > ValidatorEmailPrivate::asciiTilde) ||
327 ValidatorEmailPrivate::stringSpecials.contains(token)) {
328 returnStatus.push_back(
332 if (!token.isLetterOrNumber()) {
333 if ((uni < ValidatorEmailPrivate::asciiExclamationMark) ||
334 (uni > ValidatorEmailPrivate::asciiTilde) ||
335 ValidatorEmailPrivate::stringSpecials.contains(token)) {
336 returnStatus.push_back(
342 parseLocalPart += token;
343 atomListLocalPart[elementCount] += token;
351 case ComponentDomain:
391 if (token == QLatin1Char(
'(')) {
392 if (elementLen == 0) {
396 returnStatus.push_back((elementCount == 0)
405 contextStack.push_back(context);
406 context = ContextComment;
407 }
else if (token == QLatin1Char(
'.')) {
408 if (elementLen == 0) {
410 returnStatus.push_back((elementCount == 0)
413 }
else if (hypenFlag) {
429 if (elementLen > ValidatorEmailPrivate::maxDnsLabelLength) {
438 atomListDomain[elementCount] = QString();
439 parseDomain += token;
441 }
else if (token == QLatin1Char(
'[')) {
442 if (parseDomain.isEmpty()) {
445 contextStack.push_back(context);
446 context = ComponentLiteral;
447 parseDomain += token;
448 atomListDomain[elementCount] += token;
449 parseLiteral = QString();
453 }
else if ((token == QChar(QChar::CarriageReturn)) || (token == QChar(QChar::Space)) ||
454 (token == QChar(QChar::Tabulation))) {
455 if ((token == QChar(QChar::CarriageReturn)) &&
456 ((++i == rawLength) || email[i] != QChar(QChar::LineFeed))) {
461 if (elementLen == 0) {
462 returnStatus.push_back((elementCount == 0)
471 contextStack.push_back(context);
472 context = ContextFWS;
500 switch (contextPrior) {
505 case ComponentLiteral:
510 qCCritical(C_VALIDATOR)
511 <<
"ValidatorEmail: More atext found where none is allowed, but"
512 <<
"unrecognised prior context.";
517 const char16_t uni = token.unicode();
520 if ((uni < ValidatorEmailPrivate::asciiExclamationMark) ||
521 (uni > ValidatorEmailPrivate::asciiTilde) ||
522 ValidatorEmailPrivate::stringSpecials.contains(token)) {
524 }
else if (token == QLatin1Char(
'-')) {
525 if (elementLen == 0) {
527 returnStatus.push_back(
531 }
else if (!(((uni >= ValidatorRulePrivate::ascii_0) &&
532 (uni <= ValidatorRulePrivate::ascii_9)) ||
533 ((uni >= ValidatorRulePrivate::ascii_A) &&
534 (uni <= ValidatorRulePrivate::ascii_Z)) ||
535 ((uni >= ValidatorRulePrivate::ascii_a) &&
536 (uni <= ValidatorRulePrivate::ascii_z)))) {
541 parseDomain += token;
542 atomListDomain[elementCount] += token;
549 case ComponentLiteral:
559 if (token == QLatin1Char(
']')) {
560 if (
static_cast<int>(
561 *std::max_element(returnStatus.constBegin(), returnStatus.constEnd())) <
617 qsizetype index = -1;
618 QString addressLiteral = parseLiteral;
620 const QRegularExpressionMatch ipv4Match =
621 ValidatorEmailPrivate::ipv4Regex.match(addressLiteral);
622 if (ipv4Match.hasMatch()) {
623 index = addressLiteral.lastIndexOf(ipv4Match.captured());
626 addressLiteral.mid(0, index) +
635 }
else if (QString::compare(
636 addressLiteral.left(5),
642 const QString ipv6 = addressLiteral.mid(5);
643 const QStringList matchesIP = ipv6.split(QLatin1Char(
':'));
644 qsizetype groupCount = matchesIP.size();
645 index = ipv6.indexOf(QLatin1String(
"::"));
649 if (groupCount != maxGroups) {
653 if (index != ipv6.lastIndexOf(QLatin1String(
"::"))) {
656 if ((index == 0) || (index == (ipv6.length() - 2))) {
660 if (groupCount > maxGroups) {
662 }
else if (groupCount == maxGroups) {
663 returnStatus.push_back(
670 if ((ipv6.size() == 1 && ipv6[0] == QLatin1Char(
':')) ||
671 (ipv6[0] == QLatin1Char(
':') && ipv6[1] != QLatin1Char(
':'))) {
672 returnStatus.push_back(
675 }
else if (ipv6.right(2).at(1) == QLatin1Char(
':') &&
676 ipv6.right(2).at(0) != QLatin1Char(
':')) {
677 returnStatus.push_back(
681 int unmatchedChars = 0;
682 for (
const QString &ip : matchesIP) {
683 if (!ip.contains(ValidatorEmailPrivate::ipv6PartRegex)) {
687 if (unmatchedChars != 0) {
699 parseDomain += token;
700 atomListDomain[elementCount] += token;
702 contextPrior = context;
703 context = contextStack.takeLast();
704 }
else if (token == QLatin1Char(
'\\')) {
706 contextStack.push_back(context);
707 context = ContextQuotedPair;
708 }
else if ((token == QChar(QChar::CarriageReturn)) || (token == QChar(QChar::Space)) ||
709 (token == QChar(QChar::Tabulation))) {
710 if ((token == QChar(QChar::CarriageReturn)) &&
711 ((++i == rawLength) || (email[i] != QChar(QChar::LineFeed)))) {
717 contextStack.push_back(context);
718 context = ContextFWS;
734 const char16_t uni = token.unicode();
737 if ((uni > ValidatorEmailPrivate::asciiEnd) || (uni == 0) ||
738 (uni == QLatin1Char(
'[').unicode())) {
741 }
else if ((uni < ValidatorEmailPrivate::asciiExclamationMark) ||
742 (uni == ValidatorEmailPrivate::asciiEnd)) {
746 parseLiteral += token;
747 parseDomain += token;
748 atomListDomain[elementCount] += token;
755 case ContextQuotedString:
763 if (token == QLatin1Char(
'\\')) {
764 contextStack.push_back(context);
765 context = ContextQuotedPair;
766 }
else if ((token == QChar(QChar::CarriageReturn)) ||
767 (token == QChar(QChar::Tabulation))) {
770 if ((token == QChar(QChar::CarriageReturn)) &&
771 ((++i == rawLength) || (email[i] != QChar(QChar::LineFeed)))) {
785 parseLocalPart += QChar(QChar::Space);
786 atomListLocalPart[elementCount] += QChar(QChar::Space);
790 contextStack.push_back(context);
791 context = ContextFWS;
793 }
else if (token == QLatin1Char(
'"')) {
794 parseLocalPart += token;
795 atomListLocalPart[elementCount] += token;
797 contextPrior = context;
798 context = contextStack.takeLast();
813 const char16_t uni = token.unicode();
815 if (!allowUtf8Local) {
816 if ((uni > ValidatorEmailPrivate::asciiEnd) || (uni == 0) ||
817 (uni == ValidatorEmailPrivate::asciiLF)) {
819 }
else if ((uni < ValidatorRulePrivate::asciiSpace) ||
820 (uni == ValidatorEmailPrivate::asciiEnd)) {
824 if (!token.isLetterOrNumber()) {
825 if ((uni > ValidatorEmailPrivate::asciiEnd) || (uni == 0) ||
826 (uni == ValidatorEmailPrivate::asciiLF)) {
827 returnStatus.push_back(
829 }
else if ((uni < ValidatorRulePrivate::asciiSpace) ||
830 (uni == ValidatorEmailPrivate::asciiEnd)) {
836 parseLocalPart += token;
837 atomListLocalPart[elementCount] += token;
852 case ContextQuotedPair:
870 const char16_t uni = token.unicode();
872 if (uni > ValidatorEmailPrivate::asciiEnd) {
874 }
else if (((uni < ValidatorEmailPrivate::asciiUS) &&
875 (uni != ValidatorRulePrivate::asciiTab)) ||
876 (uni == ValidatorEmailPrivate::asciiEnd)) {
887 contextPrior = context;
888 context = contextStack.takeLast();
893 case ContextQuotedString:
894 parseLocalPart += QLatin1Char(
'\\');
895 parseLocalPart += token;
896 atomListLocalPart[elementCount] += QLatin1Char(
'\\');
897 atomListLocalPart[elementCount] += token;
901 case ComponentLiteral:
902 parseDomain += QLatin1Char(
'\\');
903 parseDomain += token;
904 atomListDomain[elementCount] += QLatin1Char(
'\\');
905 atomListDomain[elementCount] += token;
911 qCCritical(C_VALIDATOR)
912 <<
"ValidatorEmail: Quoted pair logic invoked in an invalid context.";
925 if (token == QLatin1Char(
'(')) {
927 contextStack.push_back(context);
928 context = ContextComment;
929 }
else if (token == QLatin1Char(
')')) {
930 contextPrior = context;
931 context = contextStack.takeLast();
949 }
else if (token == QLatin1Char(
'\\')) {
950 contextStack.push_back(context);
951 context = ContextQuotedPair;
952 }
else if ((token == QChar(QChar::CarriageReturn)) || (token == QChar(QChar::Space)) ||
953 (token == QChar(QChar::Tabulation))) {
954 if ((token == QChar(QChar::CarriageReturn)) &&
955 ((++i == rawLength) || (email[i] != QChar(QChar::LineFeed)))) {
961 contextStack.push_back(context);
962 context = ContextFWS;
979 const ushort uni = token.unicode();
981 if ((uni > ValidatorEmailPrivate::asciiEnd) || (uni == 0) ||
982 (uni == ValidatorEmailPrivate::asciiLF)) {
985 }
else if ((uni < ValidatorRulePrivate::asciiSpace) ||
986 (uni == ValidatorEmailPrivate::asciiEnd)) {
1008 if (tokenPrior == QChar(QChar::CarriageReturn)) {
1009 if (token == QChar(QChar::CarriageReturn)) {
1014 if (crlf_count > 0) {
1015 if (++crlf_count > 1) {
1016 returnStatus.push_back(
1024 if (token == QChar(QChar::CarriageReturn)) {
1025 if ((++i == rawLength) || (email[i] != QChar(QChar::LineFeed))) {
1029 }
else if ((token != QChar(QChar::Space)) && (token != QChar(QChar::Tabulation))) {
1030 if (tokenPrior == QChar(QChar::CarriageReturn)) {
1035 if (crlf_count > 0) {
1039 contextPrior = context;
1040 context = contextStack.takeLast();
1066 qCCritical(C_VALIDATOR) <<
"ValidatorEmail: Unknown context";
1070 if (
static_cast<int>(
1071 *std::max_element(returnStatus.constBegin(), returnStatus.constEnd())) >
1078 if (
static_cast<int>(*std::max_element(returnStatus.constBegin(), returnStatus.constEnd())) <
1080 if (context == ContextQuotedString) {
1082 }
else if (context == ContextQuotedPair) {
1084 }
else if (context == ContextComment) {
1086 }
else if (context == ComponentLiteral) {
1088 }
else if (token == QChar(QChar::CarriageReturn)) {
1090 }
else if (parseDomain.isEmpty()) {
1092 }
else if (elementLen == 0) {
1094 }
else if (hypenFlag) {
1096 }
else if (parseDomain.size() > 255) {
1100 }
else if ((parseLocalPart.size() + 1 + parseDomain.size()) > 254) {
1120 }
else if (elementLen > ValidatorEmailPrivate::maxDnsLabelLength) {
1126 bool dnsChecked =
false;
1129 (
static_cast<int>(*std::max_element(returnStatus.constBegin(), returnStatus.constEnd())) <
1130 static_cast<int>(threshold))) {
1144 if (elementCount == 0) {
1145 parseDomain += QLatin1Char(
'.');
1148 QDnsLookup mxLookup(QDnsLookup::MX, parseDomain);
1150 QObject::connect(&mxLookup, &QDnsLookup::finished, &mxLoop, &QEventLoop::quit);
1151 QTimer::singleShot(ValidatorEmailPrivate::dnsLookupTimeout, &mxLookup, &QDnsLookup::abort);
1155 if ((mxLookup.error() == QDnsLookup::NoError) && !mxLookup.mailExchangeRecords().empty()) {
1159 QDnsLookup aLookup(QDnsLookup::A, parseDomain);
1161 QObject::connect(&aLookup, &QDnsLookup::finished, &aLoop, &QEventLoop::quit);
1163 ValidatorEmailPrivate::dnsLookupTimeout, &aLookup, &QDnsLookup::abort);
1167 if ((aLookup.error() == QDnsLookup::NoError) && !aLookup.hostAddressRecords().empty()) {
1208 (
static_cast<int>(*std::max_element(returnStatus.constBegin(), returnStatus.constEnd())) <
1210 if (elementCount == 0) {
1214 if (QStringLiteral(
"0123456789").contains(atomListDomain[elementCount][0])) {
1219 if (returnStatus.size() != 1) {
1220 QList<ValidatorEmail::Diagnose> _rs;
1228 std::sort(returnStatus.begin(), returnStatus.end(), std::greater<>());
1233 if (diagnoseStruct) {
1234 diagnoseStruct->finalStatus = finalStatus;
1235 diagnoseStruct->returnStatus = returnStatus;
1236 diagnoseStruct->localpart = parseLocalPart;
1237 diagnoseStruct->domain = parseDomain;
1238 diagnoseStruct->literal = parseLiteral;
1241 return static_cast<int>(finalStatus) <
static_cast<int>(threshold);
1248 if (
label.isEmpty()) {
1252 c->
translate(
"Cutelyst::ValidatorEmail",
1253 "Address is valid. Please note that this does not mean that both the "
1254 "address and the domain actually exist. This address could be issued "
1255 "by the domain owner without breaking the rules of any RFCs.");
1259 "Cutelyst::ValidatorEmail",
1260 "Could not find an MX record for this address’ domain but an A record does exist.");
1264 "Cutelyst::ValidatorEmail",
1265 "Could neither find an MX record nor an A record for this address’ domain.");
1268 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1269 "Address is valid but at a Top Level Domain.");
1272 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1273 "Address is valid but the Top Level Domain begins with a number.");
1276 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1277 "Address is valid but contains a quoted string.");
1280 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1281 "Address is valid but uses an IP address instead of a domain name.");
1284 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1285 "Address is valid but uses an IP address that contains a :: only "
1286 "eliding one zero group. All implementations must accept and be "
1287 "able to handle any legitimate RFC 4291 format.");
1290 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"Address contains comments.");
1293 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1294 "Address contains folding white spaces like line breaks.");
1298 c->
translate(
"Cutelyst::ValidatorEmail",
"The local part is in a deprecated form.");
1301 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1302 "Address contains an obsolete form of folding white spaces.");
1305 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1306 "A quoted string contains a deprecated character.");
1309 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1310 "A quoted pair contains a deprecated character.");
1313 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1314 "Address contains a comment in a position that is deprecated.");
1317 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1318 "A comment contains a deprecated character.");
1322 "Cutelyst::ValidatorEmail",
1323 "Address contains a comment or folding white space around the @ sign.");
1326 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1327 "Address is RFC 5322 compliant but contains domain characters that "
1328 "are not allowed by DNS.");
1331 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"Address is too long.");
1334 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1335 "The local part of the address is too long.");
1338 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"The domain part is too long.");
1341 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1342 "The domain part contains an element that is too long.");
1345 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1346 "The domain literal is not a valid RFC 5321 address literal.");
1349 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1350 "The domain literal is not a valid RFC 5321 domain literal and it "
1351 "contains obsolete characters.");
1354 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1355 "The IPv6 literal address contains the wrong number of groups.");
1358 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1359 "The IPv6 literal address contains too many :: sequences.");
1362 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1363 "The IPv6 address contains an illegal group of characters.");
1366 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"The IPv6 address has too many groups.");
1369 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1370 "The IPv6 address starts with a single colon.");
1373 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1374 "The IPv6 address ends with a single colon.");
1377 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1378 "A domain literal contains a character that is not allowed.");
1381 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"Address has no local part.");
1384 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"Address has no domain part.");
1387 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1388 "The address must not contain consecutive dots.");
1391 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1392 "Address contains text after a comment or folding white space.");
1395 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1396 "Address contains text after a quoted string.");
1399 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1400 "Extra characters were found after the end of the domain literal.");
1404 "Cutelyst::ValidatorEmail",
1405 "The Address contains a character that is not allowed in a quoted pair.");
1408 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1409 "Address contains a character that is not allowed.");
1412 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1413 "A quoted string contains a character that is not allowed.");
1416 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1417 "A comment contains a character that is not allowed.");
1420 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1421 "The address can not end with a backslash.");
1424 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1425 "Neither part of the address may begin with a dot.");
1428 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1429 "Neither part of the address may end with a dot.");
1432 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1433 "A domain or subdomain can not begin with a hyphen.");
1436 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1437 "A domain or subdomain can not end with a hyphen.");
1440 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1441 "Unclosed quoted string. (Missing double quotation mark)");
1444 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1445 "Unclosed comment. (Missing closing parentheses)");
1448 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1449 "Domain literal is missing its closing bracket.");
1453 "Cutelyst::ValidatorEmail",
1454 "Folding white space contains consecutive line break sequences (CRLF).");
1457 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1458 "Folding white space ends with a line break sequence (CRLF).");
1461 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1462 "Address contains a carriage return (CR) that is not followed by a "
1466 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1467 "A fatal error occurred while parsing the address.");
1479 "Cutelyst::ValidatorEmail",
1480 "The address in the “%1” field is valid. Please note that this does not mean "
1481 "that both the address and the domain actually exist. This address could be "
1482 "issued by the domain owner without breaking the rules of any RFCs.")
1486 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1487 "Could not find an MX record for the address’ domain in the “%1” "
1488 "field but an A record does exist.")
1492 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1493 "Could neither find an MX record nor an A record for address’ "
1494 "domain in the “%1” field.")
1498 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1499 "The address in the “%1” field is valid but at a Top Level Domain.")
1503 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1504 "The address in the “%1” field is valid but the Top Level Domain "
1505 "begins with a number.")
1510 c->
translate(
"Cutelyst::ValidatorEmail",
1511 "The address in the “%1” field is valid but contains a quoted string.")
1515 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1516 "The address in the “%1” field is valid but uses an IP address "
1517 "instead of a domain name.")
1521 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1522 "The address in the “%1” field is valid but uses an IP address that "
1523 "contains a :: only eliding one zero group. All implementations "
1524 "must accept and be able to handle any legitimate RFC 4291 format.")
1528 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1529 "The address in the “%1” field contains comments.")
1533 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1534 "The address in the “%1” field contains folding white spaces like "
1540 "Cutelyst::ValidatorEmail",
1541 "The local part of the address in the “%1” field is in a deprecated form.")
1545 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1546 "The address in the “%1” field contains an obsolete form of folding "
1551 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1552 "A quoted string in the address in the “%1” field contains a "
1553 "deprecated character.")
1557 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1558 "A quoted pair in the address in the “%1” field contains a "
1559 "deprecate character.")
1563 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1564 "The address in the “%1” field contains a comment in a position "
1565 "that is deprecated.")
1571 "Cutelyst::ValidatorEmail",
1572 "A comment in the address in the “%1” field contains a deprecated character.")
1576 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1577 "The address in the “%1” field contains a comment or folding white "
1578 "space around the @ sign.")
1582 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1583 "The address in the “%1” field is RFC 5322 compliant but contains "
1584 "domain characters that are not allowed by DNS.")
1588 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1589 "The address in the “%1” field is too long.")
1593 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1594 "The local part of the address in the “%1” field is too long.")
1598 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1599 "The domain part of the address in the “%1” field is too long.")
1603 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1604 "The domain part of the address in the “%1” field contains an "
1605 "element that is too long.")
1609 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1610 "The domain literal of the address in the “%1” field is not a valid "
1611 "RFC 5321 address literal.")
1615 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1616 "The domain literal of the address in the “%1” field is not a valid "
1617 "RFC 5321 domain literal and it contains obsolete characters.")
1621 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1622 "The IPv6 literal of the address in the “%1” field contains the "
1623 "wrong number of groups.")
1627 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1628 "The IPv6 literal of the address in the “%1” field contains too "
1629 "many :: sequences.")
1633 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1634 "The IPv6 address of the email address in the “%1” field contains "
1635 "an illegal group of characters.")
1641 "Cutelyst::ValidatorEmail",
1642 "The IPv6 address of the email address in the “%1” field has too many groups.")
1646 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1647 "The IPv6 address of the email address in the “%1” field starts "
1648 "with a single colon.")
1652 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1653 "The IPv6 address of the email address in the “%1” field ends with "
1658 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1659 "A domain literal of the address in the “%1” field contains a "
1660 "character that is not allowed.")
1664 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1665 "The address in the “%1” field has no local part.")
1669 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1670 "The address in the “%1” field has no domain part.")
1674 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1675 "The address in the “%1” field must not contain consecutive dots.")
1679 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1680 "The address in the “%1” field contains text after a comment or "
1681 "folding white space.")
1685 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1686 "The address in the “%1” field contains text after a quoted string.")
1690 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1691 "Extra characters were found after the end of the domain literal of "
1692 "the address in the “%1” field.")
1696 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1697 "The address in the “%1” field contains a character that is not "
1698 "allowed in a quoted pair.")
1703 "Cutelyst::ValidatorEmail",
1704 "The address in the “%1” field contains a character that is not allowed.")
1708 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1709 "A quoted string in the address in the “%1” field contains a "
1710 "character that is not allowed.")
1714 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1715 "A comment in the address in the “%1” field contains a character "
1716 "that is not allowed.")
1720 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1721 "The address in the “%1” field can't end with a backslash.")
1726 c->
translate(
"Cutelyst::ValidatorEmail",
1727 "Neither part of the address in the “%1” field may begin with a dot.")
1731 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1732 "Neither part of the address in the “%1” field may end with a dot.")
1736 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1737 "A domain or subdomain of the address in the “%1” field can not "
1738 "begin with a hyphen.")
1742 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1743 "A domain or subdomain of the address in the “%1” field can not end "
1748 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1749 "Unclosed quoted string in the address in the “%1” field. (Missing "
1750 "double quotation mark)")
1754 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1755 "Unclosed comment in the address in the “%1” field. (Missing "
1756 "closing parentheses)")
1760 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1761 "Domain literal of the address in the “%1” field is missing its "
1766 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1767 "Folding white space in the address in the “%1” field contains "
1768 "consecutive line break sequences (CRLF).")
1772 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1773 "Folding white space in the address in the “%1” field ends with a "
1774 "line break sequence (CRLF).")
1778 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1779 "The address in the “%1” field contains a carriage return (CR) that "
1780 "is not followed by a line feed (LF).")
1785 c->
translate(
"Cutelyst::ValidatorEmail",
1786 "A fatal error occurred while parsing the address in the “%1” field.")
1800 if (
label.isEmpty()) {
1803 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"Address is valid.");
1806 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1807 "Address is valid but a DNS check was not successful.");
1810 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1811 "Address is valid for SMTP but has unusual elements.");
1814 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1815 "Address is valid within the message but can not be used unmodified "
1816 "for the envelope.");
1819 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1820 "Address contains deprecated elements but my still be valid in "
1821 "restricted contexts.");
1824 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1825 "The address is only valid according to the broad definition of RFC "
1826 "5322. It is otherwise invalid.");
1829 ret = c->
translate(
"Cutelyst::ValidatorEmail",
"Address is invalid for any purpose.");
1836 c->
translate(
"Cutelyst::ValidatorEmail",
"The address in the “%1” field is valid.")
1841 "Cutelyst::ValidatorEmail",
1842 "The address in the “%1” field is valid but a DNS check was not successful.")
1847 "Cutelyst::ValidatorEmail",
1848 "The address in the “%1” field is valid for SMTP but has unusual elements.")
1852 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1853 "The address in the “%1” field is valid within the message but can "
1854 "not be used unmodified for the envelope.")
1858 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1859 "The address in the “%1” field contains deprecated elements but my "
1860 "still be valid in restricted contexts.")
1864 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1865 "The address in the “%1” field is only valid according to the broad "
1866 "definition of RFC 5322. It is otherwise invalid.")
1870 ret = c->
translate(
"Cutelyst::ValidatorEmail",
1871 "The address in the “%1” field is invalid for any purpose.")
1883 const auto diag =
static_cast<quint8
>(diagnose);
1885 if (diag <
static_cast<quint8
>(
Valid)) {
1887 }
else if (diag <
static_cast<quint8
>(
DNSWarn)) {
1889 }
else if (diag <
static_cast<quint8
>(
RFC5321)) {
1891 }
else if (diag <
static_cast<quint8
>(
CFWS)) {
1893 }
else if (diag <
static_cast<quint8
>(
Deprecated)) {
1895 }
else if (diag <
static_cast<quint8
>(
RFC5322)) {
1910 QList<Cutelyst::ValidatorEmail::Diagnose> *diagnoses)
1912 ValidatorEmailDiagnoseStruct diag;
1913 bool ret = ValidatorEmailPrivate::checkEmail(email, options, threshold, &diag);
1916 *diagnoses = diag.returnStatus;
1922#include "moc_validatoremail.cpp"
QString translate(const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
Checks if the value is a valid email address according to specific RFCs.
static QString categoryString(Context *c, Category category, const QString &label=QString())
Returns a descriptive and translated string for the category.
static QString diagnoseString(Context *c, Diagnose diagnose, const QString &label=QString())
Returns a descriptive and translated string for the diagnose.
static Category category(Diagnose diagnose)
Returns the category the diagnose belongs to.
~ValidatorEmail() override
Deconstructs the email validator.
QString genericValidationError(Context *c, const QVariant &errorData=QVariant()) const override
Returns a generic error if validation failed.
Diagnose
Single diagnose values that show why an address is not valid.
@ ErrorUnclosedDomLiteral
ValidatorEmail(const QString &field, Category threshold=RFC5321, Options options=NoOption, const ValidatorMessages &messages=ValidatorMessages(), const QString &defValKey=QString())
Constructs a new email validator.
Category
Validation category, used as threshold to define valid addresses.
Base class for all validator rules.
QString label(Context *c) const
Returns the human readable field label used for generic error messages.
void defaultValue(Context *c, ValidatorReturnType *result) const
I a defValKey has been set in the constructor, this will try to get the default value from the stash ...
QString value(const ParamsMultiMap ¶ms) const
Returns the value of the field from the input params.
QString validationError(Context *c, const QVariant &errorData=QVariant()) const
Returns a descriptive error message if validation failed.
static bool validate(const QString &email, Category threshold=RFC5321, Options options=NoOption, QList< Diagnose > *diagnoses=nullptr)
Returns true if email is a valid address according to the Category given in the threshold.
The Cutelyst namespace holds all public Cutelyst API.
QMultiMap< QString, QString > ParamsMultiMap
Stores custom error messages and the input field label.
Contains the result of a single input parameter validation.