Warning, file /pim/trojita/tests/Imap/test_Imap_Parser_parse.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 0002 0003 This file is part of the Trojita Qt IMAP e-mail client, 0004 http://trojita.flaska.net/ 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License as 0008 published by the Free Software Foundation; either version 2 of 0009 the License or (at your option) version 3 or any later version 0010 accepted by the membership of KDE e.V. (or its successor approved 0011 by the membership of KDE e.V.), which shall act as a proxy 0012 defined in Section 14 of version 3 of the license. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #include <QBuffer> 0024 #include <QFile> 0025 #include <QTest> 0026 #include "Imap/Parser/Message.h" 0027 #include "Streams/FakeSocket.h" 0028 0029 #include "test_Imap_Parser_parse.h" 0030 0031 Q_DECLARE_METATYPE(QSharedPointer<Imap::Responses::AbstractResponse>) 0032 Q_DECLARE_METATYPE(Imap::Responses::State) 0033 Q_DECLARE_METATYPE(Imap::Sequence) 0034 0035 void ImapParserParseTest::initTestCase() 0036 { 0037 array.reset( new QByteArray() ); 0038 Streams::Socket* sock(new Streams::FakeSocket(Imap::CONN_STATE_CONNECTED_PRETLS_PRECAPS)); 0039 parser = new Imap::Parser( this, sock, 666 ); 0040 } 0041 0042 void ImapParserParseTest::cleanupTestCase() 0043 { 0044 delete parser; 0045 parser = 0; 0046 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); 0047 } 0048 0049 /** @short Test tagged response parsing */ 0050 void ImapParserParseTest::testParseTagged() 0051 { 0052 QFETCH( QByteArray, line ); 0053 QFETCH( QSharedPointer<Imap::Responses::AbstractResponse>, response ); 0054 0055 Q_ASSERT( response ); 0056 QCOMPARE( *(parser->parseTagged( line )), *response ); 0057 } 0058 0059 void ImapParserParseTest::testParseTagged_data() 0060 { 0061 using namespace Imap::Responses; 0062 0063 QTest::addColumn<QByteArray>("line"); 0064 QTest::addColumn<QSharedPointer<AbstractResponse> >("response"); 0065 0066 QSharedPointer<AbstractData> voidData( new RespData<void>() ); 0067 QSharedPointer<AbstractData> emptyList( 0068 new RespData<QStringList>( QStringList() ) ); 0069 0070 QTest::newRow("tagged-ok-simple") 0071 << QByteArray("y01 OK Everything works, man!\r\n") 0072 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Everything works, man!"), NONE, voidData ) ); 0073 0074 QTest::newRow("tagged-no-simple") 0075 << QByteArray("12345 NO Nope, something is broken\r\n") 0076 << QSharedPointer<AbstractResponse>( new State("12345", NO, QStringLiteral("Nope, something is broken"), NONE, voidData ) ); 0077 0078 QTest::newRow("tagged-bad-simple") 0079 << QByteArray("ahoj BaD WTF?\r\n") 0080 << QSharedPointer<AbstractResponse>( new State("ahoj", BAD, QStringLiteral("WTF?"), NONE, voidData ) ); 0081 0082 QTest::newRow("tagged-ok-alert") 0083 << QByteArray("y01 oK [ALERT] Server on fire\r\n") 0084 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Server on fire"), ALERT, voidData ) ); 0085 QTest::newRow("tagged-no-alert") 0086 << QByteArray("1337 no [ALeRT] Server on fire\r\n") 0087 << QSharedPointer<AbstractResponse>( new State("1337", NO, QStringLiteral("Server on fire"), ALERT, voidData ) ); 0088 0089 QTest::newRow("tagged-ok-capability") 0090 << QByteArray("y01 OK [CAPaBILITY blurdybloop IMAP4rev1 WTF] Capabilities updated\r\n") 0091 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Capabilities updated"), CAPABILITIES, 0092 QSharedPointer<AbstractData>( 0093 new RespData<QStringList>( QStringList() << QStringLiteral("blurdybloop") << QStringLiteral("IMAP4rev1") << QStringLiteral("WTF")) ) ) ); 0094 0095 QTest::newRow("tagged-ok-parse") 0096 << QByteArray("y01 OK [PArSE] Parse error. What do you feed me with?\r\n") 0097 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Parse error. What do you feed me with?"), 0098 PARSE, voidData) ); 0099 QTest::newRow("tagged-ok-permanentflags-empty") 0100 << QByteArray("y01 OK [PERMANENTfLAGS] Behold, the flags!\r\n") 0101 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Behold, the flags!"), PERMANENTFLAGS, emptyList) ); 0102 QTest::newRow("tagged-ok-permanentflags-flags") 0103 << QByteArray("y01 OK [PErMANENTFLAGS (\\Foo \\Bar SmrT)] Behold, the flags!\r\n") 0104 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Behold, the flags!"), PERMANENTFLAGS, 0105 QSharedPointer<AbstractData>( new RespData<QStringList>( 0106 QStringList() << QStringLiteral("\\Foo") << QStringLiteral("\\Bar") << QStringLiteral("SmrT") ))) ); 0107 QTest::newRow("tagged-ok-permanentflags-flags-not-enclosed") 0108 << QByteArray("y01 OK [PErMANENTFLAGS \\Foo \\Bar SmrT] Behold, the flags!\r\n") 0109 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Behold, the flags!"), PERMANENTFLAGS, 0110 QSharedPointer<AbstractData>( new RespData<QStringList>( 0111 QStringList() << QStringLiteral("\\Foo") << QStringLiteral("\\Bar") << QStringLiteral("SmrT") ))) ); 0112 QTest::newRow("tagged-ok-badcharset-empty") 0113 << QByteArray("y01 OK [BadCharset] foo\r\n") 0114 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("foo"), BADCHARSET, emptyList) ); 0115 QTest::newRow("tagged-ok-badcharset-something") 0116 << QByteArray("y01 OK [BADCHARSET (utf8)] wrong charset\r\n") 0117 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("wrong charset"), BADCHARSET, 0118 QSharedPointer<AbstractData>( new RespData<QStringList>( QStringList() << QStringLiteral("utf8") ))) ); 0119 QTest::newRow("tagged-ok-badcharset-not-enclosed") 0120 << QByteArray("y01 OK [badcharset a ba cc] Behold, the charset!\r\n") 0121 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Behold, the charset!"), BADCHARSET, 0122 QSharedPointer<AbstractData>( new RespData<QStringList>( 0123 QStringList() << QStringLiteral("a") << QStringLiteral("ba") << QStringLiteral("cc") ))) ); 0124 QTest::newRow("tagged-ok-readonly") 0125 << QByteArray("333 OK [ReAD-ONLY] No writing for you\r\n") 0126 << QSharedPointer<AbstractResponse>( new State("333", OK, QStringLiteral("No writing for you"), READ_ONLY, voidData)); 0127 QTest::newRow("tagged-ok-readwrite") 0128 << QByteArray("y01 OK [REaD-WRITE] Write!!!\r\n") 0129 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Write!!!"), READ_WRITE, voidData)); 0130 QTest::newRow("tagged-ok-trycreate") 0131 << QByteArray("y01 OK [TryCreate] ...would be better :)\r\n") 0132 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("...would be better :)"), TRYCREATE, voidData)); 0133 QTest::newRow("tagged-ok-uidnext") 0134 << QByteArray("y01 OK [uidNext 5] Next UID\r\n") 0135 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("Next UID"), UIDNEXT, 0136 QSharedPointer<AbstractData>( new RespData<uint>( 5 ) ))); 0137 QTest::newRow("tagged-ok-uidvalidity") 0138 << QByteArray("y01 OK [UIDVALIDITY 17] UIDs valid\r\n") 0139 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("UIDs valid"), UIDVALIDITY, 0140 QSharedPointer<AbstractData>( new RespData<uint>( 17 ) ))); 0141 QTest::newRow("tagged-ok-unseen") 0142 << QByteArray("y01 OK [unSeen 666] I need my glasses\r\n") 0143 << QSharedPointer<AbstractResponse>( new State("y01", OK, QStringLiteral("I need my glasses"), UNSEEN, 0144 QSharedPointer<AbstractData>( new RespData<uint>( 666 ) ))); 0145 0146 QTest::newRow("appenduid-simple") 0147 << QByteArray("A003 OK [APPENDUID 38505 3955] APPEND completed\r\n") 0148 << QSharedPointer<AbstractResponse>(new State("A003", OK, QStringLiteral("APPEND completed"), APPENDUID, 0149 QSharedPointer<AbstractData>( 0150 new RespData<QPair<uint,Imap::Sequence> >( 0151 qMakePair(38505u, Imap::Sequence(3955))) 0152 ))); 0153 /* 0154 QTest::newRow("appenduid-seq") 0155 << QByteArray("A003 OK [APPENDUID 38505 3955,333666] APPEND completed\r\n") 0156 << QSharedPointer<AbstractResponse>(new State("A003", OK, "APPEND completed", APPENDUID, 0157 QSharedPointer<AbstractData>( 0158 new RespData<QPair<uint,Imap::Sequence> >( 0159 qMakePair(38505u, Imap::Sequence(3955))) 0160 ))); 0161 0162 QTest::newRow("copyuid-simple") 0163 << QByteArray("A004 OK [COPYUID 38505 304 3956] Done\r\n") 0164 << QSharedPointer<AbstractResponse>(new State("A004", OK, "Done", COPYUID, 0165 QSharedPointer<AbstractData>( 0166 new RespData<QPair<uint,QPair<Imap::Sequence, Imap::Sequence> > >( 0167 qMakePair(38505u, 0168 qMakePair(Imap::Sequence(304), Imap::Sequence(3956)) 0169 )) 0170 ))); 0171 0172 0173 QTest::newRow("copyuid-sequence") 0174 << QByteArray("A004 OK [COPYUID 38505 304,319:320 3956:3958] Done\r\n") 0175 << QSharedPointer<AbstractResponse>(new State("A003", OK, "Done", APPENDUID, 0176 QSharedPointer<AbstractData>( 0177 new RespData<QPair<uint,Imap::Sequence> >( 0178 qMakePair(38505u, Imap::Sequence(3955))) 0179 ))); 0180 */ 0181 } 0182 0183 /** @short Test untagged response parsing */ 0184 void ImapParserParseTest::testParseUntagged() 0185 { 0186 QFETCH( QByteArray, line ); 0187 QFETCH( QSharedPointer<Imap::Responses::AbstractResponse>, response ); 0188 0189 Q_ASSERT( response ); 0190 QSharedPointer<Imap::Responses::AbstractResponse> r = parser->parseUntagged( line ); 0191 if ( Imap::Responses::Fetch* fetchResult = dynamic_cast<Imap::Responses::Fetch*>( r.data() ) ) { 0192 fetchResult->data.remove( "x-trojita-bodystructure" ); 0193 } 0194 #if 0// qDebug()'s internal buffer is too small to be useful here, that's why QCOMPARE's normal dumping is not enough 0195 if ( *r != *response ) { 0196 QTextStream s( stderr ); 0197 s << "\nPARSED:\n" << *r; 0198 s << "\nEXPETCED:\n"; 0199 s << *response; 0200 } 0201 #endif 0202 QCOMPARE( *r, *response ); 0203 } 0204 0205 void ImapParserParseTest::testParseUntagged_data() 0206 { 0207 using namespace Imap::Responses; 0208 using namespace Imap::Message; 0209 using Imap::Responses::Fetch; // needed for gcc-3.4 0210 0211 QTest::addColumn<QByteArray>("line"); 0212 QTest::addColumn<QSharedPointer<AbstractResponse> >("response"); 0213 0214 QSharedPointer<AbstractData> voidData( new RespData<void>() ); 0215 QSharedPointer<AbstractData> emptyList( 0216 new RespData<QStringList>( QStringList() ) ); 0217 0218 QTest::newRow("untagged-ok-simple") 0219 << QByteArray("* OK Everything works, man!\r\n") 0220 << QSharedPointer<AbstractResponse>( new State(QByteArray(), OK, QStringLiteral("Everything works, man!"), NONE, voidData ) ); 0221 0222 QTest::newRow("untagged-no-simple") 0223 << QByteArray("* NO Nope, something is broken\r\n") 0224 << QSharedPointer<AbstractResponse>( new State(QByteArray(), NO, QStringLiteral("Nope, something is broken"), NONE, voidData ) ); 0225 QTest::newRow("untagged-ok-uidvalidity") 0226 << QByteArray("* OK [UIDVALIDITY 17] UIDs valid\r\n") 0227 << QSharedPointer<AbstractResponse>( new State(QByteArray(), OK, QStringLiteral("UIDs valid"), UIDVALIDITY, 0228 QSharedPointer<AbstractData>( new RespData<uint>( 17 ) ))); 0229 QTest::newRow("untagged-bye") 0230 << QByteArray("* BYE go away\r\n") 0231 << QSharedPointer<AbstractResponse>( new State(QByteArray(), BYE, QStringLiteral("go away"), NONE, voidData ) ); 0232 QTest::newRow("untagged-bye-empty") 0233 << QByteArray("* BYE\r\n") 0234 << QSharedPointer<AbstractResponse>( new State(QByteArray(), BYE, QString(), NONE, voidData ) ); 0235 QTest::newRow("untagged-no-somerespcode-empty") 0236 << QByteArray("* NO [ALERT]\r\n") 0237 << QSharedPointer<AbstractResponse>( new State(QByteArray(), NO, QString(), ALERT, voidData ) ); 0238 0239 QTest::newRow("untagged-expunge") 0240 << QByteArray("* 1337 Expunge\r\n") 0241 << QSharedPointer<AbstractResponse>( new NumberResponse( EXPUNGE, 1337 ) ); 0242 QTest::newRow("untagged-exists") 0243 << QByteArray("* 3 exIsts\r\n") 0244 << QSharedPointer<AbstractResponse>( new NumberResponse( EXISTS, 3 ) ); 0245 QTest::newRow("untagged-recent") 0246 << QByteArray("* 666 recenT\r\n") 0247 << QSharedPointer<AbstractResponse>( new NumberResponse( RECENT, 666 ) ); 0248 0249 QTest::newRow("untagged-capability") 0250 << QByteArray("* CAPABILITY fooBar IMAP4rev1 blah\r\n") 0251 << QSharedPointer<AbstractResponse>( new Capability( QStringList() << QStringLiteral("fooBar") << QStringLiteral("IMAP4rev1") << QStringLiteral("blah") ) ); 0252 0253 QTest::newRow("untagged-list") 0254 << QByteArray("* LIST (\\Noselect) \".\" \"\"\r\n") 0255 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList() << QStringLiteral("\\Noselect"), QStringLiteral("."), QLatin1String(""), QMap<QByteArray,QVariant>()) ); 0256 QTest::newRow("untagged-lsub") 0257 << QByteArray("* LSUB (\\Noselect) \".\" \"\"\r\n") 0258 << QSharedPointer<AbstractResponse>( new List( LSUB, QStringList() << QStringLiteral("\\Noselect"), QStringLiteral("."), QLatin1String(""), QMap<QByteArray,QVariant>() ) ); 0259 QTest::newRow("untagged-list-moreflags") 0260 << QByteArray("* LIST (\\Noselect Blesmrt) \".\" \"\"\r\n") 0261 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList() << QStringLiteral("\\Noselect") << QStringLiteral("Blesmrt"), QStringLiteral("."), QLatin1String(""), QMap<QByteArray,QVariant>() ) ); 0262 QTest::newRow("untagged-list-mailbox") 0263 << QByteArray("* LIST () \".\" \"someName\"\r\n") 0264 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QStringLiteral("."), QStringLiteral("someName"), QMap<QByteArray,QVariant>() ) ); 0265 QTest::newRow("untagged-list-mailbox-atom") 0266 << QByteArray("* LIST () \".\" someName\r\n") 0267 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QStringLiteral("."), QStringLiteral("someName"), QMap<QByteArray,QVariant>() ) ); 0268 QTest::newRow("untagged-list-separator-nil") 0269 << QByteArray("* LIST () NiL someName\r\n") 0270 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QByteArray(), QStringLiteral("someName"), QMap<QByteArray,QVariant>() ) ); 0271 QTest::newRow("untagged-list-mailbox-quote") 0272 << QByteArray("* LIST () \".\" \"some\\\"Name\"\r\n") 0273 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QStringLiteral("."), QStringLiteral("some\"Name"), QMap<QByteArray,QVariant>() ) ); 0274 QTest::newRow("untagged-list-unicode") 0275 << QByteArray("* LIST () \"/\" \"~Peter/mail/&U,BTFw-/&ZeVnLIqe-\"\r\n") 0276 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QStringLiteral("/"), QStringLiteral("~Peter/mail/台北/日本語"), QMap<QByteArray,QVariant>() ) ); 0277 QTest::newRow("untagged-list-inbox-atom") 0278 << QByteArray("* LIST () \"/\" inBox\r\n") 0279 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QStringLiteral("/"), QStringLiteral("INBOX"), QMap<QByteArray,QVariant>()) ); 0280 QTest::newRow("untagged-list-inbox-quoted") 0281 << QByteArray("* LIST () \"/\" \"inBox\"\r\n") 0282 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QStringLiteral("/"), QStringLiteral("INBOX"), QMap<QByteArray,QVariant>()) ); 0283 QTest::newRow("untagged-list-inbox-literal") 0284 << QByteArray("* LIST () \"/\" {5}\r\ninBox\r\n") 0285 << QSharedPointer<AbstractResponse>( new List( LIST, QStringList(), QStringLiteral("/"), QStringLiteral("INBOX"), QMap<QByteArray,QVariant>()) ); 0286 QTest::newRow("untagged-list-numeric-mailbox") 0287 << QByteArray("* LIST () \"/\" 666\r\n") 0288 << QSharedPointer<AbstractResponse>(new List(LIST, QStringList(), QStringLiteral("/"), QStringLiteral("666"), QMap<QByteArray,QVariant>())); 0289 QTest::newRow("untagged-list-numeric-mixed-mailbox") 0290 << QByteArray("* LIST () \"/\" 666x333\r\n") 0291 << QSharedPointer<AbstractResponse>(new List(LIST, QStringList(), QStringLiteral("/"), QStringLiteral("666x333"), QMap<QByteArray,QVariant>())); 0292 // https://bugs.kde.org/show_bug.cgi?id=334456 0293 QTest::newRow("untagged-list-groupwise-bug-334456") 0294 << QByteArray("* LIST (\\Unmarked) \"/\" \"Calendar/GroupWise.5-Mehrfachbenutzer \\(Standard\\).MultiUser Control\"\r\n") 0295 << QSharedPointer<AbstractResponse>(new List(LIST, QStringList() << QStringLiteral("\\Unmarked"), QStringLiteral("/"), 0296 QStringLiteral("Calendar/GroupWise.5-Mehrfachbenutzer (Standard).MultiUser Control"), 0297 QMap<QByteArray,QVariant>())); 0298 0299 QMap<QByteArray,QVariant> listExtData; 0300 listExtData["CHILDINFO"] = QStringList() << QStringLiteral("SUBSCRIBED"); 0301 QTest::newRow("untagged-list-ext-childinfo") 0302 << QByteArray("* LIST () \"/\" \"Foo\" (\"CHILDINFO\" (\"SUBSCRIBED\"))\r\n") 0303 << QSharedPointer<AbstractResponse>(new List( LIST, QStringList(), QStringLiteral("/"), QStringLiteral("Foo"), listExtData)); 0304 listExtData["OLDNAME"] = QStringList() << QStringLiteral("blesmrt"); 0305 QTest::newRow("untagged-list-ext-childinfo-2") 0306 << QByteArray("* LIST () \"/\" \"Foo\" (\"CHILDINFO\" (\"SUBSCRIBED\") \"OLDNAME\" (\"blesmrt\"))\r\n") 0307 << QSharedPointer<AbstractResponse>(new List( LIST, QStringList(), QStringLiteral("/"), QStringLiteral("Foo"), listExtData)); 0308 0309 QTest::newRow("untagged-flags") 0310 << QByteArray("* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n") 0311 << QSharedPointer<AbstractResponse>( 0312 new Flags( QStringList() << QStringLiteral("\\Answered") << QStringLiteral("\\Flagged") << 0313 QStringLiteral("\\Deleted") << QStringLiteral("\\Seen") << QStringLiteral("\\Draft") ) ); 0314 QTest::newRow("untagged-flags-numeric") 0315 << QByteArray("* FLAGS (333 666x333)\r\n") 0316 << QSharedPointer<AbstractResponse>(new Flags(QStringList() << QStringLiteral("333") << QStringList(QStringLiteral("666x333")))); 0317 QTest::newRow("search-empty") 0318 << QByteArray("* SEARCH\r\n") 0319 << QSharedPointer<AbstractResponse>(new Search(Imap::Uids())); 0320 QTest::newRow("search-messages") 0321 << QByteArray("* SEARCH 1 33 666\r\n") 0322 << QSharedPointer<AbstractResponse>(new Search(Imap::Uids() << 1 << 33 << 666)); 0323 0324 ESearch::ListData_t esearchData; 0325 QTest::newRow("esearch-empty") 0326 << QByteArray("* ESEARCH\r\n") 0327 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0328 0329 QTest::newRow("esearch-empty-tag") 0330 << QByteArray("* ESEARCH (TAG x)\r\n") 0331 << QSharedPointer<AbstractResponse>(new ESearch("x", ESearch::SEQUENCE, esearchData)); 0332 0333 QTest::newRow("esearch-empty-uid") 0334 << QByteArray("* ESEARCH UiD\r\n") 0335 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::UIDS, esearchData)); 0336 0337 QTest::newRow("esearch-empty-uid-tag") 0338 << QByteArray("* ESEARCH (TAG \"1\") UiD\r\n") 0339 << QSharedPointer<AbstractResponse>(new ESearch("1", ESearch::UIDS, esearchData)); 0340 0341 esearchData.push_back(qMakePair<>(QByteArray("BLAH"), Imap::Uids() << 10)); 0342 QTest::newRow("esearch-one-number") 0343 << QByteArray("* ESEARCH BLaH 10\r\n") 0344 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0345 0346 QTest::newRow("esearch-uid-one-number") 0347 << QByteArray("* ESEArCH UiD BLaH 10\r\n") 0348 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::UIDS, esearchData)); 0349 0350 QTest::newRow("esearch-tag-one-number") 0351 << QByteArray("* ESEArCH (TaG x) BLaH 10\r\n") 0352 << QSharedPointer<AbstractResponse>(new ESearch("x", ESearch::SEQUENCE, esearchData)); 0353 0354 QTest::newRow("esearch-uid-tag-one-number") 0355 << QByteArray("* ESEArCH (TaG x) Uid BLaH 10\r\n") 0356 << QSharedPointer<AbstractResponse>(new ESearch("x", ESearch::UIDS, esearchData)); 0357 0358 esearchData.push_front(qMakePair<>(QByteArray("FOO"), Imap::Uids() << 666)); 0359 esearchData.push_front(qMakePair<>(QByteArray("FOO"), Imap::Uids() << 333)); 0360 QTest::newRow("esearch-two-numbers") 0361 << QByteArray("* ESEARCH fOO 333 foo 666 BLaH 10\r\n") 0362 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0363 0364 esearchData.clear(); 0365 esearchData.push_back(qMakePair<>(QByteArray("FOO"), Imap::Uids() << 333)); 0366 esearchData.push_back(qMakePair<>(QByteArray("BLAH"), Imap::Uids() << 10)); 0367 QTest::newRow("esearch-uid-two-numbers") 0368 << QByteArray("* ESEArCH UiD foo 333 BLaH 10\r\n") 0369 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::UIDS, esearchData)); 0370 0371 QTest::newRow("esearch-tag-two-numbers") 0372 << QByteArray("* ESEArCH (TaG x) foo 333 BLaH 10 \r\n") 0373 << QSharedPointer<AbstractResponse>(new ESearch("x", ESearch::SEQUENCE, esearchData)); 0374 0375 QTest::newRow("esearch-uid-tag-two-numbers") 0376 << QByteArray("* ESEArCH (TaG x) Uid foo 333 BLaH 10\r\n") 0377 << QSharedPointer<AbstractResponse>(new ESearch("x", ESearch::UIDS, esearchData)); 0378 0379 esearchData.clear(); 0380 esearchData.push_back(qMakePair<>(QByteArray("BLAH"), Imap::Uids() << 10 << 11 << 13 << 14 << 15 << 16 << 17)); 0381 QTest::newRow("esearch-one-list-1") 0382 << QByteArray("* ESEARCH BLaH 10,11,13:17\r\n") 0383 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0384 0385 esearchData.clear(); 0386 esearchData.push_back(qMakePair<>(QByteArray("BLAH"), Imap::Uids() << 1 << 2)); 0387 QTest::newRow("esearch-one-list-2") 0388 << QByteArray("* ESEARCH BLaH 1:2\r\n") 0389 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0390 0391 QTest::newRow("esearch-one-list-3") 0392 << QByteArray("* ESEARCH BLaH 1,2\r\n") 0393 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0394 0395 esearchData.clear(); 0396 esearchData.push_back(qMakePair<>(QByteArray("BLAH"), Imap::Uids() << 1 << 2 << 3 << 4 << 5)); 0397 QTest::newRow("esearch-one-list-4") 0398 << QByteArray("* ESEARCH BLaH 1,2:4,5\r\n") 0399 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0400 0401 QTest::newRow("esearch-one-list-extra-space-at-end") 0402 << QByteArray("* ESEARCH BLaH 1,2:4,5 \r\n") 0403 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0404 0405 esearchData.push_back(qMakePair<>(QByteArray("FOO"), Imap::Uids() << 6)); 0406 QTest::newRow("esearch-mixed-1") 0407 << QByteArray("* ESEARCH BLaH 1,2:4,5 FOO 6\r\n") 0408 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0409 0410 std::swap(esearchData[0], esearchData[1]); 0411 QTest::newRow("esearch-mixed-2") 0412 << QByteArray("* ESEARCH FOO 6 BLaH 1,2:4,5\r\n") 0413 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0414 0415 esearchData.push_back(qMakePair<>(QByteArray("BAZ"), Imap::Uids() << 33)); 0416 QTest::newRow("esearch-mixed-3") 0417 << QByteArray("* ESEARCH FOO 6 BLaH 1,2:4,5 baz 33 \r\n") 0418 << QSharedPointer<AbstractResponse>(new ESearch(QByteArray(), ESearch::SEQUENCE, esearchData)); 0419 0420 ESearch::IncrementalContextData_t incrementalEsearchData; 0421 incrementalEsearchData.push_back(ESearch::ContextIncrementalItem(ESearch::ContextIncrementalItem::ADDTO, 1, Imap::Uids() << 2733)); 0422 incrementalEsearchData.push_back(ESearch::ContextIncrementalItem(ESearch::ContextIncrementalItem::ADDTO, 1, Imap::Uids() << 2731 << 2732)); 0423 QTest::newRow("esearch-context-sort-1") 0424 << QByteArray("* ESEARCH (TAG \"C01\") UID ADDTO (1 2733) ADDTO (1 2731:2732)\r\n") 0425 << QSharedPointer<AbstractResponse>(new ESearch("C01", ESearch::UIDS, incrementalEsearchData)); 0426 0427 QTest::newRow("esearch-context-sort-2") 0428 << QByteArray("* ESEARCH (TAG \"C01\") UID ADDTO (1 2733 1 2731:2732)\r\n") 0429 << QSharedPointer<AbstractResponse>(new ESearch("C01", ESearch::UIDS, incrementalEsearchData)); 0430 0431 incrementalEsearchData.clear(); 0432 incrementalEsearchData.push_back(ESearch::ContextIncrementalItem(ESearch::ContextIncrementalItem::ADDTO, 1, Imap::Uids() << 2733)); 0433 incrementalEsearchData.push_back(ESearch::ContextIncrementalItem(ESearch::ContextIncrementalItem::ADDTO, 1, Imap::Uids() << 2732)); 0434 incrementalEsearchData.push_back(ESearch::ContextIncrementalItem(ESearch::ContextIncrementalItem::ADDTO, 1, Imap::Uids() << 2731)); 0435 QTest::newRow("esearch-context-sort-3") 0436 << QByteArray("* ESEARCH (TAG \"C01\") UID ADDTO (1 2733 1 2732 1 2731)\r\n") 0437 << QSharedPointer<AbstractResponse>(new ESearch("C01", ESearch::UIDS, incrementalEsearchData)); 0438 0439 incrementalEsearchData.clear(); 0440 incrementalEsearchData.push_back(ESearch::ContextIncrementalItem(ESearch::ContextIncrementalItem::ADDTO, 1, Imap::Uids() << 2731 << 2732 << 2733)); 0441 QTest::newRow("esearch-context-sort-4") 0442 << QByteArray("* ESEARCH (TAG \"C01\") UID ADDTO (1 2731:2733)\r\n") 0443 << QSharedPointer<AbstractResponse>(new ESearch("C01", ESearch::UIDS, incrementalEsearchData)); 0444 0445 incrementalEsearchData.clear(); 0446 incrementalEsearchData.push_back(ESearch::ContextIncrementalItem(ESearch::ContextIncrementalItem::REMOVEFROM, 0, Imap::Uids() << 32768)); 0447 QTest::newRow("esearch-context-sort-5") 0448 << QByteArray("* ESEARCH (TAG \"B01\") UID REMOVEFROM (0 32768)\r\n") 0449 << QSharedPointer<AbstractResponse>(new ESearch("B01", ESearch::UIDS, incrementalEsearchData)); 0450 0451 Status::stateDataType states; 0452 states[Status::MESSAGES] = 231; 0453 states[Status::UIDNEXT] = 44292; 0454 QTest::newRow("status-1") 0455 << QByteArray("* STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)\r\n") 0456 << QSharedPointer<AbstractResponse>( new Status( QStringLiteral("blurdybloop"), states ) ); 0457 QTest::newRow("status-numeric-only") 0458 << QByteArray("* STATUS 333 (MESSAGES 231 UIDNEXT 44292)\r\n") 0459 << QSharedPointer<AbstractResponse>(new Status(QStringLiteral("333"), states)); 0460 QTest::newRow("status-numeric-mixed") 0461 << QByteArray("* STATUS 333x666 (MESSAGES 231 UIDNEXT 44292)\r\n") 0462 << QSharedPointer<AbstractResponse>(new Status(QStringLiteral("333x666"), states)); 0463 states[Status::UIDVALIDITY] = 1337; 0464 states[Status::RECENT] = 3234567890u; 0465 QTest::newRow("status-2") 0466 << QByteArray("* STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292 UIDVALIDITY 1337 RECENT 3234567890)\r\n") 0467 << QSharedPointer<AbstractResponse>( new Status( QStringLiteral("blurdybloop"), states ) ); 0468 0469 // notice the trailing whitespace 0470 QTest::newRow("status-exchange-botched-1") 0471 << QByteArray("* STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292 UIDVALIDITY 1337 RECENT 3234567890) \r\n") 0472 << QSharedPointer<AbstractResponse>( new Status( QStringLiteral("blurdybloop"), states ) ); 0473 0474 states.clear(); 0475 states[Status::MESSAGES] = 113; 0476 QTest::newRow("status-extra-whitespace-around-atoms") 0477 << QByteArray("* STATUS blurdybloop ( MESSAGES 113 )\r\n") 0478 << QSharedPointer<AbstractResponse>( new Status( QStringLiteral("blurdybloop"), states ) ); 0479 0480 // https://bugs.kde.org/show_bug.cgi?id=365149 0481 states.clear(); 0482 states[Status::MESSAGES] = 702; 0483 QTest::newRow("untagged-extra-space-before-status") 0484 << QByteArray("* STATUS \"INBOX\" (MESSAGES 702)\r\n") 0485 << QSharedPointer<AbstractResponse>(new Status(QStringLiteral("INBOX"), states)); 0486 0487 0488 QTest::newRow("namespace-1") 0489 << QByteArray("* Namespace nil NIL nil\r\n") 0490 << QSharedPointer<AbstractResponse>( new Namespace( QList<NamespaceData>(), 0491 QList<NamespaceData>(), QList<NamespaceData>() ) ); 0492 0493 QTest::newRow("namespace-2") 0494 << QByteArray("* Namespace () NIL nil\r\n") 0495 << QSharedPointer<AbstractResponse>( new Namespace( QList<NamespaceData>(), 0496 QList<NamespaceData>(), QList<NamespaceData>() ) ); 0497 0498 QTest::newRow("namespace-3") 0499 << QByteArray("* Namespace ((\"\" \"/\")) NIL nil\r\n") 0500 << QSharedPointer<AbstractResponse>( new Namespace( QList<NamespaceData>() << NamespaceData( QLatin1String(""), QStringLiteral("/") ), 0501 QList<NamespaceData>(), QList<NamespaceData>() ) ); 0502 0503 QTest::newRow("namespace-4") 0504 << QByteArray("* Namespace ((\"prefix\" \".\")(\"\" \"/\")) ((\"blesmrt\" \"trojita\")) ((\"foo\" \"bar\"))\r\n") 0505 << QSharedPointer<AbstractResponse>( new Namespace( 0506 QList<NamespaceData>() << NamespaceData( QStringLiteral("prefix"), QStringLiteral(".") ) << NamespaceData( QLatin1String(""), QStringLiteral("/") ), 0507 QList<NamespaceData>() << NamespaceData( QStringLiteral("blesmrt"), QStringLiteral("trojita") ), 0508 QList<NamespaceData>() << NamespaceData( QStringLiteral("foo"), QStringLiteral("bar") ) ) ); 0509 0510 QTest::newRow("namespace-5") 0511 << QByteArray("* NAMESPACE ((\"\" \"/\")(\"#mhinbox\" NIL)(\"#mh/\" \"/\")) ((\"~\" \"/\")) " 0512 "((\"#shared/\" \"/\")(\"#ftp/\" \"/\")(\"#news.\" \".\")(\"#public/\" \"/\"))\r\n") 0513 << QSharedPointer<AbstractResponse>( new Namespace( 0514 QList<NamespaceData>() << NamespaceData( QLatin1String(""), QStringLiteral("/") ) << NamespaceData( QStringLiteral("#mhinbox"), QByteArray() ) 0515 << NamespaceData( QStringLiteral("#mh/"), QStringLiteral("/") ), 0516 QList<NamespaceData>() << NamespaceData( QStringLiteral("~"), QStringLiteral("/") ), 0517 QList<NamespaceData>() << NamespaceData( QStringLiteral("#shared/"), QStringLiteral("/") ) << NamespaceData( QStringLiteral("#ftp/"), QStringLiteral("/") ) 0518 << NamespaceData( QStringLiteral("#news."), QStringLiteral(".") ) << NamespaceData( QStringLiteral("#public/"), QStringLiteral("/") ) 0519 ) ); 0520 0521 QTest::newRow("sort-1") 0522 << QByteArray("* SORT") << QSharedPointer<AbstractResponse>(new Sort(Imap::Uids())); 0523 QTest::newRow("sort-2") 0524 << QByteArray("* SORT ") << QSharedPointer<AbstractResponse>(new Sort(Imap::Uids())); 0525 QTest::newRow("sort-3") 0526 << QByteArray("* SORT 13 1 6 5 7 9 10 11 12 4 3 2 8\r\n") 0527 << QSharedPointer<AbstractResponse>(new Sort(Imap::Uids() << 13 << 1 << 6 << 5 << 7 << 9 << 10 << 11 << 12 << 4 << 3 << 2 << 8)); 0528 0529 ThreadingNode node2(2), node3(3), node6(6), node4(4), node23(23), node44(44), node7(7), node96(96); 0530 QVector<ThreadingNode> rootNodes; 0531 node4.children << node23; 0532 node7.children << node96; 0533 node44.children << node7; 0534 node6.children << node4 << node44; 0535 node3.children << node6; 0536 rootNodes << node2 << node3; 0537 QTest::newRow("thread-1") 0538 << QByteArray("* THREAD (2)(3 6 (4 23)(44 7 96))\r\n") 0539 << QSharedPointer<AbstractResponse>( new Thread( rootNodes ) ); 0540 0541 rootNodes.clear(); 0542 ThreadingNode node203(3), node205(5), anonymousNode201; 0543 anonymousNode201.children << node203 << node205; 0544 rootNodes << anonymousNode201; 0545 QTest::newRow("thread-2") 0546 << QByteArray("* THREAD ((3)(5))\r\n") 0547 << QSharedPointer<AbstractResponse>( new Thread( rootNodes ) ); 0548 0549 rootNodes.clear(); 0550 ThreadingNode node301(1), node302(2), node303(3); 0551 rootNodes << node301 << node302 << node303; 0552 QTest::newRow("thread-3") 0553 << QByteArray("* THREAD (1)(2)(3)\r\n") 0554 << QSharedPointer<AbstractResponse>( new Thread( rootNodes ) ); 0555 0556 rootNodes.clear(); 0557 ThreadingNode node401(1), node402(2), node403(3); 0558 node401.children << node402 << node403; 0559 rootNodes << node401; 0560 QTest::newRow("thread-4") 0561 << QByteArray("* THREAD (1(2)(3))\r\n") 0562 << QSharedPointer<AbstractResponse>( new Thread( rootNodes ) ); 0563 0564 rootNodes.clear(); 0565 ThreadingNode node502(2), node503(3), node506(6), node504(4), node523(23), 0566 node544(44), node507(7), node596(96), node513(13), node566(66), anon501, anon502; 0567 node504.children << node523; 0568 node507.children << node596; 0569 node544.children << node507; 0570 anon502.children << node566; 0571 anon501.children << anon502; 0572 node506.children << node504 << node544 << node513 << anon501; 0573 node503.children << node506; 0574 rootNodes << node502 << node503; 0575 QTest::newRow("thread-5") 0576 << QByteArray("* THREAD (2)(3 6 (4 23)(44 7 96) (13) (((66))))\r\n") 0577 << QSharedPointer<AbstractResponse>( new Thread( rootNodes ) ); 0578 0579 rootNodes.clear(); 0580 ThreadingNode node608(8), node602(2), node603(3), node604(4), node607(7), node609(9), 0581 node610(10), node611(11), node612(12), node605(5), node601(1), node606(6), node613(13); 0582 node603.children << node604; 0583 node602.children << node603; 0584 rootNodes << node608 << node602 << node607 << node609 << node610; 0585 rootNodes << ThreadingNode(0, QVector<ThreadingNode>() << node611 << node612 ); 0586 rootNodes << node605; 0587 rootNodes << ThreadingNode(0, QVector<ThreadingNode>() << node601 << node606 ); 0588 rootNodes << node613; 0589 QTest::newRow("thread-6") 0590 << QByteArray("* THREAD (8)(2 3 4)(7)(9)(10)((11)(12))(5)((1)(6))(13)\r\n") 0591 << QSharedPointer<AbstractResponse>( new Thread( rootNodes ) ); 0592 0593 esearchData.clear(); 0594 ESearch::IncrementalThreadingData_t esearchThreading; 0595 esearchThreading.push_back(ESearch::IncrementalThreadingItem_t(666, rootNodes)); 0596 QTest::newRow("esearch-incthread-single") 0597 << QByteArray("* ESEARCH (TAG \"x\") UID INCTHREAD 666 (8)(2 3 4)(7)(9)(10)((11)(12))(5)((1)(6))(13)\r\n") 0598 << QSharedPointer<AbstractResponse>(new ESearch("x", ESearch::UIDS, esearchThreading)); 0599 rootNodes.clear(); 0600 rootNodes << ThreadingNode(123, QVector<ThreadingNode>()); 0601 esearchThreading.push_back(ESearch::IncrementalThreadingItem_t(333, rootNodes)); 0602 QTest::newRow("esearch-incthread-two") 0603 << QByteArray("* ESEARCH (TAG \"x\") UID INCTHREAD 666 (8)(2 3 4)(7)(9)(10)((11)(12))(5)((1)(6))(13) " 0604 "INCTHREAD 333 (123)\r\n") 0605 << QSharedPointer<AbstractResponse>(new ESearch("x", ESearch::UIDS, esearchThreading)); 0606 0607 Fetch::dataType fetchData; 0608 0609 QTest::newRow("fetch-empty") 0610 << QByteArray("* 66 FETCH ()\r\n") 0611 << QSharedPointer<AbstractResponse>( new Fetch( 66, fetchData ) ); 0612 0613 fetchData.clear(); 0614 fetchData[ "RFC822.SIZE" ] = QSharedPointer<AbstractData>( new RespData<quint64>( 1337 ) ); 0615 QTest::newRow("fetch-rfc822-size") 0616 << QByteArray("* 123 FETCH (rfc822.size 1337)\r\n") 0617 << QSharedPointer<AbstractResponse>( new Fetch( 123, fetchData ) ); 0618 0619 fetchData.clear(); 0620 fetchData[ "RFC822.SIZE" ] = QSharedPointer<AbstractData>( new RespData<quint64>( 1337 ) ); 0621 fetchData[ "UID" ] = QSharedPointer<AbstractData>( new RespData<uint>( 666 ) ); 0622 QTest::newRow("fetch-rfc822-size-uid") 0623 << QByteArray("* 123 FETCH (uID 666 rfc822.size 1337)\r\n") 0624 << QSharedPointer<AbstractResponse>( new Fetch( 123, fetchData ) ); 0625 QTest::newRow("fetch-rfc822-size-uid-swapped") 0626 << QByteArray("* 123 FETCH (rfc822.size 1337 uId 666)\r\n") 0627 << QSharedPointer<AbstractResponse>( new Fetch( 123, fetchData ) ); 0628 0629 fetchData.clear(); 0630 fetchData[ "RFC822.HEADER" ] = QSharedPointer<AbstractData>( new RespData<QByteArray>( "123456789012" ) ); 0631 QTest::newRow("fetch-rfc822-header") 0632 << QByteArray("* 123 FETCH (rfc822.header {12}\r\n123456789012)\r\n") 0633 << QSharedPointer<AbstractResponse>( new Fetch( 123, fetchData ) ); 0634 0635 fetchData.clear(); 0636 fetchData[ "RFC822.TEXT" ] = QSharedPointer<AbstractData>( new RespData<QByteArray>( "abcdEf" ) ); 0637 QTest::newRow("fetch-rfc822-text") 0638 << QByteArray("* 123 FETCH (rfc822.tExt abcdEf)\r\n") 0639 << QSharedPointer<AbstractResponse>( new Fetch( 123, fetchData ) ); 0640 0641 fetchData.clear(); 0642 fetchData[ "INTERNALDATE" ] = QSharedPointer<AbstractData>( 0643 new RespData<QDateTime>( QDateTime( QDate(2007, 3, 7), QTime( 14, 3, 32 ), Qt::UTC ) ) ); 0644 QTest::newRow("fetch-rfc822-internaldate") 0645 << QByteArray("* 123 FETCH (InternalDate \"07-Mar-2007 15:03:32 +0100\")\r\n") 0646 << QSharedPointer<AbstractResponse>( new Fetch( 123, fetchData ) ); 0647 0648 fetchData.clear(); 0649 fetchData[ "INTERNALDATE" ] = QSharedPointer<AbstractData>( 0650 new RespData<QDateTime>( QDateTime( QDate(1981, 4, 6), QTime( 18, 33, 32 ), Qt::UTC ) ) ); 0651 QTest::newRow("fetch-rfc822-internaldate-shorter") 0652 << QByteArray("* 123 FETCH (InternalDate \"6-Apr-1981 12:03:32 -0630\")\r\n") 0653 << QSharedPointer<AbstractResponse>( new Fetch( 123, fetchData ) ); 0654 0655 fetchData.clear(); 0656 QDateTime date( QDate( 1996, 7, 17 ), QTime( 9, 23, 25 ), Qt::UTC ); 0657 QString subject( QStringLiteral("IMAP4rev1 WG mtg summary and minutes")); 0658 QList<MailAddress> from, sender, replyTo, to, cc, bcc; 0659 from.append( MailAddress( QStringLiteral("Terry Gray"), QByteArray(), QStringLiteral("gray"), QStringLiteral("cac.washington.edu")) ); 0660 sender = replyTo = from; 0661 to.append( MailAddress( QByteArray(), QByteArray(), QStringLiteral("imap"), QStringLiteral("cac.washington.edu")) ); 0662 cc.append( MailAddress( QByteArray(), QByteArray(), QStringLiteral("minutes"), QStringLiteral("CNRI.Reston.VA.US")) ); 0663 cc.append( MailAddress( QStringLiteral("John Klensin"), QByteArray(), QStringLiteral("KLENSIN"), QStringLiteral("MIT.EDU")) ); 0664 QByteArray messageId( "B27397-0100000@cac.washington.edu" ); 0665 fetchData[ "ENVELOPE" ] = QSharedPointer<AbstractData>( 0666 new RespData<Envelope>( 0667 Envelope( date, subject, from, sender, replyTo, to, cc, bcc, QList<QByteArray>(), messageId ) 0668 ) ); 0669 QTest::newRow("fetch-envelope") 0670 << QByteArray( "* 12 FETCH (ENVELOPE (\"Wed, 17 Jul 1996 02:23:25 -0700 (PDT)\" " 0671 "\"IMAP4rev1 WG mtg summary and minutes\" " 0672 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 0673 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 0674 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 0675 "((NIL NIL \"imap\" \"cac.washington.edu\")) " 0676 "((NIL NIL \"minutes\" \"CNRI.Reston.VA.US\") " 0677 "(\"John Klensin\" NIL \"KLENSIN\" \"MIT.EDU\")) NIL NIL " 0678 "\"<B27397-0100000@cac.washington.edu>\"))\r\n" ) 0679 << QSharedPointer<AbstractResponse>( new Fetch( 12, fetchData ) ); 0680 0681 fetchData.clear(); 0682 fetchData[ "ENVELOPE" ] = QSharedPointer<AbstractData>( 0683 new RespData<Envelope>( 0684 Envelope( QDateTime(), subject, from, sender, replyTo, to, cc, bcc, QList<QByteArray>(), messageId ) 0685 ) ); 0686 QTest::newRow("fetch-envelope-nildate") 0687 << QByteArray( "* 13 FETCH (ENVELOPE (NIL " 0688 "\"IMAP4rev1 WG mtg summary and minutes\" " 0689 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 0690 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 0691 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 0692 "((NIL NIL \"imap\" \"cac.washington.edu\")) " 0693 "((NIL NIL \"minutes\" \"CNRI.Reston.VA.US\") " 0694 "(\"John Klensin\" NIL \"KLENSIN\" \"MIT.EDU\")) NIL NIL " 0695 "\"<B27397-0100000@cac.washington.edu>\"))\r\n" ) 0696 << QSharedPointer<AbstractResponse>( new Fetch( 13, fetchData ) ); 0697 0698 // FIXME: more unit tests for ENVELOPE and BODY[ 0699 0700 fetchData.clear(); 0701 AbstractMessage::bodyFldParam_t bodyFldParam; 0702 AbstractMessage::bodyFldDsp_t bodyFldDsp; 0703 bodyFldParam[ "CHARSET" ] = "UTF-8"; 0704 bodyFldParam[ "FORMAT" ] = "flowed"; 0705 fetchData[ "BODYSTRUCTURE" ] = QSharedPointer<AbstractData>( 0706 new TextMessage( "text", "plain", bodyFldParam, QByteArray(), QByteArray(), 0707 "8bit", 362, QByteArray(), bodyFldDsp, QList<QByteArray>(), 0708 QByteArray(), QVariant(), 15 ) 0709 ); 0710 QTest::newRow("fetch-bodystructure-plain") << 0711 QByteArray( "* 3 FETCH (BODYSTRUCTURE (\"text\" \"plain\" (\"chaRset\" \"UTF-8\" \"format\" \"flowed\") NIL NIL \"8bit\" 362 15 NIL NIL NIL))\r\n" ) << 0712 QSharedPointer<AbstractResponse>( new Fetch( 3, fetchData ) ); 0713 0714 0715 fetchData.clear(); 0716 QList<QSharedPointer<AbstractMessage> > msgList; 0717 // 1.1 0718 bodyFldParam.clear(); 0719 bodyFldDsp = AbstractMessage::bodyFldDsp_t(); 0720 bodyFldParam[ "CHARSET" ] = "US-ASCII"; 0721 bodyFldParam[ "DELSP" ] = "yes"; 0722 bodyFldParam[ "FORMAT" ] = "flowed"; 0723 msgList.append( QSharedPointer<AbstractMessage>( 0724 new TextMessage( "text", "plain", bodyFldParam, QByteArray(), 0725 QByteArray(), "7bit", 990, QByteArray(), bodyFldDsp, 0726 QList<QByteArray>(), QByteArray(), QVariant(), 27 ) 0727 ) ); 0728 // 1.2 0729 bodyFldParam.clear(); 0730 bodyFldParam[ "X-MAC-TYPE" ] = "70674453"; 0731 bodyFldParam[ "NAME" ] = "PGP.sig"; 0732 bodyFldDsp = AbstractMessage::bodyFldDsp_t(); 0733 bodyFldDsp.first = "inline"; 0734 bodyFldDsp.second[ "FILENAME" ] = "PGP.sig"; 0735 msgList.append( QSharedPointer<AbstractMessage>( 0736 new TextMessage( "application", "pgp-signature", bodyFldParam, 0737 QByteArray(), "This is a digitally signed message part", 0738 "7bit", 193, QByteArray(), bodyFldDsp, QList<QByteArray>(), 0739 QByteArray(), QVariant(), 0 ) 0740 ) ); 0741 // 1 0742 bodyFldParam.clear(); 0743 bodyFldParam[ "PROTOCOL" ] = "application/pgp-signature"; 0744 bodyFldParam[ "MICALG" ] = "pgp-sha1"; 0745 bodyFldParam[ "BOUNDARY" ] = "Apple-Mail-10--856231115"; 0746 bodyFldDsp = AbstractMessage::bodyFldDsp_t(); 0747 fetchData[ "BODYSTRUCTURE" ] = QSharedPointer<AbstractData>( 0748 new MultiMessage( msgList, "signed", bodyFldParam, bodyFldDsp, QList<QByteArray>(), QByteArray(), QVariant() ) 0749 ); 0750 QTest::newRow("fetch-bodystructure-signed") << 0751 QByteArray("* 1 FETCH (BODYSTRUCTURE ((\"text\" \"plain\" (\"charset\" \"US-ASCII\" \"delsp\" \"yes\" \"format\" \"flowed\") NIL NIL \"7bit\" 990 27 NIL NIL NIL)(\"application\" \"pgp-signature\" (\"x-mac-type\" \"70674453\" \"name\" \"PGP.sig\") NIL \"This is a digitally signed message part\" \"7bit\" 193 NIL (\"inline\" (\"filename\" \"PGP.sig\")) NIL) \"signed\" (\"protocol\" \"application/pgp-signature\" \"micalg\" \"pgp-sha1\" \"boundary\" \"Apple-Mail-10--856231115\") NIL NIL))\r\n") << 0752 QSharedPointer<AbstractResponse>( new Fetch( 1, fetchData ) ); 0753 0754 fetchData.clear(); 0755 bodyFldParam.clear(); 0756 bodyFldParam[ "CHARSET" ] = "UTF-8"; 0757 bodyFldParam[ "FORMAT" ] = "flowed"; 0758 fetchData[ "BODYSTRUCTURE" ] = QSharedPointer<AbstractData>( 0759 new TextMessage( "text", "plain", bodyFldParam, QByteArray(), QByteArray(), 0760 "quoted-printable", 0, QByteArray(), bodyFldDsp, QList<QByteArray>(), QByteArray(), QVariant(), 0 ) ); 0761 QTest::newRow("fetch-exchange-screwup-1") << 0762 QByteArray("* 61 FETCH " 0763 "(BODYSTRUCTURE (\"text\" \"plain\" (\"charset\" \"UTF-8\" \"format\" \"flowed\") " 0764 "NIL NIL \"quoted-printable\" -1 -1 NIL NIL NIL NIL))\r\n") << 0765 QSharedPointer<AbstractResponse>( new Fetch( 61, fetchData ) ); 0766 0767 msgList.clear(); 0768 bodyFldParam.clear(); 0769 bodyFldDsp = AbstractMessage::bodyFldDsp_t(); 0770 bodyFldParam["CHARSET"] = "utf-8"; 0771 msgList.append(QSharedPointer<AbstractMessage>(new TextMessage("text", "plain", bodyFldParam, 0772 QByteArray(), QByteArray(), "quoted-printable", 333, QByteArray(), 0773 bodyFldDsp, QList<QByteArray>(), QByteArray(), QVariant(), 10))); 0774 msgList.append(QSharedPointer<AbstractMessage>(new TextMessage("text", "html", bodyFldParam, 0775 QByteArray(), QByteArray(), "7bit", 666, QByteArray(), 0776 bodyFldDsp, QList<QByteArray>(), QByteArray(), QVariant(), 20))); 0777 fetchData.clear(); 0778 bodyFldParam.clear(); 0779 bodyFldParam["BOUNDARY"] = "=_1234"; 0780 fetchData["BODYSTRUCTURE"] = QSharedPointer<AbstractData>(new MultiMessage(msgList, "alternative", bodyFldParam, bodyFldDsp, QList<QByteArray>(), QByteArray(), QVariant())); 0781 // Exchange sends utter crap inside the body-fld-dsp, unfortunately. 0782 // This was reported thhrough an encrypted mail in a followup to https://bugs.kde.org/show_bug.cgi?id=334056, 0783 // but the problem is unrelted to the original topic of that bug. 0784 QTest::newRow("fetch-exchange-screwup-bodystructure-body-fld-dsp") 0785 << QByteArray("* 1 FETCH (BODYSTRUCTURE (" 0786 "(\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"quoted-printable\" 333 10 NIL NIL NIL NIL)" 0787 "(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 666 20 NIL NIL NIL NIL) " 0788 "\"alternative\" (\"boundary\" \"=_1234\") \"random@exchange!crap!goes!here!\" NIL))\r\n") 0789 << QSharedPointer<AbstractResponse>(new Fetch(1, fetchData)); 0790 0791 fetchData.clear(); 0792 bodyFldParam.clear(); 0793 bodyFldDsp = AbstractMessage::bodyFldDsp_t(); 0794 bodyFldDsp.first = "inline"; 0795 bodyFldParam["CHARSET"] = "utf-8"; 0796 fetchData["BODYSTRUCTURE"] = QSharedPointer<AbstractData>( 0797 new TextMessage("text", "html", bodyFldParam, QByteArray(), QByteArray(), "quoted-printable", 4848, 0798 QByteArray(), bodyFldDsp, QList<QByteArray>(), QByteArray(), QVariant(), 25)); 0799 QTest::newRow("fetch-body-fld-dsp-inline-citadel") 0800 << QByteArray("* 12 FETCH (BODYSTRUCTURE (\"text\" \"html\" (\"CHARSET\" \"utf-8\") NIL NIL \"quoted-printable\" 4848 25 NIL (\"inline\") NIL))\r\n") 0801 << QSharedPointer<AbstractResponse>(new Fetch(12, fetchData)); 0802 0803 // GMail and its flawed representation of a nested message/rfc822 0804 fetchData.clear(); 0805 from.clear(); from << MailAddress(QStringLiteral("somebody"), QString(), QStringLiteral("info"), QStringLiteral("example.com")); 0806 sender = replyTo = from; 0807 to.clear(); to << MailAddress(QStringLiteral("destination"), QString(), QStringLiteral("foobar"), QStringLiteral("gmail.com")); 0808 cc.clear(); 0809 bcc.clear(); 0810 fetchData["ENVELOPE"] = QSharedPointer<AbstractData>( 0811 new RespData<Envelope>( 0812 Envelope( QDateTime(QDate(2011, 1, 11), QTime(9, 21, 42), Qt::UTC), QStringLiteral("blablabla"), from, sender, replyTo, to, cc, bcc, QList<QByteArray>(), QByteArray() ) 0813 )); 0814 fetchData["UID"] = QSharedPointer<AbstractData>(new RespData<uint>(8803)); 0815 fetchData["RFC822.SIZE"] = QSharedPointer<AbstractData>(new RespData<quint64>(56144)); 0816 0817 msgList.clear(); 0818 bodyFldParam.clear(); 0819 bodyFldParam["CHARSET"] = "iso-8859-2"; 0820 msgList.append(QSharedPointer<AbstractMessage>( 0821 new TextMessage("text", "plain", bodyFldParam, QByteArray(), QByteArray(), "QUOTED-PRINTABLE", 52, QByteArray(), 0822 AbstractMessage::bodyFldDsp_t(), QList<QByteArray>(), QByteArray(), QVariant(), 2))); 0823 msgList.append(QSharedPointer<AbstractMessage>( 0824 new TextMessage("text", "html", bodyFldParam, QByteArray(), QByteArray(), "QUOTED-PRINTABLE", 1739, QByteArray(), 0825 AbstractMessage::bodyFldDsp_t(), QList<QByteArray>(), QByteArray(), QVariant(), 66))); 0826 bodyFldParam.clear(); 0827 bodyFldParam["BOUNDARY"] = "----=_NextPart_001_0078_01CBB179.57530990"; 0828 msgList = QList<QSharedPointer<AbstractMessage> >() << QSharedPointer<AbstractMessage>( 0829 new MultiMessage( msgList, "alternative", bodyFldParam, AbstractMessage::bodyFldDsp_t(), QList<QByteArray>(), QByteArray(), QVariant() ) ); 0830 msgList << QSharedPointer<AbstractMessage>( 0831 new MsgMessage("message", "rfc822", AbstractMessage::bodyFldParam_t(), QByteArray(), QByteArray(), "7BIT", 836, 0832 QByteArray(), AbstractMessage::bodyFldDsp_t(), QList<QByteArray>(), QByteArray(), QVariant(), 0833 Envelope(), QSharedPointer<AbstractMessage>( 0834 new BasicMessage("attachment", QByteArray(), AbstractMessage::bodyFldParam_t(), QByteArray(), QByteArray(), 0835 QByteArray(), 0, QByteArray(), AbstractMessage::bodyFldDsp_t(), QList<QByteArray>(), QByteArray(), QVariant()) 0836 ), 0 )); 0837 msgList << QSharedPointer<AbstractMessage>( 0838 new MsgMessage("message", "rfc822", AbstractMessage::bodyFldParam_t(), QByteArray(), QByteArray(), "7BIT", 50785, 0839 QByteArray(), AbstractMessage::bodyFldDsp_t(), QList<QByteArray>(), QByteArray(), QVariant(), 0840 Envelope(), QSharedPointer<AbstractMessage>( 0841 new BasicMessage("attachment", QByteArray(), AbstractMessage::bodyFldParam_t(), QByteArray(), QByteArray(), 0842 QByteArray(), 0, QByteArray(), AbstractMessage::bodyFldDsp_t(), QList<QByteArray>(), QByteArray(), QVariant()) 0843 ), 0 )); 0844 bodyFldParam.clear(); 0845 bodyFldParam["BOUNDARY"] = "----=_NextPart_000_0077_01CBB179.57530990"; 0846 bodyFldDsp = AbstractMessage::bodyFldDsp_t(); 0847 fetchData["BODYSTRUCTURE"] = QSharedPointer<AbstractData>( 0848 new MultiMessage( msgList, "mixed", bodyFldParam, bodyFldDsp, QList<QByteArray>(), QByteArray(), QVariant())); 0849 QTest::newRow("fetch-envelope-blupix-gmail") 0850 << QByteArray("* 6116 FETCH (UID 8803 RFC822.SIZE 56144 ENVELOPE (\"Tue, 11 Jan 2011 10:21:42 +0100\" " 0851 "\"blablabla\" ((\"somebody\" NIL \"info\" \"example.com\")) " 0852 "((\"somebody\" NIL \"info\" \"example.com\")) " 0853 "((\"somebody\" NIL \"info\" \"example.com\")) " 0854 "((\"destination\" NIL \"foobar\" \"gmail.com\")) " 0855 "NIL NIL NIL \"\") " 0856 "BODYSTRUCTURE (((\"TEXT\" \"PLAIN\" (\"CHARSET\" \"iso-8859-2\") NIL NIL " 0857 "\"QUOTED-PRINTABLE\" 52 2 NIL NIL NIL)(\"TEXT\" \"HTML\" (\"CHARSET\" \"iso-8859-2\") " 0858 "NIL NIL \"QUOTED-PRINTABLE\" 1739 66 NIL NIL NIL) \"ALTERNATIVE\" " 0859 "(\"BOUNDARY\" \"----=_NextPart_001_0078_01CBB179.57530990\") NIL NIL)" 0860 "(\"MESSAGE\" \"RFC822\" NIL NIL NIL \"7BIT\" 836 NIL (\"ATTACHMENT\" NIL) NIL)" 0861 "(\"MESSAGE\" \"RFC822\" NIL NIL NIL \"7BIT\" 50785 NIL (\"ATTACHMENT\" NIL) NIL) " 0862 "\"MIXED\" (\"BOUNDARY\" \"----=_NextPart_000_0077_01CBB179.57530990\") NIL NIL))\r\n") 0863 << QSharedPointer<AbstractResponse>( new Fetch( 6116, fetchData ) ); 0864 0865 msgList.clear(); 0866 bodyFldParam.clear(); 0867 bodyFldParam["CHARSET"] = "UTF-8"; 0868 msgList << QSharedPointer<AbstractMessage>(new TextMessage("text", "plain", bodyFldParam, {}, {}, "QUOTED-PRINTABLE", 388, {}, {}, {}, {}, {}, 12)); 0869 msgList << QSharedPointer<AbstractMessage>(new TextMessage("text", "html", bodyFldParam, {}, {}, "QUOTED-PRINTABLE", 1576, {}, {}, {}, {}, {}, 46)); 0870 bodyFldParam.clear(); 0871 bodyFldParam["BOUNDARY"] = "001a113fbc1264f3cd0551bfbcf8"; 0872 msgList = QList<QSharedPointer<AbstractMessage>>() << QSharedPointer<AbstractMessage>( 0873 new MultiMessage(msgList, "alternative", bodyFldParam, {}, {}, {}, {})); 0874 bodyFldParam.clear(); 0875 bodyFldParam["NAME"] = "icon.png"; 0876 bodyFldDsp = AbstractMessage::bodyFldDsp_t(); 0877 bodyFldDsp.first = "ATTACHMENT"; 0878 bodyFldDsp.second["FILENAME"] = "icon.png"; 0879 msgList << QSharedPointer<AbstractMessage>(new BasicMessage("image", "png", bodyFldParam, {}, {}, "BASE64", 7864, {}, bodyFldDsp, {}, {}, {})); 0880 bodyFldParam.clear(); 0881 bodyFldParam["BOUNDARY"] = "001a113fbc1264f3bd0551bfbcf7"; 0882 msgList = QList<QSharedPointer<AbstractMessage>>() << QSharedPointer<AbstractMessage>( 0883 new MultiMessage(msgList, "related", bodyFldParam, {}, {}, {}, {})); 0884 msgList << QSharedPointer<AbstractMessage>(new BasicMessage("message", "delivery-status", {}, {}, {}, "7BIT", 571, {}, {}, {}, {}, {})); 0885 bodyFldParam.clear(); 0886 bodyFldParam["x-trojita-original-mime-type"] = "message/rfc822"; 0887 msgList << QSharedPointer<AbstractMessage>( 0888 new BasicMessage("application", "x-trojita-malformed-part-from-imap-response", bodyFldParam, {}, {}, 0889 "QUOTED-PRINTABLE", 6109, {}, {}, {}, {}, {})); 0890 bodyFldParam.clear(); 0891 bodyFldParam["BOUNDARY"] = "001a113fbc1264e9640551bfbcf6"; 0892 bodyFldParam["REPORT-TYPE"] = "delivery-status"; 0893 fetchData.clear(); 0894 fetchData["BODYSTRUCTURE"] = QSharedPointer<AbstractData>( 0895 new MultiMessage(msgList, "report", bodyFldParam, {}, {}, {}, {})); 0896 QTest::newRow("2018-gmail-message-rfc822-not-list") 0897 << QByteArray("* 380 FETCH (BODYSTRUCTURE (" 0898 // A first part of multipart/report: a human-readable version. So far so good. 0899 "(" 0900 "(" 0901 "(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"UTF-8\") NIL NIL \"QUOTED-PRINTABLE\" 388 12 NIL NIL NIL)" 0902 "(\"TEXT\" \"HTML\" (\"CHARSET\" \"UTF-8\") NIL NIL \"QUOTED-PRINTABLE\" 1576 46 NIL NIL NIL)" 0903 " \"ALTERNATIVE\" (\"BOUNDARY\" \"001a113fbc1264f3cd0551bfbcf8\") NIL NIL" 0904 ")" 0905 "(\"IMAGE\" \"PNG\" (\"NAME\" \"icon.png\") \"\" NIL \"BASE64\" 7864 NIL (\"ATTACHMENT\" (\"FILENAME\" \"icon.png\")) NIL)" 0906 " \"RELATED\" (\"BOUNDARY\" \"001a113fbc1264f3bd0551bfbcf7\") NIL NIL" 0907 ")" 0908 // The second part: a machine-readable report. OK. 0909 "(\"MESSAGE\" \"DELIVERY-STATUS\" NIL NIL NIL \"7BIT\" 571 NIL NIL NIL)" 0910 // Third part: this has a bug, it says that it's a message/rfc822, but it is not because it has a NIL envelope and a NIL body. 0911 "(\"MESSAGE\" \"RFC822\" NIL NIL NIL \"QUOTED-PRINTABLE\" 6109 NIL NIL NIL)" 0912 // the top-level multipart/report 0913 " \"REPORT\" (\"BOUNDARY\" \"001a113fbc1264e9640551bfbcf6\" \"REPORT-TYPE\" \"delivery-status\") NIL NIL))\r\n") 0914 << QSharedPointer<AbstractResponse>(new Fetch(380, fetchData)); 0915 0916 fetchData.clear(); 0917 fetchData["UID"] = QSharedPointer<AbstractData>(new RespData<uint>(42463)); 0918 fetchData["FLAGS"] = QSharedPointer<AbstractData>(new RespData<QStringList>(QStringList() << QStringLiteral("\\Seen"))); 0919 fetchData["MODSEQ"] = QSharedPointer<AbstractData>(new RespData<quint64>(quint64(45278))); 0920 QTest::newRow("fetch-flags-modseq") 0921 << QByteArray("* 11235 FETCH (UID 42463 MODSEQ (45278) FLAGS (\\Seen))\r\n") 0922 << QSharedPointer<AbstractResponse>(new Fetch(11235, fetchData)); 0923 0924 fetchData.clear(); 0925 fetchData["FLAGS"] = QSharedPointer<AbstractData>( 0926 new RespData<QStringList>(QStringList() << QStringLiteral("\\Seen") << QStringLiteral("\\Answered"))); 0927 QTest::newRow("fetch-two-flags") 0928 << QByteArray("* 2 FETCH (FLAGS (\\Seen \\Answered))\r\n") 0929 << QSharedPointer<AbstractResponse>(new Fetch(2, fetchData)); 0930 0931 fetchData.clear(); 0932 fetchData["UID"] = QSharedPointer<AbstractData>(new RespData<uint>(81)); 0933 fetchData["BODY[HEADER.FIELDS (MESSAGE-ID IN-REPLY-TO REFERENCES DATE)]"] = QSharedPointer<AbstractData>( 0934 new RespData<QByteArray>("01234567\r\n")); 0935 QTest::newRow("fetch-header-fields-1") 0936 << QByteArray("* 81 FETCH (UID 81 BODY[HEADER.FIELDS (MESSAGE-ID In-REPLY-TO REFERENCES DATE)] {10}\r\n01234567\r\n)\r\n") 0937 << QSharedPointer<AbstractResponse>(new Fetch(81, fetchData)); 0938 0939 fetchData.clear(); 0940 fetchData["UID"] = QSharedPointer<AbstractData>(new RespData<uint>(81)); 0941 fetchData["BODY[HEADER.FIELDS (MESSAGE-ID)]"] = QSharedPointer<AbstractData>( 0942 new RespData<QByteArray>("01234567\r\n")); 0943 QTest::newRow("fetch-header-fields-2") 0944 << QByteArray("* 81 FETCH (UID 81 BODY[HEADER.FIELDS (MESSAgE-Id)]{10}\r\n01234567\r\n)\r\n") 0945 << QSharedPointer<AbstractResponse>(new Fetch(81, fetchData)); 0946 0947 QTest::newRow("id-nil") 0948 << QByteArray("* ID nIl\r\n") 0949 << QSharedPointer<AbstractResponse>(new Id(QMap<QByteArray,QByteArray>())); 0950 0951 QTest::newRow("id-empty") 0952 << QByteArray("* ID ()\r\n") 0953 << QSharedPointer<AbstractResponse>(new Id(QMap<QByteArray,QByteArray>())); 0954 0955 QMap<QByteArray,QByteArray> sampleId; 0956 sampleId["foo "] = "bar"; 0957 QTest::newRow("id-something") 0958 << QByteArray("* ID (\"foo \" \"bar\")\r\n") 0959 << QSharedPointer<AbstractResponse>(new Id(sampleId)); 0960 0961 sampleId.clear(); 0962 sampleId["v1"] = "333"; 0963 sampleId["v2"] = "666x333"; 0964 QTest::newRow("id-numeric-bits") 0965 << QByteArray("* ID (\"v1\" 333 \"v2\" 666x333)\r\n") 0966 << QSharedPointer<AbstractResponse>(new Id(sampleId)); 0967 0968 QTest::newRow("enabled-empty") 0969 << QByteArray("* ENABLED\r\n") 0970 << QSharedPointer<AbstractResponse>(new Enabled(QList<QByteArray>())); 0971 0972 QTest::newRow("enabled-empty-space") 0973 << QByteArray("* ENABLED \r\n") 0974 << QSharedPointer<AbstractResponse>(new Enabled(QList<QByteArray>())); 0975 0976 QTest::newRow("enabled-condstore") 0977 << QByteArray("* ENABLED CONDSToRE\r\n") 0978 << QSharedPointer<AbstractResponse>(new Enabled(QList<QByteArray>() << "CONDSToRE")); 0979 0980 QTest::newRow("enabled-condstore-qresync") 0981 << QByteArray("* ENABLED CONDSToRE qresync\r\n") 0982 << QSharedPointer<AbstractResponse>(new Enabled(QList<QByteArray>() << "CONDSToRE" << "qresync")); 0983 0984 QTest::newRow("vanished-one") 0985 << QByteArray("* VANIShED 1\r\n") 0986 << QSharedPointer<AbstractResponse>(new Vanished(Vanished::NOT_EARLIER, Imap::Uids() << 1)); 0987 0988 QTest::newRow("vanished-earlier-one") 0989 << QByteArray("* VANIShED (EARlIER) 1\r\n") 0990 << QSharedPointer<AbstractResponse>(new Vanished(Vanished::EARLIER, Imap::Uids() << 1)); 0991 0992 QTest::newRow("vanished-earlier-set") 0993 << QByteArray("* VANISHED (EARLIER) 300:303,405,411\r\n") 0994 << QSharedPointer<AbstractResponse>(new Vanished(Vanished::EARLIER, Imap::Uids() << 300 << 301 << 302 << 303 << 405 << 411)); 0995 0996 QTest::newRow("genurlauth-1") 0997 << QByteArray("* GENURLAUTH \"imap://joe@example.com/INBOX/;uid=20/;section=1.2;urlauth=submit+fred:internal:91354a473744909de610943775f92038\"\r\n") 0998 << QSharedPointer<AbstractResponse>(new GenUrlAuth(QStringLiteral("imap://joe@example.com/INBOX/;uid=20/;section=1.2;urlauth=submit+fred:internal:91354a473744909de610943775f92038"))); 0999 1000 QTest::newRow("genurlauth-2") 1001 << QByteArray("* GENURLAUTH meh\r\n") 1002 << QSharedPointer<AbstractResponse>(new GenUrlAuth(QStringLiteral("meh"))); 1003 1004 QSharedPointer<AbstractData> modSeqData(new RespData<quint64>(5875136264581852368ULL)); 1005 QTest::newRow("highestmodseq-64bit") 1006 << QByteArray("* OK [HIGHESTMODSEQ 5875136264581852368] x\r\n") 1007 << QSharedPointer<AbstractResponse>(new State("", OK, QStringLiteral("x"), HIGHESTMODSEQ, modSeqData)); 1008 1009 fetchData.clear(); 1010 fetchData["UID"] = QSharedPointer<AbstractData>(new RespData<uint>(123)); 1011 fetchData["MODSEQ"] = QSharedPointer<AbstractData>(new RespData<quint64>(5875136264581852368ULL)); 1012 QTest::newRow("fetch-highestmodseq-64bit") 1013 << QByteArray("* 33 FETCH (UID 123 MODSEQ (5875136264581852368))\r\n") 1014 << QSharedPointer<AbstractResponse>(new Fetch(33, fetchData)); 1015 1016 fetchData.clear(); 1017 from.clear(); 1018 sender = replyTo = to = cc = bcc = from; 1019 fetchData["ENVELOPE"] = QSharedPointer<AbstractData>(new RespData<Envelope>( 1020 Envelope(QDateTime(), QByteArray(), from, sender, replyTo, to, cc, bcc, QList<QByteArray>(), 1021 QByteArray("CAPunWhCDfYrqx_Px-072QAjZbog2DFz9O=48WnCxaxOov-VNVQ@mail.gmail.com")))); 1022 QTest::newRow("aox-messageid-spacing") 1023 << QByteArray("* 666 FETCH (ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL NIL {70}\r\n" 1024 "\n <CAPunWhCDfYrqx_Px-072QAjZbog2DFz9O=48WnCxaxOov-VNVQ@mail.gmail.com>))\r\n") 1025 << QSharedPointer<AbstractResponse>(new Fetch(666, fetchData)); 1026 } 1027 1028 /** @short Test that parsing this garbage doesn't result in an expceiton 1029 1030 In a erfect world with unlimited resources, it would be nice to verify the result of the parsing. However, I'm trying to feed 1031 real-world data to the test cases and this might mean having to construct tens of lines using code which is just tedious to create. 1032 This is better than nothing. 1033 */ 1034 void ImapParserParseTest::testParseFetchGarbageWithoutExceptions() 1035 { 1036 QFETCH(QByteArray, line); 1037 try { 1038 QSharedPointer<Imap::Responses::AbstractResponse> r = parser->parseUntagged(line); 1039 QVERIFY(r.dynamicCast<Imap::Responses::Fetch>()); 1040 } catch (const Imap::ParseError &err) { 1041 qDebug() << err.what(); 1042 QFAIL("Parsing resulted in an exception"); 1043 } 1044 } 1045 1046 void ImapParserParseTest::testParseFetchGarbageWithoutExceptions_data() 1047 { 1048 QTest::addColumn<QByteArray>("line"); 1049 1050 QTest::newRow("fetch-seznam.cz-quirk-minus-two-as-uint") 1051 << QByteArray("* 997 FETCH (UID 8636 ENVELOPE (NIL \"Merkantilismus\" ((\"\" NIL \"tony.szturc\" \"seznam.cz\")) " 1052 "((\"\" NIL \"tony.szturc\" \"seznam.cz\")) ((\"\" NIL \"tony.szturc\" \"seznam.cz\")) " 1053 "((\"\" NIL \"xxx\" \"seznam.cz\")) NIL NIL NIL \"\") INTERNALDATE \"15-Jan-2013 12:17:06 +0000\" " 1054 "BODYSTRUCTURE ((\"text\" \"plain\" (\"charset\" \"us- ascii\") NIL NIL \"7bit\" -2 1 NIL NIL NIL)" 1055 "(\"application\" \"msword\" (\"name\" " 1056 "\"=?utf-8?B?NC10cmFkaWNuaV9ob3Nwb2RhcnNrZV9teXNsZW5pLG5vdm92ZWtlX2Vrb25vbWlja2VfdGVvcmllLmRvY2==?=\") " 1057 "NIL NIL \"base64\" 51146 NIL NIL NIL)" 1058 "(\"application\" \"msword\" (\"name\" \"=?utf-8?B?NS1ob3Nwb2RhcnNreXZ5dm9qLmRvY2==?=\") NIL NIL " 1059 "\"base64\" 205984 NIL NIL NIL)" 1060 "(\"application\" \"vnd.ms-powerpoint\" (\"name\" \"=?utf-8?B?Mi5faG9zcG9kYXJza3lfdnl2b2pfY2Vza3ljaF96ZW1pLnBwdH==?=\") " 1061 "NIL NIL \"base64\" 3986596 NIL NIL NIL) \"mixed\" NIL NIL NIL) RFC822.SIZE 4245505)\r\n"); 1062 1063 // Test data from http://thread.gmane.org/gmane.mail.squirrelmail.user/26433 1064 QTest::newRow("random-squirrelmail-report") 1065 << QByteArray("* 1 FETCH (BODYSTRUCTURE " 1066 "(((\"text\" \"plain\" (\"charset\" \"US-ASCII\") NIL NIL \"7bit\" 2 1 NIL NIL " 1067 "NIL)(\"text\" \"html\" (\"charset\" \"US-ASCII\") NIL NIL \"quoted-printable\" 486 " 1068 "10 NIL NIL NIL) \"alternative\" (\"boundary\" " 1069 "\"-----------------------------1131387468\") NIL NIL)(\"message\" \"rfc822\" NIL " 1070 "NIL NIL NIL 191761 (\"Thu, 3 Nov 2005 14:19:49 EST\" \"Fwd: Fw: Fw:\" ((NIL " 1071 "NIL \"Ernestgerp12\" \"aol.com\")) NIL NIL ((NIL NIL \"BagLady1933\" " 1072 "\"aol.com\")(NIL NIL \"BOBPEGRUKS\" \"cs.com\")(NIL NIL \"bren804\" " 1073 "\"webtv.net\")(NIL NIL \"khgsk\" \"comcast.net\")(NIL NIL \"KOKOGOSIK\" " 1074 "\"COMCAST.NET\")(NIL NIL \"MAG2215\" \"aol.com\")(NIL NIL \"Mamabenc\" " 1075 "\"aol.com\")(NIL NIL \"Ifix2th\" \"aol.com\")(NIL NIL \"Ooosal\" \"aol.com\")(NIL " 1076 "NIL \"rtalalaj\" \"comcast.net\")) NIL NIL NIL \"e3.1fdeccbc.309bbcd5 <at> aol.com\") " 1077 "(((\"text\" \"plain\" (\"charset\" \"US-ASCII\") NIL NIL \"7bit\" 2 1 NIL NIL " 1078 "NIL)(\"text\" \"html\" (\"charset\" \"US-ASCII\") NIL NIL \"quoted-printable\" 486 " 1079 "10 NIL NIL NIL) \"alternative\" (\"boundary\" " 1080 "\"-----------------------------1131045588\") NIL NIL)(\"message\" \"rfc822\" NIL " 1081 "NIL NIL NIL 190153 NIL (((\"text\" \"plain\" (\"charset\" \"iso-8859-1\") NIL NIL " 1082 "\"quoted-printable\" 6584 293 NIL NIL NIL)(\"text\" \"html\" (\"charset\" " 1083 "\"iso-8859-1\") NIL NIL \"quoted-printable\" 61190 948 NIL NIL NIL) " 1084 "\"alternative\" (\"boundary\" \"----=_NextPart_001_004C_01C5E044.F95592A0\") NIL " 1085 "NIL)(\"image\" \"gif\" (\"name\" \"ATT0000712221112121.gif\") NIL NIL \"base64\" " 1086 "68496 NIL NIL NIL)(\"image\" \"gif\" (\"name\" \"ATT0001023332223232.gif\") NIL " 1087 "NIL \"base64\" 20038 NIL NIL NIL)(\"image\" \"gif\" (\"name\" " 1088 "\"image001334343.gif\") NIL NIL \"base64\" 10834 NIL NIL NIL)(\"image\" \"gif\" " 1089 "(\"name\" \"ATT0001646665545455.gif\") NIL NIL \"base64\" 7146 NIL NIL " 1090 "NIL)(\"audio\" \"mid\" (\"name\" \"ATT0001951116651516.mid\") NIL NIL \"base64\" " 1091 "12938 NIL NIL NIL) \"related\" (\"boundary\" " 1092 "\"----=_NextPart_000_004B_01C5E044.F95592A0\" \"type\" " 1093 "\"multipart/alternative\") NIL NIL) NIL NIL (\"INLINE\" NIL) NIL) \"mixed\" " 1094 "(\"boundary\" \"part2_d7.319e0427.309bbcd5_boundary\") NIL NIL) NIL NIL " 1095 "(\"INLINE\" NIL) NIL) \"mixed\" (\"boundary\" " 1096 "\"part1_d7.319e0427.30a0f44c_boundary\") NIL NIL)" 1097 " )\r\n"); 1098 1099 QTest::newRow("davmail-by-ashp") 1100 << QByteArray("* 1125 FETCH (BODYSTRUCTURE ((\"TEXT\" \"HTML\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"QUOTED-PRINTABLE\" 562 7)" 1101 "(\"APPLICATION\" \"OCTET-STREAM\" (\"NAME\" \"zzz.xml\") NIL " 1102 "\"ZZZ.XML\" \"BASE64\" NIL NIL) \"MIXED\"))\r\n"); 1103 } 1104 1105 void ImapParserParseTest::benchmark() 1106 { 1107 QByteArray line1 = "* 1 FETCH (BODYSTRUCTURE ((\"text\" \"plain\" " 1108 "(\"charset\" \"US-ASCII\" \"delsp\" \"yes\" \"format\" \"flowed\") " 1109 "NIL NIL \"7bit\" 990 27 NIL NIL NIL)" 1110 "(\"application\" \"pgp-signature\" (\"x-mac-type\" \"70674453\" \"name\" \"PGP.sig\") NIL " 1111 "\"This is a digitally signed message part\" \"7bit\" 193 NIL (\"inline\" " 1112 "(\"filename\" \"PGP.sig\")) NIL) \"signed\" (\"protocol\" " 1113 "\"application/pgp-signature\" \"micalg\" \"pgp-sha1\" \"boundary\" " 1114 "\"Apple-Mail-10--856231115\") NIL NIL))\r\n"; 1115 QByteArray line2 = "* 13 FETCH (ENVELOPE (NIL " 1116 "\"IMAP4rev1 WG mtg summary and minutes\" " 1117 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 1118 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 1119 "((\"Terry Gray\" NIL \"gray\" \"cac.washington.edu\")) " 1120 "((NIL NIL \"imap\" \"cac.washington.edu\")) " 1121 "((NIL NIL \"minutes\" \"CNRI.Reston.VA.US\") " 1122 "(\"John Klensin\" NIL \"KLENSIN\" \"MIT.EDU\")) NIL NIL " 1123 "\"<B27397-0100000@cac.washington.edu>\"))\r\n"; 1124 QByteArray line3 = "* 123 FETCH (InternalDate \"6-Apr-1981 12:03:32 -0630\")\r\n"; 1125 1126 QBENCHMARK { 1127 parser->processLine( line1 ); 1128 parser->processLine( line2 ); 1129 parser->processLine( line3 ); 1130 1131 while (parser->hasResponse()) 1132 parser->getResponse(); 1133 } 1134 } 1135 1136 void ImapParserParseTest::benchmarkInitialChat() 1137 { 1138 QByteArray line4 = "* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE STARTTLS AUTH=PLAIN] Dovecot ready.\r\n"; 1139 QByteArray line5 = "* CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE STARTTLS AUTH=PLAIN\r\n"; 1140 QByteArray line6 = "1 OK Pre-login capabilities listed, post-login capabilities have more.\r\n"; 1141 QByteArray line7 = "* CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY " 1142 "THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 " 1143 "CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE\r\n"; 1144 QByteArray line8 = "2 OK Logged in\r\n"; 1145 QByteArray line9 = "3 OK Capability completed.\r\n"; 1146 QByteArray line10 = "* ENABLED QRESYNC\r\n"; 1147 QByteArray line11 = "4 OK Enabled.\r\n"; 1148 QByteArray line12 = "* NAMESPACE ((\"\" \".\")) NIL NIL\r\n"; 1149 QByteArray line13 = "5 OK Namespace completed.\r\n"; 1150 1151 QBENCHMARK { 1152 parser->processLine(line4); 1153 parser->processLine(line5); 1154 parser->processLine(line6); 1155 parser->processLine(line7); 1156 parser->processLine(line8); 1157 parser->processLine(line9); 1158 parser->processLine(line10); 1159 parser->processLine(line11); 1160 parser->processLine(line12); 1161 parser->processLine(line13); 1162 while (parser->hasResponse()) 1163 parser->getResponse(); 1164 } 1165 } 1166 1167 void ImapParserParseTest::testSequences() 1168 { 1169 QFETCH( Imap::Sequence, sequence ); 1170 QFETCH( QByteArray, muster ); 1171 QCOMPARE( sequence.toByteArray(), muster ); 1172 } 1173 1174 void ImapParserParseTest::testSequences_data() 1175 { 1176 QTest::addColumn<Imap::Sequence>("sequence"); 1177 QTest::addColumn<QByteArray>("muster"); 1178 1179 QTest::newRow("sequence-one") << 1180 Imap::Sequence( 33 ) << QByteArray("33"); 1181 1182 QTest::newRow("sequence-unlimited") << 1183 Imap::Sequence::startingAt(666) << QByteArray("666:*"); 1184 1185 QTest::newRow("sequence-range") << 1186 Imap::Sequence( 333, 666 ) << QByteArray("333:666"); 1187 1188 QTest::newRow("sequence-distinct") << 1189 Imap::Sequence( 20 ).add( 10 ).add( 30 ) << QByteArray("10,20,30"); 1190 1191 QTest::newRow("sequence-collapsed-2") << 1192 Imap::Sequence( 10 ).add( 11 ) << QByteArray("10:11"); 1193 1194 QTest::newRow("sequence-collapsed-3") << 1195 Imap::Sequence( 10 ).add( 11 ).add( 12 ) << QByteArray("10:12"); 1196 1197 QTest::newRow("sequence-head-and-collapsed") << 1198 Imap::Sequence( 3 ).add( 31 ).add( 32 ).add( 33 ) << QByteArray("3,31:33"); 1199 1200 QTest::newRow("sequence-collapsed-and-tail") << 1201 Imap::Sequence( 666 ).add( 31 ).add( 32 ).add( 33 ) << QByteArray("31:33,666"); 1202 1203 QTest::newRow("sequence-head-collapsed-tail") << 1204 Imap::Sequence( 666 ).add( 31 ).add( 32 ).add( 1 ).add( 33 ) << QByteArray("1,31:33,666"); 1205 1206 QTest::newRow("sequence-same") << 1207 Imap::Sequence( 2 ).add( 2 ) << QByteArray("2"); 1208 1209 QTest::newRow("sequence-multiple-consequent") << 1210 Imap::Sequence( 2 ).add( 3 ).add( 4 ).add( 6 ).add( 7 ) << QByteArray("2:4,6:7"); 1211 1212 QTest::newRow("sequence-complex") << 1213 Imap::Sequence( 2 ).add( 3 ).add( 4 ).add( 6 ).add( 7 ).add( 1 ) 1214 .add( 100 ).add( 101 ).add( 102 ).add( 99 ).add( 666 ).add( 333 ).add( 666 ) << 1215 QByteArray("1:4,6:7,99:102,333,666"); 1216 1217 QTest::newRow("sequence-from-list-1") << 1218 Imap::Sequence::fromVector(Imap::Uids() << 2 << 3 << 4 << 6 << 7 << 1 << 100 << 101 << 102 << 99 << 666 << 333 << 666) << 1219 QByteArray("1:4,6:7,99:102,333,666"); 1220 } 1221 1222 /** @short Test responses which fail to parse */ 1223 void ImapParserParseTest::testThrow() 1224 { 1225 QFETCH(QByteArray, line); 1226 QFETCH(QString, exceptionClass); 1227 QFETCH(QString, error); 1228 1229 try { 1230 QSharedPointer<Imap::Responses::AbstractResponse> ptr = parser->parseUntagged(line); 1231 QVERIFY2(!ptr, "should have thrown"); 1232 } catch (Imap::ImapException &e) { 1233 QCOMPARE(QString::fromUtf8(e.exceptionClass().c_str()), exceptionClass); 1234 QCOMPARE(QString::fromUtf8(e.msg().c_str()), error); 1235 } 1236 } 1237 1238 /** @short Test data for testThrow() */ 1239 void ImapParserParseTest::testThrow_data() 1240 { 1241 QTest::addColumn<QByteArray>("line"); 1242 QTest::addColumn<QString>("exceptionClass"); 1243 QTest::addColumn<QString>("error"); 1244 1245 QTest::newRow("garbage") 1246 << QByteArray("blah") 1247 << QStringLiteral("UnrecognizedResponseKind") 1248 << QStringLiteral("AH"); // uppercase of "blah" after cutting the two leading characters 1249 1250 QTest::newRow("garbage-well-formed") 1251 << QByteArray("* blah\r\n") 1252 << QStringLiteral("UnrecognizedResponseKind") 1253 << QStringLiteral("BLAH"); 1254 1255 QTest::newRow("expunge-number-at-the-end") 1256 << QByteArray("* expunge 666\r\n") << QStringLiteral("UnexpectedHere") << QStringLiteral("Malformed response: the number should go first"); 1257 1258 QTest::newRow("thread-non-numbers") 1259 << QByteArray("* THREAD (ahoj)\r\n") << QStringLiteral("UnexpectedHere") << QStringLiteral("THREAD response: cannot parse \"ahoj\" as an unsigned integer"); 1260 } 1261 1262 QTEST_GUILESS_MAIN( ImapParserParseTest ) 1263 1264 namespace QTest { 1265 1266 template<> char * toString( const Imap::Responses::AbstractResponse& resp ) 1267 { 1268 QByteArray buf; 1269 QTextStream stream( &buf ); 1270 stream << resp; 1271 stream.flush(); 1272 return qstrdup( buf.data() ); 1273 } 1274 1275 }