Revert "Implement RFC5162 - QRESYNC extension"

This reverts commit 2dd47223.

Way too many issues with syncing have been found, so it needs to be
reverted for now.

CCMAIL: dvratil@kde.org
parent c7c41224
cmake_minimum_required(VERSION 3.5)
set(PIM_VERSION "5.15.41")
set(PIM_VERSION "5.15.40")
project(KIMAP VERSION ${PIM_VERSION})
......
......@@ -26,7 +26,6 @@ KIMAP_UNIT_TESTS(
loginjobtest
logoutjobtest
capabilitiesjobtest
closejobtest
selectjobtest
createjobtest
deletejobtest
......
/*
SPDX-FileCopyrightText: 2020 Daniel Vrátil <dvratil@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <QTest>
#include "kimaptest/fakeserver.h"
#include "kimap/session.h"
#include "kimap/closejob.h"
#include <QTest>
class CloseJobTest: public QObject
{
Q_OBJECT
private Q_SLOTS:
void testClose_data()
{
QTest::addColumn<QList<QByteArray>>("scenario");
QTest::addColumn<quint64>("highestModSeq");
QList<QByteArray> scenario;
scenario << FakeServer::preauth()
<< "C: A000001 CLOSE"
<< "S: A000001 OK Closed";
QTest::newRow("good") << scenario << 0ULL;
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 CLOSE"
<< "S: A000001 BAD No mailbox selected";
QTest::newRow("bad") << scenario << 0ULL;
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 CLOSE"
<< "S: A000001 OK [HIGHESTMODSEQ 123456789] Closed.";
QTest::newRow("qresync") << scenario << 123456789ULL;
}
void testClose()
{
QFETCH(QList<QByteArray>, scenario);
QFETCH(quint64, highestModSeq);
FakeServer fakeServer;
fakeServer.setScenario(scenario);
fakeServer.startAndWait();
KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989);
auto *job = new KIMAP::CloseJob(&session);
bool result = job->exec();
QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
QVERIFY(result);
if (result) {
QCOMPARE(job->newHighestModSeq(), highestModSeq);
}
fakeServer.quit();
}
};
QTEST_GUILESS_MAIN(CloseJobTest)
#include "closejobtest.moc"
......@@ -9,7 +9,6 @@
#include "kimaptest/fakeserver.h"
#include "kimap/session.h"
#include "kimap/expungejob.h"
#include "imapset.h"
#include <QTest>
......@@ -21,9 +20,7 @@ private Q_SLOTS:
void testDelete_data()
{
QTest::addColumn<QList<QByteArray>>("scenario");
QTest::addColumn<KIMAP::ImapSet>("vanishedSet");
QTest::addColumn<quint64>("highestModSeq");
QTest::addColumn<QList<QByteArray> >("scenario");
QList<QByteArray> scenario;
scenario << FakeServer::preauth()
......@@ -32,43 +29,31 @@ private Q_SLOTS:
<< "S: * 2 EXPUNGE"
<< "S: * 3 EXPUNGE"
<< "S: A000001 OK EXPUNGE completed";
QTest::newRow("good") << scenario << KIMAP::ImapSet{} << 0ULL;
QTest::newRow("good") << scenario;
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 EXPUNGE"
<< "S: * 1" // missing EXPUNGE word
<< "S: A000001 OK EXPUNGE completed";
QTest::newRow("non-standard response") << scenario << KIMAP::ImapSet{} << 0ULL;
QTest::newRow("non-standard response") << scenario;
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 EXPUNGE"
<< "S: A000001 BAD command unknown or arguments invalid";
QTest::newRow("bad") << scenario << KIMAP::ImapSet{} << 0ULL;
QTest::newRow("bad") << scenario;
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 EXPUNGE"
<< "S: A000001 NO access denied";
QTest::newRow("no") << scenario << KIMAP::ImapSet{} << 0ULL;
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 EXPUNGE"
<< "S: * VANISHED 405,407,410:420"
<< "S: A000001 OK [HIGHESTMODSEQ 123456789] Expunged.";
KIMAP::ImapSet vanishedSet;
vanishedSet.add({405, 407});
vanishedSet.add(KIMAP::ImapInterval{410, 420});
QTest::newRow("qresync") << scenario << vanishedSet << 123456789ULL;
QTest::newRow("no") << scenario;
}
void testDelete()
{
QFETCH(QList<QByteArray>, scenario);
QFETCH(KIMAP::ImapSet, vanishedSet);
QFETCH(quint64, highestModSeq);
FakeServer fakeServer;
fakeServer.setScenario(scenario);
......@@ -81,10 +66,6 @@ private Q_SLOTS:
QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
QEXPECT_FAIL("no" , "Expected failure on NO response", Continue);
QVERIFY(result);
if (result) {
QCOMPARE(job->vanishedMessages(), vanishedSet);
QCOMPARE(job->newHighestModSeq(), highestModSeq);
}
fakeServer.quit();
}
......
......@@ -12,7 +12,6 @@
#include "kimap/fetchjob.h"
#include <QTest>
#include <QSignalSpy>
Q_DECLARE_METATYPE(KIMAP::FetchJob::FetchScope)
......@@ -20,12 +19,6 @@ class FetchJobTest: public QObject
{
Q_OBJECT
public:
FetchJobTest()
{
qRegisterMetaType<KIMAP::ImapSet>();
}
private:
QStringList m_signals;
......@@ -87,11 +80,10 @@ private Q_SLOTS:
qRegisterMetaType<KIMAP::FetchJob::FetchScope>();
QTest::addColumn<bool>("uidBased");
QTest::addColumn<KIMAP::ImapSet>("set");
QTest::addColumn< KIMAP::ImapSet >("set");
QTest::addColumn<int>("expectedMessageCount");
QTest::addColumn<QList<QByteArray>>("scenario");
QTest::addColumn< QList<QByteArray> >("scenario");
QTest::addColumn<KIMAP::FetchJob::FetchScope>("scope");
QTest::addColumn<KIMAP::ImapSet>("expectedVanished");
KIMAP::FetchJob::FetchScope scope;
scope.mode = KIMAP::FetchJob::FetchScope::Flags;
......@@ -107,7 +99,7 @@ private Q_SLOTS:
<< "S: A000001 OK fetch done";
QTest::newRow("messages have empty flags (with changedsince)") << false << KIMAP::ImapSet(1, 4) << 4
<< scenario << scope << KIMAP::ImapSet{};
<< scenario << scope;
scenario.clear();
scope.changedSince = 0;
......@@ -120,7 +112,7 @@ private Q_SLOTS:
<< "S: A000001 OK fetch done";
QTest::newRow("messages have empty flags") << false << KIMAP::ImapSet(1, 4) << 4
<< scenario << scope << KIMAP::ImapSet{};
<< scenario << scope;
scenario.clear();
// kill the connection part-way through a list, with carriage returns at end
......@@ -132,7 +124,7 @@ private Q_SLOTS:
<< "S: From: John Smith <jonathanr.smith@foobarbaz.com>\r\nTo: \"amagicemailaddress@foobarbazbarfoo.com\"\r\n\t<amagicemailaddress@foobarbazbarfoo.com>\r\nDate: Mon, 11 Oct 2010 03:34:48 +0100\r\nSubject: unsubscribe\r\nMessage-ID: <ASDFFDSASDFFDS@foobarbaz.com>\r\n\r\n"
<< "X";
scope.mode = KIMAP::FetchJob::FetchScope::Headers;
QTest::newRow("connection drop") << false << KIMAP::ImapSet(11, 11) << 1 << scenario << scope << KIMAP::ImapSet{};
QTest::newRow("connection drop") << false << KIMAP::ImapSet(11, 11) << 1 << scenario << scope;
scenario.clear();
// Important bit here if "([127.0.0.1])" which used to crash the stream parser
......@@ -142,7 +134,7 @@ private Q_SLOTS:
<< "S: ([127.0.0.1])\r\nDate: Mon, 11 Oct 2010 03:34:48 +0100\r\nSubject: unsubscribe\r\nMessage-ID: <ASDFFDSASDFFDS@foobarbaz.com>\r\n\r\n"
<< "X";
scope.mode = KIMAP::FetchJob::FetchScope::Headers;
QTest::newRow("buffer overwrite") << false << KIMAP::ImapSet(11, 11) << 1 << scenario << scope << KIMAP::ImapSet{};
QTest::newRow("buffer overwrite") << false << KIMAP::ImapSet(11, 11) << 1 << scenario << scope;
scenario.clear();
// We're assuming a buffer overwrite here which made us miss the opening parenthesis
......@@ -152,7 +144,7 @@ private Q_SLOTS:
<< "S: * 11 FETCH {10}doh!\r\n\r\n\r\n)\r\n"
<< "X";
scope.mode = KIMAP::FetchJob::FetchScope::Headers;
QTest::newRow("buffer overwrite 2") << false << KIMAP::ImapSet(11, 11) << 1 << scenario << scope << KIMAP::ImapSet{};
QTest::newRow("buffer overwrite 2") << false << KIMAP::ImapSet(11, 11) << 1 << scenario << scope;
scenario.clear();
scenario << FakeServer::preauth()
......@@ -163,24 +155,7 @@ private Q_SLOTS:
scope.mode = KIMAP::FetchJob::FetchScope::FullHeaders;
scope.changedSince = 123456789;
QTest::newRow("fetch full headers") << false << KIMAP::ImapSet(11, 11) << 1
<< scenario << scope << KIMAP::ImapSet{};
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 UID FETCH 300:500 (FLAGS UID) (CHANGEDSINCE 12345 VANISHED)"
<< "S: * VANISHED (EARLIER) 300:310,405,411"
<< "S: * 1 FETCH (UID 404 MODSEQ (65402) FLAGS (\\Seen))"
<< "S: * 2 FETCH (UID 406 MODSEQ (75403) FLAGS (\\Deleted))"
<< "S: * 4 FETCH (UID 408 MODSEQ (29738) FLAGS ($Nojunk $AutoJunk $MDNSent))"
<< "S: A000001 OK Fetch completed";
scope.mode = KIMAP::FetchJob::FetchScope::Flags;
scope.changedSince = 12345;
scope.qresync = true;
KIMAP::ImapSet vanished;
vanished.add(KIMAP::ImapInterval{300, 310});
vanished.add({405, 411});
QTest::newRow("qresync") << true << KIMAP::ImapSet(300, 500) << 3 << scenario << scope << vanished;
<< scenario << scope;
}
void testFetch()
......@@ -190,7 +165,6 @@ private Q_SLOTS:
QFETCH(int, expectedMessageCount);
QFETCH(QList<QByteArray>, scenario);
QFETCH(KIMAP::FetchJob::FetchScope, scope);
QFETCH(KIMAP::ImapSet, expectedVanished);
FakeServer fakeServer;
fakeServer.setScenario(scenario);
......@@ -218,9 +192,6 @@ private Q_SLOTS:
connect(job, &KIMAP::FetchJob::messagesAvailable,
this, &FetchJobTest::onMessagesAvailable);
QSignalSpy vanishedSpy(job, &KIMAP::FetchJob::messagesVanished);
QVERIFY(vanishedSpy.isValid());
bool result = job->exec();
QEXPECT_FAIL("connection drop", "Expected failure on connection drop", Continue);
QEXPECT_FAIL("buffer overwrite", "Expected failure on confused list", Continue);
......@@ -230,10 +201,6 @@ private Q_SLOTS:
QVERIFY(m_signals.count() > 0);
QCOMPARE(m_uids.count(), expectedMessageCount);
QCOMPARE(m_msgs.count(), expectedMessageCount);
if (scope.qresync) {
QCOMPARE(vanishedSpy.size(), 1);
QCOMPARE(vanishedSpy.at(0).at(0).value<KIMAP::ImapSet>(), expectedVanished);
}
}
QVERIFY(fakeServer.isAllScenarioDone());
......
......@@ -15,26 +15,11 @@
#include "kimap/selectjob.h"
#include <QTest>
#include <QSignalSpy>
using Messages = QMap<qint64, KIMAP::Message>;
Q_DECLARE_METATYPE(KIMAP::Message)
Q_DECLARE_METATYPE(Messages);
class SelectJobTest: public QObject
{
Q_OBJECT
public:
explicit SelectJobTest()
{
qRegisterMetaType<KIMAP::ImapSet>();
qRegisterMetaType<KIMAP::Message>();
qRegisterMetaType<QMap<qint64, KIMAP::Message>>("QMap<qint64,KIMAP::Message>");
}
private Q_SLOTS:
void testSingleSelect_data()
......@@ -50,11 +35,6 @@ private Q_SLOTS:
QTest::addColumn<quint64>("highestmodseq");
QTest::addColumn<bool>("condstoreEnabled");
QTest::addColumn<bool>("readonly");
QTest::addColumn<qint64>("lastUidvalidity");
QTest::addColumn<quint64>("lastModseq");
QTest::addColumn<KIMAP::ImapSet>("vanished");
QTest::addColumn<Messages>("modified");
QList<QByteArray> scenario;
QList<QByteArray> flags;
......@@ -73,8 +53,7 @@ private Q_SLOTS:
flags << "\\Answered" << "\\Flagged" << "\\Deleted" << "\\Seen" << "\\Draft";
permanentflags << "\\Deleted" << "\\Seen" << "\\*";
QTest::newRow("good") << scenario << flags << permanentflags << 172 << 1 << 12 << 3857529045LL << 4392LL << 123456789ULL << true << false
<< -1LL << 0ULL << KIMAP::ImapSet{} << Messages{};
QTest::newRow("good") << scenario << flags << permanentflags << 172 << 1 << 12 << (qint64)3857529045 << (qint64)4392 << (quint64)123456789 << true << false;
scenario.clear();
flags.clear();
......@@ -82,8 +61,7 @@ private Q_SLOTS:
scenario << FakeServer::preauth()
<< "C: A000001 SELECT \"INBOX\""
<< "S: A000001 BAD command unknown or arguments invalid";
QTest::newRow("bad") << scenario << flags << permanentflags << 0 << 0 << 0 << 0LL << 0LL << 0ULL << false << false
<< -1LL << 0ULL << KIMAP::ImapSet{} << Messages{};
QTest::newRow("bad") << scenario << flags << permanentflags << 0 << 0 << 0 << (qint64)0 << (qint64)0 << (quint64)0 << false << false;
scenario.clear();
flags.clear();
......@@ -91,40 +69,7 @@ private Q_SLOTS:
scenario << FakeServer::preauth()
<< "C: A000001 SELECT \"INBOX\""
<< "S: A000001 NO select failure";
QTest::newRow("no") << scenario << flags << permanentflags << 0 << 0 << 0 << 0LL << 0LL << 0ULL << false << false
<< -1LL << 0ULL << KIMAP::ImapSet{} << Messages{};
scenario.clear();
scenario << FakeServer::preauth()
<< "C: A000001 SELECT \"INBOX\" (QRESYNC (67890007 90060115194045000))"
<< "S: * 314 EXISTS"
<< "S: * 15 RECENT"
<< "S: * OK [UIDVALIDITY 67890007] UIDVALIDITY"
<< "S: * OK [UIDNEXT 567] Predicted next UID"
<< "S: * OK [HIGHESTMODSEQ 90060115205545359]"
<< "S: * OK [UNSEEN 7] There are some unseen messages in the mailbox"
<< "S: * FLAGS (\\Answered \\Flagged \\Draft \\Deleted \\Seen)"
<< "S: * OK [PERMANENTFLAGS (\\Answered \\Flagged \\Draft \\Deleted \\Seen \\*)] Permanent flags"
<< "S: * VANISHED (EARLIER) 41,43:116,118,120:211,214:540"
<< "S: * 49 FETCH (UID 117 FLAGS (\\Seen \\Answered) MODSEQ (90060115194045001))"
<< "S: * 50 FETCH (UID 119 FLAGS (\\Draft $MDNSent) MODSEQ (90060115194045308))"
<< "S: * 100 FETCH (UID 541 FLAGS (\\Seen $Forwarded) MODSEQ (90060115194045001))"
<< "S: A000001 OK [READ-WRITE] mailbox selected";
permanentflags = {"\\Answered", "\\Flagged", "\\Draft", "\\Deleted", "\\Seen", "\\*"};
flags = {"\\Answered", "\\Flagged", "\\Draft", "\\Deleted", "\\Seen"};
KIMAP::ImapSet vanished;
vanished.add(41);
vanished.add(KIMAP::ImapInterval{43, 116});
vanished.add(118);
vanished.add(KIMAP::ImapInterval{120, 211});
vanished.add(KIMAP::ImapInterval{214, 540});
Messages modified = {
{49, KIMAP::Message{117, 0, {"\\Seen", "\\Answered"}, {{"MODSEQ", QVariant{90060115194045001ULL}}}, {}, {}}},
{50, KIMAP::Message{119, 0, {"\\Draft", "$MDNSent"}, {{"MODSEQ", QVariant{90060115194045308ULL}}}, {}, {}}},
{100, KIMAP::Message{541, 0, {"\\Seen", "$Forwarded"}, {{"MODSEQ", QVariant{90060115194045001ULL}}}, {}, {}}}
};
QTest::newRow("QResync") << scenario << flags << permanentflags << 314 << 15 << 7 << 67890007LL << 567LL << 90060115205545359ULL << false << false
<< 67890007LL << 90060115194045000ULL << vanished << modified;
QTest::newRow("no") << scenario << flags << permanentflags << 0 << 0 << 0 << (qint64)0 << (qint64)0 << (quint64)0 << false << false;
}
void testSingleSelect()
......@@ -139,10 +84,6 @@ private Q_SLOTS:
QFETCH(qint64, nextUid);
QFETCH(quint64, highestmodseq);
QFETCH(bool, condstoreEnabled);
QFETCH(qint64, lastUidvalidity);
QFETCH(quint64, lastModseq);
QFETCH(KIMAP::ImapSet, vanished);
QFETCH(Messages, modified);
FakeServer fakeServer;
fakeServer.setScenario(scenario);
......@@ -153,16 +94,6 @@ private Q_SLOTS:
KIMAP::SelectJob *job = new KIMAP::SelectJob(&session);
job->setCondstoreEnabled(condstoreEnabled);
job->setMailBox(QStringLiteral("INBOX"));
if (lastUidvalidity > -1 && lastModseq > 0) {
job->setQResync(lastUidvalidity, lastModseq);
}
QSignalSpy vanishedSpy(job, &KIMAP::SelectJob::vanished);
QVERIFY(vanishedSpy.isValid());
QSignalSpy modifiedSpy(job, &KIMAP::SelectJob::modified);
QVERIFY(modifiedSpy.isValid());
bool result = job->exec();
QEXPECT_FAIL("bad" , "Expected failure on BAD scenario", Continue);
QEXPECT_FAIL("no" , "Expected failure on NO scenario", Continue);
......@@ -176,20 +107,6 @@ private Q_SLOTS:
QCOMPARE(job->uidValidity(), uidValidity);
QCOMPARE(job->nextUid(), nextUid);
QCOMPARE(job->highestModSequence(), highestmodseq);
if (!vanished.isEmpty()) {
QCOMPARE(vanishedSpy.size(), 1);
QCOMPARE(vanishedSpy.at(0).at(0).value<KIMAP::ImapSet>(), vanished);
}
if (!modified.isEmpty()) {
Messages collectedModified;
for (const auto &modifiedSpyCatch : modifiedSpy) {
collectedModified.insert(modifiedSpyCatch.at(0).value<Messages>());
}
QCOMPARE(collectedModified, modified);
}
}
fakeServer.quit();
......
......@@ -18,8 +18,7 @@ class CloseJobPrivate : public JobPrivate
{
public:
CloseJobPrivate(Session *session, const QString &name) : JobPrivate(session, name) { }
quint64 highestModSeq = 0;
~CloseJobPrivate() { }
};
}
......@@ -30,25 +29,12 @@ CloseJob::CloseJob(Session *session)
{
}
void CloseJob::doStart()
CloseJob::~CloseJob()
{
Q_D(CloseJob);
d->tags << d->sessionInternal()->sendCommand("CLOSE");
}
quint64 CloseJob::newHighestModSeq() const
{
Q_D(const CloseJob);
return d->highestModSeq;
}
void CloseJob::handleResponse(const Response &response)
void CloseJob::doStart()
{
Q_D(CloseJob);
if (response.responseCode.size() >= 2 && response.responseCode[0].toString() == "HIGHESTMODSEQ") {
d->highestModSeq = response.responseCode[1].toString().toULongLong();
}
Job::handleErrorReplies(response);
d->tags << d->sessionInternal()->sendCommand("CLOSE");
}
......@@ -31,9 +31,7 @@ class CloseJobPrivate;
* messages were expunged, so this is quicker than doing
* an expunge and then implicitly closing the mailbox
* (by selecting or examining another mailbox or logging
* out). If the QRESYNC extension (RFC5162) is available on the
* server and has been enabled, the job will provide a new
* modification sequence after expunging the deleted messages.
* out).
*
* No messages are removed if the mailbox is open in a read-only
* state, or if the server supports ACLs and the user does not
......@@ -48,21 +46,10 @@ class KIMAP_EXPORT CloseJob : public Job
public:
explicit CloseJob(Session *session);
~CloseJob() override = default;
~CloseJob() override;
/**
* Returns new modification sequence number after expunging messages.
*
* This value is only valid when server supports the QRESYNC extension
* (RFC5162) and it has been explicitly enabled on this session.
*
* @see KIMAP::EnableJob
* @since 5.16
*/
quint64 newHighestModSeq() const;
protected:
void doStart() override;
void handleResponse(const Response &response) override;
};
}
......
......@@ -27,10 +27,7 @@ class EnableJobPrivate;
* new capabilities to enable will be specified by the user. The user is
* responsible for making sure the capabilities are supported by the server.
*
* The example usecase for this job is to enable support for the QRESYNC
* extension (RFC5162) on the server.
*
* @since 5.16
* @since 5.15
*/
class KIMAP_EXPORT EnableJob : public Job
{
......
......@@ -12,7 +12,6 @@
#include "job_p.h"
#include "response_p.h"
#include "session_p.h"
#include "imapset.h"
namespace KIMAP
{
......@@ -20,11 +19,10 @@ class ExpungeJobPrivate : public JobPrivate
{
public:
ExpungeJobPrivate(Session *session, const QString &name) : JobPrivate(session, name) { }
~ExpungeJobPrivate() { }
#if 0
QList< int > items;
#endif
KIMAP::ImapSet vanished;
quint64 highestModSeq = 0;
};
}
......@@ -35,16 +33,8 @@ ExpungeJob::ExpungeJob(Session *session)
{
}
KIMAP::ImapSet ExpungeJob::vanishedMessages() const
ExpungeJob::~ExpungeJob()
{
Q_D(const ExpungeJob);
return d->vanished;
}
quint64 ExpungeJob::newHighestModSeq() const
{
Q_D(const ExpungeJob);
return d->highestModSeq;
}
void ExpungeJob::doStart()
......@@ -55,22 +45,12 @@ void ExpungeJob::doStart()
void ExpungeJob::handleResponse(const Response &response)
{
Q_D(ExpungeJob);
// Must be handler before handleErrorReplies(), so the value is available
// before the result is emitted.
if (response.responseCode.size() >= 2) {
if (response.responseCode[0].toString() == "HIGHESTMODSEQ") {
d->highestModSeq = response.responseCode[1].toString().toULongLong();
}
}
// Q_D(ExpungeJob);
if (handleErrorReplies(response) == NotHandled) {
if (response.content.size() >= 3) {
if (response.content[1].toString() == "VANISHED") {
d->vanished = KIMAP::ImapSet::fromImapSequenceSet(response.content[2].toString());
return;
} else if (response.content[2].toString() == "EXPUNGE") {
QByteArray code = response.content[2].toString();
if (code == "EXPUNGE") {
#if 0
QByteArray s = response.content[1].toString();
bool ok = true;
......@@ -84,5 +64,6 @@ void ExpungeJob::handleResponse(const Response &response)
}
}
qCDebug(KIMAP_LOG) << "Unhandled response: " << response.toString().constData();
}
}
......@@ -16,7 +16,6 @@ namespace KIMAP
class Session;
struct Response;
class ImapSet;
class ExpungeJobPrivate;
/**
......@@ -40,29 +39,7 @@ class KIMAP_EXPORT ExpungeJob : public Job
public:
explicit ExpungeJob(Session *session);
~ExpungeJob() override = default;
/**
* Returns UIDs of messages that have been expunged.