Commit d5ab6167 authored by Daniel Vrátil's avatar Daniel Vrátil 🤖

Start porting Akonadi Jobs to the new protocol API

Nothing compiles yet due to everything including everything and not
everything being ported yet, but we have all Collection jobs and
most Items jobs (theoretically) done.
parent 8d6e3879
......@@ -18,9 +18,11 @@
*/
#include "collectioncopyjob.h"
#include "collection.h"
#include "job_p.h"
#include "protocolhelper_p.h"
#include <akonadi/private/protocol_p.h>
using namespace Akonadi;
......@@ -53,11 +55,14 @@ void CollectionCopyJob::doStart()
{
Q_D(CollectionCopyJob);
QByteArray command = d->newTag();
command += " COLCOPY ";
command += QByteArray::number(d->mSource.id());
command += ' ';
command += QByteArray::number(d->mTarget.id());
command += '\n';
d->writeData(command);
d->sendCommand(Protocol::CopyCollectionCommand(d->mSource.id(), d->mTarget.id()));
}
void CollectionCopyJob::doHandleResponse(qint64 tag, const Protocol::Command &response)
{
if (!response.isResponse() || response.type() != Protocol::Command::CreateCollection) {
Job::doHandleResponse(tag, response);
}
emitResult();
}
\ No newline at end of file
......@@ -76,6 +76,7 @@ public:
protected:
void doStart() Q_DECL_OVERRIDE;
void doHandleResponse(qint64 tag, const Protocol::Command &response) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(CollectionCopyJob)
......
......@@ -18,13 +18,13 @@
*/
#include "collectioncreatejob.h"
#include <akonadi/private/imapparser_p.h>
#include "protocolhelper_p.h"
#include "job_p.h"
#include <qdebug.h>
#include <akonadi/private/protocol_p.h>
#include <KLocalizedString>
using namespace Akonadi;
class Akonadi::CollectionCreateJobPrivate : public JobPrivate
......@@ -60,39 +60,25 @@ void CollectionCreateJob::doStart()
return;
}
QByteArray command = d->newTag();
if (d->mCollection.parentCollection().id() < 0) {
command += " RID";
Protocol::CreateCollectionCommand cmd;
cmd.setName(d->mCollection.name());
cmd.setParent(ProtocolHelper::entitySetToScope(Collection::List() << d->mCollection.parentCollection()));
cmd.setMimeTypes(d->mCollection.contentMimeTypes());
cmd.setRemoteId(d->mCollection.remoteId());
cmd.setRemoteRevision(d->mCollection.remoteRevision());
cmd.setIsVirtual(d->mCollection.isVirtual());
cmd.setEnabled(d->mCollection.enabled());
cmd.setDisplayPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListDisplay)));
cmd.setSyncPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListDisplay)));
cmd.setIndexPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListIndex)));
cmd.setCachePolicy(ProtocolHelper::cachePolicyToProtocol(d->mCollection.cachePolicy()));
Protocol::Attributes attrs;
for (Attribute *attr : d->mCollection.attributes()) {
attrs.insert(attr->type(), attr->serialized());
}
command += " CREATE " + ImapParser::quote(d->mCollection.name().toUtf8()) + ' ';
if (d->mCollection.parentCollection().id() >= 0) {
command += QByteArray::number(d->mCollection.parentCollection().id());
} else {
command += ImapParser::quote(d->mCollection.parentCollection().remoteId().toUtf8());
}
command += " (";
if (!d->mCollection.contentMimeTypes().isEmpty()) {
QList<QByteArray> cList;
const QStringList mimeTypes = d->mCollection.contentMimeTypes();
cList.reserve(mimeTypes.count());
foreach (const QString &s, mimeTypes) {
cList << s.toLatin1();
}
command += "MIMETYPE (" + ImapParser::join(cList, QByteArray(" ")) + ')';
}
command += " REMOTEID " + ImapParser::quote(d->mCollection.remoteId().toUtf8());
command += " REMOTEREVISION " + ImapParser::quote(d->mCollection.remoteRevision().toUtf8());
command += " VIRTUAL " + QByteArray::number(d->mCollection.isVirtual());
command += ' ' + ProtocolHelper::enabled(d->mCollection.enabled());
command += ' ' + ProtocolHelper::listPreference(Collection::ListDisplay, d->mCollection.localListPreference(Collection::ListDisplay));
command += ' ' + ProtocolHelper::listPreference(Collection::ListSync, d->mCollection.localListPreference(Collection::ListSync));
command += ' ' + ProtocolHelper::listPreference(Collection::ListIndex, d->mCollection.localListPreference(Collection::ListIndex));
foreach (Attribute *attr, d->mCollection.attributes()) {
command += ' ' + attr->type() + ' ' + ImapParser::quote(attr->serialized());
}
command += ' ' + ProtocolHelper::cachePolicyToByteArray(d->mCollection.cachePolicy());
command += ")\n";
d->writeData(command);
cmd.setAttributes(attrs);
d->sendCommand(cmd);
emitWriteFinished();
}
......@@ -103,24 +89,28 @@ Collection CollectionCreateJob::collection() const
return d->mCollection;
}
void CollectionCreateJob::doHandleResponse(const QByteArray &tag, const QByteArray &data)
void CollectionCreateJob::doHandleResponse(qint64 tag, const Protocol::Command &response)
{
Q_D(CollectionCreateJob);
if (tag == "*") {
Collection col;
ProtocolHelper::parseCollection(data, col);
if (!col.isValid()) {
return;
}
col.setParentCollection(d->mCollection.parentCollection());
col.setName(d->mCollection.name());
col.setRemoteId(d->mCollection.remoteId());
col.setRemoteRevision(d->mCollection.remoteRevision());
col.setVirtual(d->mCollection.isVirtual());
d->mCollection = col;
} else {
if (!response.isResponse()) {
Job::doHandleResponse(tag, data);
return;
}
if (response.type() == Protocol::Command::FetchCollections) {
Protocol::FetchCollectionsResponse resp(response);
d->mCollection = ProtocolHelper::parseCollection(resp);
if (!d->mCollection) {
setError(Unknown);
setErrorText(i18n("Failed to parse Collection from response");
emitResult();
}
return;
} else if (response.type() == Protocol::Command::CreateCollection) {
emitResult();
return;
}
Job::doHandleResponse(tag, data);
}
......@@ -77,7 +77,7 @@ public:
protected:
void doStart() Q_DECL_OVERRIDE;
void doHandleResponse(const QByteArray &tag, const QByteArray &data) Q_DECL_OVERRIDE;
void doHandleResponse(qint64 tag, const Protocol::Command &response) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(CollectionCreateJob)
......
......@@ -18,11 +18,12 @@
*/
#include "collectiondeletejob.h"
#include "collection.h"
#include "job_p.h"
#include <protocolhelper_p.h>
#include <akonadi/private/protocol_p.h>
#include <akonadi/private/imapparser_p.h>
#include <KLocalizedString>
using namespace Akonadi;
......@@ -61,9 +62,14 @@ void CollectionDeleteJob::doStart()
return;
}
if (d->mCollection.isValid()) {
d->writeData(d->newTag() + " DELETE " + QByteArray::number(d->mCollection.id()) + '\n');
} else {
d->writeData(d->newTag() + " RID DELETE " + ImapParser::quote(d->mCollection.remoteId().toUtf8()) + '\n');
d->sendCommand(Protocol::DeleteCollectionCommand(ProtocolHelper::entitySetToScope({ d->mCollection })));
}
void CollectionDeleteJob::doHandleResponse(qint64 tag, const Protocol::Command &response)
{
if (!response.isResponse() || response.type() != Protocol::Command::DeleteCollection) {
Job::doHandleResponse(tag, response);
}
emitResult();
}
......@@ -84,6 +84,7 @@ public:
protected:
void doStart() Q_DECL_OVERRIDE;
void doHandleResponse(qint64 tag, const Protocol::Command &response) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(CollectionDeleteJob)
......
......@@ -19,17 +19,18 @@
#include "collectionfetchjob.h"
#include <akonadi/private/imapparser_p.h>
#include "job_p.h"
#include <akonadi/private/protocol_p.h>
#include "protocolhelper_p.h"
#include "entity_p.h"
#include "collectionfetchscope.h"
#include "collectionutils.h"
#include "protocolhelper_p.h"
#include <akonadi/private/protocol_p.h>
#include <qdebug.h>
#include <KLocalizedString>
#include <QtCore/QObject>
#include <QtCore/QHash>
#include <QtCore/QStringList>
#include <QtCore/QTimer>
......@@ -233,70 +234,35 @@ void CollectionFetchJob::doStart()
return;
}
QByteArray command = d->newTag();
if (!d->mBase.isValid()) {
if (CollectionUtils::hasValidHierarchicalRID(d->mBase)) {
command += " HRID";
} else {
command += " " AKONADI_CMD_RID;
}
}
command += " LIST ";
if (d->mBase.isValid()) {
command += QByteArray::number(d->mBase.id());
} else if (CollectionUtils::hasValidHierarchicalRID(d->mBase)) {
command += '(' + ProtocolHelper::hierarchicalRidToByteArray(d->mBase) + ')';
} else {
command += ImapParser::quote(d->mBase.remoteId().toUtf8());
}
command += ' ';
Protocol::FetchCollectionsCommand cmd(ProtocolHelper::entityToScope(d->mBase));
switch (d->mType) {
case Base:
command += "0 (";
cmd.setDepth(Protocol::FetchCollectionsCommand::BaseCollection);
break;
case FirstLevel:
command += "1 (";
case Akonadi::CollectionFetchJob::FirstLevel:
cmd.setDepth(Protocol::FetchCollectionsCommand::ParentCollection);
break;
case Recursive:
command += "INF (";
case Akonadi::CollectionFetchJob::Recursive:
cmd.setDepth(Protocol::FetchCollectionsCommand::AllCollections);
break;
default:
Q_ASSERT(false);
}
QList<QByteArray> filter;
if (!d->mScope.resource().isEmpty()) {
filter.append("RESOURCE");
// FIXME: Does this need to be quoted??
filter.append(d->mScope.resource().toUtf8());
}
const QStringList mimeTypes = d->mScope.contentMimeTypes();
if (!mimeTypes.isEmpty()) {
filter.append("MIMETYPE");
QList<QByteArray> mts;
mts.reserve(mimeTypes.count());
foreach (const QString &mt, mimeTypes) {
// FIXME: Does this need to be quoted??
mts.append(mt.toUtf8());
}
filter.append('(' + ImapParser::join(mts, " ") + ')');
}
cmd.setResource(d->mScope.resource());
cmd.setMimeTypes(d->mScope.contentMimeTypes());
switch (d->mScope.listFilter()) {
case CollectionFetchScope::Display:
filter.append("DISPLAY TRUE");
cmd.setDisplayPref(true);
break;
case CollectionFetchScope::Sync:
filter.append("SYNC TRUE");
cmd.setSyncPref(true);
break;
case CollectionFetchScope::Index:
filter.append("INDEX TRUE");
cmd.setIndexPref(true);
break;
case CollectionFetchScope::Enabled:
filter.append("ENABLED TRUE");
cmd.setEnabled(true);
break;
case CollectionFetchScope::NoFilter:
break;
......@@ -304,59 +270,26 @@ void CollectionFetchJob::doStart()
Q_ASSERT(false);
}
QList<QByteArray> options;
if (d->mScope.includeStatistics()) {
options.append("STATISTICS");
options.append("true");
cmd.setFetchStats(d->mScope.includeStatistics());
switch (d->mScope.ancestorRetrieval()) {
case CollectionFetchScope::None:
cmd.setAncestorsDepth(Protocol::Ancestor::NoAncestor);
break;
case CollectionFetchScope::Parent:
cmd.setAncestorsDepth(Protocol::Ancestor::ParentAncestor);
break;
case CollectionFetchScope::All:
cmd.setAncestorsDepth(Protocol::Ancestor::AllAncestors);
break;
}
if (d->mScope.ancestorRetrieval() != CollectionFetchScope::None) {
options.append("ANCESTORS");
if (d->mScope.ancestorFetchScope().fetchIdOnly()) {
switch (d->mScope.ancestorRetrieval()) {
case CollectionFetchScope::None:
options.append("0");
break;
case CollectionFetchScope::Parent:
options.append("1");
break;
case CollectionFetchScope::All:
options.append("INF");
break;
default:
Q_ASSERT(false);
}
} else {
QByteArray ancestorFetchScope = "(";
ancestorFetchScope += "DEPTH ";
switch (d->mScope.ancestorRetrieval()) {
case CollectionFetchScope::None:
ancestorFetchScope += "0 ";
break;
case CollectionFetchScope::Parent:
ancestorFetchScope += "1 ";
break;
case CollectionFetchScope::All:
ancestorFetchScope += "INF ";
break;
default:
Q_ASSERT(false);
}
ancestorFetchScope += "NAME ";
ancestorFetchScope += "REMOTEID ";
Q_FOREACH (const QByteArray &ancestorAttribute, d->mScope.ancestorFetchScope().attributes()) {
ancestorFetchScope += ancestorAttribute + " ";
}
ancestorFetchScope += ")";
options.append(ancestorFetchScope);
}
cmd.setAncestorsAttributes(d->mScope.ancestorFetchScope().attributes());
}
command += ImapParser::join(filter, " ") + ") (" + ImapParser::join(options, " ") + ")\n";
d->writeData(command);
d->sendCommand(cmd);
}
void CollectionFetchJob::doHandleResponse(const QByteArray &tag, const QByteArray &data)
void CollectionFetchJob::doHandleResponse(qint64 tag, const Protocol::Command &response)
{
Q_D(CollectionFetchJob);
......@@ -364,22 +297,29 @@ void CollectionFetchJob::doHandleResponse(const QByteArray &tag, const QByteArra
return;
}
if (tag == "*") {
Collection collection;
ProtocolHelper::parseCollection(data, collection);
if (!collection.isValid()) {
return;
}
if (!response.isResponse() || response.type() != Protocol::Command::FetchCollections) {
Job::doHandleResponse(tag, response);
return;
}
collection.d_ptr->resetChangeLog();
d->mCollections.append(collection);
d->mPendingCollections.append(collection);
if (!d->mEmitTimer->isActive()) {
d->mEmitTimer->start();
}
Protocol::FetchCollectionsResponse resp(response);
// Invalid response (no ID) means this was the last response
if (resp.id() = -1) {
emitResult();
return;
}
Collection collection = ProtocolHelper::parseCollection(resp, true);
if (!collection.isValid()) {
return;
}
qDebug() << "Unhandled server response" << tag << data;
collection.d_ptr->resetChangeLog();
d->mCollections.append(collection);
d->mPendingCollections.append(collection);
if (!d->mEmitTimer->isActive()) {
d->mEmitTimer->start();
}
}
static Collection::List filterDescendants(const Collection::List &list)
......
......@@ -178,7 +178,7 @@ Q_SIGNALS:
protected:
void doStart() Q_DECL_OVERRIDE;
void doHandleResponse(const QByteArray &tag, const QByteArray &data) Q_DECL_OVERRIDE;
void doHandleResponse(qint64 tag, const Protocol::Command &response) Q_DECL_OVERRIDE;
protected Q_SLOTS:
//@cond PRIVATE
......
......@@ -22,7 +22,6 @@
#include "changemediator_p.h"
#include "collection_p.h"
#include "collectionstatistics.h"
#include <akonadi/private/imapparser_p.h>
#include "job_p.h"
#include "protocolhelper_p.h"
......@@ -60,9 +59,10 @@ CollectionModifyJob::~CollectionModifyJob()
void CollectionModifyJob::doStart()
{
Q_D(CollectionModifyJob);
QByteArray command = d->newTag();
Protocol::ModifyCollectionCommand cmd;
try {
command += ProtocolHelper::entityIdToByteArray(d->mCollection, AKONADI_CMD_COLLECTIONMODIFY);
cmd = Protocol::ModifyCollectionCommand(ProtocolHelper::entityToScope(d->mCollection));
} catch (const std::exception &e) {
setError(Job::Unknown);
setErrorText(QString::fromUtf8(e.what()));
......@@ -70,58 +70,62 @@ void CollectionModifyJob::doStart()
return;
}
QByteArray changes;
if (d->mCollection.d_func()->contentTypesChanged) {
QList<QByteArray> bList;
const QStringList mimeTypes = d->mCollection.contentMimeTypes();
bList.reserve(mimeTypes.count());
foreach (const QString &s, mimeTypes) {
bList << s.toLatin1();
}
changes += " MIMETYPE (" + ImapParser::join(bList, " ") + ')';
cmd.setMimeTypes(d->mCollection.contentMimeTypes());
}
if (d->mCollection.parentCollection().id() >= 0) {
changes += " PARENT " + QByteArray::number(d->mCollection.parentCollection().id());
cmd.setParentId(d->mCollection.parentCollection().id());
}
if (!d->mCollection.name().isEmpty()) {
changes += " NAME " + ImapParser::quote(d->mCollection.name().toUtf8());
cmd.setName(d->mCollection.name());
}
if (!d->mCollection.remoteId().isNull()) {
changes += " REMOTEID " + ImapParser::quote(d->mCollection.remoteId().toUtf8());
cmd.setRemoteId(d->mCollection.remoteId());
}
if (!d->mCollection.remoteRevision().isNull()) {
changes += " REMOTEREVISION " + ImapParser::quote(d->mCollection.remoteRevision().toUtf8());
cmd.setRemoteRevision(d->mCollection.remoteRevision());
}
if (d->mCollection.d_func()->cachePolicyChanged) {
changes += ' ' + ProtocolHelper::cachePolicyToByteArray(d->mCollection.cachePolicy());
cmd.setCachePolicy(ProtocolHelper::cachePolicyToProtocol(d->mCollection.cachePolicy()));
}
if (d->mCollection.d_func()->enabledChanged) {
changes += ' ' + ProtocolHelper::enabled(d->mCollection.enabled());
cmd.setEnabled(d->mCollection.enabled());
}
if (d->mCollection.d_func()->listPreferenceChanged) {
changes += ' ' + ProtocolHelper::listPreference(Collection::ListDisplay, d->mCollection.localListPreference(Collection::ListDisplay));
changes += ' ' + ProtocolHelper::listPreference(Collection::ListSync, d->mCollection.localListPreference(Collection::ListSync));
changes += ' ' + ProtocolHelper::listPreference(Collection::ListIndex, d->mCollection.localListPreference(Collection::ListIndex));
cmd.setDisplayPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListDisplay)));
cmd.setSyncPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListSync)));
cmd.setIndexPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListIndex)));
}
if (d->mCollection.d_func()->referencedChanged) {
changes += ' ' + ProtocolHelper::referenced(d->mCollection.referenced());
cmd.setReferenced(d->mCollection.referenced());
}
if (d->mCollection.attributes().count() > 0) {
changes += ' ' + ProtocolHelper::attributesToByteArray(d->mCollection);
cmd.setAttributes(ProtocolHelper::attributesToProtocol(d->mCollection));
}
foreach (const QByteArray &b, d->mCollection.d_func()->mDeletedAttributes) {
changes += " -" + b;
if (!d->mCollection.d_func()->mDeletedAttributes.isEmpty()) {
cmd.setRemovedAttributes(d->mCollection.d_func()->mDeletedAttributes);
}
if (changes.isEmpty()) {
if (cmd.modifiedParts() == Protocol::ModifyCollectionCommand::None) {
emitResult();
return;
}
command += changes + '\n';
d->writeData(command);
d->sendCommand(cmd);
ChangeMediator::invalidateCollection(d->mCollection);
}
void CollectionModifyJob::doHandleResponse(qint64 tag, const Protocol::Command &response)
{
if (!response.isResponse() || response.type() != Protocol::Command::ModifyCollection) {
Job::doHandleResponse(tag, response);
return;
}
emitResult();
}
Collection CollectionModifyJob::collection() const
{
const Q_D(CollectionModifyJob);
......
......@@ -109,6 +109,7 @@ public:
protected:
void doStart() Q_DECL_OVERRIDE;
void doHandleResponse(qint64 tag, const Protocol::Command &response) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(CollectionModifyJob)
......
......@@ -20,17 +20,23 @@
#include "collectionmovejob.h"
#include "collection.h"
#include "job_p.h"
#include "movejobimpl_p.h"
#include "protocolhelper_p.h"
#include <akonadi/private/protocol_p.h>
using namespace Akonadi;
class Akonadi::CollectionMoveJobPrivate : public MoveJobImpl<Collection, CollectionMoveJob>
class Akonadi::CollectionMoveJobPrivate : public JobPrivate
{
public:
CollectionMoveJobPrivate(CollectionMoveJob *parent)
: MoveJobImpl<Collection, CollectionMoveJob>(parent)
: JobPrivate(parent)