File indexing completed on 2024-05-12 05:17:14
0001 /* 0002 SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org> 0003 SPDX-FileCopyrightText: 2009 Andras Mantia <amantia@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #pragma once 0009 0010 #include "kimap_export.h" 0011 0012 #include <exception> 0013 0014 #include <QByteArray> 0015 #include <QList> 0016 #include <QString> 0017 0018 class QIODevice; 0019 0020 namespace KIMAP 0021 { 0022 class ImapParserException : public std::exception 0023 { 0024 public: 0025 explicit ImapParserException(const char *what) throw() 0026 : mWhat(what) 0027 { 0028 } 0029 explicit ImapParserException(const QByteArray &what) throw() 0030 : mWhat(what) 0031 { 0032 } 0033 explicit ImapParserException(const QString &what) throw() 0034 : mWhat(what.toUtf8()) 0035 { 0036 } 0037 ImapParserException(const ImapParserException &other) throw() 0038 : std::exception(other) 0039 , mWhat(other.what()) 0040 { 0041 } 0042 ~ImapParserException() throw() override 0043 { 0044 } 0045 const char *what() const throw() override 0046 { 0047 return mWhat.constData(); 0048 } 0049 virtual const char *type() const throw() 0050 { 0051 return "ImapParserException"; 0052 } 0053 0054 private: 0055 QByteArray mWhat; 0056 }; 0057 0058 /** 0059 Parser for IMAP messages that operates on a local socket stream. 0060 */ 0061 class KIMAP_EXPORT ImapStreamParser 0062 { 0063 public: 0064 /** 0065 * Construct the parser. 0066 * @param socket the local socket to work with. 0067 * @param serverModeEnabled true if the parser has to assume we're writing a server (e.g. sends 0068 * continuation message automatically) 0069 */ 0070 explicit ImapStreamParser(QIODevice *socket, bool serverModeEnabled = false); 0071 0072 /** 0073 * Get a string from the message. If the upcoming data is not a quoted string, unquoted string or a literal, 0074 * the behavior is undefined. Use @ref hasString to be sure a string comes. This call might block. 0075 * @return the next string from the message as an utf8 string 0076 */ 0077 QString readUtf8String(); 0078 0079 /** 0080 * Same as above, but without decoding it to utf8. 0081 * @return the next string from the message 0082 */ 0083 QByteArray readString(); 0084 0085 /** 0086 * Get he next parenthesized list. If the upcoming data is not a parenthesized list, 0087 * the behavior is undefined. Use @ref hasList to be sure a string comes. This call might block. 0088 * @return the next parenthesized list. 0089 */ 0090 QList<QByteArray> readParenthesizedList(); 0091 0092 /** 0093 * Get the next data as a number. This call might block. 0094 * @param ok true if the data found was a number 0095 * @return the number 0096 */ 0097 qint64 readNumber(bool *ok = nullptr); 0098 0099 /** 0100 * Check if the next data is a string or not. This call might block. 0101 * @return true if a string follows 0102 */ 0103 bool hasString(); 0104 0105 /** 0106 * Check if the next data is a literal data or not. If a literal is found, the 0107 * internal position pointer is set to the beginning of the literal data. 0108 * This call might block. 0109 * @return true if a literal follows 0110 */ 0111 bool hasLiteral(); 0112 0113 /** 0114 * Read the next literal sequence. This might or might not be the full data. Example code to read a literal would be: 0115 * @code 0116 * ImapStreamParser parser; 0117 * ... 0118 * if (parser.hasLiteral()) 0119 * { 0120 * while (!parser.atLiteralEnd()) 0121 * { 0122 * QByteArray data = parser.readLiteralPart(); 0123 * // do something with the data 0124 * } 0125 * } 0126 * @endcode 0127 * 0128 * This call might block. 0129 * 0130 * @return part of a literal data 0131 */ 0132 QByteArray readLiteralPart(); 0133 0134 /** 0135 * Check if the literal data end was reached. See @ref hasLiteral and @ref readLiteralPart . 0136 * @return true if the literal was completely read. 0137 */ 0138 bool atLiteralEnd() const; 0139 0140 /** 0141 * Check if the next data is a parenthesized list. This call might block. 0142 * @return true if a parenthesized list comes. 0143 */ 0144 bool hasList(); 0145 0146 /** 0147 * Check if the next data is a parenthesized list end. This call might block. 0148 * @return true if a parenthesized list end. 0149 */ 0150 bool atListEnd(); 0151 0152 /** 0153 * Check if the next data is a response code. This call might block. 0154 * @return true if a response code comes. 0155 */ 0156 bool hasResponseCode(); 0157 0158 /** 0159 * Check if the next data is a response code end. This call might block. 0160 * @return true if a response code end. 0161 */ 0162 bool atResponseCodeEnd(); 0163 0164 /** 0165 * Check if the command end was reached 0166 * @return true if the end of command is reached 0167 */ 0168 bool atCommandEnd(); 0169 0170 /** 0171 * Return everything that remained from the command. 0172 * @return the remaining command data 0173 */ 0174 QByteArray readUntilCommandEnd(); 0175 0176 /** 0177 * Return all the data that was read from the socket, but not processed yet. 0178 * @return the remaining unprocessed data 0179 */ 0180 QByteArray readRemainingData(); 0181 0182 int availableDataSize() const; 0183 0184 void setData(const QByteArray &data); 0185 0186 private: 0187 void stripLeadingSpaces(); 0188 QByteArray parseQuotedString(); 0189 0190 /** 0191 * If the condition is true, wait for more data to be available from the socket. 0192 * If no data comes after a timeout (30000ms), it aborts and returns false. 0193 * @param wait the condition 0194 * @return true if more data is available 0195 */ 0196 bool waitForMoreData(bool wait); 0197 0198 /** 0199 * Inform the client to send more literal data. 0200 */ 0201 void sendContinuationResponse(qint64 size); 0202 0203 /** 0204 * Remove already read data from the internal buffer if necessary. 0205 */ 0206 void trimBuffer(); 0207 0208 QIODevice *m_socket = nullptr; 0209 bool m_isServerModeEnabled = false; 0210 QByteArray m_data; 0211 int m_position = -1; 0212 qint64 m_literalSize = -1; 0213 }; 0214 0215 }