10#include "headerparsing.h"
11#include "headerparsing_p.h"
13#include "headerfactory_p.h"
19#include "kmime_debug.h"
24#include <QStringDecoder>
31using namespace KMime::Types;
39 struct KMIME_EXPORT QStringOrQPair {
45namespace HeaderParsing
49bool parseEncodedWord(
const char *&scursor,
const char *
const send,
54 assert(*(scursor - 1) ==
'=');
71 const char *charsetStart = scursor;
72 const char *languageStart =
nullptr;
76 for (; scursor != send ; scursor++) {
77 if (*scursor ==
'?') {
79 }
else if (*scursor ==
'*' && languageStart ==
nullptr) {
80 languageStart = scursor + 1;
85 if (scursor == send || *scursor !=
'?') {
87 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
93 QByteArray maybeLanguage(languageStart, scursor - languageStart);
97 (languageStart ? languageStart - 1 : scursor) - charsetStart);
106 const char *encodingStart = scursor;
109 for (; scursor != send ; scursor++) {
110 if (*scursor ==
'?') {
116 if (scursor == send || *scursor !=
'?') {
118 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
123 QByteArray maybeEncoding(encodingStart, scursor - encodingStart);
136 const char *encodedTextStart = scursor;
139 for (; scursor != send ; scursor++) {
140 if (*scursor ==
'?') {
141 if (scursor + 1 != send) {
142 if (*(scursor + 1) !=
'=') {
143 KMIME_WARN <<
"Stray '?' in q-encoded word, ignoring this.";
150 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
156 if (*(scursor - 2) !=
'?' || *(scursor - 1) !=
'=' ||
157 scursor < encodedTextStart + 2) {
158 KMIME_WARN_PREMATURE_END_OF(EncodedWord);
163 const char *
const encodedTextEnd = scursor - 2;
173 KMIME_WARN_UNKNOWN(Encoding, maybeEncoding);
183 if (maybeCharset.isEmpty()) {
188 usedCS = cachedCharset(defaultCS);
192 usedCS = cachedCharset(defaultCS);
195 usedCS = cachedCharset(maybeCharset);
200 KMIME_WARN_UNKNOWN(Charset, maybeCharset);
208 const auto encodedTextLength = encodedTextEnd - encodedTextStart;
211 char *bbegin = buffer.
data();
212 char *bend = bbegin + buffer.
length();
219 if (!
dec->decode(encodedTextStart, encodedTextEnd, bbegin, bend)) {
220 KMIME_WARN << codec->
name() <<
"codec lies about its maxDecodedSizeFor("
221 << encodedTextLength <<
")\nresult may be truncated";
229 language = maybeLanguage;
234static inline void eatWhiteSpace(
const char *&scursor,
const char *
const send)
236 while (scursor != send &&
237 (*scursor ==
' ' || *scursor ==
'\n' ||
238 *scursor ==
'\t' || *scursor ==
'\r')) {
243bool parseAtom(
const char*&scursor,
const char *
const send,
246 bool success =
false;
247 const char *
start = scursor;
249 while (scursor != send) {
250 signed char ch = *scursor++;
251 if (ch > 0 && isAText(ch)) {
254 }
else if (allow8Bit && ch < 0) {
270bool parseToken(
const char*&scursor,
const char *
const send,
273 bool success =
false;
274 const char *
start = scursor;
276 while (scursor != send) {
277 signed char ch = *scursor++;
278 if (ch > 0 && isTText(ch)) {
281 }
else if ((flags & ParseTokenAllow8Bit) && ch < 0) {
285 }
else if ((flags & ParseTokenRelaxedTText) && ch ==
'/') {
299#define READ_ch_OR_FAIL if ( scursor == send ) { \
300 KMIME_WARN_PREMATURE_END_OF( GenericQuotedString ); \
310bool parseGenericQuotedString(
const char *&scursor,
const char *
const send,
312 const char openChar,
const char closeChar)
319 assert(*(scursor - 1) == openChar || *(scursor - 1) == closeChar);
321 while (scursor != send) {
322 char ch = *scursor++;
324 if (ch == closeChar || ch == openChar) {
334 KMIME_WARN_IF_8BIT(ch);
355 if (ch ==
' ' || ch ==
'\t') {
364 KMIME_WARN_NON_FOLDING(CRLF);
382 if (!isCRLF && (ch ==
' ' || ch ==
'\t')) {
398 if (scursor == send) {
402 const char *oldscursor = scursor;
406 if (*scursor++ ==
'?') {
408 if (parseEncodedWord(scursor, send, tmp, lang, charset)) {
411 if (scursor == send) {
413 }
else if (*scursor++ ==
' ') {
414 if (scursor == send) {
417 }
else if (*scursor++ ==
'=') {
418 if (scursor == send) {
422 }
else if (*scursor++ ==
'?') {
437 scursor = oldscursor;
440 scursor = oldscursor;
446 KMIME_WARN_IF_8BIT(ch);
458bool parseComment(
const char *&scursor,
const char *
const send,
459 QString &result,
bool isCRLF,
bool reallySave)
461 int commentNestingDepth = 1;
462 const char *afterLastClosingParenPos =
nullptr;
464 const char *oldscursor = scursor;
466 assert(*(scursor - 1) ==
'(');
468 while (commentNestingDepth) {
470 if (parseGenericQuotedString(scursor, send, cmntPart, isCRLF,
'(',
')')) {
471 assert(*(scursor - 1) ==
')' || *(scursor - 1) ==
'(');
474 switch (*(scursor - 1)) {
480 if (commentNestingDepth > 1) {
486 afterLastClosingParenPos = scursor;
487 --commentNestingDepth;
493 maybeCmnt += cmntPart;
496 ++commentNestingDepth;
502 if (afterLastClosingParenPos) {
503 scursor = afterLastClosingParenPos;
505 scursor = oldscursor;
516bool parsePhrase(
const char *&scursor,
const char *
const send,
520 None, Phrase, Atom, EncodedWord, QuotedString
527 const char *successfullyParsed =
nullptr;
529 const char *oldscursor;
532 bool lastWasEncodedWord =
false;
534 while (scursor != send) {
535 char ch = *scursor++;
542 if (scursor != send && (*scursor ==
' ' || *scursor ==
'\t')) {
547 successfullyParsed = scursor;
552 if (parseGenericQuotedString(scursor, send, tmp, isCRLF,
'"',
'"')) {
553 successfullyParsed = scursor;
554 assert(*(scursor - 1) ==
'"');
557 found = QuotedString;
569 lastWasEncodedWord =
false;
587 if (parseComment(scursor, send, tmp, isCRLF,
589 successfullyParsed = scursor;
590 lastWasEncodedWord =
false;
595 scursor = successfullyParsed;
602 oldscursor = scursor;
605 if (parseEncodedWord(scursor, send, tmp, lang, charset)) {
606 successfullyParsed = scursor;
615 if (!lastWasEncodedWord) {
622 lastWasEncodedWord =
true;
627 scursor = oldscursor;
634 if (parseAtom(scursor, send, tmpAtom,
true )) {
635 successfullyParsed = scursor;
650 lastWasEncodedWord =
false;
656 scursor = successfullyParsed;
661 eatWhiteSpace(scursor, send);
664 return found !=
None;
667bool parseDotAtom(
const char *&scursor,
const char *
const send,
670 eatCFWS(scursor, send, isCRLF);
673 const char *successfullyParsed;
676 if (!parseAtom(scursor, send, maybeAtom,
false )) {
680 successfullyParsed = scursor;
682 while (scursor != send) {
685 if (scursor == send || *scursor !=
'.') {
690 if (scursor == send || !isAText(*scursor)) {
694 scursor = successfullyParsed;
700 if (!parseAtom(scursor, send, maybeAtom,
false )) {
701 scursor = successfullyParsed;
706 successfullyParsed = scursor;
709 scursor = successfullyParsed;
713void eatCFWS(
const char *&scursor,
const char *
const send,
bool isCRLF)
717 while (scursor != send) {
718 const char *oldscursor = scursor;
720 char ch = *scursor++;
730 if (parseComment(scursor, send, dummy, isCRLF,
false )) {
733 scursor = oldscursor;
737 scursor = oldscursor;
743bool parseDomain(
const char *&scursor,
const char *
const send,
746 eatCFWS(scursor, send, isCRLF);
747 if (scursor == send) {
757 if (*scursor ==
'[') {
762 while (parseGenericQuotedString(scursor, send, maybeDomainLiteral,
764 if (scursor == send) {
766 if (*(scursor - 1) ==
']') {
768 result = maybeDomainLiteral;
777 if (*(scursor - 1) ==
'[') {
782 result = maybeDomainLiteral;
788 if (parseDotAtom(scursor, send, maybeDotAtom, isCRLF)) {
790 if (scursor != send && *scursor ==
'.') {
801bool parseObsRoute(
const char *&scursor,
const char *
const send,
804 while (scursor != send) {
805 eatCFWS(scursor, send, isCRLF);
806 if (scursor == send) {
811 if (*scursor ==
',') {
820 if (*scursor ==
':') {
829 if (*scursor !=
'@') {
836 if (!parseDomain(scursor, send, maybeDomain, isCRLF)) {
840 result.
append(maybeDomain);
844 eatCFWS(scursor, send, isCRLF);
845 if (scursor == send) {
848 if (*scursor ==
':') {
852 if (*scursor ==
',') {
860bool parseAddrSpec(
const char *&scursor,
const char *
const send,
861 AddrSpec &result,
bool isCRLF)
874 while (scursor != send) {
876 eatCFWS(scursor, send, isCRLF);
878 char ch = *scursor++;
890 if (parseGenericQuotedString(scursor, send, tmp, isCRLF,
'"',
'"')) {
891 maybeLocalPart += tmp;
899 if (parseAtom(scursor, send, tmpAtom,
false )) {
917 assert(*(scursor - 1) ==
'@');
920 if (!parseDomain(scursor, send, maybeDomain, isCRLF)) {
924 result.localPart = maybeLocalPart;
925 result.domain = maybeDomain;
930bool parseAngleAddr(
const char *&scursor,
const char *
const send,
931 AddrSpec &result,
bool isCRLF)
934 eatCFWS(scursor, send, isCRLF);
935 if (scursor == send || *scursor !=
'<') {
940 eatCFWS(scursor, send, isCRLF);
941 if (scursor == send) {
945 if (*scursor ==
'@' || *scursor ==
',') {
947 KMIME_WARN <<
"obsolete source route found! ignoring.";
949 if (!parseObsRoute(scursor, send, dummy,
954 if (scursor == send) {
960 AddrSpec maybeAddrSpec;
961 if (!parseAddrSpec(scursor, send, maybeAddrSpec, isCRLF)) {
965 eatCFWS(scursor, send, isCRLF);
966 if (scursor == send || *scursor !=
'>') {
971 result = maybeAddrSpec;
987bool parseMailbox(
const char *&scursor,
const char *
const send,
990 eatCFWS(scursor, send, isCRLF);
991 if (scursor == send) {
995 AddrSpec maybeAddrSpec;
999 const char *oldscursor = scursor;
1000 if (parseAddrSpec(scursor, send, maybeAddrSpec, isCRLF)) {
1003 eatWhiteSpace(scursor, send);
1004 if (scursor != send && *scursor ==
'(') {
1006 if (!parseComment(scursor, send, maybeDisplayName, isCRLF,
true )) {
1010 result.
setName(stripQuotes(maybeDisplayName));
1013 scursor = oldscursor;
1016 if (!parsePhrase(scursor, send, maybeDisplayName, isCRLF)) {
1018 maybeDisplayName.
clear();
1019 scursor = oldscursor;
1022 eatCFWS(scursor, send, isCRLF);
1023 if (scursor == send) {
1029 if (!parseAngleAddr(scursor, send, maybeAddrSpec, isCRLF)) {
1033 if (maybeDisplayName.
isNull()) {
1035 eatWhiteSpace(scursor, send);
1036 if (scursor != send && *scursor ==
'(') {
1038 if (!parseComment(scursor, send, maybeDisplayName, isCRLF,
true )) {
1044 result.
setName(stripQuotes(maybeDisplayName));
1049bool parseGroup(
const char *&scursor,
const char *
const send,
1050 Address &result,
bool isCRLF)
1057 eatCFWS(scursor, send, isCRLF);
1058 if (scursor == send) {
1064 if (!parsePhrase(scursor, send, maybeDisplayName, isCRLF)) {
1069 eatCFWS(scursor, send, isCRLF);
1070 if (scursor == send || *scursor !=
':') {
1076 result.displayName = removeBidiControlChars(maybeDisplayName);
1080 while (scursor != send) {
1081 eatCFWS(scursor, send, isCRLF);
1082 if (scursor == send) {
1087 if (*scursor ==
',') {
1093 if (*scursor ==
';') {
1099 if (!parseMailbox(scursor, send, maybeMailbox, isCRLF)) {
1102 result.mailboxList.
append(maybeMailbox);
1104 eatCFWS(scursor, send, isCRLF);
1106 if (scursor == send) {
1110 if (*scursor ==
';') {
1115 if (*scursor ==
',') {
1122bool parseAddress(
const char *&scursor,
const char *
const send,
1123 Address &result,
bool isCRLF)
1127 eatCFWS(scursor, send, isCRLF);
1128 if (scursor == send) {
1134 const char *oldscursor = scursor;
1135 if (parseMailbox(scursor, send, maybeMailbox, isCRLF)) {
1137 result.displayName.
clear();
1138 result.mailboxList.
append(maybeMailbox);
1141 scursor = oldscursor;
1143 Address maybeAddress;
1146 if (!parseGroup(scursor, send, maybeAddress, isCRLF)) {
1150 result = maybeAddress;
1154bool parseAddressList(
const char *&scursor,
const char *
const send,
1157 while (scursor != send) {
1158 eatCFWS(scursor, send, isCRLF);
1160 if (scursor == send) {
1164 if (*scursor ==
',') {
1169 if (*scursor ==
';') {
1175 Address maybeAddress;
1176 if (!parseAddress(scursor, send, maybeAddress, isCRLF)) {
1179 result.
append(maybeAddress);
1181 eatCFWS(scursor, send, isCRLF);
1183 if (scursor == send) {
1187 if (*scursor ==
',') {
1194static bool parseParameter(
const char *&scursor,
const char *
const send,
1195 QPair<QByteArray, QStringOrQPair> &result,
bool isCRLF)
1207 eatCFWS(scursor, send, isCRLF);
1208 if (scursor == send) {
1216 if (!parseToken(scursor, send, maybeAttribute, ParseTokenNoFlag)) {
1220 eatCFWS(scursor, send, isCRLF);
1222 if (scursor == send || *scursor !=
'=') {
1227 eatCFWS(scursor, send, isCRLF);
1228 if (scursor == send) {
1230 if (maybeAttribute.
endsWith(
'*')) {
1231 KMIME_WARN <<
"attribute ends with \"*\", but value is empty!"
1232 "Chopping away \"*\".";
1233 maybeAttribute.
chop(1);
1239 const char *oldscursor = scursor;
1244 QStringOrQPair maybeValue;
1245 if (*scursor ==
'"') {
1248 if (maybeAttribute.
endsWith(
'*')) {
1252 KMIME_WARN <<
"attribute ends with \"*\", but value is a quoted-string!"
1253 "Chopping away \"*\".";
1254 maybeAttribute.
chop(1);
1257 if (!parseGenericQuotedString(scursor, send, maybeValue.qstring, isCRLF)) {
1258 scursor = oldscursor;
1264 if (!parseToken(scursor, send, maybeValue.view, ParseTokenRelaxedTText)) {
1265 scursor = oldscursor;
1275static bool parseRawParameterList(
const char *&scursor,
const char *
const send,
1276 std::map<QByteArray, QStringOrQPair> &result,
1288 while (scursor != send) {
1289 eatCFWS(scursor, send, isCRLF);
1291 if (scursor == send) {
1295 if (*scursor ==
';') {
1299 QPair<QByteArray, QStringOrQPair> maybeParameter;
1300 if (!parseParameter(scursor, send, maybeParameter, isCRLF)) {
1308 if (maybeParameter.first.isNull()) {
1311 while (scursor != send) {
1312 if (*scursor++ ==
';') {
1323 result[maybeParameter.first] = maybeParameter.second;
1325 eatCFWS(scursor, send, isCRLF);
1327 if (scursor == send) {
1331 if (*scursor ==
';') {
1340 bool isContinuation,
QString &value,
1347 const char *decBegin = source.
data();
1348 const char *decCursor = decBegin;
1349 const char *decEnd = decCursor + source.
size();
1351 if (!isContinuation) {
1353 while (decCursor != decEnd) {
1354 if (*decCursor ==
'\'') {
1361 if (decCursor == decEnd) {
1364 KMIME_WARN <<
"No charset in extended-initial-value."
1365 "Assuming \"iso-8859-1\".";
1370 charset =
QByteArray(decBegin, decCursor - decBegin);
1372 const char *oldDecCursor = ++decCursor;
1374 while (decCursor != decEnd) {
1375 if (*decCursor ==
'\'') {
1381 if (decCursor == decEnd) {
1382 KMIME_WARN <<
"No language in extended-initial-value."
1383 "Trying to recover.";
1384 decCursor = oldDecCursor;
1398 KMIME_WARN_UNKNOWN(Charset, charset);
1402 if (!rfc2231Codec) {
1404 assert(rfc2231Codec);
1421 QByteArray::Iterator bit = buffer.
begin();
1422 QByteArray::ConstIterator bend = buffer.
end();
1424 if (!
dec->decode(decCursor, decEnd, bit, bend)) {
1425 KMIME_WARN << rfc2231Codec->
name()
1426 <<
"codec lies about its maxDecodedSizeFor()"
1428 <<
"result may be truncated";
1442bool parseParameterListWithCharset(
const char *&scursor,
1443 const char *
const send,
1444 Headers::ParameterMap &result,
1448 std::map<QByteArray, QStringOrQPair> rawParameterList;
1449 if (!parseRawParameterList(scursor, send, rawParameterList, isCRLF)) {
1453 if (rawParameterList.empty()) {
1467 NoMode = 0x0, Continued = 0x1, Encoded = 0x2
1476 for (
auto &it : rawParameterList) {
1477 if (attribute.
isNull() || !it.first.startsWith(attribute)) {
1483 if (!attribute.
isNull()) {
1484 result[attribute] = value;
1488 attribute = it.
first;
1490 EncodingMode encodingMode = NoEncoding;
1496 encodingMode = RFC2231;
1499 if (!it.second.qstring.isNull() &&
1502 encodingMode = RFC2047;
1512 if (mode & Encoded) {
1513 if (encodingMode == RFC2231) {
1514 decodeRFC2231Value(rfc2231Codec, textcodec,
1516 value, it.second.view, charset);
1517 }
else if (encodingMode == RFC2047) {
1522 if (!it.second.view.isNull()) {
1525 value += it.second.qstring;
1533 if (!(mode & Continued)) {
1535 result[attribute] = value;
1545 if (it.first.endsWith(
'*')) {
1547 decodeRFC2231Value(rfc2231Codec, textcodec,
1549 value, it.second.view, charset);
1552 if (!it.second.view.isNull()) {
1555 value += it.second.qstring;
1561 if (!attribute.
isNull()) {
1562 result[attribute] = value;
1568static const char stdDayNames[][4] = {
1569 "Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
1571static const int stdDayNamesLen =
sizeof stdDayNames /
sizeof *stdDayNames;
1573static bool parseDayName(
const char *&scursor,
const char *
const send)
1576 if (send - scursor < 3) {
1580 for (
int i = 0 ; i < stdDayNamesLen ; ++i) {
1581 if (qstrnicmp(scursor, stdDayNames[i], 3) == 0) {
1591static const char stdMonthNames[][4] = {
1592 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
1593 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
1595static const int stdMonthNamesLen =
1596 sizeof stdMonthNames /
sizeof *stdMonthNames;
1598static bool parseMonthName(
const char *&scursor,
const char *
const send,
1602 if (send - scursor < 3) {
1606 for (result = 0 ; result < stdMonthNamesLen ; ++result) {
1607 if (qstrnicmp(scursor, stdMonthNames[result], 3) == 0) {
1617static const struct {
1618 const char tzName[5];
1624 {
"EDT", -4 * 3600 },
1625 {
"EST", -5 * 3600 },
1626 {
"MST", -5 * 3600 },
1627 {
"CST", -6 * 3600 },
1628 {
"MDT", -6 * 3600 },
1629 {
"MST", -7 * 3600 },
1630 {
"PDT", -7 * 3600 },
1631 {
"PST", -8 * 3600 },
1633 {
"CET", 1 * 3600 },
1634 {
"MET", 1 * 3600 },
1636 {
"CEST", 2 * 3600 },
1637 {
"BST", 1 * 3600 },
1650 {
"K", -10 * 3600 },
1651 {
"L", -11 * 3600 },
1652 {
"M", -12 * 3600 },
1666static const int timeZonesLen =
sizeof timeZones /
sizeof *timeZones;
1668static bool parseAlphaNumericTimeZone(
const char *&scursor,
1669 const char *
const send,
1670 long int &secsEastOfGMT,
1671 bool &timeZoneKnown)
1674 if (scursor < send && *scursor ==
'"') {
1677 if (scursor == send) {
1683 if (!parseToken(scursor, send, maybeTimeZone, ParseTokenNoFlag)) {
1686 for (
int i = 0 ; i < timeZonesLen ; ++i) {
1688 scursor += maybeTimeZone.
size();
1689 secsEastOfGMT = timeZones[i].secsEastOfGMT;
1690 timeZoneKnown =
true;
1692 if (scursor < send && *scursor ==
'"') {
1701 KMIME_WARN_UNKNOWN(time zone, maybeTimeZone);
1703 timeZoneKnown =
false;
1708int parseDigits(
const char *&scursor,
const char *
const send,
int &result)
1712 for (; scursor != send && isdigit(*scursor) ; scursor++, digits++) {
1714 result += int(*scursor -
'0');
1719static bool parseTimeOfDay(
const char *&scursor,
const char *
const send,
1720 int &hour,
int &min,
int &sec,
bool isCRLF =
false)
1727 if (!parseDigits(scursor, send, hour)) {
1731 eatCFWS(scursor, send, isCRLF);
1732 if (scursor == send || *scursor !=
':') {
1737 eatCFWS(scursor, send, isCRLF);
1738 if (scursor == send) {
1745 if (!parseDigits(scursor, send, min)) {
1749 eatCFWS(scursor, send, isCRLF);
1750 if (scursor == send) {
1757 if (*scursor ==
':') {
1760 eatCFWS(scursor, send, isCRLF);
1761 if (scursor == send) {
1765 if (!parseDigits(scursor, send, sec)) {
1775bool parseTime(
const char *&scursor,
const char *send,
1776 int &hour,
int &min,
int &sec,
long int &secsEastOfGMT,
1777 bool &timeZoneKnown,
bool isCRLF)
1789 eatCFWS(scursor, send, isCRLF);
1790 if (scursor == send) {
1794 if (!parseTimeOfDay(scursor, send, hour, min, sec, isCRLF)) {
1798 eatCFWS(scursor, send, isCRLF);
1800 if ((scursor == send) || isdigit(*scursor)) {
1801 timeZoneKnown =
false;
1806 timeZoneKnown =
true;
1807 if (*scursor ==
'+' || *scursor ==
'-') {
1809 const char sign = *scursor++;
1812 const int tzDigits = parseDigits(scursor, send, maybeTimeZone);
1813 if (tzDigits != 4) {
1815 if (tzDigits == 2 && scursor != send && *scursor ==
':') {
1818 if (parseDigits(scursor, send, maybeTimeZone2) != 2) {
1821 maybeTimeZone = maybeTimeZone * 100 + maybeTimeZone2;
1826 secsEastOfGMT = 60 * (maybeTimeZone / 100 * 60 + maybeTimeZone % 100);
1828 secsEastOfGMT *= -1;
1829 if (secsEastOfGMT == 0) {
1830 timeZoneKnown =
false;
1835 if (!parseAlphaNumericTimeZone(scursor, send, secsEastOfGMT, timeZoneKnown)) {
1842bool parseQDateTime(
const char *&scursor,
const char *
const send,
1845 eatCFWS(scursor, send, isCRLF);
1846 if (scursor == send || std::distance(scursor, send) < 17) {
1857bool parseDateTime(
const char *&scursor,
const char *
const send,
1872 eatCFWS(scursor, send, isCRLF);
1873 if (scursor == send) {
1880 if (parseDayName(scursor, send)) {
1881 eatCFWS(scursor, send, isCRLF);
1882 if (scursor == send) {
1886 if (*scursor ==
',') {
1888 eatCFWS(scursor, send, isCRLF);
1892 int maybeMonth = -1;
1893 bool asctimeFormat =
false;
1896 if (!isdigit(*scursor) && parseMonthName(scursor, send, maybeMonth)) {
1897 asctimeFormat =
true;
1898 eatCFWS(scursor, send, isCRLF);
1905 if (!parseDigits(scursor, send, maybeDay)) {
1909 eatCFWS(scursor, send, isCRLF);
1910 if (scursor == send) {
1915 if (*scursor ==
',') {
1922 if (!asctimeFormat && !parseMonthName(scursor, send, maybeMonth)) {
1925 if (scursor == send) {
1928 assert(maybeMonth >= 0); assert(maybeMonth <= 11);
1931 eatCFWS(scursor, send, isCRLF);
1932 if (scursor == send) {
1937 bool timeAfterYear =
true;
1938 if ((send - scursor > 3) && ((scursor[1] ==
':') || (scursor[2] ==
':'))) {
1939 timeAfterYear =
false;
1947 if (timeAfterYear && !parseDigits(scursor, send, maybeYear)) {
1951 eatCFWS(scursor, send, isCRLF);
1955 long int secsEastOfGMT = 0;
1958 if (scursor != send) {
1962 bool timeZoneKnown =
true;
1964 if (!parseTime(scursor, send,
1965 maybeHour, maybeMinute, maybeSecond,
1966 secsEastOfGMT, timeZoneKnown, isCRLF)) {
1971 if (!timeAfterYear) {
1972 eatCFWS(scursor, send, isCRLF);
1973 if (scursor == send) {
1977 if (!parseDigits(scursor, send, maybeYear)) {
1983 if (maybeYear < 50) {
1985 }
else if (maybeYear < 1000) {
1989 if (maybeYear < 1900) {
1993 maybeDate =
QDate(maybeYear, maybeMonth, maybeDay);
1994 maybeTime =
QTime(maybeHour, maybeMinute, maybeSecond);
2000 maybeDate =
QDate(maybeYear, maybeMonth, maybeDay);
2001 maybeTime =
QTime(0, 0, 0);
2017 auto startOfFieldBody = head.
indexOf(
':', headerStart);
2018 if (startOfFieldBody < 0) {
2022 const char *rawType = head.
constData() + headerStart;
2023 const size_t rawTypeLen = startOfFieldBody - headerStart;
2026 if (startOfFieldBody < head.
size() - 1 && head[startOfFieldBody] ==
' ') {
2030 bool folded =
false;
2031 endOfFieldBody = findHeaderLineEnd(head, startOfFieldBody, &folded);
2034 if (rawTypeLen > 0) {
2035 header = HeaderFactory::createHeader(
QByteArrayView(rawType, rawTypeLen));
2042 const auto unfoldedBody = unfoldHeader(head.
constData() + startOfFieldBody, endOfFieldBody - startOfFieldBody);
2053std::unique_ptr<KMime::Headers::Base> parseNextHeader(
QByteArrayView &head)
2055 qsizetype endOfFieldBody = 0;
2056 std::unique_ptr<KMime::Headers::Base> header(extractHeader(head, 0, endOfFieldBody));
2058 head = head.
mid(endOfFieldBody + 1);
2077 auto pos = content.
indexOf(
"\n\n", 0);
2079 header = content.
left(++pos);
2080 body = content.
mid(pos + 1);
2092 qsizetype cursor = 0;
2093 while (cursor < head.
size()) {
2094 const auto headerStart = cursor;
2095 qsizetype endOfFieldBody;
2096 if (
auto header = extractHeader(head, headerStart, endOfFieldBody)) {
2098 cursor = endOfFieldBody + 1;
static Codec * codecForName(QByteArrayView name)
virtual Decoder * makeDecoder(NewlineType newline=NewlineLF) const=0
virtual const char * name() const=0
virtual qsizetype maxDecodedSizeFor(qsizetype insize, NewlineType newline=NewlineLF) const=0
Represents an (email address, display name) pair according RFC 2822, section 3.4.
void setName(const QString &name)
Sets the name.
void setAddress(const AddrSpec &addr)
Sets the email address.
Q_SCRIPTABLE Q_NOREPLY void start()
KCODECS_EXPORT QString decodeRFC2047String(QByteArrayView src, QByteArray *usedCS, const QByteArray &defaultCS=QByteArray(), CharsetOption option=NoOption)
const char * constData() const const
bool endsWith(QByteArrayView bv) const const
QByteArray first(qsizetype n) const const
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
bool isNull() const const
QByteArray left(qsizetype len) const const
qsizetype length() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
void resize(qsizetype newSize, char c)
QByteArray right(qsizetype len) const const
qsizetype size() const const
bool startsWith(QByteArrayView bv) const const
QByteArray toLower() const const
QByteArrayView mid(qsizetype start, qsizetype length) const const
void chop(qsizetype length)
int compare(QByteArrayView bv, Qt::CaseSensitivity cs) const const
const_pointer constData() const const
const_pointer data() const const
bool endsWith(QByteArrayView bv) const const
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
qsizetype size() const const
QByteArray toByteArray() const const
bool isValid(int year, int month, int day)
bool setDate(int year, int month, int day)
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
bool isValid() const const
void append(QList< T > &&value)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString fromLatin1(QByteArrayView str)
bool isNull() const const
QString mid(qsizetype position, qsizetype n) const const
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isValid() const const
EncodedData< QByteArrayView > decode(QByteArrayView ba)
QTextStream & dec(QTextStream &stream)
QTextStream & endl(QTextStream &stream)
bool isValid(int h, int m, int s, int ms)
QTimeZone fromSecondsAheadOfUtc(int offset)