7 #include "imapparser_p.h"
15 class Akonadi::ImapParserPrivate
26 bool checkLiteralStart(
const QByteArray &readBuffer,
int pos = 0)
38 literalSize = readBuffer.
mid(begin + 1, end - begin - 1).
toLongLong();
41 if (literalSize == 0) {
46 dataBuffer.
reserve(dataBuffer.
size() +
static_cast<int>(literalSize) + 1);
55 template<
typename T>
int parseParenthesizedListHelper(
const QByteArray &data, T &result,
int start)
70 int sublistBegin =
start;
71 bool insideQuote =
false;
72 for (
int i = begin + 1; i < data.
length(); ++i) {
73 const char currentChar = data[i];
74 if (currentChar ==
'(' && !insideQuote) {
83 if (currentChar ==
')' && !insideQuote) {
89 result.
append(data.
mid(sublistBegin, i - sublistBegin + 1));
96 if (currentChar ==
' ' || currentChar ==
'\n' || currentChar ==
'\r') {
102 const int consumed = ImapParser::parseString(data, ba, i);
105 }
else if (count > 0) {
106 if (currentChar ==
'"') {
107 insideQuote = !insideQuote;
108 }
else if (currentChar ==
'\\' && insideQuote) {
122 return parseParenthesizedListHelper(data, result,
start);
127 return parseParenthesizedListHelper(data, result,
start);
134 if (begin >= data.
length()) {
140 if (data[begin] ==
'{') {
142 Q_ASSERT(end > begin);
143 int size = data.
mid(begin + 1, end - begin - 1).
toInt();
147 if (begin < data.
length() && data[begin] ==
'\r') {
150 if (begin < data.
length() && data[begin] ==
'\n') {
155 result = data.
mid(begin, end - begin);
160 return parseQuotedString(data, result, begin);
168 if (begin >= data.
length()) {
172 bool foundSlash =
false;
174 if (data[begin] ==
'"') {
177 for (
int i = begin; i < data.
length(); ++i) {
178 const char ch = data.
at(i);
183 }
else if (ch ==
'n') {
185 }
else if (ch ==
'\\') {
187 }
else if (ch ==
'\"') {
207 bool reachedInputEnd =
true;
208 for (
int i = begin; i < data.
length(); ++i) {
209 const char ch = data.
at(i);
210 if (ch ==
' ' || ch ==
'(' || ch ==
')' || ch ==
'\n' || ch ==
'\r') {
212 reachedInputEnd =
false;
219 if (reachedInputEnd) {
222 result = data.
mid(begin, end - begin);
225 if (result ==
"NIL") {
246 if (data[i] !=
' ') {
257 bool insideQuote =
false;
259 const char ch = data[i];
261 insideQuote = !insideQuote;
264 if (ch ==
'\\' && insideQuote) {
268 if (ch ==
'(' && !insideQuote) {
272 if (ch ==
')' && !insideQuote) {
294 for (; it != endIt; ++it) {
295 resultSize += (*it).size();
303 for (; it != endIt; ++it) {
315 return ImapParser::join(list, separator);
321 const int end = parseString(data, tmp,
start);
326 int ImapParser::parseNumber(
const QByteArray &data, qint64 &result,
bool *ok,
int start)
332 int pos = stripLeadingSpaces(data,
start);
333 if (pos >= data.
length()) {
338 for (; pos < data.
length(); ++pos) {
339 if (!isdigit(data.
at(pos))) {
357 const int inputLength = data.
length();
358 int stuffToQuote = 0;
359 for (
int i = 0; i < inputLength; ++i) {
360 const char ch = data.
at(i);
361 if (ch ==
'"' || ch ==
'\\' || ch ==
'\n' || ch ==
'\r') {
367 result.
reserve(inputLength + stuffToQuote + 2);
371 if (stuffToQuote == 0) {
374 for (
int i = 0; i < inputLength; ++i) {
375 const char ch = data.
at(i);
386 if (ch ==
'"' || ch ==
'\\') {
398 int ImapParser::parseSequenceSet(
const QByteArray &data, ImapSet &result,
int start)
404 for (
int i = begin; i < data.
length(); ++i) {
405 if (data[i] ==
'*') {
407 }
else if (data[i] ==
':') {
409 }
else if (isdigit(data[i])) {
411 i = parseNumber(data, value, &ok, i);
419 result.add(ImapInterval(lower, upper));
423 if (data[i] !=
',') {
434 if (lower >= 0 && upper >= 0) {
435 result.add(ImapInterval(lower, upper));
464 int pos = stripLeadingSpaces(data,
start);
465 if (data.
length() <= pos) {
470 if (data[pos] ==
'"') {
474 if (data.
length() <= pos + 26) {
478 if (data.
length() < pos + 26) {
484 const int day = (data[pos] ==
' ' ? data[pos + 1] -
'0'
491 static const QByteArray shortMonthNames(
"janfebmaraprmayjunjulaugsepoctnovdec");
492 int month = shortMonthNames.indexOf(data.
mid(pos, 3).
toLower());
497 month = month / 3 + 1;
499 const int year = data.
mid(pos, 4).
toInt(&ok);
505 const int hours = data.
mid(pos, 2).
toInt(&ok);
511 const int minutes = data.
mid(pos, 2).
toInt(&ok);
517 const int seconds = data.
mid(pos, 2).
toInt(&ok);
523 const int tzhh = data.
mid(pos, 2).
toInt(&ok);
529 const int tzmm = data.
mid(pos, 2).
toInt(&ok);
534 int tzsecs = tzhh * 60 * 60 + tzmm * 60;
535 if (data[pos - 3] ==
'-') {
539 const QDate date(year, month, day);
540 const QTime time(hours, minutes, seconds);
546 dateTime = dateTime.
addSecs(-tzsecs);
549 if (data.
length() <= pos || !quoted) {
553 if (data[pos] ==
'"') {
562 const int startPos = data.
indexOf(
'[');
563 const int endPos = data.
indexOf(
']');
564 if (startPos != -1 && endPos != -1) {
565 if (endPos > startPos) {
573 key = data.
left(startPos);
581 ImapParser::ImapParser()
582 : d(new ImapParserPrivate)
587 ImapParser::~ImapParser() =
default;
589 bool ImapParser::parseNextLine(
const QByteArray &readBuffer)
591 d->continuation =
false;
594 if (d->tagBuffer.isEmpty()) {
595 const int startOfData = ImapParser::parseString(readBuffer, d->tagBuffer);
596 if (startOfData < readBuffer.
length() && startOfData >= 0) {
597 d->dataBuffer = readBuffer.
mid(startOfData + 1);
601 d->dataBuffer += readBuffer;
605 if (d->literalSize > 0) {
606 d->literalSize -= readBuffer.
size();
609 if (d->literalSize > 0) {
614 if (d->literalSize < 0) {
616 d->parenthesesCount += ImapParser::parenthesesBalance(readBuffer, readBuffer.
length() +
static_cast<int>(d->literalSize));
619 if (d->checkLiteralStart(readBuffer, readBuffer.
length() +
static_cast<int>(d->literalSize))) {
625 if (d->parenthesesCount > 0) {
631 d->parenthesesCount += ImapParser::parenthesesBalance(readBuffer);
634 if (d->checkLiteralStart(readBuffer)) {
639 if (d->parenthesesCount > 0) {
649 void ImapParser::parseBlock(
const QByteArray &data)
651 Q_ASSERT(d->literalSize >= data.
size());
652 d->literalSize -= data.
size();
653 d->dataBuffer += data;
663 return d->dataBuffer;
666 void ImapParser::reset()
668 d->dataBuffer.
clear();
669 d->tagBuffer.clear();
670 d->parenthesesCount = 0;
672 d->continuation =
false;
675 bool ImapParser::continuationStarted()
const
677 return d->continuation;
680 qint64 ImapParser::continuationSize()
const
682 return d->literalSize;