11#include "imapstreamparser.h"
23 m_isServerModeEnabled = serverModeEnabled;
37 if (!waitForMoreData(m_data.
isEmpty())) {
38 throw ImapParserException(
"Unable to read more data");
41 if (!waitForMoreData(m_position >= m_data.
length())) {
42 throw ImapParserException(
"Unable to read more data");
55 return parseQuotedString();
60 if (!waitForMoreData(m_position >= m_data.
length())) {
61 throw ImapParserException(
"Unable to read more data");
63 int savedPos = m_position;
66 m_position = savedPos;
67 const char dataChar = m_data.
at(pos);
68 if (dataChar ==
'{') {
70 }
else if (dataChar ==
'"') {
72 }
else if (dataChar !=
' ' && dataChar !=
'(' && dataChar !=
')' && dataChar !=
'[' && dataChar !=
']' && dataChar !=
'\n' && dataChar !=
'\r') {
81 if (!waitForMoreData(m_position >= m_data.
length())) {
82 throw ImapParserException(
"Unable to read more data");
84 int savedPos = m_position;
86 if (m_data.
at(m_position) ==
'{') {
89 end = m_data.
indexOf(
'}', m_position);
90 if (!waitForMoreData(end == -1)) {
91 throw ImapParserException(
"Unable to read more data");
94 Q_ASSERT(end > m_position);
95 m_literalSize = m_data.
mid(m_position + 1, end - m_position - 1).
toInt();
99 if (!waitForMoreData(m_position + 1 >= m_data.
length())) {
100 throw ImapParserException(
"Unable to read more data");
102 if (m_position < m_data.
length() && m_data.
at(m_position) ==
'\r') {
105 if (m_position < m_data.
length() && m_data.
at(m_position) ==
'\n') {
110 if (m_isServerModeEnabled && m_literalSize > 0) {
111 sendContinuationResponse(m_literalSize);
115 m_position = savedPos;
122 return (m_literalSize == 0);
127 static const qint64 maxLiteralPartSize = 4096;
128 int size = qMin(maxLiteralPartSize, m_literalSize);
130 if (!waitForMoreData(m_data.
length() < m_position + size)) {
131 throw ImapParserException(
"Unable to read more data");
134 if (m_data.
length() < m_position + size) {
136 size = m_data.
length() - m_position;
141 m_literalSize -= size;
142 Q_ASSERT(m_literalSize >= 0);
150 if (!waitForMoreData(m_position >= m_data.
length())) {
151 throw ImapParserException(
"Unable to read more data");
153 int savedPos = m_position;
154 stripLeadingSpaces();
155 int pos = m_position;
156 m_position = savedPos;
157 if (m_data.
at(pos) ==
'(') {
165 if (!waitForMoreData(m_position >= m_data.
length())) {
166 throw ImapParserException(
"Unable to read more data");
168 int savedPos = m_position;
169 stripLeadingSpaces();
170 int pos = m_position;
171 m_position = savedPos;
172 if (m_data.
at(pos) ==
')') {
173 m_position = pos + 1;
182 if (!waitForMoreData(m_data.
length() <= m_position)) {
183 throw ImapParserException(
"Unable to read more data");
186 stripLeadingSpaces();
187 if (m_data.
at(m_position) !=
'(') {
191 bool concatToLast =
false;
193 int sublistbegin = m_position;
194 int i = m_position + 1;
196 if (!waitForMoreData(m_data.
length() <= i)) {
198 throw ImapParserException(
"Unable to read more data");
200 if (m_data.
at(i) ==
'(') {
208 if (m_data.
at(i) ==
')') {
214 result.
append(m_data.
mid(sublistbegin, i - sublistbegin + 1));
220 if (m_data.
at(i) ==
' ') {
224 if (m_data.
at(i) ==
'"') {
232 if (m_data.
at(i) ==
'[') {
237 result.
last() +=
'[';
241 if (m_data.
at(i) ==
']') {
242 concatToLast =
false;
243 result.
last() +=
']';
260 while ((m_position < m_data.
size()) && (m_data.
at(m_position) ==
'\r' || m_data.
at(m_position) ==
'\n')) {
274 throw ImapParserException(
"Something went very very wrong!");
279 if (!waitForMoreData(m_position >= m_data.
length())) {
280 throw ImapParserException(
"Unable to read more data");
282 int savedPos = m_position;
283 stripLeadingSpaces();
284 int pos = m_position;
285 m_position = savedPos;
286 if (m_data.
at(pos) ==
'[') {
287 m_position = pos + 1;
295 if (!waitForMoreData(m_position >= m_data.
length())) {
296 throw ImapParserException(
"Unable to read more data");
298 int savedPos = m_position;
299 stripLeadingSpaces();
300 int pos = m_position;
301 m_position = savedPos;
302 if (m_data.
at(pos) ==
']') {
303 m_position = pos + 1;
309QByteArray ImapStreamParser::parseQuotedString()
312 if (!waitForMoreData(m_data.
length() == 0)) {
313 throw ImapParserException(
"Unable to read more data");
315 stripLeadingSpaces();
316 int end = m_position;
318 if (!waitForMoreData(m_position >= m_data.
length())) {
319 throw ImapParserException(
"Unable to read more data");
321 if (!waitForMoreData(m_position >= m_data.
length())) {
322 throw ImapParserException(
"Unable to read more data");
325 bool foundSlash =
false;
327 if (m_data.
at(m_position) ==
'"') {
331 if (!waitForMoreData(m_data.
length() <= i)) {
333 throw ImapParserException(
"Unable to read more data");
335 if (m_data.
at(i) ==
'\\') {
340 if (m_data.
at(i) ==
'"') {
341 result = m_data.
mid(m_position, i - m_position);
351 bool reachedInputEnd =
true;
354 if (!waitForMoreData(m_data.
length() <= i)) {
356 throw ImapParserException(
"Unable to read more data");
358 if (m_data.
at(i) ==
' ' || m_data.
at(i) ==
'(' || m_data.
at(i) ==
')' || m_data.
at(i) ==
'[' || m_data.
at(i) ==
']' || m_data.
at(i) ==
'\n'
359 || m_data.
at(i) ==
'\r' || m_data.
at(i) ==
'"') {
361 reachedInputEnd =
false;
364 if (m_data.
at(i) ==
'\\') {
369 if (reachedInputEnd) {
373 result = m_data.
mid(m_position, end - m_position);
395 if (!waitForMoreData(m_data.
length() == 0)) {
396 throw ImapParserException(
"Unable to read more data");
398 stripLeadingSpaces();
399 if (!waitForMoreData(m_position >= m_data.
length())) {
400 throw ImapParserException(
"Unable to read more data");
402 if (m_position >= m_data.
length()) {
403 throw ImapParserException(
"Unable to read more data");
407 if (!waitForMoreData(m_data.
length() <= i)) {
409 throw ImapParserException(
"Unable to read more data");
411 if (!isdigit(m_data.
at(i))) {
417 result = tmp.toLongLong(ok);
422void ImapStreamParser::stripLeadingSpaces()
424 for (
int i = m_position; i < m_data.
length(); ++i) {
425 if (m_data.
at(i) !=
' ') {
430 m_position = m_data.
length();
433bool ImapStreamParser::waitForMoreData(
bool wait)
445void ImapStreamParser::setData(
const QByteArray &data)
452 return m_data.
mid(m_position);
455int ImapStreamParser::availableDataSize()
const
462 int savedPos = m_position;
464 if (!waitForMoreData(m_position >= m_data.
length())) {
465 throw ImapParserException(
"Unable to read more data");
467 stripLeadingSpaces();
468 }
while (m_position >= m_data.
size());
470 if (m_data.
at(m_position) ==
'\n' || m_data.
at(m_position) ==
'\r') {
471 if (m_data.
at(m_position) ==
'\r') {
474 if (m_position < m_data.
length() && m_data.
at(m_position) ==
'\n') {
483 m_position = savedPos;
491 int paranthesisBalance = 0;
493 if (!waitForMoreData(m_data.
length() <= i)) {
495 throw ImapParserException(
"Unable to read more data");
497 if (m_data.
at(i) ==
'{') {
506 if (m_data.
at(i) ==
'(') {
507 paranthesisBalance++;
509 if (m_data.
at(i) ==
')') {
510 paranthesisBalance--;
512 if ((i == m_data.
length() && paranthesisBalance == 0) || m_data.
at(i) ==
'\n' || m_data.
at(i) ==
'\r') {
523void ImapStreamParser::sendContinuationResponse(qint64 size)
526 m_socket->
write(block);
530void ImapStreamParser::trimBuffer()
532 if (m_position < 4096) {
535 m_data = std::move(m_data).
right(m_data.
size() - m_position);
qint64 readNumber(bool *ok=nullptr)
Get the next data as a number.
ImapStreamParser(QIODevice *socket, bool serverModeEnabled=false)
Construct the parser.
QList< QByteArray > readParenthesizedList()
Get he next parenthesized list.
bool atListEnd()
Check if the next data is a parenthesized list end.
bool hasList()
Check if the next data is a parenthesized list.
bool atResponseCodeEnd()
Check if the next data is a response code end.
bool atCommandEnd()
Check if the command end was reached.
bool atLiteralEnd() const
Check if the literal data end was reached.
QByteArray readRemainingData()
Return all the data that was read from the socket, but not processed yet.
bool hasLiteral()
Check if the next data is a literal data or not.
QByteArray readString()
Same as above, but without decoding it to utf8.
bool hasString()
Check if the next data is a string or not.
QByteArray readUntilCommandEnd()
Return everything that remained from the command.
bool hasResponseCode()
Check if the next data is a response code.
QString readUtf8String()
Get a string from the message.
QByteArray readLiteralPart()
Read the next literal sequence.
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
QByteArray & append(QByteArrayView data)
char at(qsizetype i) const const
bool contains(QByteArrayView bv) const const
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
bool isEmpty() const const
qsizetype length() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray number(double n, char format, int precision)
QByteArray & replace(QByteArrayView before, QByteArrayView after)
QByteArray right(qsizetype len) const const
qsizetype size() const const
int toInt(bool *ok, int base) const const
QByteArrayView mid(qsizetype start, qsizetype length) const const
virtual qint64 bytesAvailable() const const
virtual bool waitForBytesWritten(int msecs)
virtual bool waitForReadyRead(int msecs)
qint64 write(const QByteArray &data)
void append(QList< T > &&value)
bool isEmpty() const const
QString fromUtf8(QByteArrayView str)