summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Vrátil <dvratil@kde.org>2016-10-22 22:33:14 (GMT)
committerDaniel Vrátil <dvratil@kde.org>2016-10-22 22:33:18 (GMT)
commitfa93d5df53c33b3c579a49424e58e191a30f16b0 (patch)
tree810e4f9b9195cac8a0932c34599cce63fee18825
parent7516820e0e1fa25e1a820b28c05a45917a7625e9 (diff)
Introduce MoveJob which implements the MOVE extension (RFC6851)
The MoveJob API is the same as CopyJob API, since the RFC6851 is modelled closely from the COPY command, having the same parameters and responses. Unlike with the traditional COPY + STORE \Deleted + EXPUNGE approach, the RFC6851 guarantees the entire operation to be atomic and is faster and uses less bandwidth. When UIDPLUS extension is supported, the resulting UIDs are returned via COPYUID response (like with CopyJob).
-rw-r--r--CMakeLists.txt2
-rw-r--r--autotests/CMakeLists.txt1
-rw-r--r--autotests/movejobtest.cpp91
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/movejob.cpp137
-rw-r--r--src/movejob.h122
6 files changed, 354 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ab0307..f851d8d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,7 @@ include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(ECMQtDeclareLoggingCategory)
-set(PIM_VERSION "5.3.40")
+set(PIM_VERSION "5.3.41")
set(KIMAP_LIB_VERSION ${PIM_VERSION})
set(KMIME_LIBS_VERSION "5.3.40")
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
index 823bbca..46bc8c6 100644
--- a/autotests/CMakeLists.txt
+++ b/autotests/CMakeLists.txt
@@ -46,4 +46,5 @@ KIMAP_UNIT_TESTS(
setmetadatajobtest
appendjobtest
statusjobtest
+ movejobtest
)
diff --git a/autotests/movejobtest.cpp b/autotests/movejobtest.cpp
new file mode 100644
index 0000000..0af6992
--- /dev/null
+++ b/autotests/movejobtest.cpp
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2016 Daniel Vrátil <dvratil@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/imapset.h"
+#include "../src/movejob.h"
+
+#include <QtTest>
+
+class MoveJobTest: public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void testMove_data()
+ {
+ QTest::addColumn<bool>("uidBased");
+ QTest::addColumn<qint64>("id");
+ QTest::addColumn<qint64>("resultUid");
+ QTest::addColumn<QString>("mailbox");
+ QTest::addColumn< QList<QByteArray> >("scenario");
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 MOVE 3 \"foo\""
+ << "S: * OK [COPYUID 12345 3 7]"
+ << "S: A000001 OK MOVE completed";
+
+ QTest::newRow("not uid based") << false << qint64(3) << qint64(7)
+ << QStringLiteral("foo") << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 UID MOVE 1024 \"bar\""
+ << "S: * OK [COPYUID 12346 4 2048]"
+ << "S: A000001 OK MOVE completed";
+
+ QTest::newRow("uid based") << true << qint64(1024) << qint64(2048)
+ << QStringLiteral("bar") << scenario;
+ }
+
+ void testMove()
+ {
+ QFETCH(bool, uidBased);
+ QFETCH(qint64, id);
+ QFETCH(qint64, resultUid);
+ QFETCH(QString, mailbox);
+ QFETCH(QList<QByteArray>, scenario);
+
+ FakeServer fakeServer;
+ fakeServer.setScenario(scenario);
+ fakeServer.startAndWait();
+
+ KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989);
+
+ auto job = new KIMAP::MoveJob(&session);
+ job->setMailBox(mailbox);
+ job->setUidBased(uidBased);
+ job->setSequenceSet(KIMAP::ImapSet(id));
+ bool result = job->exec();
+ QVERIFY(result);
+ QCOMPARE(job->resultingUids(), KIMAP::ImapSet(resultUid));
+
+ fakeServer.quit();
+ }
+
+};
+
+QTEST_GUILESS_MAIN(MoveJobTest)
+
+#include "movejobtest.moc"
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 59fe5f6..2bb2b0e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -30,6 +30,7 @@ set(kimap_SRCS
loginjob.cpp
logoutjob.cpp
metadatajobbase.cpp
+ movejob.cpp
myrightsjob.cpp
namespacejob.cpp
quotajobbase.cpp
@@ -104,6 +105,7 @@ ecm_generate_headers(KIMAP_CamelCase_HEADERS
LoginJob
LogoutJob
MetaDataJobBase
+ MoveJob
MyRightsJob
QuotaJobBase
RenameJob
diff --git a/src/movejob.cpp b/src/movejob.cpp
new file mode 100644
index 0000000..f78f868
--- /dev/null
+++ b/src/movejob.cpp
@@ -0,0 +1,137 @@
+/*
+ Copyright (c) 2016 Daniel Vrátil <dvratil@kde.org>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#include "movejob.h"
+
+#include "job_p.h"
+#include "message_p.h"
+#include "session_p.h"
+#include "rfccodecs.h"
+
+#include <KLocalizedString>
+
+//TODO: when custom error codes are introduced, handle the NO [TRYCREATE] response
+
+namespace KIMAP
+{
+class MoveJobPrivate : public JobPrivate
+{
+public:
+ MoveJobPrivate(Session *session, const QString &name)
+ : JobPrivate(session, name)
+ , uidBased(false)
+ {}
+
+ ~MoveJobPrivate()
+ {}
+
+ QString mailBox;
+ ImapSet set;
+ bool uidBased;
+ ImapSet resultingUids;
+};
+}
+
+using namespace KIMAP;
+
+MoveJob::MoveJob(Session *session)
+ : Job(*new MoveJobPrivate(session, i18n("Move")))
+{
+ Q_D(MoveJob);
+ d->uidBased = false;
+}
+
+MoveJob::~MoveJob()
+{
+}
+
+void MoveJob::setMailBox(const QString &mailBox)
+{
+ Q_D(MoveJob);
+ d->mailBox = mailBox;
+}
+
+QString MoveJob::mailBox() const
+{
+ Q_D(const MoveJob);
+ return d->mailBox;
+}
+
+void MoveJob::setSequenceSet(const ImapSet &set)
+{
+ Q_D(MoveJob);
+ d->set = set;
+}
+
+ImapSet MoveJob::sequenceSet() const
+{
+ Q_D(const MoveJob);
+ return d->set;
+}
+
+void MoveJob::setUidBased(bool uidBased)
+{
+ Q_D(MoveJob);
+ d->uidBased = uidBased;
+}
+
+bool MoveJob::isUidBased() const
+{
+ Q_D(const MoveJob);
+ return d->uidBased;
+}
+
+ImapSet MoveJob::resultingUids() const
+{
+ Q_D(const MoveJob);
+ return d->resultingUids;
+}
+
+void MoveJob::doStart()
+{
+ Q_D(MoveJob);
+
+ QByteArray parameters = d->set.toImapSequenceSet() + ' ';
+ parameters += '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"';
+
+ QByteArray command = "MOVE";
+ if (d->uidBased) {
+ command = "UID " + command;
+ }
+
+ d->tags << d->sessionInternal()->sendCommand(command, parameters);
+}
+
+void MoveJob::handleResponse(const Message &response)
+{
+ Q_D(MoveJob);
+
+ for (QList<Message::Part>::ConstIterator it = response.responseCode.begin();
+ it != response.responseCode.end(); ++it) {
+ if (it->toString() == "COPYUID") {
+ it = it + 3;
+ if (it < response.responseCode.end()) {
+ d->resultingUids = ImapSet::fromImapSequenceSet(it->toString());
+ }
+ break;
+ }
+ }
+
+ handleErrorReplies(response);
+}
diff --git a/src/movejob.h b/src/movejob.h
new file mode 100644
index 0000000..5ac7d54
--- /dev/null
+++ b/src/movejob.h
@@ -0,0 +1,122 @@
+/*
+ Copyright (c) 2016 Daniel Vrátil <dvratil@kde.org>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#ifndef KIMAP_MOVE_H_
+#define KIMAP_MOVE_H_
+
+#include "kimap_export.h"
+
+#include "job.h"
+#include "imapset.h"
+
+namespace KIMAP {
+
+class MoveJobPrivate;
+
+/**
+ * Moves messages from current mailbox to another
+ *
+ * Note that move functionality is not specified in the base IMAP
+ * protocol and is defined as an extension in RFC6851. That means
+ * that the MoveJob can only be used when the server lists "MOVE"
+ * in response to CAPABILITY command.
+ *
+ * Unlike the traditional emulation of moving messages, i.e. COPY + STORE + EXPUNGE,
+ * MOVE guarantees the transaction to be atomic on the server.
+ *
+ * @since 5.4
+ */
+class KIMAP_EXPORT MoveJob : public Job
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(MoveJob)
+
+ friend class SessionPrivate;
+
+public:
+ explicit MoveJob(Session *session);
+ virtual ~MoveJob();
+
+ /**
+ * Set the destination mailbox
+ *
+ * If the mailbox does not exist, the server should not create
+ * it automatically and the job should fail. Note, however,
+ * that a conforming server may create the mailbox automatically.
+ *
+ * @param mailBox the (unquoted) name of the mailbox where the
+ * messages should be moved to
+ */
+ void setMailBox(const QString &mailbox);
+ /**
+ * The destination mailbox
+ */
+ QString mailBox() const;
+
+ /**
+ * Sets the messages to be moved,
+ *
+ * If sequence numbers are given, isUidBased() should be false. If UIDs
+ * are given, isUidBased() should be true.
+ *
+ * @param set the sequence numbers or UIDs of the messages to be moved
+ */
+ void setSequenceSet(const ImapSet &set);
+ /**
+ * The messages that will be moved.
+ *
+ * isUidBased() can be used to check whether the ImapSet contains
+ * sequence numbers or UIDs.
+ *
+ * @return the sequence numbers or UIDs of the messages to be moved
+ */
+ ImapSet sequenceSet() const;
+
+ /**
+ * Set how the sequence set should be interpreted.
+ *
+ * @param uidBased if @c true the argument to setSequenceSet will be
+ * interpreted as UIDs, if @c false it will be interpreted
+ * as sequence numbers
+ */
+ void setUidBased(bool uidBased);
+ /**
+ * How to interpret the sequence set.
+ *
+ * @return if @c true the result of sequenceSet() should be
+ * interpreted as UIDs, if @c false it should be interpreted
+ * as sequence numbers
+ */
+ bool isUidBased() const;
+
+ /**
+ * The UIDs of the moved messages in the destination mailbox.
+ *
+ * This will be an empty set if no messages have been moved yet
+ * or if the server does not support the UIDPLUS extension.
+ */
+ ImapSet resultingUids() const;
+
+protected:
+ void doStart() Q_DECL_OVERRIDE;
+ void handleResponse(const KIMAP::Message &response) Q_DECL_OVERRIDE;
+};
+
+}
+#endif