1 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
2 
3    This file is part of the Trojita Qt IMAP e-mail client,
4    http://trojita.flaska.net/
5 
6    This program is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License as
8    published by the Free Software Foundation; either version 2 of
9    the License or (at your option) version 3 or any later version
10    accepted by the membership of KDE e.V. (or its successor approved
11    by the membership of KDE e.V.), which shall act as a proxy
12    defined in Section 14 of version 3 of the license.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 #ifndef IMAP_RESPONSE_H
23 #define IMAP_RESPONSE_H
24 
25 #include <QMap>
26 #include <QPair>
27 #include <QSharedPointer>
28 #include <QStringList>
29 #include <QTextStream>
30 #include <QVariantList>
31 #include <QVector>
32 #include "Command.h"
33 #include "../Exceptions.h"
34 #include "Data.h"
35 #include "ThreadingNode.h"
36 #include "Uids.h"
37 
38 #ifdef _MSC_VER
39 // Disable warnings about throw/nothrow
40 #pragma warning(disable: 4290)
41 #endif
42 
43 class QSslCertificate;
44 class QSslError;
45 
46 /**
47  * @file
48  * @short Various data structures related to IMAP responses
49  *
50  * @author Jan Kundrát <jkt@flaska.net>
51  */
52 
53 /** @short Namespace for IMAP interaction */
54 namespace Imap
55 {
56 
57 namespace Mailbox
58 {
59 class Model;
60 class ImapTask;
61 }
62 
63 class Parser;
64 
65 /** @short IMAP server responses
66  *
67  * @ref AbstractResponse is an abstact parent of all classes. Each response
68  * that might be received from the server is a child of this one.
69  * */
70 namespace Responses
71 {
72 
73 /** @short Result of a command */
74 enum Kind {
75     OK /**< @short OK */,
76     NO /**< @short NO */,
77     BAD /**< @short BAD */,
78     BYE,
79     PREAUTH,
80     EXPUNGE,
81     FETCH,
82     EXISTS,
83     RECENT,
84     CAPABILITY,
85     LIST,
86     LSUB,
87     FLAGS,
88     SEARCH,
89     ESEARCH, /**< @short RFC 4731 ESEARCH */
90     STATUS,
91     NAMESPACE,
92     SORT,
93     THREAD,
94     ID,
95     ENABLED, /**< @short RFC 5161 ENABLE */
96     VANISHED, /**< @short RFC 5162 VANISHED (for QRESYNC) */
97     GENURLAUTH /**< @short GENURLAUTH, RFC 4467 */
98 }; // aren't those comments just sexy? :)
99 
100 /** @short Response Code */
101 enum Code {
102     NONE /**< @short No response code specified */,
103     ATOM /**< @short Not recognized */,
104     ALERT /**< @short ALERT */,
105     BADCHARSET /**< @short BADCHARSET */,
106     /** @short CAPABILITY.
107      *
108      * Yeah, it's different than the RFC3501 name for it.
109      * Responses::Kind already defines a CAPABILITY and we aren't using
110      * C++0x yet.
111      *
112      * */
113     CAPABILITIES,
114     PARSE /**< @short PARSE */,
115     PERMANENTFLAGS /**< @short PERMANENTFLAGS */,
116     READ_ONLY /**< @short READ-ONLY */,
117     READ_WRITE /**< @short READ-WRITE */,
118     TRYCREATE /**< @short TRYCREATE */,
119     UIDNEXT /**< @short UIDNEXT */,
120     UIDVALIDITY /**< @short UIDVALIDITY */,
121     UNSEEN /**< @short UNSEEN */,
122 
123     // obsolete from RFC 2060
124     NEWNAME /**< Obsolete NEWNAME from RFC 2060 */,
125 
126     // RFC 2221
127     REFERRAL /**< REFERRAL from RFC 2221 */,
128 
129     // RFC 3516
130     UNKNOWN_CTE /**< UNKNOWN-CTE from RFC 3516 */,
131 
132     // RFC 4315
133     UIDNOTSTICKY /**< UIDNOTSTICKY from RFC 4315 */,
134     APPENDUID /**< APPENDUID from RFC 4315 */,
135     COPYUID /**< COPYUID from RFC 4315 */,
136 
137     // RFC 4467
138     URLMECH /**< URLMECH from RFC 4467 */,
139 
140     // RFC 4469
141     TOOBIG /**< RFC 4469's TOOBIG */,
142     BADURL /**< BADURL from RFC 4469 */,
143 
144     // RFC 4551
145     HIGHESTMODSEQ /**< HIGHESTMODSEQ from RFC 4451 */,
146     NOMODSEQ /**< NOMODSEQ from RFC 4551 */,
147     MODIFIED /**< MODIFIED from RFC 4551 */,
148 
149     // RFC 4978
150     COMPRESSIONACTIVE /**< COMPRESSIONACTIVE from RFC 4978 */,
151 
152     // RFC 5162
153     CLOSED /**< CLOSED from the QRESYNC RFC 5162 */,
154 
155     // RFC 5182
156     NOTSAVED /**< NOTSAVED from RFC 5182 */,
157 
158     // RFC 5255
159     BADCOMPARATOR /**< BADCOMPARATOR from RFC 5255 */,
160 
161     // RFC 5257
162     ANNOTATE /**< ANNOTATE from RFC 5257 */,
163     ANNOTATIONS /**< ANNOTATIONS from RFC 5257 */,
164 
165     // RFC 5259
166     TEMPFAIL /**< TEMPFAIL from RFC 5259 */,
167     MAXCONVERTMESSAGES /**< MAXCONVERTMESSAGES from RFC 5259 */,
168     MAXCONVERTPARTS /**< MAXCONVERTPARTS from RFC 5259 */,
169 
170     // RFC 5267
171     NOUPDATE /**< NOUPDATE from RFC 5267 */,
172 
173     // RFC 5464
174     METADATA /**< METADATA from RFC 5464 */,
175 
176     // RFC 5465
177     NOTIFICATIONOVERFLOW /**< NOTIFICATIONOVERFLOW from RFC 5465 */,
178     BADEVENT /**< BADEVENT from RFC 5465 */,
179 
180     // RFC 5466
181     UNDEFINED_FILTER /**< UNDEFINED-FILTER from RFC 5466 */,
182 
183     // RFC5530
184     UNAVAILABLE /**< UNAVAILABLE from RFC 5530 */,
185     AUTHENTICATIONFAILED /**< AUTHENTICATIONFAILED from RFC 5530 */,
186     AUTHORIZATIONFAILED /**< AUTHORIZATIONFAILED from RFC 5530 */,
187     EXPIRED /**< EXPIRED from RFC 5530 */,
188     PRIVACYREQUIRED /**< PRIVACYREQUIRED from RFC 5530 */,
189     CONTACTADMIN /**< CONTACTADMIN from RFC 5530 */,
190     NOPERM /**< NOPERM from RFC 5530 */,
191     INUSE /**< INUSE from RFC 5530 */,
192     EXPUNGEISSUED /**< EXPUNGEISSUED from RFC 5530 */,
193     CORRUPTION /**< CORRUPTION from RFC 5530 */,
194     SERVERBUG /**< SERVERBUG from RFC 5530 */,
195     CLIENTBUG /**< CLIENTBUG from RFC 5530 */,
196     CANNOT /**< CANNOT from RFC 5530 */,
197     LIMIT /**< LIMIT from RFC 5530 */,
198     OVERQUOTA /**< OVERQUOTA from RFC 5530 */,
199     ALREADYEXISTS /**< ALREADYEXISTS from RFC 5530 */,
200     NONEXISTENT /**< NONEXISTENT from RFC 5530 */,
201 
202     // draft-imap-sendmail by yours truly
203     POLICYDENIED,
204     SUBMISSIONRACE
205 
206 }; // luvly comments, huh? :)
207 
208 /** @short Parent class for all server responses */
209 class AbstractResponse
210 {
211 public:
AbstractResponse()212     AbstractResponse() {}
213     virtual ~AbstractResponse();
214     /** @short Helper for operator<<() */
215     virtual QTextStream &dump(QTextStream &) const = 0;
216     /** @short Helper for operator==() */
217     virtual bool eq(const AbstractResponse &other) const = 0;
218     /** @short Helper for Imap::Mailbox::MailboxModel to prevent ugly
219      * dynamic_cast<>s */
220     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const = 0;
221     virtual bool plug(Imap::Mailbox::ImapTask *task) const = 0;
222 };
223 
224 /** @short Structure storing OK/NO/BAD/PREAUTH/BYE responses */
225 class State : public AbstractResponse
226 {
227 public:
228     /** @short Tag name or QString::null if untagged */
229     QByteArray tag;
230 
231     /** @short Kind of response
232      *
233      * A tagged status response might be either OK, NO or BAD.
234      * Untagged status response might be either te same as tagged or BYE or
235      * PREAUTH.
236      * */
237     Kind kind;
238 
239     /** @short Textual information embedded in the response
240      *
241      * While this information might be handy for correct understanding of
242      * what happens at ther server, its value is not standardized so the
243      * meaning is usually either duplicate to what's already said elsewhere
244      * or only a hint to the user. Nevertheless, we decode and store it.
245      * */
246     QString message;
247 
248     /** @short Kind of optional Response Code
249      *
250      * For each supported value, type of ResponseCodeData stored in the
251      * respCodeData is defined as follows:
252      *
253      *  ALERT, PARSE, READ_ONLY, READ_WRITE, TRYCREATE:
254      *      Nothing else should be included, ie. void
255      *
256      *  UIDNEXT, UIDVALIDITY, UNSEEN:
257      *      Only number, ie. unsigned int
258      *
259      *  BADCHARSET, PERMANENTFLAGS:
260      *      List of strings, ie. QStringList
261      *
262      *  default:
263      *      Any data, ie. QString
264      * */
265     Code respCode;
266 
267     /** @short Response Code Data
268      *
269      * Format is explained in the respCode documentation.
270      * We have to use pointer indirection because virtual methods wouldn't
271      * work otherwise.
272      * */
273     QSharedPointer<AbstractData> respCodeData;
274 
275     /** @short Default constructor
276      *
277      * No error checking takes place, we assume _respCodeData's type
278      * actually corresponds to all invariants we declare as per respCode's
279      * documentation.
280      * */
State(const QByteArray & tag,const Kind kind,const QString & message,const Code respCode,const QSharedPointer<AbstractData> respCodeData)281     State(const QByteArray &tag, const Kind kind, const QString &message, const Code respCode, const QSharedPointer<AbstractData> respCodeData):
282         tag(tag), kind(kind), message(message), respCode(respCode), respCodeData(respCodeData) {}
283 
284     /** @short "Smart" constructor that parses a response out of a QByteArray */
285     State(const QByteArray &tag, const Kind kind, const QByteArray &line, int &start);
286 
287     /** @short Default destructor that makes containers and QtTest happy */
State()288     State(): respCode(NONE) {}
289 
290     /** @short helper for operator<<( QTextStream& ) */
291     virtual QTextStream &dump(QTextStream &s) const;
292     virtual bool eq(const AbstractResponse &other) const;
293     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
294     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
295 };
296 
297 /** @short Structure storing a CAPABILITY untagged response */
298 class Capability : public AbstractResponse
299 {
300 public:
301     /** @short List of capabilities */
302     QStringList capabilities;
Capability(const QStringList & capabilities)303     Capability(const QStringList &capabilities): capabilities(capabilities) {}
304     virtual QTextStream &dump(QTextStream &s) const;
305     virtual bool eq(const AbstractResponse &other) const;
306     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
307     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
308 };
309 
310 /** @short Structure for EXISTS/EXPUNGE/RECENT responses */
311 class NumberResponse : public AbstractResponse
312 {
313 public:
314     Kind kind;
315     /** @short Number that we're storing */
316     uint number;
317     NumberResponse(const Kind kind, const uint number) throw(UnexpectedHere);
318     virtual QTextStream &dump(QTextStream &s) const;
319     virtual bool eq(const AbstractResponse &other) const;
320     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
321     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
322 };
323 
324 /** @short Structure storing a LIST untagged response */
325 class List : public AbstractResponse
326 {
327 public:
328     /** @short LIST or LSUB */
329     Kind kind;
330     /** @short Flags for this particular mailbox */
331     QStringList flags;
332     /** @short Hierarchy separator
333      *
334      * QString::null in case original response containded NIL
335      * */
336     QString separator;
337     /** @short Mailbox name */
338     QString mailbox;
339 
340     /** @short Extended LIST data (mbox-list-extended from RFC5258) */
341     QMap<QByteArray, QVariant> extendedData;
342 
343     /** @short Parse line and construct List object from it */
344     List(const Kind kind, const QByteArray &line, int &start);
List(const Kind kind,const QStringList & flags,const QString & separator,const QString & mailbox,const QMap<QByteArray,QVariant> & extendedData)345     List(const Kind kind, const QStringList &flags, const QString &separator, const QString &mailbox,
346          const QMap<QByteArray, QVariant> &extendedData):
347         kind(kind), flags(flags), separator(separator), mailbox(mailbox), extendedData(extendedData) {}
348     virtual QTextStream &dump(QTextStream &s) const;
349     virtual bool eq(const AbstractResponse &other) const;
350     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
351     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
352 };
353 
354 struct NamespaceData {
355     QString prefix;
356     QString separator;
NamespaceDataNamespaceData357     NamespaceData(const QString &prefix, const QString &separator): prefix(prefix), separator(separator) {};
358     bool operator==(const NamespaceData &other) const;
359     bool operator!=(const NamespaceData &other) const;
360     static QList<NamespaceData> listFromLine(const QByteArray &line, int &start);
361 };
362 
363 /** @short Structure storing a NAMESPACE untagged response */
364 class Namespace : public AbstractResponse
365 {
366 public:
367     QList<NamespaceData> personal, users, other;
368     /** @short Parse line and construct List object from it */
369     Namespace(const QByteArray &line, int &start);
Namespace(const QList<NamespaceData> & personal,const QList<NamespaceData> & users,const QList<NamespaceData> & other)370     Namespace(const QList<NamespaceData> &personal, const QList<NamespaceData> &users,
371               const QList<NamespaceData> &other):
372         personal(personal), users(users), other(other) {};
373     virtual QTextStream &dump(QTextStream &s) const;
374     virtual bool eq(const AbstractResponse &other) const;
375     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
376     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
377 };
378 
379 
380 /** @short Structure storing a FLAGS untagged response */
381 class Flags : public AbstractResponse
382 {
383 public:
384     /** @short List of flags */
385     QStringList flags;
Flags(const QStringList & flags)386     Flags(const QStringList &flags) : flags(flags) {};
387     Flags(const QByteArray &line, int &start);
388     virtual QTextStream &dump(QTextStream &s) const;
389     virtual bool eq(const AbstractResponse &other) const;
390     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
391     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
392 };
393 
394 /** @short Structure storing a SEARCH untagged response */
395 class Search : public AbstractResponse
396 {
397 public:
398     /** @short List of matching messages */
399     Uids items;
400     Search(const QByteArray &line, int &start);
Search(const Uids & items)401     Search(const Uids &items) : items(items) {};
402     virtual QTextStream &dump(QTextStream &s) const;
403     virtual bool eq(const AbstractResponse &other) const;
404     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
405     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
406 };
407 
408 /** @short Structure storing an ESEARCH untagged response */
409 class ESearch : public AbstractResponse
410 {
411 public:
412     /** @short Is the response given in UIDs, or just in sequence numbers */
413     typedef enum {
414         SEQUENCE, /**< @short In sequence numbers */
415         UIDS /**< @short In UIDs */
416     } SequencesOrUids;
417 
418     /** @short Convenience typedef for the received data of the list type */
419     typedef QVector<QPair<QByteArray, Uids>> ListData_t;
420 
421     /** @short Compare identifiers of the ListData_t list */
422     template <typename T>
423     class CompareListDataIdentifier: public std::unary_function<const typename T::value_type&, bool> {
424         QByteArray keyOne;
425         QByteArray keyTwo;
426         bool hasKeyTwo;
427     public:
428         /** @short Find a record which matches the given key */
CompareListDataIdentifier(const QByteArray & key)429         explicit CompareListDataIdentifier(const QByteArray &key): keyOne(key), hasKeyTwo(false) {}
430 
431         /** @short Find a record matching any of the two passed keys */
CompareListDataIdentifier(const QByteArray & keyOne,const QByteArray & keyTwo)432         explicit CompareListDataIdentifier(const QByteArray &keyOne, const QByteArray &keyTwo):
433             keyOne(keyOne), keyTwo(keyTwo), hasKeyTwo(true) {}
434 
operator()435         bool operator() (const typename T::value_type & item) {
436             if (hasKeyTwo) {
437                 return item.first == keyOne || item.first == keyTwo;
438             } else {
439                 return item.first == keyOne;
440             }
441         }
442     };
443 
444     /** @short Represent one item to be added/removed by an incremental SEARCH/SORT response */
445     struct ContextIncrementalItem {
446 
447         /** @short Is this incremental update record about adding an item, or removing it?
448 
449         These correspond to RFC 5267's ADDTO and REMOVEFROM identifiers.
450         */
451         typedef enum {
452             ADDTO, /**< ADDTO, adding items to the search/sort criteria */
453             REMOVEFROM /**< REMOVEFROM, removing items from the list of matches */
454         } Modification;
455 
456         /** @short Type of modification */
457         Modification modification;
458 
459         /** @short Offset at which the modification shall be performed */
460         uint offset;
461 
462         /** @short Sequence of UIDs to apply */
463         Uids uids;
464 
ContextIncrementalItemContextIncrementalItem465         ContextIncrementalItem(const Modification modification, const uint offset, const Uids &uids):
466             modification(modification), offset(offset), uids(uids) {}
467 
468         bool operator==(const ContextIncrementalItem &other) const {
469             return modification == other.modification && offset == other.offset && uids == other.uids;
470         }
471     };
472 
473     typedef QList<ContextIncrementalItem> IncrementalContextData_t;
474 
475     /** @short The tag of the command which requested in this operation */
476     QByteArray tag;
477 
478     /** @short Are the numbers given in UIDs, or as sequence numbers? */
479     SequencesOrUids seqOrUids;
480 
481     /** @short The received data: list of numbers */
482     ListData_t listData;
483 
484     /** @short The received data: incremental updates to SEARCH/SORT according to RFC 5267 */
485     IncrementalContextData_t incrementalContextData;
486 
487     /** @short Incremental threading information along its identifier and the preceding thread root in an ESEARCH response */
488     struct IncrementalThreadingItem_t {
489         /** @short UID of the previous thread root's item or 0 if there's no previous item */
490         uint previousThreadRoot;
491 
492         /** @short A complete subthread */
493         QVector<ThreadingNode> thread;
494 
IncrementalThreadingItem_tIncrementalThreadingItem_t495         IncrementalThreadingItem_t(const uint previousThreadRoot, const QVector<ThreadingNode> &thread):
496             previousThreadRoot(previousThreadRoot), thread(thread) {}
497 
498         bool operator==(const IncrementalThreadingItem_t &other) const {
499             return previousThreadRoot == other.previousThreadRoot && thread == other.thread;
500         }
501     };
502 
503     /** @short Typedef for all threading data sent over ESEARCH */
504     typedef QList<IncrementalThreadingItem_t> IncrementalThreadingData_t;
505 
506     /** @short The threading information, draft-imap-incthread */
507     IncrementalThreadingData_t incThreadData;
508 
509     // Other forms of returned data are quite explicitly not supported.
510 
511     ESearch(const QByteArray &line, int &start);
ESearch(const QByteArray & tag,const SequencesOrUids seqOrUids,const ListData_t & listData)512     ESearch(const QByteArray &tag, const SequencesOrUids seqOrUids, const ListData_t &listData) :
513         tag(tag), seqOrUids(seqOrUids), listData(listData) {}
ESearch(const QByteArray & tag,const SequencesOrUids seqOrUids,const IncrementalContextData_t & incrementalContextData)514     ESearch(const QByteArray &tag, const SequencesOrUids seqOrUids, const IncrementalContextData_t &incrementalContextData) :
515         tag(tag), seqOrUids(seqOrUids), incrementalContextData(incrementalContextData) {}
ESearch(const QByteArray & tag,const SequencesOrUids seqOrUids,const IncrementalThreadingData_t & incThreadData)516     ESearch(const QByteArray &tag, const SequencesOrUids seqOrUids, const IncrementalThreadingData_t &incThreadData):
517         tag(tag), seqOrUids(seqOrUids), incThreadData(incThreadData) {}
518     virtual QTextStream &dump(QTextStream &stream) const;
519     virtual bool eq(const AbstractResponse &other) const;
520     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
521     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
522 };
523 
524 /** @short Structure storing a STATUS untagged response */
525 class Status : public AbstractResponse
526 {
527 public:
528     /** @short Indentifies type of status data */
529     enum StateKind {
530         MESSAGES,
531         RECENT,
532         UIDNEXT,
533         UIDVALIDITY,
534         UNSEEN
535     };
536 
537     typedef QMap<StateKind,uint> stateDataType;
538 
539     /** @short Mailbox name */
540     QString mailbox;
541     /** @short Associative array of states */
542     stateDataType states;
543 
Status(const QString & mailbox,const stateDataType & states)544     Status(const QString &mailbox, const stateDataType &states) :
545         mailbox(mailbox), states(states) {};
546     Status(const QByteArray &line, int &start);
547     virtual QTextStream &dump(QTextStream &s) const;
548     virtual bool eq(const AbstractResponse &other) const;
549     static StateKind stateKindFromStr(QString s);
550     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
551     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
552 };
553 
554 /** @short FETCH response */
555 class Fetch : public AbstractResponse
556 {
557 public:
558     typedef QMap<QByteArray,QSharedPointer<AbstractData> > dataType;
559 
560     /** @short Sequence number of message that we're working with */
561     uint number;
562 
563     /** @short Fetched items */
564     dataType data;
565 
566     Fetch(const uint number, const QByteArray &line, int &start);
567     Fetch(const uint number, const dataType &data);
568     virtual QTextStream &dump(QTextStream &s) const;
569     virtual bool eq(const AbstractResponse &other) const;
570     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
571     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
572 private:
573     static QDateTime dateify(QByteArray str, const QByteArray &line, const int start);
574 };
575 
576 /** @short Structure storing a SORT untagged response */
577 class Sort : public AbstractResponse
578 {
579 public:
580     /** @short List of sequence/UID numbers as returned by the server */
581     Uids numbers;
582     Sort(const QByteArray &line, int &start);
Sort(const Uids & items)583     Sort(const Uids &items): numbers(items) {}
584     virtual QTextStream &dump(QTextStream &s) const;
585     virtual bool eq(const AbstractResponse &other) const;
586     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
587     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
588 };
589 
590 /** @short Structure storing a THREAD untagged response */
591 class Thread : public AbstractResponse
592 {
593 public:
594     /** @short List of "top-level" messages */
595     QVector<ThreadingNode> rootItems;
596     Thread(const QByteArray &line, int &start);
Thread(const QVector<ThreadingNode> & items)597     Thread(const QVector<ThreadingNode> &items): rootItems(items) {}
598     virtual QTextStream &dump(QTextStream &s) const;
599     virtual bool eq(const AbstractResponse &other) const;
600     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
601     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
602 };
603 
604 /** @short Structure storing the result of the ID command */
605 class Id : public AbstractResponse
606 {
607 public:
608     /** @short List of sequence/UID numbers as returned by the server */
609     QMap<QByteArray,QByteArray> data;
610     Id(const QByteArray &line, int &start);
Id(const QMap<QByteArray,QByteArray> & items)611     Id(const QMap<QByteArray,QByteArray> &items): data(items) {}
612     virtual QTextStream &dump(QTextStream &s) const;
613     virtual bool eq(const AbstractResponse &other) const;
614     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
615     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
616 };
617 
618 /** @short Structure storing each enabled extension */
619 class Enabled: public AbstractResponse
620 {
621 public:
622     QList<QByteArray> extensions;
623     Enabled(const QByteArray &line, int &start);
Enabled(const QList<QByteArray> & extensions)624     Enabled(const QList<QByteArray> &extensions): extensions(extensions) {}
625     virtual QTextStream &dump(QTextStream &s) const;
626     virtual bool eq(const AbstractResponse &other) const;
627     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
628     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
629 };
630 
631 /** @short VANISHED contains information about UIDs of removed messages */
632 class Vanished: public AbstractResponse
633 {
634 public:
635     typedef enum {EARLIER, NOT_EARLIER} EarlierOrNow;
636     EarlierOrNow earlier;
637     Uids uids;
638     Vanished(const QByteArray &line, int &start);
Vanished(EarlierOrNow earlier,const Uids & uids)639     Vanished(EarlierOrNow earlier, const Uids &uids): earlier(earlier), uids(uids) {}
640     virtual QTextStream &dump(QTextStream &s) const;
641     virtual bool eq(const AbstractResponse &other) const;
642     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
643     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
644 };
645 
646 /** @short The GENURLAUTH response */
647 class GenUrlAuth: public AbstractResponse
648 {
649 public:
650     QString url;
651     GenUrlAuth(const QByteArray &line, int &start);
GenUrlAuth(const QString & url)652     GenUrlAuth(const QString &url): url(url) {}
653     virtual QTextStream &dump(QTextStream &s) const;
654     virtual bool eq(const AbstractResponse &other) const;
655     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
656     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
657 };
658 
659 /** @short A fake response for passing along the SSL state */
660 class SocketEncryptedResponse : public AbstractResponse
661 {
662 public:
663     QList<QSslCertificate> sslChain;
664     QList<QSslError> sslErrors;
665     /** @short List of sequence/UID numbers as returned by the server */
666     SocketEncryptedResponse(const QList<QSslCertificate> &certificateChain, const QList<QSslError> &sslErrors);
667     virtual QTextStream &dump(QTextStream &s) const;
668     virtual bool eq(const AbstractResponse &other) const;
669     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
670     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
671 };
672 
673 /** @short A fake response saying that the socket got disconnected */
674 class SocketDisconnectedResponse : public AbstractResponse
675 {
676 public:
677     QString message;
SocketDisconnectedResponse(const QString & message)678     explicit SocketDisconnectedResponse(const QString &message): message(message) {}
679     virtual QTextStream &dump(QTextStream &s) const;
680     virtual bool eq(const AbstractResponse &other) const;
681     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
682     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
683 };
684 
685 /** @short A fake response about a parsing error */
686 class ParseErrorResponse : public AbstractResponse
687 {
688 public:
689     QString message;
690     QString exceptionClass;
691     QByteArray line;
692     int offset;
693     explicit ParseErrorResponse(const ImapException &e);
694     virtual QTextStream &dump(QTextStream &s) const;
695     virtual bool eq(const AbstractResponse &other) const;
696     virtual void plug(Imap::Parser *parser, Imap::Mailbox::Model *model) const;
697     virtual bool plug(Imap::Mailbox::ImapTask *task) const;
698 };
699 
700 QTextStream &operator<<(QTextStream &stream, const Code &r);
701 QTextStream &operator<<(QTextStream &stream, const Kind &res);
702 QTextStream &operator<<(QTextStream &stream, const Status::StateKind &kind);
703 QTextStream &operator<<(QTextStream &stream, const AbstractResponse &res);
704 QTextStream &operator<<(QTextStream &stream, const NamespaceData &res);
705 
706 inline bool operator==(const AbstractResponse &first, const AbstractResponse &other)
707 {
708     return first.eq(other);
709 }
710 
711 inline bool operator!=(const AbstractResponse &first, const AbstractResponse &other)
712 {
713     return !first.eq(other);
714 }
715 
716 /** @short Build Responses::Kind from textual value */
717 Kind kindFromString(QByteArray str) throw(UnrecognizedResponseKind);
718 
719 }
720 
721 }
722 
723 #endif // IMAP_RESPONSE_H
724