Commit 0548dd1f authored by Daniel Vrátil's avatar Daniel Vrátil 🤖

Allow FETCH and DELETE without SELECT and implement Tags-based fetch

Akonadi server now supports doing FETCHes without having to do SELECT
before. This ports the ItemFetchJob and ItemDeleteJob to the new
syntax and extends ItemFetchJob API to allow fetching all items
tagged with a specific tag.
parent 85f5152d
......@@ -31,7 +31,7 @@ class CollectionSelectJobPrivate;
* @internal
* Selects a specific collection. See RFC 3501 for select semantics.
*/
class AKONADI_EXPORT CollectionSelectJob : public Job
class AKONADI_DEPRECATED_EXPORT CollectionSelectJob : public Job
{
Q_OBJECT
public:
......
......@@ -39,24 +39,13 @@ public:
{
}
void selectResult(KJob *job);
Q_DECLARE_PUBLIC(ItemDeleteJob)
Item::List mItems;
Collection mCollection;
Tag mTag;
};
void ItemDeleteJobPrivate::selectResult(KJob *job)
{
if (job->error()) {
return; // KCompositeJob takes care of errors
}
const QByteArray command = newTag() + " " AKONADI_CMD_ITEMDELETE " 1:*\n";
writeData(command);
}
ItemDeleteJob::ItemDeleteJob(const Item &item, QObject *parent)
: Job(new ItemDeleteJobPrivate(this), parent)
{
......@@ -96,23 +85,11 @@ void ItemDeleteJob::doStart()
{
Q_D(ItemDeleteJob);
if (!d->mItems.isEmpty()) {
QByteArray command = d->newTag();
try {
command += ProtocolHelper::entitySetToByteArray(d->mItems, AKONADI_CMD_ITEMDELETE);
} catch (const std::exception &e) {
setError(Unknown);
setErrorText(QString::fromUtf8(e.what()));
emitResult();
return;
}
command += '\n';
d->writeData(command);
} else {
CollectionSelectJob *job = new CollectionSelectJob(d->mCollection, this);
connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
addSubjob(job);
}
QByteArray command = d->newTag();
command += ProtocolHelper::commandContextToByteArray(d->mCollection, d->mTag, d->mItems, AKONADI_CMD_ITEMDELETE);
command += '\n';
d->writeData(command);
}
#include "moc_itemdeletejob.cpp"
......@@ -114,6 +114,17 @@ public:
*/
explicit ItemDeleteJob(const Collection &collection, QObject *parent = 0);
/**
* Creates a new item delete job that deletes all items that have assigned
* the tag @p tag.
*
* @param tag The tag which content should be deleted.
* @param parent The parent object.
*
* @since 4.14
*/
explicit ItemDeleteJob(const Tag &tag, QObject *parent = 0);
/**
* Destroys the item delete job.
*/
......@@ -131,7 +142,6 @@ protected:
private:
//@cond PRIVATE
Q_DECLARE_PRIVATE(ItemDeleteJob)
Q_PRIVATE_SLOT(d_func(), void selectResult(KJob *))
//@endcond
};
......
......@@ -82,9 +82,6 @@ public:
}
}
void startFetchJob();
void selectDone(KJob *job);
QString jobDebuggingString() const /*Q_DECL_OVERRIDE*/
{
if (mRequestedItems.isEmpty()) {
......@@ -105,6 +102,7 @@ public:
Q_DECLARE_PUBLIC(ItemFetchJob)
Collection mCollection;
Tag mTag;
Item::List mRequestedItems;
Item::List mResultItems;
ItemFetchScope mFetchScope;
......@@ -115,43 +113,6 @@ public:
int mCount;
};
void ItemFetchJobPrivate::startFetchJob()
{
Q_Q(ItemFetchJob);
QByteArray command = newTag();
if (mRequestedItems.isEmpty()) {
command += " " AKONADI_CMD_ITEMFETCH " 1:*";
} else {
try {
command += ProtocolHelper::entitySetToByteArray(mRequestedItems, AKONADI_CMD_ITEMFETCH);
} catch (const Exception &e) {
q->setError(Job::Unknown);
q->setErrorText(QString::fromUtf8(e.what()));
q->emitResult();
return;
}
}
//This is only required for 4.10
if (protocolVersion() < 30) {
if (mFetchScope.ignoreRetrievalErrors()) {
kDebug() << "IGNOREERRORS is not available with this akonadi protocol version";
}
mFetchScope.setIgnoreRetrievalErrors(false);
}
command += ProtocolHelper::itemFetchScopeToByteArray(mFetchScope);
writeData(command);
}
void ItemFetchJobPrivate::selectDone(KJob *job)
{
if (!job->error()) {
// the collection is now selected, fetch the message(s)
startFetchJob();
}
}
ItemFetchJob::ItemFetchJob(const Collection &collection, QObject *parent)
: Job(new ItemFetchJobPrivate(this), parent)
{
......@@ -191,6 +152,16 @@ ItemFetchJob::ItemFetchJob(const QList<Akonadi::Item::Id> &items, QObject *paren
}
}
ItemFetchJob::ItemFetchJob(const Tag &tag, QObject *parent)
: Job(new ItemFetchJobPrivate(this), parent)
{
Q_D(ItemFetchJob);
d->init();
d->mTag = tag;
d->mValuePool = new ProtocolHelperValuePool;
}
ItemFetchJob::~ItemFetchJob()
{
}
......@@ -199,19 +170,19 @@ void ItemFetchJob::doStart()
{
Q_D(ItemFetchJob);
if (d->mCollection == Collection::root()) {
if (d->mRequestedItems.isEmpty()) { // collection content listing
setErrorText(i18n("Cannot list root collection."));
setError(Unknown);
emitResult();
} else {
d->startFetchJob();
QByteArray command = d->newTag();
command += ProtocolHelper::commandContextToByteArray(d->mCollection, d->mTag, d->mRequestedItems, AKONADI_CMD_ITEMFETCH);
// This is only required for 4.10
if (d->protocolVersion() < 30) {
if (d->mFetchScope.ignoreRetrievalErrors()) {
kDebug() << "IGNOREERRORS is not available with this version of Akonadi server";
}
} else {
CollectionSelectJob *job = new CollectionSelectJob(d->mCollection, this);
connect(job, SIGNAL(result(KJob*)), SLOT(selectDone(KJob*)));
addSubjob(job);
d->mFetchScope.setIgnoreRetrievalErrors(false);
}
command += ProtocolHelper::itemFetchScopeToByteArray(d->mFetchScope);
d->writeData(command);
}
void ItemFetchJob::doHandleResponse(const QByteArray &tag, const QByteArray &data)
......
......@@ -135,6 +135,17 @@ public:
*/
explicit ItemFetchJob(const QList<Item::Id> &items, QObject *parent = 0);
/**
* Creates a new item fetch job that retrieves all items tagged with specified @p tag.
*
* @param tag The tag to fetch all items from.
* @param parent The parent object.
*
* @since 4.14
*/
explicit ItemFetchJob(const Tag &tag, QObject *parent = 0);
/**
* Destroys the item fetch job.
*/
......@@ -255,7 +266,6 @@ private:
Q_DECLARE_PRIVATE(ItemFetchJob)
//@cond PRIVATE
Q_PRIVATE_SLOT(d_func(), void selectDone(KJob *))
Q_PRIVATE_SLOT(d_func(), void timeout())
//@endcond
};
......
......@@ -336,6 +336,36 @@ QByteArray ProtocolHelper::tagSetToByteArray( const Tag::List &_objects, const Q
throw Exception( "Not all tags have a uid" );
}
QByteArray ProtocolHelper::commandContextToByteArray(const Akonadi::Collection &collection, const Akonadi::Tag &tag,
const Item::List &requestedItems, const QByteArray &command)
{
QByteArray r = " ";
if (requestedItems.isEmpty()) {
r += command + " 1:*";
} else {
r += ProtocolHelper::entitySetToByteArray(requestedItems, command);
}
if (tag.isValid()) {
r += " " AKONADI_PARAM_TAGID " " + QByteArray::number(tag.id()) + " ";
}
if (collection == Collection::root()) {
if (requestedItems.isEmpty()) { // collection content listing
throw Exception("Cannot perform item operations on root collection.");
}
} else {
if (collection.isValid()) {
r += " " AKONADI_PARAM_COLLECTIONID " " + QByteArray::number(collection.id()) + ' ';
} else if (!collection.remoteId().isEmpty()) {
r += " " AKONADI_PARAM_COLLECTION " " + collection.remoteId().toLatin1() + ' ';
}
}
return r;
}
QByteArray ProtocolHelper::hierarchicalRidToByteArray( const Collection &col )
{
if ( col == Collection::root() )
......
......@@ -192,6 +192,10 @@ public:
static QByteArray tagSetToImapSequenceSet(const Akonadi::Tag::List &_objects);
static QByteArray tagSetToByteArray(const Akonadi::Tag::List &_objects, const QByteArray &command);
static QByteArray commandContextToByteArray(const Akonadi::Collection &collection, const Akonadi::Tag &tag,
const Item::List &requestedItems, const QByteArray &command);
/**
Converts the given object identifier into a protocol representation.
@throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment