File indexing completed on 2024-05-12 05:17:26

0001 /**
0002   * This file is part of the KDE project
0003   * Copyright (C) 2009 Kevin Ottens <ervin@kde.org>
0004   * Copyright (C) 2009 Andras Mantia <amantia@kde.org>
0005   *
0006   * This library is free software; you can redistribute it and/or
0007   * modify it under the terms of the GNU Library General Public
0008   * License as published by the Free Software Foundation; either
0009   * version 2 of the License, or (at your option) any later version.
0010   *
0011   * This library is distributed in the hope that it will be useful,
0012   * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014   * Library General Public License for more details.
0015   *
0016   * You should have received a copy of the GNU Library General Public License
0017   * along with this library; see the file COPYING.LIB.  If not, write to
0018   * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019   * Boston, MA 02110-1301, USA.
0020   */
0021 
0022 #include <qdebug.h>
0023 #include <qtcpsocket.h>
0024 #include <QCoreApplication>
0025 #include <qsignalspy.h>
0026 
0027 #include "acl.h"
0028 #include "session.h"
0029 #include "appendjob.h"
0030 #include "capabilitiesjob.h"
0031 #include "fetchjob.h"
0032 #include "listjob.h"
0033 #include "loginjob.h"
0034 #include "logoutjob.h"
0035 #include "selectjob.h"
0036 #include "closejob.h"
0037 #include "expungejob.h"
0038 #include "createjob.h"
0039 #include "deletejob.h"
0040 #include "namespacejob.h"
0041 #include "subscribejob.h"
0042 #include "unsubscribejob.h"
0043 #include "renamejob.h"
0044 #include "storejob.h"
0045 #include "setacljob.h"
0046 #include "getacljob.h"
0047 #include "deleteacljob.h"
0048 #include "myrightsjob.h"
0049 #include "listrightsjob.h"
0050 #include "setmetadatajob.h"
0051 #include "getmetadatajob.h"
0052 
0053 using namespace KIMAP2;
0054 
0055 void dumpContentHelper(KMime::Content *part, const QString &partId = QString())
0056 {
0057     if (partId.isEmpty()) {
0058         qDebug() << "** Message root **";
0059     } else {
0060         qDebug() << "** Part" << partId << "**";
0061     }
0062 
0063     qDebug() << part->head();
0064 
0065     KMime::Content::List children = part->contents();
0066     for (int i = 0; i < children.size(); i++) {
0067         QString newId = partId;
0068         if (!newId.isEmpty()) {
0069             newId += QLatin1String(".");
0070         }
0071         newId += QString::number(i + 1);
0072         dumpContentHelper(children[i], newId);
0073     }
0074 }
0075 
0076 void listFolders(Session *session, bool includeUnsubscribed = false, const QString &nameFilter = QLatin1String(""))
0077 {
0078     ListJob *list = new ListJob(session);
0079     list->setOption(KIMAP2::ListJob::IncludeUnsubscribed);
0080     list->exec();
0081     Q_ASSERT_X(list->error() == 0, "ListJob", list->errorString().toLocal8Bit().constData());
0082     int count = list->mailBoxes().size();
0083     for (int i = 0; i < count; ++i) {
0084         MailBoxDescriptor descriptor = list->mailBoxes()[i];
0085         if (descriptor.name.endsWith(nameFilter)) {
0086             qDebug() << descriptor.separator << descriptor.name;
0087         }
0088     }
0089 
0090 }
0091 
0092 void testMetaData(Session *session)
0093 {
0094     qDebug() << "TESTING: METADATA commands";
0095     CreateJob *create = new CreateJob(session);
0096     create->setMailBox(QStringLiteral("INBOX/TestFolder"));
0097     create->exec();
0098 
0099     SetMetaDataJob *setmetadata = new SetMetaDataJob(session);
0100     setmetadata->setMailBox(QStringLiteral("INBOX/TestFolder"));
0101     setmetadata->setServerCapability(SetMetaDataJob::Annotatemore);
0102     setmetadata->setEntry("/comment");
0103     setmetadata->addMetaData("value.priv", "My new comment");
0104     setmetadata->exec();
0105 
0106     setmetadata = new SetMetaDataJob(session);
0107     setmetadata->setMailBox(QStringLiteral("INBOX/TestFolder"));
0108     setmetadata->setServerCapability(SetMetaDataJob::Annotatemore);
0109     setmetadata->setEntry("/check");
0110     setmetadata->addMetaData("value.priv", "true");
0111     setmetadata->exec();
0112 
0113     GetMetaDataJob *getmetadata = new GetMetaDataJob(session);
0114     getmetadata->setMailBox(QStringLiteral("INBOX/TestFolder"));
0115     getmetadata->setServerCapability(SetMetaDataJob::Annotatemore);
0116     getmetadata->addEntry("/*", "value.priv");
0117     getmetadata->exec();
0118     Q_ASSERT_X(getmetadata->metaData(QLatin1String("INBOX/TestFolder"), "/check", "value.priv") == "true", "",  "/check metadata should be true");
0119     Q_ASSERT_X(getmetadata->metaData(QLatin1String("INBOX/TestFolder"), "/comment", "value.priv") == "My new comment", "",  "/check metadata should be My new comment");
0120 
0121     //cleanup
0122     DeleteJob *deletejob = new DeleteJob(session);
0123     deletejob->setMailBox(QLatin1String("INBOX/TestFolder"));
0124     deletejob->exec();
0125 }
0126 
0127 void testAcl(Session *session, const QString &user)
0128 {
0129     qDebug() << "TESTING: ACL commands";
0130     CreateJob *create = new CreateJob(session);
0131     create->setMailBox(QLatin1String("INBOX/TestFolder"));
0132     create->exec();
0133 
0134     ListRightsJob *listRights = new ListRightsJob(session);
0135     listRights->setMailBox(QLatin1String("INBOX/TestFolder"));
0136     listRights->setIdentifier(user.toLatin1());
0137     listRights->exec();
0138     qDebug() << "Default rights on INBOX/TestFolder: " << Acl::rightsToString(listRights->defaultRights());
0139     QList<Acl::Rights> possible = listRights->possibleRights();
0140     QStringList strList;
0141     Q_FOREACH (Acl::Rights r, possible) {
0142         strList << QString::fromLatin1(Acl::rightsToString(r));
0143     }
0144     qDebug() << "Possible rights on INBOX/TestFolder: " << strList;
0145 
0146     MyRightsJob *myRights = new MyRightsJob(session);
0147     myRights->setMailBox(QLatin1String("INBOX/TestFolder"));
0148     myRights->exec();
0149 
0150     Acl::Rights mine = myRights->rights();
0151     qDebug() << "My rights on INBOX/TestFolder: " << Acl::rightsToString(mine);
0152     qDebug() << "Reading INBOX/TestFolder is possible: " << myRights->hasRightEnabled(Acl::Read);
0153     Q_ASSERT_X(myRights->hasRightEnabled(Acl::Read), "Reading INBOX is NOT possible", "");
0154 
0155     GetAclJob *getAcl = new GetAclJob(session);
0156     getAcl->setMailBox(QLatin1String("INBOX/TestFolder"));
0157     getAcl->exec();
0158     qDebug() << "Anyone rights on INBOX/TestFolder: " << getAcl->rights("anyone");
0159     Acl::Rights users = getAcl->rights(user.toLatin1());
0160     qDebug() << user << " rights on INBOX/TestFolder: " << Acl::rightsToString(users);
0161     Q_ASSERT_X(mine == users, "GETACL returns different rights for the same user", "");
0162 
0163     qDebug() << "Removing Delete right ";
0164     mine = Acl::Delete;
0165     SetAclJob *setAcl = new SetAclJob(session);
0166     setAcl->setMailBox(QLatin1String("INBOX/TestFolder"));
0167     setAcl->setIdentifier(user.toLatin1());
0168     setAcl->setRights(AclJobBase::Remove, mine);
0169     setAcl->exec();
0170 
0171     getAcl = new GetAclJob(session);
0172     getAcl->setMailBox(QLatin1String("INBOX/TestFolder"));
0173     getAcl->exec();
0174     users = getAcl->rights(user.toLatin1());
0175     qDebug() << user << " rights on INBOX/TestFolder: " << Acl::rightsToString(users);
0176 
0177     qDebug() << "Adding back Delete right ";
0178     mine = Acl::Delete;
0179     setAcl = new SetAclJob(session);
0180     setAcl->setMailBox(QLatin1String("INBOX/TestFolder"));
0181     setAcl->setIdentifier(user.toLatin1());
0182     setAcl->setRights(AclJobBase::Add, mine);
0183     setAcl->exec();
0184 
0185     getAcl = new GetAclJob(session);
0186     getAcl->setMailBox(QLatin1String("INBOX/TestFolder"));
0187     getAcl->exec();
0188     users = getAcl->rights(user.toLatin1());
0189     qDebug() << user << " rights on INBOX/TestFolder: " << Acl::rightsToString(users);
0190 
0191     //cleanup
0192     DeleteJob *deletejob = new DeleteJob(session);
0193     deletejob->setMailBox(QLatin1String("INBOX/TestFolder"));
0194     deletejob->exec();
0195 }
0196 
0197 void testAppendAndStore(Session *session)
0198 {
0199     qDebug() << "TESTING: APPEND and STORE";
0200     //setup
0201     CreateJob *create = new CreateJob(session);
0202     create->setMailBox(QLatin1String("INBOX/TestFolder"));
0203     create->exec();
0204 
0205     QByteArray testMailContent =
0206         "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)\r\n"
0207         "From: Fred Foobar <foobar@Blurdybloop.COM>\r\n"
0208         "Subject: afternoon meeting\r\n"
0209         "To: mooch@owatagu.siam.edu\r\n"
0210         "Message-Id: <B27397-0100000@Blurdybloop.COM>\r\n"
0211         "MIME-Version: 1.0\r\n"
0212         "Content-Type: TEXT/PLAIN; CHARSET=US-ASCII\r\n"
0213         "\r\n"
0214         "Hello Joe, do you think we can meet at 3:30 tomorrow?\r\n";
0215 
0216     qDebug() << "Append a message in INBOX/TestFolder...";
0217     AppendJob *append = new AppendJob(session);
0218     append->setMailBox(QLatin1String("INBOX/TestFolder"));
0219     append->setContent(testMailContent);
0220     append->exec();
0221     Q_ASSERT_X(append->error() == 0, "AppendJob", append->errorString().toLocal8Bit().constData());
0222 
0223     qDebug() << "Read the message back and compare...";
0224     SelectJob *select = new SelectJob(session);
0225     select->setMailBox(QLatin1String("INBOX/TestFolder"));
0226     select->exec();
0227 
0228     FetchJob *fetch = new FetchJob(session);
0229     FetchJob::FetchScope scope;
0230     fetch->setSequenceSet(ImapSet(1));
0231     scope.parts.clear();
0232     scope.mode = FetchJob::FetchScope::Content;
0233     fetch->setScope(scope);
0234     fetch->exec();
0235     MessagePtr message = fetch->messages()[1];
0236     Q_ASSERT_X(fetch->error() == 0, "FetchJob", fetch->errorString().toLocal8Bit().constData());
0237     testMailContent.replace("\r\n", "\n");
0238     Q_ASSERT_X(testMailContent == message->head() + "\n" + message->body(),
0239                "Message differs from reference", QByteArray(message->head() + "\n" + message->body()).constData());
0240 
0241     fetch = new FetchJob(session);
0242     fetch->setSequenceSet(ImapSet(1));
0243     scope.parts.clear();
0244     scope.mode = FetchJob::FetchScope::Flags;
0245     fetch->setScope(scope);
0246     fetch->exec();
0247     MessageFlags expectedFlags = fetch->flags()[1];
0248     qDebug() << "Read the message flags:" << expectedFlags;
0249 
0250     qDebug() << "Add the \\Deleted flag...";
0251     expectedFlags << "\\Deleted";
0252     qSort(expectedFlags);
0253     StoreJob *store = new StoreJob(session);
0254     store->setSequenceSet(ImapSet(1));
0255     store->setMode(StoreJob::AppendFlags);
0256     store->setFlags(QList<QByteArray>() << "\\Deleted");
0257     store->exec();
0258     Q_ASSERT_X(store->error() == 0, "StoreJob", store->errorString().toLocal8Bit().constData());
0259 
0260     QList<QByteArray> resultingFlags = store->resultingFlags()[1];
0261     qSort(resultingFlags);
0262     if (expectedFlags != resultingFlags) {
0263         qDebug() << resultingFlags;
0264     }
0265     Q_ASSERT(expectedFlags == resultingFlags);
0266 
0267     select = new SelectJob(session);
0268     select->setMailBox(QStringLiteral("INBOX"));
0269     select->exec();
0270 
0271     //cleanup
0272     DeleteJob *deletejob = new DeleteJob(session);
0273     deletejob->setMailBox(QStringLiteral("INBOX/TestFolder"));
0274     deletejob->exec();
0275     deletejob = new DeleteJob(session);
0276     deletejob->setMailBox(QStringLiteral("INBOX/RenamedTestFolder"));
0277     deletejob->exec();
0278 }
0279 
0280 void testRename(Session *session)
0281 {
0282     qDebug() << "TESTING: RENAME";
0283     //setup
0284     CreateJob *create = new CreateJob(session);
0285     create->setMailBox(QLatin1String("INBOX/TestFolder"));
0286     create->exec();
0287 
0288     qDebug() << "Listing mailboxes with name TestFolder:";
0289     listFolders(session, true, QLatin1String("TestFolder"));
0290 
0291     //actual tests
0292     qDebug() << "Renaming to RenamedTestFolder";
0293     RenameJob *rename = new RenameJob(session);
0294     rename->setSourceMailBox(QLatin1String("INBOX/TestFolder"));
0295     rename->setDestinationMailBox(QLatin1String("INBOX/RenamedTestFolder"));
0296     rename->exec();
0297 
0298     qDebug() << "Listing mailboxes with name TestFolder:";
0299     listFolders(session, true, QLatin1String("TestFolder"));
0300     qDebug() << "Listing mailboxes with name RenamedTestFolder:";
0301     listFolders(session, true, QLatin1String("RenamedTestFolder"));
0302 
0303     //cleanup
0304     DeleteJob *deletejob = new DeleteJob(session);
0305     deletejob->setMailBox(QLatin1String("INBOX/TestFolder"));
0306     deletejob->exec();
0307     deletejob = new DeleteJob(session);
0308     deletejob->setMailBox(QLatin1String("INBOX/RenamedTestFolder"));
0309     deletejob->exec();
0310 }
0311 
0312 void testSubscribe(Session *session)
0313 {
0314     qDebug() << "TESTING: SUBSCRIBE/UNSUBSCRIBE";
0315     //setup
0316     CreateJob *create = new CreateJob(session);
0317     create->setMailBox(QLatin1String("INBOX/TestFolder"));
0318     create->exec();
0319 
0320     qDebug() << "Listing  subscribed mailboxes with name TestFolder:";
0321     listFolders(session, false, QLatin1String("TestFolder"));
0322 
0323     //actual tests
0324     qDebug() << "Subscribing to INBOX/TestFolder";
0325     SubscribeJob *subscribe = new SubscribeJob(session);
0326     subscribe->setMailBox(QLatin1String("INBOX/TestFolder"));
0327     subscribe->exec();
0328 
0329     qDebug() << "Listing  subscribed mailboxes with name TestFolder:";
0330     listFolders(session, false, QLatin1String("TestFolder"));
0331 
0332     qDebug() << "Unsubscribing from INBOX/TestFolder";
0333     UnsubscribeJob *unsubscribe = new UnsubscribeJob(session);
0334     unsubscribe->setMailBox(QLatin1String("INBOX/TestFolder"));
0335     unsubscribe->exec();
0336 
0337     qDebug() << "Listing  subscribed mailboxes with name TestFolder:";
0338     listFolders(session, false, QLatin1String("TestFolder"));
0339 
0340     //cleanup
0341     DeleteJob *deletejob = new DeleteJob(session);
0342     deletejob->setMailBox(QLatin1String("INBOX/TestFolder"));
0343     deletejob->exec();
0344 }
0345 
0346 void testDelete(Session *session)
0347 {
0348     qDebug() << "TESTING: DELETE";
0349     qDebug() << "Creating INBOX/TestFolder:";
0350     CreateJob *create = new CreateJob(session);
0351     create->setMailBox(QLatin1String("INBOX/TestFolder"));
0352     create->exec();
0353 
0354     qDebug() << "Listing  with name TestFolder  before DELETE:";
0355     listFolders(session, true, QLatin1String("TestFolder"));
0356 
0357     qDebug() << "Deleting INBOX/TestFolder";
0358     DeleteJob *deletejob = new DeleteJob(session);
0359     deletejob->setMailBox(QLatin1String("INBOX/TestFolder"));
0360     deletejob->exec();
0361 
0362     qDebug() << "Listing with name TestFolder after DELETE:";
0363     listFolders(session, true, QLatin1String("TestFolder"));
0364 }
0365 
0366 int main(int argc, char **argv)
0367 {
0368     QCoreApplication::setApplicationName(QStringLiteral("TestImapServer"));
0369 
0370     if (argc < 4) {
0371         qCritical() << "Not enough parameters, expecting: <server> <user> <password>";
0372     }
0373 
0374     QString server = QString::fromLocal8Bit(argv[1]);
0375     int port = 143;
0376     if (server.count(QLatin1Char(':')) == 1) {
0377         port = server.split(QLatin1Char(':')).last().toInt();
0378         server = server.split(QLatin1Char(':')).first();
0379     }
0380     QString user = QString::fromLocal8Bit(argv[2]);
0381     QString password = QString::fromLocal8Bit(argv[3]);
0382 
0383     qDebug() << "Querying:" << server << port << user << password;
0384     qDebug();
0385 
0386     QCoreApplication app(argc, argv);
0387     Session session(server, port);
0388 
0389     QObject::connect(&session, &KIMAP2::Session::sslErrors, [&session](const QList<QSslError> &errors) {
0390         qWarning() << "Got ssl error: " << errors;
0391         session.ignoreErrors(errors);
0392     });
0393 
0394     qDebug() << "Logging in...";
0395     LoginJob *login = new LoginJob(&session);
0396     //login->setEncryptionMode( LoginJob::TlsV1 );
0397     //login->setAuthenticationMode( LoginJob::Plain );
0398     login->setUserName(user);
0399     login->setPassword(password);
0400     login->exec();
0401     qDebug();
0402 
0403     /*if (login->encryptionMode() == LoginJob::Unencrypted)
0404     {
0405       qDebug() << "Encrypted login not possible, try to log in without encryption";
0406       login = new LoginJob( &session );
0407       login->setUserName( user );
0408       login->setPassword( password );
0409       login->exec();
0410       Q_ASSERT_X( login->error() == 0, "LoginJob", login->errorString().toLocal8Bit().constData() );
0411       Q_ASSERT( session.state() == Session::Authenticated );
0412       qDebug();
0413 
0414     }*/
0415 
0416     qDebug() << "Server greeting:" << session.serverGreeting();
0417 
0418     qDebug() << "Asking for capabilities:";
0419     CapabilitiesJob *capabilities = new CapabilitiesJob(&session);
0420     capabilities->exec();
0421     Q_ASSERT_X(capabilities->error() == 0, "CapabilitiesJob", capabilities->errorString().toLocal8Bit().constData());
0422     Q_ASSERT(session.state() == Session::Authenticated);
0423     qDebug() << capabilities->capabilities();
0424     qDebug();
0425 
0426     qDebug() << "Asking for namespaces:";
0427     NamespaceJob *namespaces = new NamespaceJob(&session);
0428     namespaces->exec();
0429     Q_ASSERT_X(namespaces->error() == 0, "CapabilitiesJob", namespaces->errorString().toLocal8Bit().constData());
0430     Q_ASSERT(session.state() == Session::Authenticated);
0431 
0432     qDebug() << "Contains empty namespace:" << namespaces->containsEmptyNamespace();
0433 
0434     qDebug() << "Personal:";
0435     foreach (MailBoxDescriptor ns, namespaces->personalNamespaces()) {
0436         qDebug() << ns.separator << ns.name;
0437     }
0438 
0439     qDebug() << "User:    ";
0440     foreach (MailBoxDescriptor ns, namespaces->userNamespaces()) {
0441         qDebug() << ns.separator << ns.name;
0442     }
0443 
0444     qDebug() << "Shared:  ";
0445     foreach (MailBoxDescriptor ns, namespaces->sharedNamespaces()) {
0446         qDebug() << ns.separator << ns.name;
0447     }
0448     qDebug();
0449 
0450     qDebug() << "Listing mailboxes:";
0451     listFolders(&session);
0452     Q_ASSERT(session.state() == Session::Authenticated);
0453 
0454     qDebug() << "Selecting INBOX:";
0455     SelectJob *select = new SelectJob(&session);
0456     select->setMailBox(QLatin1String("INBOX"));
0457     select->exec();
0458     Q_ASSERT_X(select->error() == 0, "SelectJob", select->errorString().toLocal8Bit().constData());
0459     Q_ASSERT(session.state() == Session::Selected);
0460     qDebug() << "Flags:" << select->flags();
0461     qDebug() << "Permanent flags:" << select->permanentFlags();
0462     qDebug() << "Total Number of Messages:" << select->messageCount();
0463     qDebug() << "Number of recent Messages:" << select->recentCount();
0464     qDebug() << "First Unseen Message Index:" << select->firstUnseenIndex();
0465     qDebug() << "UID validity:" << select->uidValidity();
0466     qDebug() << "Next UID:" << select->nextUid();
0467     qDebug();
0468 
0469     qDebug() << "Fetching first 3 messages headers:";
0470     FetchJob *fetch = new FetchJob(&session);
0471     FetchJob::FetchScope scope;
0472     fetch->setSequenceSet(ImapSet(1, 3));
0473     scope.parts.clear();
0474     scope.mode = FetchJob::FetchScope::Headers;
0475     fetch->setScope(scope);
0476     fetch->exec();
0477     Q_ASSERT_X(fetch->error() == 0, "FetchJob", fetch->errorString().toLocal8Bit().constData());
0478     Q_ASSERT(session.state() == Session::Selected);
0479     QMap<qint64, MessagePtr> messages = fetch->messages();
0480     foreach (qint64 id, messages.keys()) {
0481         qDebug() << "* Message" << id << "(" << fetch->sizes()[id] << "bytes )";
0482         qDebug() << "  From      :" << messages[id]->from()->asUnicodeString();
0483         qDebug() << "  To        :" << messages[id]->to()->asUnicodeString();
0484         qDebug() << "  Date      :" << messages[id]->date()->asUnicodeString();
0485         qDebug() << "  Subject   :" << messages[id]->subject()->asUnicodeString();
0486         qDebug() << "  Message-ID:" << messages[id]->messageID()->asUnicodeString();
0487     }
0488     qDebug();
0489 
0490     qDebug() << "Fetching first 3 messages flags:";
0491     fetch = new FetchJob(&session);
0492     fetch->setSequenceSet(ImapSet(1, 3));
0493     scope.parts.clear();
0494     scope.mode = FetchJob::FetchScope::Flags;
0495     fetch->setScope(scope);
0496     fetch->exec();
0497     Q_ASSERT_X(fetch->error() == 0, "FetchJob", fetch->errorString().toLocal8Bit().constData());
0498     Q_ASSERT(session.state() == Session::Selected);
0499     QMap<qint64, MessageFlags> flags = fetch->flags();
0500     foreach (qint64 id, flags.keys()) {
0501         qDebug() << "* Message" << id << "flags:" << flags[id];
0502     }
0503     qDebug();
0504 
0505     qDebug() << "Fetching first message structure:";
0506     fetch = new FetchJob(&session);
0507     fetch->setSequenceSet(ImapSet(1));
0508     scope.parts.clear();
0509     scope.mode = FetchJob::FetchScope::Structure;
0510     fetch->setScope(scope);
0511     fetch->exec();
0512     Q_ASSERT_X(fetch->error() == 0, "FetchJob", fetch->errorString().toLocal8Bit().constData());
0513     Q_ASSERT(session.state() == Session::Selected);
0514     MessagePtr message = fetch->messages()[1];
0515     dumpContentHelper(message.data());
0516     qDebug();
0517 
0518     qDebug() << "Fetching first message second part headers:";
0519     fetch = new FetchJob(&session);
0520     fetch->setSequenceSet(ImapSet(1));
0521     scope.parts.clear();
0522     scope.parts << "2";
0523     scope.mode = FetchJob::FetchScope::Headers;
0524     fetch->setScope(scope);
0525     fetch->exec();
0526     Q_ASSERT_X(fetch->error() == 0, "FetchJob", fetch->errorString().toLocal8Bit().constData());
0527     Q_ASSERT(session.state() == Session::Selected);
0528     QMap<qint64, MessageParts> allParts = fetch->parts();
0529     foreach (qint64 id, allParts.keys()) {
0530         qDebug() << "* Message" << id << "parts headers";
0531         MessageParts parts = allParts[id];
0532         foreach (const QByteArray &partId, parts.keys()) {
0533             qDebug() << "  ** Part" << partId;
0534             qDebug() << "     Name       :" << parts[partId]->contentType()->name();
0535             qDebug() << "     Mimetype   :" << parts[partId]->contentType()->mimeType();
0536             qDebug() << "     Description:" << parts[partId]->contentDescription()->asUnicodeString().simplified();
0537         }
0538     }
0539     qDebug();
0540 
0541     qDebug() << "Fetching first message second part content:";
0542     fetch = new FetchJob(&session);
0543     fetch->setSequenceSet(ImapSet(1));
0544     scope.parts.clear();
0545     scope.parts << "2";
0546     scope.mode = FetchJob::FetchScope::Content;
0547     fetch->setScope(scope);
0548     fetch->exec();
0549     Q_ASSERT_X(fetch->error() == 0, "FetchJob", fetch->errorString().toLocal8Bit().constData());
0550     Q_ASSERT(session.state() == Session::Selected);
0551     allParts = fetch->parts();
0552     foreach (int id, allParts.keys()) {
0553         MessageParts parts = allParts[id];
0554         foreach (const QByteArray &partId, parts.keys()) {
0555             qDebug() << "* Message" << id << "part" << partId << "content:";
0556             qDebug() << parts[partId]->body();
0557         }
0558     }
0559     qDebug();
0560 
0561     testDelete(&session);
0562 
0563     testSubscribe(&session);
0564 
0565     testRename(&session);
0566 
0567     testAppendAndStore(&session);
0568 
0569     testAcl(&session, user);
0570 
0571     testMetaData(&session);
0572 
0573     qDebug() << "Expunge INBOX:";
0574     ExpungeJob *expunge = new ExpungeJob(&session);
0575     expunge->exec();
0576 
0577     qDebug() << "Closing INBOX:";
0578     CloseJob *close = new CloseJob(&session);
0579     close->exec();
0580     Q_ASSERT(session.state() == Session::Authenticated);
0581     qDebug();
0582 
0583     qDebug() << "Logging out...";
0584     LogoutJob *logout = new LogoutJob(&session);
0585     logout->exec();
0586     Q_ASSERT_X(logout->error() == 0, "LogoutJob", logout->errorString().toLocal8Bit().constData());
0587     Q_ASSERT(session.state() == Session::Disconnected);
0588 
0589     return 0;
0590 }