summaryrefslogtreecommitdiff
path: root/kimap/imapstreamparser.h
blob: 7c43d1ddc9619bb0ef0547eefdd2e55261aedabd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
    Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
    Copyright (c) 2009 Andras Mantia <amantia@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#ifndef KIMAP_IMAPSTREAMPARSER_P_H
#define KIMAP_IMAPSTREAMPARSER_P_H

#include "kimap_export.h"

#include <exception>

#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QString>

class QIODevice;

namespace KIMAP {

class ImapParserException : public std::exception
{
  public:
    ImapParserException( const char *what ) throw() : mWhat( what ) {}
    ImapParserException( const QByteArray &what ) throw() : mWhat( what ) {}
    ImapParserException( const QString &what ) throw() : mWhat( what.toUtf8() ) {}
    ImapParserException( const ImapParserException &other ) throw() : std::exception( other ), mWhat( other.what() ) {}
    virtual ~ImapParserException() throw() {}
    const char *what() const throw() { return mWhat.constData(); }
    virtual const char *type() const throw() { return "ImapParserException"; }
  private:
    QByteArray mWhat;
};

/**
  Parser for IMAP messages that operates on a local socket stream.
*/
class KIMAP_EXPORT ImapStreamParser
{
  public:
    /**
     * Construct the parser.
     * @param socket the local socket to work with.
     * @param serverModeEnabled true if the parser has to assume we're writing a server (e.g. sends
     * continuation message automatically)
     */
    explicit ImapStreamParser( QIODevice *socket, bool serverModeEnabled = false );

    /**
     * Destructor.
     */
    ~ImapStreamParser();

    /**
     * Get a string from the message. If the upcoming data is not a quoted string, unquoted string or a literal,
     * the behavior is undefined. Use @ref hasString to be sure a string comes. This call might block.
     * @return the next string from the message as an utf8 string
     */
    QString readUtf8String();

    /**
     * Same as above, but without decoding it to utf8.
     * @return the next string from the message
     */
    QByteArray readString();

    /**
     * Get he next parenthesized list. If the upcoming data is not a parenthesized list,
     * the behavior is undefined. Use @ref hasList to be sure a string comes. This call might block.
     * @return the next parenthesized list.
     */
    QList<QByteArray> readParenthesizedList();


    /**
     * Get the next data as a number. This call might block.
     * @param ok true if the data found was a number
     * @return the number
     */
    qint64 readNumber( bool * ok = 0 );

    /**
     * Check if the next data is a string or not. This call might block.
     * @return true if a string follows
     */
    bool hasString();

    /**
     * Check if the next data is a literal data or not. If a literal is found, the
     * internal position pointer is set to the beginning of the literal data.
     * This call might block.
     * @return true if a literal follows
     */
    bool hasLiteral();

    /**
     * Read the next literal sequence. This might or might not be the full data. Example code to read a literal would be:
     * @code
     * ImapStreamParser parser;
     *  ...
     * if (parser.hasLiteral())
     * {
     *   while (!parser.atLiteralEnd())
     *   {
     *      QByteArray data = parser.readLiteralPart();
     *      // do something with the data
     *   }
     * }
     * @endcode
     *
     * This call might block.
     *
     * @return part of a literal data
     */
    QByteArray readLiteralPart();

    /**
     * Check if the literal data end was reached. See @ref hasLiteral and @ref readLiteralPart .
     * @return true if the literal was completely read.
     */
    bool atLiteralEnd() const;

    /**
     * Check if the next data is a parenthesized list. This call might block.
     * @return true if a parenthesized list comes.
    */
    bool hasList();

     /**
     * Check if the next data is a parenthesized list end. This call might block.
     * @return true if a parenthesized list end.
      */
    bool atListEnd();

    /**
     * Check if the next data is a response code. This call might block.
     * @return true if a response code comes.
     */
    bool hasResponseCode();

     /**
     * Check if the next data is a response code end. This call might block.
     * @return true if a response code end.
      */
    bool atResponseCodeEnd();

    /**
     * Check if the command end was reached
     * @return true if the end of command is reached
     */
    bool atCommandEnd();

    /**
     * Return everything that remained from the command.
     * @return the remaining command data
     */
    QByteArray readUntilCommandEnd();

    /**
     * Return all the data that was read from the socket, but not processed yet.
     * @return the remaining unprocessed data
     */
    QByteArray readRemainingData();

    int availableDataSize() const;

    void setData( const QByteArray &data );


  private:
    void stripLeadingSpaces();
    QByteArray parseQuotedString();

    /**
     * If the condition is true, wait for more data to be available from the socket.
     * If no data comes after a timeout (30000ms), it aborts and returns false.
     * @param wait the condition
     * @return true if more data is available
     */
    bool waitForMoreData( bool wait);

    /**
     * Inform the client to send more literal data.
     */
    void sendContinuationResponse( qint64 size );

    /**
     * Remove already read data from the internal buffer if necessary.
     */
    void trimBuffer();

    QIODevice *m_socket;
    bool m_isServerModeEnabled;
    QByteArray m_data;
    int m_position;
    qint64 m_literalSize;
};

}

#endif