1/*
2 Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
3 Copyright (c) 2009 Andras Mantia <amantia@kde.org>
4
5 This library is free software; you can redistribute it and/or modify it
6 under the terms of the GNU Library General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or (at your
8 option) any later version.
9
10 This library is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301, USA.
19*/
20
21#ifndef KIMAP_IMAPSTREAMPARSER_P_H
22#define KIMAP_IMAPSTREAMPARSER_P_H
23
24#include "kimap_export.h"
25
26#include <exception>
27
28#include <QtCore/QByteArray>
29#include <QtCore/QList>
30#include <QtCore/QString>
31
32class QIODevice;
33
34namespace KIMAP {
35
36class ImapParserException : public std::exception
37{
38 public:
39 explicit ImapParserException( const char *what ) throw() : mWhat( what ) {}
40 explicit ImapParserException( const QByteArray &what ) throw() : mWhat( what ) {}
41 explicit ImapParserException( const QString &what ) throw() : mWhat( what.toUtf8() ) {}
42 ImapParserException( const ImapParserException &other ) throw() : std::exception( other ), mWhat( other.what() ) {}
43 virtual ~ImapParserException() throw() {}
44 const char *what() const throw() { return mWhat.constData(); }
45 virtual const char *type() const throw() { return "ImapParserException"; }
46 private:
47 QByteArray mWhat;
48};
49
50/**
51 Parser for IMAP messages that operates on a local socket stream.
52*/
53class KIMAP_EXPORT ImapStreamParser
54{
55 public:
56 /**
57 * Construct the parser.
58 * @param socket the local socket to work with.
59 * @param serverModeEnabled true if the parser has to assume we're writing a server (e.g. sends
60 * continuation message automatically)
61 */
62 explicit ImapStreamParser( QIODevice *socket, bool serverModeEnabled = false );
63
64 /**
65 * Destructor.
66 */
67 ~ImapStreamParser();
68
69 /**
70 * Get a string from the message. If the upcoming data is not a quoted string, unquoted string or a literal,
71 * the behavior is undefined. Use @ref hasString to be sure a string comes. This call might block.
72 * @return the next string from the message as an utf8 string
73 */
74 QString readUtf8String();
75
76 /**
77 * Same as above, but without decoding it to utf8.
78 * @return the next string from the message
79 */
80 QByteArray readString();
81
82 /**
83 * Get he next parenthesized list. If the upcoming data is not a parenthesized list,
84 * the behavior is undefined. Use @ref hasList to be sure a string comes. This call might block.
85 * @return the next parenthesized list.
86 */
87 QList<QByteArray> readParenthesizedList();
88
89 /**
90 * Get the next data as a number. This call might block.
91 * @param ok true if the data found was a number
92 * @return the number
93 */
94 qint64 readNumber( bool * ok = 0 );
95
96 /**
97 * Check if the next data is a string or not. This call might block.
98 * @return true if a string follows
99 */
100 bool hasString();
101
102 /**
103 * Check if the next data is a literal data or not. If a literal is found, the
104 * internal position pointer is set to the beginning of the literal data.
105 * This call might block.
106 * @return true if a literal follows
107 */
108 bool hasLiteral();
109
110 /**
111 * Read the next literal sequence. This might or might not be the full data. Example code to read a literal would be:
112 * @code
113 * ImapStreamParser parser;
114 * ...
115 * if (parser.hasLiteral())
116 * {
117 * while (!parser.atLiteralEnd())
118 * {
119 * QByteArray data = parser.readLiteralPart();
120 * // do something with the data
121 * }
122 * }
123 * @endcode
124 *
125 * This call might block.
126 *
127 * @return part of a literal data
128 */
129 QByteArray readLiteralPart();
130
131 /**
132 * Check if the literal data end was reached. See @ref hasLiteral and @ref readLiteralPart .
133 * @return true if the literal was completely read.
134 */
135 bool atLiteralEnd() const;
136
137 /**
138 * Check if the next data is a parenthesized list. This call might block.
139 * @return true if a parenthesized list comes.
140 */
141 bool hasList();
142
143 /**
144 * Check if the next data is a parenthesized list end. This call might block.
145 * @return true if a parenthesized list end.
146 */
147 bool atListEnd();
148
149 /**
150 * Check if the next data is a response code. This call might block.
151 * @return true if a response code comes.
152 */
153 bool hasResponseCode();
154
155 /**
156 * Check if the next data is a response code end. This call might block.
157 * @return true if a response code end.
158 */
159 bool atResponseCodeEnd();
160
161 /**
162 * Check if the command end was reached
163 * @return true if the end of command is reached
164 */
165 bool atCommandEnd();
166
167 /**
168 * Return everything that remained from the command.
169 * @return the remaining command data
170 */
171 QByteArray readUntilCommandEnd();
172
173 /**
174 * Return all the data that was read from the socket, but not processed yet.
175 * @return the remaining unprocessed data
176 */
177 QByteArray readRemainingData();
178
179 int availableDataSize() const;
180
181 void setData( const QByteArray &data );
182
183 private:
184 void stripLeadingSpaces();
185 QByteArray parseQuotedString();
186
187 /**
188 * If the condition is true, wait for more data to be available from the socket.
189 * If no data comes after a timeout (30000ms), it aborts and returns false.
190 * @param wait the condition
191 * @return true if more data is available
192 */
193 bool waitForMoreData( bool wait);
194
195 /**
196 * Inform the client to send more literal data.
197 */
198 void sendContinuationResponse( qint64 size );
199
200 /**
201 * Remove already read data from the internal buffer if necessary.
202 */
203 void trimBuffer();
204
205 QIODevice *m_socket;
206 bool m_isServerModeEnabled;
207 QByteArray m_data;
208 int m_position;
209 qint64 m_literalSize;
210};
211
212}
213
214#endif
215