[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [KSecretService] 28c4090: Refactor the generic backends and its
From: Michael Leupold <lemma () confuego ! org>
Date: 2010-11-09 19:14:26
Message-ID: 20101109191426.BB6A8A60DE () git ! kde ! org
[Download RAW message or body]
A daemon/tests/tempblockingjobs.h [License: GPL(v2)]
A daemon/tests/tempblockingjobs.cpp [License: GPL(v2)]
A backend/temporary/temporaryjobs.h [License: GPL(v2)]
A backend/temporary/temporaryjobs.cpp [License: GPL(v2)]
A backend/ksecret/ksecretjobs.h [License: GPL(v2)]
A backend/ksecret/ksecretjobs.cpp [License: GPL(v2)]
A backend/ksecret/TODO [License: Trivialfile.]
A backend/backendjob.h [License: GPL(v2)]
A backend/backendjob.cpp [License: GPL(v2)]
commit 28c4090dc655cce6662a8b7987032df2a8e9947b
Author: Michael Leupold <lemma@confuego.org>
Date: Sat Aug 28 20:45:38 2010 +0000
Refactor the generic backends and its implementation to use the new internal \
QueuedJob/BackendJob API. Adapt unit-test to succeed. Add unit-tests for the \
asynchronous backend methods. Add missing Q_OBJECT macro.
Fix the D-Bus daemon part to play along nicely with the new BackendJob classes. \
Unit-tests up and running again.
svn path=/trunk/playground/base/ksecretservice/; revision=1169252
diff --git a/TODO b/TODO
index c33bb8e..b622496 100644
--- a/TODO
+++ b/TODO
@@ -9,3 +9,5 @@ There's still plenty of things to do (assorted, incomplete):
/proc)
- ways to implement calls that require used-interaction (authorization)
- devising a new file-format that supports the features of the D-Bus API
+- do Prompt objects need a maximum lifetime? It seems misbehaving clients could just
+ create a lot of them and neither execute nor dismiss them
\ No newline at end of file
diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt
index c2da991..f5e127b 100644
--- a/backend/CMakeLists.txt
+++ b/backend/CMakeLists.txt
@@ -3,20 +3,21 @@ ADD_SUBDIRECTORY (tests)
SET (ksecretservice_backend_SRCS
# Backend
- backendbase.cpp
+ backendjob.cpp
backendcollection.cpp
backendcollectionmanager.cpp
backenditem.cpp
backendmaster.cpp
- asynccall.cpp
securebuffer.cpp
temporary/temporarycollection.cpp
temporary/temporarycollectionmanager.cpp
temporary/temporaryitem.cpp
+ temporary/temporaryjobs.cpp
ksecret/ksecretfile.cpp
ksecret/ksecretcollectionmanager.cpp
ksecret/ksecretcollection.cpp
ksecret/ksecretitem.cpp
+ ksecret/ksecretjobs.cpp
)
KDE4_ADD_LIBRARY (ksecretservicebackend STATIC ${ksecretservice_backend_SRCS})
diff --git a/backend/asynccall.cpp b/backend/asynccall.cpp
deleted file mode 100644
index df545e8..0000000
--- a/backend/asynccall.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "asynccall.h"
-#include "backendmaster.h"
-#include "backendcollectionmanager.h"
-#include "backendcollection.h"
-#include "backenditem.h"
-#include <QDebug>
-
-AsyncCall::AsyncCall(AsyncType type, BackendBase *destination)
- : QObject(destination), m_destination(destination), m_type(type), \
m_enqueued(false),
- m_executed(false), m_completed(false), m_dismissed(false), m_error(NoError)
-{
-}
-
-AsyncCall::~AsyncCall()
-{
-}
-
-AsyncCall::AsyncType AsyncCall::type() const
-{
- return m_type;
-}
-
-bool AsyncCall::isCompleted() const
-{
- return m_completed;
-}
-
-bool AsyncCall::isDismissed() const
-{
- return m_dismissed;
-}
-
-ErrorType AsyncCall::error() const
-{
- return m_error;
-}
-
-const QString &AsyncCall::windowId() const
-{
- return m_windowId;
-}
-
-void AsyncCall::setError(ErrorType error)
-{
- m_error = error;
- m_completed = true;
- emit completed(this, false);
-}
-
-BackendBase *AsyncCall::destination() const
-{
- return m_destination;
-}
-
-void AsyncCall::enqueue(const QString &windowId)
-{
- if (!m_enqueued) {
- m_enqueued = true;
- m_windowId = windowId;
- m_destination->enqueueCall(this);
- }
-}
-
-bool AsyncCall::dismiss()
-{
- // only dismiss if not already dismissed
- if (!m_dismissed) {
- if (!m_enqueued) {
- // not executed yet
- m_completed = true;
- m_dismissed = true;
- emit completed(this, true);
- deleteLater();
- } else {
- // TODO: try to dismiss in parent
- deleteLater();
- return false;
- }
- }
-
- return true;
-}
-
-void AsyncCall::complete()
-{
- // only complete if not already completed
- if (!m_completed) {
- m_completed = true;
- m_dismissed = false;
- emit completed(this, false);
- deleteLater();
- }
-}
-
-void AsyncCall::slotCompleted(AsyncCall *, bool)
-{
- // TODO: kFatal: this call can't be chained
- Q_ASSERT(false);
-}
-
-AsyncSimpleBooleanCall::AsyncSimpleBooleanCall(AsyncCall::AsyncType type, \
BackendBase *destination)
- : AsyncCall(type, destination)
-{
-}
-
-bool AsyncSimpleBooleanCall::result() const
-{
- return m_result;
-}
-
-void AsyncSimpleBooleanCall::execute()
-{
- BackendReturn<bool> rc(false);
-
- BackendItem *item = qobject_cast<BackendItem*>(destination());
- BackendCollection *collection = qobject_cast<BackendCollection*>(destination());
- Q_ASSERT(item != 0 || collection != 0);
-
- switch (type()) {
-
- case AsyncCall::AsyncUnlock:
- if (item) {
- rc = item->unlock();
- } else {
- rc = collection->unlock();
- }
- break;
-
- case AsyncCall::AsyncLock:
- if (item) {
- rc = item->lock();
- } else {
- rc = collection->lock();
- }
- break;
-
- case AsyncCall::AsyncDeleteCollection:
- Q_ASSERT(collection);
- rc = collection->deleteCollection();
- break;
-
- case AsyncCall::AsyncChangeAuthentication:
- if (item) {
- rc = item->changeAuthentication();
- } else {
- rc = collection->changeAuthentication();
- }
- break;
- case AsyncCall::AsyncDeleteItem:
- Q_ASSERT(item);
- rc = item->deleteItem();
- break;
-
- default:
- // TODO: kFatal
- Q_ASSERT(false);
- break;
- }
-
- if (rc.isError()) {
- setError(rc.error());
- } else {
- m_result = rc.value();
- complete();
- }
- deleteLater();
-}
-
-void AsyncSimpleBooleanCall::slotCompleted(AsyncCall *call, bool dismissed)
-{
- Q_ASSERT(type() == call->type());
- if (dismissed) {
- // if the call we're attached to was dismissed, re-enqueue this call
- enqueue(windowId());
- } else {
- AsyncSimpleBooleanCall *other = qobject_cast<AsyncSimpleBooleanCall*>(call);
- // a different type signals a serious logical error somewhere else.
- Q_ASSERT(other);
- m_result = other->result();
- emit completed(this, false);
- }
-}
-
-AsyncCreateCollectionMaster::AsyncCreateCollectionMaster(const QString &label, bool \
locked,
- BackendMaster *master)
- : AsyncCall(AsyncCall::AsyncCreateCollectionMaster, master), m_master(master),
- m_label(label), m_locked(locked), m_result(0)
-{
- Q_ASSERT(master);
-}
-
-const QString &AsyncCreateCollectionMaster::label() const
-{
- return m_label;
-}
-
-bool AsyncCreateCollectionMaster::locked() const
-{
- return m_locked;
-}
-
-BackendCollection *AsyncCreateCollectionMaster::result() const
-{
- return m_result;
-}
-
-void AsyncCreateCollectionMaster::execute()
-{
- BackendReturn<BackendCollection*> rc = m_master->createCollection(m_label, \
m_locked);
- if (rc.isError()) {
- m_result = 0;
- delete rc.value();
- setError(rc.error());
- } else {
- m_result = rc.value();
- complete();
- }
- deleteLater();
-}
-
-AsyncCreateCollection::AsyncCreateCollection(const QString &label, bool locked,
- BackendCollectionManager *manager)
- : AsyncCall(AsyncCall::AsyncCreateCollection, manager), m_manager(manager),
- m_label(label), m_locked(locked), m_result(0)
-{
- Q_ASSERT(manager);
-}
-
-const QString &AsyncCreateCollection::label() const
-{
- return m_label;
-}
-
-bool AsyncCreateCollection::locked() const
-{
- return m_locked;
-}
-
-BackendCollection *AsyncCreateCollection::result() const
-{
- return m_result;
-}
-
-void AsyncCreateCollection::execute()
-{
- BackendReturn<BackendCollection*> rc = m_manager->createCollection(m_label, \
m_locked);
- if (rc.isError()) {
- m_result = 0;
- delete rc.value();
- setError(rc.error());
- } else {
- m_result = rc.value();
- complete();
- }
- deleteLater();
-}
-
-AsyncCreateItem::AsyncCreateItem(const QString &label, const QMap<QString, QString> \
&attributes,
- const QCA::SecureArray &secret, bool locked, bool \
replace,
- BackendCollection *collection)
- : AsyncCall(AsyncCall::AsyncCreateItem, collection), m_collection(collection), \
m_label(label),
- m_attributes(attributes), m_secret(secret), m_locked(locked), m_replace(replace),
- m_result(0)
-{
- Q_ASSERT(collection != 0);
-}
-
-const QString &AsyncCreateItem::label() const
-{
- return m_label;
-}
-
-const QMap<QString, QString> &AsyncCreateItem::attributes() const
-{
- return m_attributes;
-}
-
-const QCA::SecureArray &AsyncCreateItem::secret() const
-{
- return m_secret;
-}
-
-bool AsyncCreateItem::locked() const
-{
- return m_locked;
-}
-
-bool AsyncCreateItem::replace() const
-{
- return m_replace;
-}
-
-BackendItem *AsyncCreateItem::result() const
-{
- return m_result;
-}
-
-BackendCollection *AsyncCreateItem::collection() const
-{
- return m_collection;
-}
-
-void AsyncCreateItem::execute()
-{
- BackendReturn<BackendItem*> rc = m_collection->createItem(m_label, m_attributes, \
m_secret,
- m_replace, m_locked);
- if (rc.isError()) {
- m_result = 0;
- delete rc.value();
- setError(rc.error());
- } else {
- m_result = rc.value();
- complete();
- }
- deleteLater();
-}
-
-#include "asynccall.moc"
diff --git a/backend/asynccall.h b/backend/asynccall.h
deleted file mode 100644
index b913aa3..0000000
--- a/backend/asynccall.h
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BACKENDASYNCCALL_H
-#define BACKENDASYNCCALL_H
-
-#include "backendreturn.h"
-
-#include <QtCore/QObject>
-#include <QtCrypto/QtCrypto>
-
-class BackendBase;
-class BackendMaster;
-class BackendCollection;
-class BackendCollectionManager;
-class BackendItem;
-
-/**
- * Base class for backend async call objects.
- *
- * An async call encapsulates an action that might be delayed because it
- * requires user input or has to wait for another action to be completed
- * before it can be performed.
- */
-class AsyncCall : public QObject
-{
- Q_OBJECT
-
-public:
- friend class BackendBase;
-
- /**
- * Type of the async call.
- */
- enum AsyncType {
- AsyncCreateCollectionMaster,
- AsyncCreateCollection,
- AsyncUnlock,
- AsyncLock,
- AsyncDeleteCollection,
- AsyncCreateItem,
- AsyncDeleteItem,
- AsyncChangeAuthentication
- };
-
- /**
- * Constructor
- *
- * @param type type of the call
- * @param base backend base object that will execute the call; this object also
- * becomes the call's parent
- */
- AsyncCall(AsyncType type, BackendBase *destination);
-
- /**
- * Destructor
- */
- virtual ~AsyncCall();
-
- /**
- * Get the async call's type.
- *
- * @return the async call's type
- */
- AsyncType type() const;
-
- /**
- * Check if the encapsulated action is completed.
- *
- * @return true if the encapsulated action is completed, false else.
- * @remarks An async call can set itself to completed even before execute() is
- * called (ie. the action doesn't need to be delayed).
- */
- bool isCompleted() const;
-
- /**
- * Check if the encapsulated action was dismissed or canceled.
- *
- * @return true if the encapsulated action was dismissed or canceled,
- * false else
- */
- bool isDismissed() const;
-
- /**
- * Check if the encapsulated action had an error.
- *
- * @return the error or NoError if there was no error
- */
- ErrorType error() const;
-
- /**
- * Get the window id associated with this async call.
- *
- * @return the window id or 0 if there's no window id or the call is not yet
- * being executed.
- */
- const QString &windowId() const;
-
- /**
- * Set this call erroneous and complete the call.
- *
- * @param error the type of the error to return
- */
- void setError(ErrorType error);
-
- /**
- * Get the call's destination object.
- *
- * @return the destination the call will be enqueued at
- */
- BackendBase *destination() const;
-
-protected:
- /**
- * Execute the call by calling the corresponding backend object's method.
- */
- virtual void execute() = 0;
-
- /**
- * Set this call completed, send the completed signal to everyone listening
- * and schedule this object for deletion.
- */
- void complete();
-
-public Q_SLOTS:
- /**
- * The enqueue call enqueues the call in the corresponding object's call
- * queue and schedules it for execution.
- *
- * @param windowId if there's a dialog to be shown, it will be modal
- * to the window with this id.
- * @todo make sense of the WId parameter
- */
- void enqueue(const QString &windowId = QString());
-
- /**
- * Dismiss or cancel the pending call.
- *
- * @return true if the action was dismissed successfully, false else
- * @remarks There's no guarantee that dismissing or cancelling will
- * work for a certain action (some might be uncancelable).
- */
- bool dismiss();
-
-protected Q_SLOTS:
- /**
- * This slot can be connected to a second calL's completed signal and will
- * chain the calls together. If the connected call completes, this call copies \
the
- * results and reemits the signals.
- *
- * @param call the async call that completed
- * @param dismissed true if the call was dismissed, false else
- */
- virtual void slotCompleted(AsyncCall *call, bool dismissed);
-
-Q_SIGNALS:
- /**
- * Signals the completion of the encapsulated action.
- *
- * @param call the actual async call
- * @param dismissed true if the call was dismissed, false else
- *
- * @remarks The call handles its own deletion. If you need any of the call
- * object's properties after the slot connected to this signal has
- * been called, you have to copy them.
- */
- void completed(AsyncCall *call, bool dismissed);
-
-private:
- BackendBase *m_destination;
-
- AsyncType m_type;
- QString m_windowId;
- bool m_enqueued;
- bool m_executed;
- bool m_completed;
- bool m_dismissed;
- ErrorType m_error;
-};
-
-/**
- * Class that encapsulates all calls which take no arguments and return a boolean
- * value.
- */
-class AsyncSimpleBooleanCall : public AsyncCall
-{
- Q_OBJECT
-
-public:
- /**
- * Constructor for creating a call to an item or a collection.
- *
- * @param type detailed type of the call
- * @param destination destination item for the call
- */
- AsyncSimpleBooleanCall(AsyncCall::AsyncType type, BackendBase *destination);
-
- /**
- * The result of the call.
- *
- * @return the call's result. If the call wasn't completed successfully, the \
value
- * is undefined.
- */
- bool result() const;
-
-protected:
- /**
- * Execute the call by calling the corresponding backend object's method.
- */
- virtual void execute();
-
-protected Q_SLOTS:
- /**
- * This slot can be connected to a second calL's completed signal and will
- * chain the calls together. If the connected call completes, this call copies \
the
- * results and reemits the signals.
- *
- * @param call the async call that completed
- * @param dismissed true if the call was dismissed, false else
- */
- virtual void slotCompleted(AsyncCall *call, bool dismissed);
-
-private:
- bool m_result;
-};
-
-/**
- * Call for creating a new collection. This call is queued in the BackendMaster and
- * lets the user choose the type of collection to create.
- */
-class AsyncCreateCollectionMaster : public AsyncCall
-{
- Q_OBJECT
-
-public:
- /**
- * Constructor.
- *
- * @param label human-readable label for the new collection
- * @param locked true if the collection should be locked after creation, false \
else
- * @param master the master used to create the collection
- */
- AsyncCreateCollectionMaster(const QString &label, bool locked,
- BackendMaster *master);
-
- /**
- * The label to assign to the new collection.
- */
- const QString &label() const;
-
- /**
- * If true, the new collection should be created locked, if false it should be
- * unlocked after creation.
- */
- bool locked() const;
-
- /**
- * The collection that was created or 0 if creating the collection failed.
- */
- BackendCollection *result() const;
-
-protected:
- /**
- * Execute the call by calling the corresponding backend object's method.
- */
- virtual void execute();
-
-private:
- BackendMaster *m_master;
- QString m_label;
- bool m_locked;
-
- BackendCollection *m_result;
-};
-
-/**
- * Call for creating a new collection. This directly calls the backend that's \
supposed
- * to create the collection.
- */
-class AsyncCreateCollection : public AsyncCall
-{
- Q_OBJECT
-
-public:
- /**
- * Constructor.
- *
- * @param label human-readable label for the new collection
- * @param locked true if the collection should be locked after creation, false \
else
- * @param manager the manager used to create the collection
- */
- AsyncCreateCollection(const QString &label, bool locked,
- BackendCollectionManager *manager);
-
- /**
- * The label to assign to the new collection.
- */
- const QString &label() const;
-
- /**
- * If true, the new collection should be created locked, if false it should be
- * unlocked after creation.
- */
- bool locked() const;
-
- /**
- * The collection that was created or 0 if creating the collection failed.
- */
- BackendCollection *result() const;
-
-protected:
- /**
- * Execute the call by calling the corresponding backend object's method.
- */
- virtual void execute();
-
-private:
- BackendCollectionManager *m_manager;
- QString m_label;
- bool m_locked;
-
- BackendCollection *m_result;
-};
-
-/**
- * Call for creating a new item.
- */
-class AsyncCreateItem : public AsyncCall
-{
- Q_OBJECT
-
-public:
- friend class BackendCollection;
-
- /**
- * Constructor.
- *
- * @param label human-readable label for the new item
- * @param attributes attributes to set for the new item
- * @param secret the secret to store
- * @param locked true if the item should be locked after creation, false else
- * @param replace if true, replace an item with the same attributes if it already \
exists
- * @param collection Collection to create the item in
- */
- AsyncCreateItem(const QString &label, const QMap<QString, QString> &attributes,
- const QCA::SecureArray &secret, bool locked, bool replace,
- BackendCollection *collection);
-
- /**
- * The label to assign to the new item.
- */
- const QString &label() const;
-
- /**
- * The attributes to assign to the new item.
- */
- const QMap<QString, QString> &attributes() const;
-
- /**
- * The secret that should be stored.
- *
- * @todo make secure
- */
- const QCA::SecureArray &secret() const;
-
- /**
- * If true, the new item should be created locked, if false it should be unlocked
- * after creation.
- */
- bool locked() const;
-
- /**
- * If true, an existing item with the same attributes should be replaced by the \
new item,
- * if false creating an item with the same attributes as an existing item will \
fail.
- *
- * @todo or will it create a second item?
- */
- bool replace() const;
-
- /**
- * The item that was created or 0 if creating the item failed.
- */
- BackendItem *result() const;
-
- /**
- * The collection inside which the item should be created.
- */
- BackendCollection *collection() const;
-
-protected:
- /**
- * Execute the call by calling the corresponding backend object's method.
- */
- virtual void execute();
-
-private:
- BackendCollection *m_collection;
- QString m_label;
- QMap<QString, QString> m_attributes;
- QCA::SecureArray m_secret;
- bool m_locked;
- bool m_replace;
-
- BackendItem *m_result;
-};
-
-#endif
diff --git a/backend/backendbase.cpp b/backend/backendbase.cpp
deleted file mode 100644
index 9cf2c8d..0000000
--- a/backend/backendbase.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "backendbase.h"
-#include "backendreturn.h"
-#include "asynccall.h"
-
-#include <QtCore/QQueue>
-#include <QtCore/QTimer>
-
-BackendBase::BackendBase(QObject *parent)
- : QObject(parent), m_processingCall(false)
-{
-}
-
-BackendBase::~BackendBase()
-{
- // TODO: handle remaining calls
-}
-
-void BackendBase::enqueueCall(AsyncCall *call)
-{
- // if the call is an unlock call, try to "merge" it with an already existing
- // unlock call by chaining the previous call's completed signal to this call's
- // slotCompleted.
- bool merged = false;
-
- if (call->type() == AsyncCall::AsyncUnlock) {
- Q_FOREACH(AsyncCall *other, m_pendingCalls) {
- if (other->type() == AsyncCall::AsyncUnlock) {
- call->connect(other, SIGNAL(completed(AsyncCall*, bool)),
- SLOT(slotCompleted(AsyncCall*, bool)));
- merged = true;
- break;
- }
- }
- }
-
- if (!merged) {
- m_pendingCalls.enqueue(call);
- }
-
- if (!m_processingCall) {
- QTimer::singleShot(0, this, SLOT(processCalls()));
- }
-}
-
-bool BackendBase::queueContainsCall(AsyncCall::AsyncType type) const
-{
- Q_FOREACH(AsyncCall *call, m_pendingCalls) {
- if (call && call->type() == type) {
- return true;
- }
- }
-
- return false;
-}
-
-void BackendBase::processCalls()
-{
- // only process if not processing yet
- if (!m_processingCall && !m_pendingCalls.isEmpty()) {
- m_processingCall = true;
-
- // get the next call to process
- AsyncCall *currentCall = 0;
- while (currentCall == 0) {
- if (m_pendingCalls.isEmpty()) {
- m_processingCall = false;
- return;
- } else {
- currentCall = m_pendingCalls.dequeue();
- }
- }
-
- // process the call
- currentCall->execute();
- m_processingCall = false;
-
- // keep processing
- if (!m_pendingCalls.isEmpty()) {
- QTimer::singleShot(0, this, SLOT(processCalls()));
- }
- }
-}
-
-#include "backendbase.moc"
diff --git a/backend/backendbase.h b/backend/backendbase.h
deleted file mode 100644
index 8e31cd7..0000000
--- a/backend/backendbase.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BACKENDBASE_H
-#define BACKENDBASE_H
-
-#include "asynccall.h"
-
-#include <QtCore/QObject>
-#include <QtCore/QQueue>
-
-/**
- * Base for classes implementing the processing of pending calls
- * (CollectionManager, Collection, Item).
- */
-class BackendBase : public QObject
-{
- Q_OBJECT
-
-public:
- /**
- * Constructor.
- *
- * @param parent parent object
- */
- BackendBase(QObject *parent);
-
- /**
- * Destructor.
- */
- virtual ~BackendBase();
-
- /**
- * Enqueue an async call for processing.
- *
- * @param call Call to enqueue
- */
- void enqueueCall(AsyncCall *call);
-
- /**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
- *
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is
- * required.
- */
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const = 0;
-
-protected:
- /**
- * Check if the queue contains a call with the type given.
- *
- * @param type the type of call to search for in the queue
- * @return true if the queue contains a call of this type,
- * false if it doesn't
- * @remarks this method is meant to be called by child classes
- * inside the isCallImmediate() method to decide based
- * on the state of the queue.
- */
- bool queueContainsCall(AsyncCall::AsyncType type) const;
-
-private Q_SLOTS:
- /**
- * Start processing of enqueued calls.
- */
- void processCalls();
-
-private:
- QQueue<AsyncCall*> m_pendingCalls; // queue of waiting calls
- bool m_processingCall; // true if a call is currently being \
processed
-};
-
-#endif
diff --git a/backend/backendcollection.cpp b/backend/backendcollection.cpp
index 9720cb0..49f7f0a 100644
--- a/backend/backendcollection.cpp
+++ b/backend/backendcollection.cpp
@@ -21,9 +21,9 @@
#include "backendcollection.h"
#include "backenditem.h"
#include "backendcollectionmanager.h"
-#include "asynccall.h"
-BackendCollection::BackendCollection(BackendCollectionManager *manager) : \
BackendBase(manager) +BackendCollection::BackendCollection(BackendCollectionManager \
*manager) + : QObject(manager)
{
}
diff --git a/backend/backendcollection.h b/backend/backendcollection.h
index 26bd29d..1e72e4f 100644
--- a/backend/backendcollection.h
+++ b/backend/backendcollection.h
@@ -21,8 +21,10 @@
#ifndef BACKENDCOLLECTION_H
#define BACKENDCOLLECTION_H
-#include "backendbase.h"
#include "backendreturn.h"
+#include "backendjob.h"
+
+#include <jobqueue.h>
#include <QtCore/QObject>
#include <QtCore/QString>
@@ -31,8 +33,6 @@
#include <QtCore/QMap>
#include <QtCrypto/QtCrypto>
-class AsyncSimpleBooleanCall;
-class AsyncCreateItem;
class BackendCollectionManager;
class BackendItem;
@@ -44,14 +44,11 @@ class BackendItem;
* \sa itemCreated, \sa itemDeleted, \sa itemChanged, \sa collectionDeleted and
* \sa collectionChanged signals.
*/
-class BackendCollection : public BackendBase
+class BackendCollection : public QObject, public JobQueue
{
Q_OBJECT
public:
- friend class AsyncSimpleBooleanCall;
- friend class AsyncCreateItem;
-
/**
* Constructor
*/
@@ -116,36 +113,22 @@ public:
const QMap<QString, QString> &attributes) const = 0;
/**
- * Unlock this collection.
- *
- * @return true if the collection is now unlocked, false if unlocking
- * failed.
- * @remarks this is only called by processCall.
+ * Create a job for unlocking this collection.
*/
- virtual BackendReturn<bool> unlock() = 0;
+ virtual UnlockCollectionJob *createUnlockJob() = 0;
/**
- * Lock this collection.
- *
- * @return true if the collection is now locked, false if locking
- * failed (the collection couldn't be locked or unlocking is not
- * supported by this backend).
- * @remarks this is only called by processCall. To set a lock call
- * erroneous, use the Base::setError() call.
+ * Create a job for locking this collection.
*/
- virtual BackendReturn<bool> lock() = 0;
+ virtual LockCollectionJob *createLockJob() = 0;
/**
- * Delete this collection.
- *
- * @return true if the collection was deleted, false if it wasn't.
- * @remarks this is only called by processCall. To set a deleteCollection call
- * erroneous, use the Base::setError() call.
+ * Create a job for deleting this collection.
*/
- virtual BackendReturn<bool> deleteCollection() = 0;
+ virtual DeleteCollectionJob *createDeleteJob() = 0;
/**
- * Create an item.
+ * Create a job for creating an item.
*
* @param label label to assign to the new item
* @param attributes attributes to store for the new item
@@ -154,20 +137,16 @@ public:
* will be replaced, if false no item will be created
* if one with the same attributes already exists
* @param locked if true, the item will be locked after creation
- * @return the item created or 0 if an error occurred.
*/
- virtual BackendReturn<BackendItem*> createItem(const QString &label,
- const QMap<QString, QString> \
&attributes,
- const QCA::SecureArray &secret, \
bool replace,
- bool locked) = 0;
+ virtual CreateItemJob *createCreateItemJob(const QString &label,
+ const QMap<QString, QString> \
&attributes, + const QCA::SecureArray \
&secret, bool replace, + bool locked) = \
0;
/**
- * Change this collection's authentication.
- *
- * @return true if the authentication was changed, false if it wasn't.
- * @remarks What this method does is all up to the class inheriting from \
BackendCollection. + * Create a job for changing this collection's authentication.
*/
- virtual BackendReturn<bool> changeAuthentication() = 0;
+ virtual ChangeAuthenticationCollectionJob *createChangeAuthenticationJob() = 0;
Q_SIGNALS:
/**
diff --git a/backend/backendcollectionmanager.cpp \
b/backend/backendcollectionmanager.cpp index 4d4f8d7..73ded02 100644
--- a/backend/backendcollectionmanager.cpp
+++ b/backend/backendcollectionmanager.cpp
@@ -22,7 +22,7 @@
#include "backendcollection.h"
BackendCollectionManager::BackendCollectionManager(QObject *parent)
- : BackendBase(parent)
+ : QObject(parent)
{
}
diff --git a/backend/backendcollectionmanager.h b/backend/backendcollectionmanager.h
index 541a553..0da62c5 100644
--- a/backend/backendcollectionmanager.h
+++ b/backend/backendcollectionmanager.h
@@ -21,10 +21,13 @@
#ifndef BACKENDCOLLECTIONMANAGER_H
#define BACKENDCOLLECTIONMANAGER_H
-#include "backendbase.h"
#include "backendreturn.h"
-class AsyncCreateCollection;
+#include <jobqueue.h>
+
+#include <QtCore/QObject>
+
+class CreateCollectionJob;
class BackendCollection;
/**
@@ -38,13 +41,11 @@ class BackendCollection;
* pure virtual methods. The inheriting class is responsible for emitting the
* \sa collectionCreated, \sa collectionDeleted and \sa collectionChanged signals.
*/
-class BackendCollectionManager : public BackendBase
+class BackendCollectionManager : public QObject, public JobQueue
{
Q_OBJECT
public:
- friend class AsyncCreateCollection;
-
/**
* Constructor
*
@@ -58,17 +59,14 @@ public:
virtual ~BackendCollectionManager();
/**
- * Create a new collection.
+ * Create a job for creating a new collection.
*
* @param label the label of the new collection
* @param lock if true the collection should be locked after creation,
* if false it should be unlocked
- * @return the collection or 0 on error
- * @remarks this is only called by processCall. To set a createCollection call
- * erroneous, use the Base::setError() call.
*/
- virtual BackendReturn<BackendCollection*> createCollection(const QString &label,
- bool locked) = 0;
+ virtual CreateCollectionJob *createCreateCollectionJob(const QString &label,
+ bool locked) = 0;
Q_SIGNALS:
/**
diff --git a/backend/backenditem.cpp b/backend/backenditem.cpp
index a5bdb87..9fce471 100644
--- a/backend/backenditem.cpp
+++ b/backend/backenditem.cpp
@@ -21,10 +21,10 @@
#include "backenditem.h"
#include "backendcollection.h"
-BackendItem::BackendItem(BackendCollection *collection) : BackendBase(collection)
+BackendItem::BackendItem(BackendCollection *collection) : QObject(collection)
{
}
-
+
BackendItem::~BackendItem()
{
}
diff --git a/backend/backenditem.h b/backend/backenditem.h
index 815eec6..1dc2eec 100644
--- a/backend/backenditem.h
+++ b/backend/backenditem.h
@@ -21,8 +21,10 @@
#ifndef BACKENDITEM_H
#define BACKENDITEM_H
-#include "backendbase.h"
#include "backendreturn.h"
+#include "backendjob.h"
+
+#include <jobqueue.h>
#include <QtCore/QMap>
#include <QtCore/QDateTime>
@@ -38,13 +40,11 @@ class BackendCollection;
* virtual methods. The inheriting class is responsible for emitting the
* \sa itemDeleted and \sa itemChanged signals.
*/
-class BackendItem : public BackendBase
+class BackendItem : public QObject, public JobQueue
{
Q_OBJECT
public:
- friend class AsyncSimpleBooleanCall;
-
/**
* Constructor
*/
@@ -121,40 +121,24 @@ public:
virtual bool isLocked() const = 0;
/**
- * Unlock this item.
- *
- * @return true if the item was unlocked successfully, false if unlocking failed
- * or an error occurred.
- * @remarks
+ * Create a call for unlocking this item.
*/
- virtual BackendReturn<bool> unlock() = 0;
+ virtual UnlockItemJob *createUnlockJob() = 0;
/**
- * Lock this item.
- *
- * @return true if the item was locked successfully, false if locking failed
- * or an error occurred.
- * @remarks this is only called by processCall. To set a lock call
- * erroneous, use the Base::setError() call.
+ * Create a call for locking this item.
*/
- virtual BackendReturn<bool> lock() = 0;
+ virtual LockItemJob *createLockJob() = 0;
/**
- * Delete this item.
- *
- * @return true if the item was deleted, false if it wasn't or an error occurred.
- * @remarks this is only called by processCall. To set a delete call
- * erroneous, use the Base::setError() call.
+ * Create a call for deleting this item.
*/
- virtual BackendReturn<bool> deleteItem() = 0;
+ virtual DeleteItemJob *createDeleteJob() = 0;
/**
- * Change this item's authentication.
- *
- * @return true if the authentication was changed, false if it wasn't.
- * @remarks What this method does is all up to the class inheriting from \
BackendItem. + * Create a job for changing this item's authentication.
*/
- virtual BackendReturn<bool> changeAuthentication() = 0;
+ virtual ChangeAuthenticationItemJob *createChangeAuthenticationJob() = 0;
Q_SIGNALS:
/**
diff --git a/backend/backendjob.cpp b/backend/backendjob.cpp
new file mode 100644
index 0000000..eb0c0a3
--- /dev/null
+++ b/backend/backendjob.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "backendjob.h"
+#include "backendmaster.h"
+#include "backendcollectionmanager.h"
+#include "backendcollection.h"
+#include "backenditem.h"
+
+#include <klocalizedstring.h>
+
+BackendJob::BackendJob(JobType type, JobQueue *queue)
+ : QueuedJob(queue), m_type(type), m_dismissed(false), m_error(NoError)
+{
+}
+
+bool BackendJob::isImmediate() const
+{
+ return true;
+}
+
+BackendJob::JobType BackendJob::type() const
+{
+ return m_type;
+}
+
+bool BackendJob::isDismissed() const
+{
+ return m_dismissed;
+}
+
+void BackendJob::dismiss()
+{
+ m_dismissed = true;
+ deleteLater();
+ emitResult();
+}
+
+ErrorType BackendJob::error() const
+{
+ return m_error;
+}
+
+const QString &BackendJob::errorMessage() const
+{
+ return m_errorMessage;
+}
+
+void BackendJob::start()
+{
+ exec();
+}
+
+void BackendJob::setError(ErrorType error, const QString &errorMessage)
+{
+ m_error = error;
+ m_errorMessage = errorMessage;
+}
+
+CreateCollectionJob::CreateCollectionJob(const QString &label, bool locked,
+ BackendCollectionManager *manager)
+ : BackendJob(BackendJob::TypeCreateCollection, manager), m_label(label),
+ m_locked(locked), m_manager(manager), m_collection(0)
+{
+}
+
+BackendCollection *CreateCollectionJob::collection()
+{
+ return m_collection;
+}
+
+const QString &CreateCollectionJob::label() const
+{
+ return m_label;
+}
+
+bool CreateCollectionJob::locked() const
+{
+ return m_locked;
+}
+
+BackendCollectionManager *CreateCollectionJob::manager() const
+{
+ return m_manager;
+}
+
+void CreateCollectionJob::setCollection(BackendCollection *collection)
+{
+ m_collection = collection;
+}
+
+CreateCollectionMasterJob::CreateCollectionMasterJob(const QString &label,
+ bool locked,
+ BackendMaster *master)
+ : BackendJob(BackendJob::TypeCreateCollectionMaster, master), m_label(label),
+ m_locked(locked), m_master(master), m_subJob(0), m_collection(0)
+{
+}
+
+CreateCollectionMasterJob::~CreateCollectionMasterJob()
+{
+ // FIXME: do something about a possible subJob!
+}
+
+bool CreateCollectionMasterJob::isImmediate() const
+{
+ if (m_master->managers().count() == 0) {
+ // no manager => job fails
+ return true;
+ } else {
+ // It's safe to assume that the call is not immediate if there are backends
+ // available, as only the most basic ones are synchronous.
+ return false;
+ }
+}
+
+void CreateCollectionMasterJob::exec()
+{
+ if (m_master->managers().count() == 0) {
+ setError(ErrorOther, i18n("No backend to create the collection was found."));
+ emitResult();
+ } else {
+ // can't call synchronous if there's a backend.
+ Q_ASSERT(false);
+ }
+}
+
+void CreateCollectionMasterJob::start()
+{
+ if (m_master->managers().count() == 0) {
+ setError(ErrorOther, i18n("No backend to create the collection was found."));
+ emitResult();
+ } else if (m_master->managers().count() == 1) {
+ createSubJob(m_master->managers().first());
+ connect(m_subJob, SIGNAL(result(QueuedJob*)),
+ SLOT(createCollectionJobFinished(QueuedJob*)));
+ m_subJob->start();
+ } else {
+ setError(ErrorOther, i18n("Not implemented."));
+ emitResult();
+ }
+}
+
+BackendCollection *CreateCollectionMasterJob::collection() const
+{
+ return m_collection;
+}
+
+void CreateCollectionMasterJob::createCollectionJobFinished(QueuedJob *subJob)
+{
+ // copy the subjob's result
+ Q_ASSERT(m_subJob == subJob);
+ CreateCollectionJob *ccj = qobject_cast<CreateCollectionJob*>(subJob);
+ Q_ASSERT(ccj);
+ if (ccj->error() != NoError) {
+ setError(ccj->error(), ccj->errorMessage());
+ } else {
+ m_collection = ccj->collection();
+ }
+ emitResult();
+}
+
+void CreateCollectionMasterJob::createSubJob(BackendCollectionManager *manager)
+{
+ Q_ASSERT(!m_subJob);
+ m_subJob = manager->createCreateCollectionJob(m_label, m_locked);
+}
+
+BooleanResultJob::BooleanResultJob(BackendJob::JobType type, JobQueue* queue)
+ : BackendJob(type, queue)
+{
+}
+
+bool BooleanResultJob::result() const
+{
+ return m_result;
+}
+
+void BooleanResultJob::setResult(bool result)
+{
+ m_result = result;
+}
+
+LockCollectionJob::LockCollectionJob(BackendCollection *collection)
+ : BooleanResultJob(BackendJob::TypeLockCollection, collection),
+ m_collection(collection)
+{
+}
+
+BackendCollection *LockCollectionJob::collection()
+{
+ return m_collection;
+}
+
+LockItemJob::LockItemJob(BackendItem *item)
+ : BooleanResultJob(BackendJob::TypeLockItem, item), m_item(item)
+{
+}
+
+BackendItem *LockItemJob::item()
+{
+ return m_item;
+}
+
+UnlockCollectionJob::UnlockCollectionJob(BackendCollection *collection)
+ : BooleanResultJob(BackendJob::TypeUnlockCollection, collection),
+ m_collection(collection)
+{
+}
+
+BackendCollection *UnlockCollectionJob::collection()
+{
+ return m_collection;
+}
+
+UnlockItemJob::UnlockItemJob(BackendItem *item)
+ : BooleanResultJob(BackendJob::TypeUnlockItem, item), m_item(item)
+{
+}
+
+BackendItem *UnlockItemJob::item()
+{
+ return m_item;
+}
+
+DeleteCollectionJob::DeleteCollectionJob(BackendCollection* collection)
+ : BooleanResultJob(BackendJob::TypeDeleteCollection, collection),
+ m_collection(collection)
+{
+}
+
+BackendCollection *DeleteCollectionJob::collection()
+{
+ return m_collection;
+}
+
+DeleteItemJob::DeleteItemJob(BackendItem* item)
+ : BooleanResultJob(BackendJob::TypeDeleteItem, item), m_item(item)
+{
+}
+
+BackendItem *DeleteItemJob::item()
+{
+ return m_item;
+}
+
+ChangeAuthenticationCollectionJob::ChangeAuthenticationCollectionJob(BackendCollection* \
collection) + : BooleanResultJob(BackendJob::TypeChangeAuthenticationCollection, \
collection), + m_collection(collection)
+{
+}
+
+BackendCollection *ChangeAuthenticationCollectionJob::collection()
+{
+ return m_collection;
+}
+
+ChangeAuthenticationItemJob::ChangeAuthenticationItemJob(BackendItem *item)
+ : BooleanResultJob(BackendJob::TypeChangeAuthenticationItem, item), m_item(item)
+{
+}
+
+BackendItem *ChangeAuthenticationItemJob::item()
+{
+ return m_item;
+}
+
+CreateItemJob::CreateItemJob(const QString &label,
+ const QMap<QString, QString> &attributes,
+ const QCA::SecureArray &secret, bool locked,
+ bool replace, BackendCollection *collection)
+ : BackendJob(BackendJob::TypeCreateItem, collection), m_collection(collection),
+ m_label(label), m_attributes(attributes), m_secret(secret), m_locked(locked),
+ m_replace(replace)
+{
+}
+
+BackendItem *CreateItemJob::item() const
+{
+ return m_item;
+}
+
+const QString &CreateItemJob::label() const
+{
+ return m_label;
+}
+
+const QMap<QString, QString> &CreateItemJob::attributes() const
+{
+ return m_attributes;
+}
+
+const QCA::SecureArray &CreateItemJob::secret() const
+{
+ return m_secret;
+}
+
+bool CreateItemJob::locked() const
+{
+ return m_locked;
+}
+
+bool CreateItemJob::replace() const
+{
+ return m_replace;
+}
+
+BackendCollection *CreateItemJob::collection()
+{
+ return m_collection;
+}
+
+void CreateItemJob::setItem(BackendItem *item)
+{
+ m_item = item;
+}
+
+#include "backendjob.moc"
diff --git a/backend/backendjob.h b/backend/backendjob.h
new file mode 100644
index 0000000..010a07c
--- /dev/null
+++ b/backend/backendjob.h
@@ -0,0 +1,589 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BACKENDJOB_H
+#define BACKENDJOB_H
+
+#include <QtCore/QMap>
+#include <qca.h>
+#include <qwindowdefs.h>
+#include <queuedjob.h>
+#include "backendreturn.h"
+
+/**
+ * Queued job for implementing various backend actions which need queueing.
+ */
+class BackendJob : public QueuedJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Types of jobs.
+ */
+ enum JobType {
+ TypeCreateCollectionMaster,
+ TypeCreateCollection,
+ TypeUnlockCollection,
+ TypeLockCollection,
+ TypeDeleteCollection,
+ TypeChangeAuthenticationCollection,
+ TypeCreateItem,
+ TypeDeleteItem,
+ TypeLockItem,
+ TypeUnlockItem,
+ TypeChangeAuthenticationItem
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param type the type of job
+ * @param queue the queue object this call will be enqueued to
+ * @todo add WId parameter in a way that makes sense (!)
+ */
+ BackendJob(JobType type, JobQueue *queue);
+
+ /**
+ * Default implementation for isImmediate() which unconditionally returns
+ * true. This is for convenience reasons are many of the inheriting classes
+ * implement jobs immediately.
+ *
+ * @warning this MUST be reimplemented if the job being implemented is not
+ * always immediate or needs special handling.
+ */
+ virtual bool isImmediate() const;
+
+ /**
+ * Get the job's type.
+ *
+ * @return the job's type
+ */
+ JobType type() const;
+
+ /**
+ * Check if this call has been dismissed.
+ *
+ * @return true if this call has been dismissed, false else
+ */
+ bool isDismissed() const;
+
+ /**
+ * Dismiss this job.
+ */
+ void dismiss();
+
+ /**
+ * Check if the job had an error.
+ *
+ * @return the error or NoError if there was no error
+ */
+ ErrorType error() const;
+
+ /**
+ * Get the error message if there is any.
+ *
+ * @return the error message or an empty string if there is none
+ */
+ const QString &errorMessage() const;
+
+ /**
+ * Default implementation for start() which just calls exec. This is
+ * implemented for convenience reasons as it eases the implementation of
+ * jobs which can be called immediately.
+ *
+ * @warning this MUST be reimplemented if the job being implemented is not
+ * always immediate or needs special handling.
+ */
+ virtual void start();
+
+protected:
+ /**
+ * Set the job result to be an error.
+ *
+ * @param error error code
+ * @param errorMessage error message
+ */
+ void setError(ErrorType error, const QString &errorMessage = QString());
+
+private:
+ JobType m_type;
+ bool m_dismissed;
+ ErrorType m_error;
+ QString m_errorMessage;
+};
+
+class BackendMaster;
+class BackendCollectionManager;
+class BackendCollection;
+class BackendItem;
+
+/**
+ * Queued job class for creating a collection.
+ *
+ * This is the job that operates on the collection manager chosen before.
+ */
+class CreateCollectionJob : public BackendJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ *
+ * @param label human-readable label for the new collection
+ * @param locked true if the collection should be locked after creation,
+ * false else
+ * @param manager the collection manager that should create the collection
+ */
+ CreateCollectionJob(const QString &label, bool locked,
+ BackendCollectionManager *manager);
+
+ /**
+ * The collection that was created.
+ *
+ * @return the collection created or 0 in case of an error
+ */
+ BackendCollection *collection();
+
+protected:
+ /**
+ * Get the label for the new collection.
+ */
+ const QString &label() const;
+
+ /**
+ * Check whether the new collection should be created locked.
+ */
+ bool locked() const;
+
+ /**
+ * The manager to call for creating the collection.
+ */
+ BackendCollectionManager *manager() const;
+
+ /**
+ * Set the collection created of the job.
+ */
+ void setCollection(BackendCollection *collection);
+
+private:
+ QString m_label;
+
+ bool m_locked;
+ BackendCollectionManager *m_manager;
+
+ BackendCollection *m_collection;
+};
+
+/**
+ * Queued job class for creating a collection.
+ *
+ * This is the job that operates on the BackendMaster. When a collection
+ * manager for creating the collection is chosen, this job creates a
+ * CreateCollectionJob and calls it on the manager that was chosen.
+ */
+class CreateCollectionMasterJob : public BackendJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ *
+ * @param label human-readable label for the new collection
+ * @param locked true if the collection should be locked after creation,
+ * false else
+ * @param master the master used to create the collection
+ */
+ CreateCollectionMasterJob(const QString &label, bool locked,
+ BackendMaster *master);
+
+ /**
+ * Destructor.
+ */
+ virtual ~CreateCollectionMasterJob();
+
+ /**
+ * Checks if this call can be made immediately/synchronously.
+ *
+ * @return true if the call can be made immediately, false if it needs to
+ * be queued
+ */
+ virtual bool isImmediate() const;
+
+ /**
+ * Execute the job synchronously.
+ */
+ virtual void exec();
+
+ /**
+ * Start the job asynchronously.
+ */
+ virtual void start();
+
+ /**
+ * Get the collection created by the job.
+ *
+ * @return the BackendCollection which was created or 0 on failure.
+ */
+ BackendCollection *collection() const;
+
+private Q_SLOTS:
+ /**
+ * Called when the CreateCollectionJob sent to the collection manager
+ * is finished.
+ *
+ * @param subJob the sub job that finished
+ */
+ void createCollectionJobFinished(QueuedJob *subJob);
+
+private:
+ QString m_label;
+ bool m_locked;
+ BackendMaster *m_master;
+ QueuedJob *m_subJob;
+
+ // create a subjob enqueued at the given manager
+ void createSubJob(BackendCollectionManager *manager);
+
+ BackendCollection *m_collection;
+};
+
+/**
+ * Base class for jobs implementing parameterless functionality and returning
+ * a boolean value.
+ */
+class BooleanResultJob : public BackendJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ *
+ * @param type concrete type of the job
+ * @param queue JobQueue to perform the action on
+ */
+ BooleanResultJob(BackendJob::JobType type, JobQueue *queue);
+
+ /**
+ * Get the boolean result of the job.
+ *
+ * @return the result of the job
+ */
+ bool result() const;
+
+protected:
+ /**
+ * Set the result of the job.
+ *
+ * @param result the job's result
+ * @remarks this is called by classes implementing the jobs
+ */
+ void setResult(bool result);
+
+private:
+ bool m_result;
+};
+
+/**
+ * Base class for jobs locking a collection.
+ *
+ * @remarks inherited classes should use setResult() to set the result
+ */
+class LockCollectionJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor for a job that locks a collection.
+ */
+ explicit LockCollectionJob(BackendCollection *collection);
+
+ /**
+ * Get the collection to lock.
+ *
+ * @remarks public as needed by ServiceMultiPrompt
+ */
+ BackendCollection *collection();
+
+private:
+ BackendCollection *m_collection;
+};
+
+/**
+ * Base class for jobs locking an item.
+ *
+ * @remarks inherited classes should use setResult() to set the result
+ */
+class LockItemJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor for a job that locks an item.
+ */
+ explicit LockItemJob(BackendItem *item);
+
+ /**
+ * Get the item to lock.
+ *
+ * @remarks public as needed by ServiceMultiPrompt
+ */
+ BackendItem *item();
+
+private:
+ BackendItem *m_item;
+};
+
+/**
+ * Base class for jobs unlocking a collection.
+ *
+ * @remarks inherited classes should use setResult() to set the result
+ */
+class UnlockCollectionJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ explicit UnlockCollectionJob(BackendCollection *collection);
+
+ /**
+ * Get the collection to unlock.
+ *
+ * @remarks public as needed by ServiceMultiPrompt
+ */
+ BackendCollection *collection();
+
+private:
+ BackendCollection *m_collection;
+};
+
+/**
+ * Base class for jobs unlocking an item.
+ *
+ * @remarks inherited classes should use setResult() to set the result
+ */
+class UnlockItemJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ explicit UnlockItemJob(BackendItem *item);
+
+ /**
+ * Get the item to unlock.
+ *
+ * @remarks public as needed by ServiceMultiPrompt
+ */
+ BackendItem *item();
+
+private:
+ BackendItem *m_item;
+};
+
+/**
+ * Base class for a job for deleting a collection.
+ */
+class DeleteCollectionJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ explicit DeleteCollectionJob(BackendCollection *collection);
+
+protected:
+ /**
+ * Get the collection to delete.
+ */
+ BackendCollection *collection();
+
+private:
+ BackendCollection *m_collection;
+};
+
+/**
+ * Base class for a job deleting an item.
+ */
+class DeleteItemJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ explicit DeleteItemJob(BackendItem *item);
+
+protected:
+ /**
+ * Get the item to delete.
+ */
+ BackendItem *item();
+
+private:
+ BackendItem *m_item;
+};
+
+/**
+ * Base class for a job changing a collection's authentication.
+ */
+class ChangeAuthenticationCollectionJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ explicit ChangeAuthenticationCollectionJob(BackendCollection *collection);
+
+protected:
+ /**
+ * Get the collection to change the authentication for.
+ */
+ BackendCollection *collection();
+
+private:
+ BackendCollection *m_collection;
+};
+
+/**
+ * Base class for a job changing an item's authentication.
+ */
+class ChangeAuthenticationItemJob : public BooleanResultJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ */
+ explicit ChangeAuthenticationItemJob(BackendItem *item);
+
+protected:
+ /**
+ * Get the collection to change the authentication for.
+ */
+ BackendItem *item();
+
+private:
+ BackendItem *m_item;
+};
+
+/**
+ * Base class for jobs creating a new item inside a collection.
+ */
+class CreateItemJob : public BackendJob
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ *
+ * @param label human-readable label for the new item
+ * @param attributes attributes to set for the new item
+ * @param secret the secret to store
+ * @param locked true if the item should be locked after creation, false else
+ * @param replace if true, replace an item with the same attributes if it already \
exists + * @param collection Collection to create the item in
+ */
+ CreateItemJob(const QString &label, const QMap<QString, QString> &attributes,
+ const QCA::SecureArray &secret, bool locked, bool replace,
+ BackendCollection *collection);
+
+ /**
+ * The item that was created or 0 if creating the item failed.
+ */
+ BackendItem *item() const;
+
+ /**
+ * The collection inside which the item should be created.
+ *
+ * @remarks this is public because retrieving the collection is needed
+ * by PromptSingleJob objects.
+ */
+ BackendCollection *collection();
+
+protected:
+ /**
+ * The label to assign to the new item.
+ */
+ const QString &label() const;
+
+ /**
+ * The attributes to assign to the new item.
+ */
+ const QMap<QString, QString> &attributes() const;
+
+ /**
+ * The secret that should be stored.
+ *
+ * @todo make secure
+ */
+ const QCA::SecureArray &secret() const;
+
+ /**
+ * If true, the new item should be created locked, if false it should be unlocked
+ * after creation.
+ */
+ bool locked() const;
+
+ /**
+ * If true, an existing item with the same attributes should be replaced by the \
new item, + * if false creating an item with the same attributes as an existing \
item will fail. + *
+ * @todo or will it create a second item?
+ */
+ bool replace() const;
+
+ /**
+ * Set the item created.
+ *
+ * @param item the item which was created.
+ * @remarks this is called by inheriting classes
+ */
+ void setItem(BackendItem *item);
+
+private:
+ BackendCollection *m_collection;
+ QString m_label;
+ QMap<QString, QString> m_attributes;
+ QCA::SecureArray m_secret;
+ bool m_locked;
+ bool m_replace;
+
+ BackendItem *m_item;
+};
+
+#endif // BACKENDJOB_H
diff --git a/backend/backendmaster.cpp b/backend/backendmaster.cpp
index 56db545..791575e 100644
--- a/backend/backendmaster.cpp
+++ b/backend/backendmaster.cpp
@@ -24,7 +24,7 @@
#include <QtCore/QEventLoop>
-BackendMaster::BackendMaster(QObject *parent) : BackendBase(parent)
+BackendMaster::BackendMaster(QObject *parent) : QObject(parent)
{
}
@@ -57,64 +57,15 @@ const QList<BackendCollection*> &BackendMaster::collections() \
const return m_collections;
}
-bool BackendMaster::isCallImmediate(AsyncCall::AsyncType type) const
+QList<BackendCollectionManager*> &BackendMaster::managers()
{
- switch (type) {
- case AsyncCall::AsyncCreateCollectionMaster:
- // create collection will be immediate if the list of managers
- // contains only a single manager which can process the call
- // immediately. for all other cases the user needs to choose
- // which type of collection to create.
- if (m_collectionManagers.count() == 1) {
- return m_collectionManagers.first()->isCallImmediate(type);
- } else {
- return false;
- }
- break;
-
- default:
- // unexpected call. return true (immediate error).
- break;
- }
-
- return true;
+ return m_collectionManagers;
}
-BackendReturn<BackendCollection*> BackendMaster::createCollection(const QString \
&label,
- bool locked)
+CreateCollectionMasterJob *BackendMaster::createCreateCollectionMasterJob(
+ const QString &label, bool locked)
{
- // manager to use for creating the collection
- BackendCollectionManager *manager = 0;
-
- if (m_collectionManagers.count() == 1) {
- manager = m_collectionManagers.first();
- } else {
- // TODO: implement dialog so the user can choose the type of collection
- // she wants.
- }
-
- if (manager == 0) {
- // no manager found or chosen.
- return 0;
- } else if (manager->isCallImmediate(AsyncCall::AsyncCreateCollection)) {
- // call is immediate.
- return manager->createCollection(label, locked);
- } else {
- // call has to be queued. use an eventloop for waiting for its return.
- QEventLoop loop;
- AsyncCreateCollection *call = new AsyncCreateCollection(label, locked, \
manager);
- connect(call, SIGNAL(completed(AsyncCall*, bool)), &loop, SLOT(quit()));
- call->enqueue();
- loop.exec();
-
- // when the eventloop returns the call either completed or the daemon is \
exiting.
- // FIXME: AsyncCall doesn't have an error message. Do we actually need it?
- if (call->isCompleted()) {
- return BackendReturn<BackendCollection*>(call->result(), call->error(), \
"");
- } else {
- return 0;
- }
- }
+ return new CreateCollectionMasterJob(label, locked, this);
}
void BackendMaster::slotCollectionCreated(BackendCollection *collection)
diff --git a/backend/backendmaster.h b/backend/backendmaster.h
index 384d786..e6b1ac9 100644
--- a/backend/backendmaster.h
+++ b/backend/backendmaster.h
@@ -21,15 +21,16 @@
#ifndef BACKENDMASTER_H
#define BACKENDMASTER_H
-#include "backendbase.h"
#include "backendreturn.h"
+#include "backendjob.h"
+
+#include <jobqueue.h>
#include <QtCore/QObject>
#include <QtCore/QList>
class BackendCollection;
class BackendCollectionManager;
-class AsyncCreateCollection;
/**
* @todo find a better name for this class
@@ -41,7 +42,7 @@ class AsyncCreateCollection;
* @remarks this class exists to allow several different frontends to operate on
* the same backends.
*/
-class BackendMaster : public BackendBase
+class BackendMaster : public QObject, public JobQueue
{
Q_OBJECT
@@ -75,35 +76,30 @@ public:
void removeManager(BackendCollectionManager *manager);
/**
- * Get the list of known collections.
+ * Get the list of registered collection managers
*
- * @return The list of known collections
+ * @return the list of registered collection managers
*/
- const QList<BackendCollection*> &collections() const;
-
+ QList<BackendCollectionManager*> &managers();
+
/**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
+ * Get the list of known collections.
*
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is
- * required.
- * @remarks always returns true as all calls on temporary
- * items are immediate
+ * @return The list of known collections
*/
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
+ const QList<BackendCollection*> &collections() const;
/**
- * Create a new collection. The master decides which manager to use for
- * creation (usually based on user input).
+ * Create a job for creating a new collection. The job decides which manager
+ * to use for creation (usually based on user input).
*
* @param label the label of the new collection
* @param lock if true, the collection should be locked after creation,
* if false it should be unlocked
- * @return the collection or 0 on error
+ * @return the collection creation job
*/
- BackendReturn<BackendCollection*> createCollection(const QString &label, bool \
locked); + CreateCollectionMasterJob *createCreateCollectionMasterJob(const QString \
&label, + bool locked);
private Q_SLOTS:
/**
diff --git a/backend/ksecret/TODO b/backend/ksecret/TODO
new file mode 100644
index 0000000..ec98ba9
--- /dev/null
+++ b/backend/ksecret/TODO
@@ -0,0 +1,3 @@
+- the new BackendJobs still lack the possibility to merge equivalent jobs
+ (eg. 2 unlock requests on the same target)
+
\ No newline at end of file
diff --git a/backend/ksecret/ksecretcollection.cpp \
b/backend/ksecret/ksecretcollection.cpp index b2c4909..d29caef 100644
--- a/backend/ksecret/ksecretcollection.cpp
+++ b/backend/ksecret/ksecretcollection.cpp
@@ -20,6 +20,7 @@
#include "ksecretcollection.h"
#include "ksecretcollectionmanager.h"
+#include "ksecretjobs.h"
#include "ksecretfile.h"
#include "../securebuffer.h"
#include <secrettool.h>
@@ -27,6 +28,7 @@
#include <QtCore/QBuffer>
#include <QtCore/QFile>
#include <QtCore/QSet>
+#include <QtCore/QTimer>
#include <klocalizedstring.h>
#include <ksavefile.h>
@@ -142,24 +144,6 @@ BackendReturn<QList<BackendItem*> > KSecretCollection::items() \
const return itemList;
}
-bool KSecretCollection::isCallImmediate(AsyncCall::AsyncType type) const
-{
- switch (type) {
-
- case AsyncCall::AsyncUnlock:
- // unlock is immediate if the collection is already unlocked
- return !isLocked();
-
- case AsyncCall::AsyncChangeAuthentication:
- // changing the authentication is never immediate
- return false;
-
- default:
- // all other calls are immediate
- return true;
- }
-}
-
BackendReturn<QList<BackendItem*> > KSecretCollection::searchItems(
const QMap<QString, QString> &attributes) const
{
@@ -184,83 +168,18 @@ BackendReturn<QList<BackendItem*> > \
KSecretCollection::searchItems( }
}
-BackendReturn<bool> KSecretCollection::unlock()
+UnlockCollectionJob *KSecretCollection::createUnlockJob()
{
- if (!isLocked()) {
- return true;
- } else {
- // TODO: make it actually unlock, needs UI
-
- // TODO: check authenticated parts
-
- // TODO: check if the key is actually correct
-
- // FIXME: this is bogus
-
- // create a key to unlock the actual symmetric key
- m_symmetricKey = new QCA::SymmetricKey;
- QCA::SymmetricKey *keyUnlockKey = new \
QCA::SymmetricKey(QByteArray("12345678901234567890"));
- Q_FOREACH(EncryptedKey *key, m_encryptedSymKeys) {
- if (key->m_type == KSecretFile::KeyBogus) {
- QCA::Cipher keyCipher("blowfish", QCA::Cipher::CBC);
- keyCipher.setup(QCA::Decode, *keyUnlockKey);
- *m_symmetricKey += QCA::SecureArray(keyCipher.update(key->m_key));
- *m_symmetricKey += QCA::SecureArray(keyCipher.final());
- break;
- }
- }
-
- Q_ASSERT(m_symmetricKey);
-
- QCA::SecureArray decryptedPart;
- Q_FOREACH(const QByteArray &partContents, m_encryptedItemParts) {
- if (!deserializePartEncrypted(partContents, decryptedPart)) {
- return false;
- }
-
- // deserialize the items inside the decrypted part
- SecureBuffer device(&decryptedPart);
- KSecretFile itemFile(&device, KSecretFile::Read);
- if (!deserializeItemsUnlocked(itemFile)) {
- return false;
- }
- }
- return false;
- }
+ return new KSecretUnlockCollectionJob(this);
}
-BackendReturn<bool> KSecretCollection::lock()
+LockCollectionJob *KSecretCollection::createLockJob()
{
- // TODO: reference/open counting?
-
- // TODO: emit signals?
-
- if (isLocked()) {
- return true;
- } else {
- // TODO: only serialize if dirty
- QString errorMessage;
- if (!serialize(errorMessage)) {
- return BackendReturn<bool>(false, ErrorOther, errorMessage);
- }
-
- // then remove the key
- delete m_hash;
- m_hash = 0;
- delete m_cipher;
- m_cipher = 0;
-
- // remove individual item secrets
- QHash<QString, KSecretItem*>::iterator it = m_items.begin();
- QHash<QString, KSecretItem*>::iterator end = m_items.end();
- for ( ; it != end; ++it) {
- // FIXME: it.value()->removeSecrets();
- }
-
- return true;
- }
+ return new KSecretLockCollectionJob(this);
}
+
+
BackendReturn<bool> KSecretCollection::deleteCollection()
{
// remove the ksecret file
@@ -274,10 +193,23 @@ BackendReturn<bool> KSecretCollection::deleteCollection()
return true;
}
+CreateItemJob *KSecretCollection::createCreateItemJob(const QString &label,
+ const QMap<QString, QString> \
&attributes, + const \
QCA::SecureArray &secret, + bool \
locked, bool replace) +{
+ return new KSecretCreateItemJob(label, attributes, secret, locked, replace, \
this); +}
+
+ChangeAuthenticationCollectionJob \
*KSecretCollection::createChangeAuthenticationJob() +{
+ return new KSecretChangeAuthenticationCollectionJob(this);
+}
+
BackendReturn<BackendItem*> KSecretCollection::createItem(const QString &label,
const QMap<QString, \
QString> &attributes,
const QCA::SecureArray \
&secret,
- bool replace, bool locked)
+ bool locked, bool replace)
{
// TODO: use locked argument
Q_UNUSED(locked);
@@ -334,12 +266,6 @@ BackendReturn<BackendItem*> KSecretCollection::createItem(const \
QString &label, }
}
-BackendReturn<bool> KSecretCollection::changeAuthentication()
-{
- // TODO: needs ui
- return false;
-}
-
const QString &KSecretCollection::path() const
{
return m_path;
@@ -406,6 +332,67 @@ KSecretCollection *KSecretCollection::deserialize(const QString \
&path, return coll;
}
+const QList<EncryptedKey*> &KSecretCollection::encryptedSymKeys() const
+{
+ return m_encryptedSymKeys;
+}
+
+void KSecretCollection::setSymKey(QCA::SymmetricKey *key)
+{
+ m_symmetricKey = key;
+}
+
+bool KSecretCollection::tryUnlock()
+{
+ QCA::SecureArray decryptedPart;
+ Q_FOREACH(const QByteArray &partContents, m_encryptedItemParts) {
+ if (!deserializePartEncrypted(partContents, decryptedPart)) {
+ return false;
+ }
+
+ // deserialize the items inside the decrypted part
+ SecureBuffer device(&decryptedPart);
+ KSecretFile itemFile(&device, KSecretFile::Read);
+ if (!deserializeItemsUnlocked(itemFile)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+BackendReturn<bool> KSecretCollection::lock()
+{
+ // TODO: reference/open counting?
+
+ // TODO: emit signals?
+
+ if (isLocked()) {
+ return true;
+ } else {
+ // TODO: only serialize if dirty
+ QString errorMessage;
+ if (!serialize(errorMessage)) {
+ return BackendReturn<bool>(false, ErrorOther, errorMessage);
+ }
+
+ // then remove the key
+ delete m_hash;
+ m_hash = 0;
+ delete m_cipher;
+ m_cipher = 0;
+
+ // remove individual item secrets
+ QHash<QString, KSecretItem*>::iterator it = m_items.begin();
+ QHash<QString, KSecretItem*>::iterator end = m_items.end();
+ for ( ; it != end; ++it) {
+ // FIXME: it.value()->removeSecrets();
+ }
+
+ return true;
+ }
+}
+
bool KSecretCollection::setupAlgorithms(QString &errorMessage)
{
// figure out algorithms to use
diff --git a/backend/ksecret/ksecretcollection.h \
b/backend/ksecret/ksecretcollection.h index c796009..bfe94db 100644
--- a/backend/ksecret/ksecretcollection.h
+++ b/backend/ksecret/ksecretcollection.h
@@ -26,6 +26,10 @@
#include "ksecretfile.h"
class KSecretCollectionManager;
+class KSecretUnlockCollectionJob;
+class KSecretLockCollectionJob;
+class KSecretDeleteCollectionJob;
+class KSecretCreateItemJob;
/**
* Represents a part of the ksecret file stored in memory. The part's type
@@ -140,17 +144,6 @@ public:
virtual BackendReturn<QList<BackendItem*> > items() const;
/**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
- *
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is
- * required.
- */
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
-
- /**
* Return all items whose attributes match the search terms.
*
* @param attributes attributes against which the items should be matched
@@ -163,31 +156,22 @@ public:
const QMap<QString, QString> &attributes) const;
/**
- * Unlock this collection.
- *
- * @return true if the collection is now unlocked, false if unlocking
- * failed.
+ * Create a job for unlocking this collection.
*/
- virtual BackendReturn<bool> unlock();
+ virtual UnlockCollectionJob *createUnlockJob();
/**
- * Lock this collection.
- *
- * @return true if the collection is now locked, false if locking
- * failed (the collection couldn't be locked or unlocking is not
- * supported by this backend).
+ * Create a job for locking this collection.
*/
- virtual BackendReturn<bool> lock();
+ virtual LockCollectionJob *createLockJob();
/**
- * Delete this collection.
- *
- * @return true if the collection was deleted, false if it wasn't.
+ * Create a job for deleting this collection.
*/
- virtual BackendReturn<bool> deleteCollection();
+ virtual DeleteCollectionJob *createDeleteJob();
/**
- * Create an item.
+ * Create a job for creating an item.
*
* @param label label to assign to the new item
* @param attributes attributes to store for the new item
@@ -196,19 +180,16 @@ public:
* will be replaced, if false no item will be created
* if one with the same attributes already exists
* @param locked if true, the item will be locked after creation
- * @return the item created or 0 if an error occurred.
*/
- virtual BackendReturn<BackendItem*> createItem(const QString &label,
- const QMap<QString, QString> \
&attributes,
- const QCA::SecureArray &secret, \
bool replace,
- bool locked);
+ virtual CreateItemJob *createCreateItemJob(const QString &label,
+ const QMap<QString, QString> \
&attributes, + const QCA::SecureArray \
&secret, bool locked, + bool replace);
/**
- * Change this collection's authentication.
- *
- * @return Always false as TemporaryCollection doesn't support authentication
+ * Create a job for changing this collection's authentication.
*/
- virtual BackendReturn<bool> changeAuthentication();
+ virtual ChangeAuthenticationCollectionJob* createChangeAuthenticationJob();
/**
* Get the path of the ksecret file the collection is stored inside.
@@ -245,7 +226,59 @@ public:
static KSecretCollection *deserialize(const QString &path, \
KSecretCollectionManager *parent, QString &errorMessage);
+protected:
+ /**
+ * Get the encrypted symmetric keys.
+ *
+ * @remarks this is used by KSecretUnlockCollectionJob
+ */
+ const QList<EncryptedKey*> &encryptedSymKeys() const;
+
+ /**
+ * Set the (unencrypted) symmetric key to use for encryption/decryption.
+ *
+ * @remarks this is used by KSecretUnlockCollectionJob
+ */
+ void setSymKey(QCA::SymmetricKey *key);
+
+ /**
+ * Try to unlock using the symmetric key set using setSymKey().
+ *
+ * @return true if unlocking succeeded, false if it failed
+ * @remarks this is used by KSecretUnlockCollectionJob
+ */
+ bool tryUnlock();
+
+ /**
+ * Lock this collection. This is implemented here for convenience purposes.
+ *
+ * @remarks this is used by KSecretLockCollectionJob
+ */
+ BackendReturn<bool> lock();
+
+ /**
+ * Create a new item inside this collection.
+ *
+ * @remarks this is used by KSecretCreateItemJob
+ */
+ BackendReturn<BackendItem*> createItem(const QString &label,
+ const QMap<QString, QString> &attributes,
+ const QCA::SecureArray &secret, bool \
locked, + bool replace);
+
+ /**
+ * Delete this collection and emit the corresponding signals.
+ *
+ * @remarks this is used by KSecretDeleteCollectionJob
+ */
+ BackendReturn<bool> deleteCollection();
+
private:
+ friend class KSecretUnlockCollectionJob;
+ friend class KSecretLockCollectionJob;
+ friend class KSecretDeleteCollectionJob;
+ friend class KSecretCreateItemJob;
+
/**
* Application permissions stored inside the ksecret file.
*/
@@ -356,7 +389,7 @@ private:
/**
* Serialize this ksecret collection back to a KSecretFile.
*
- * @param errorMessage set if there's an error
+ * @param errorMessage set if there's an replaceerror
* @return true on success, false in case of an error
*/
bool serialize(QString &errorMessage) const;
@@ -424,7 +457,7 @@ private:
* Serialize a file part by writing it to the ksecret file and appending a hash \
mac
* to sign its contents.
*
- * @param data data to write to the part
+ * @param data data to write to the partreplace
* @param file ksecret file to write the data to
* @return true if serializing was successful, false else
*/
diff --git a/backend/ksecret/ksecretcollectionmanager.cpp \
b/backend/ksecret/ksecretcollectionmanager.cpp index 619d267..6b56d40 100644
--- a/backend/ksecret/ksecretcollectionmanager.cpp
+++ b/backend/ksecret/ksecretcollectionmanager.cpp
@@ -20,6 +20,7 @@
#include "ksecretcollectionmanager.h"
#include "ksecretcollection.h"
+#include "ksecretjobs.h"
#include <secrettool.h>
@@ -39,38 +40,9 @@ KSecretCollectionManager::~KSecretCollectionManager()
// TODO: cleanup?
}
-bool KSecretCollectionManager::isCallImmediate(AsyncCall::AsyncType type) const
+void KSecretCollectionManager::addCollection(KSecretCollection *collection)
{
- // TODO: based on available authentication methods this may return true
- if (type == AsyncCall::AsyncCreateCollectionMaster) {
- return false;
- } else {
- return true;
- }
-}
-
-BackendReturn<BackendCollection*> KSecretCollectionManager::createCollection(const \
QString &label,
- bool \
locked)
-{
- // TODO: collection needs authentication methods, filenames, ...
- QString errorMessage;
- KSecretCollection *coll = KSecretCollection::create(createId(), this, \
errorMessage);
- coll->setLabel(label);
-
- // TODO: coll has be added to m_collections before serializing it for the first
- // time, so when slotDirectoryChanged is called, the collection is already
- // known.
- m_collections.insert(coll->path(), coll);
-
- connect(coll, SIGNAL(collectionDeleted(BackendCollection*)),
- SIGNAL(collectionDeleted(BackendCollection*)));
- emit collectionCreated(coll);
-
- if (locked) {
- coll->lock();
- }
-
- return coll;
+ m_collections.insert(collection->path(), collection);
}
void KSecretCollectionManager::slotDirectoryChanged(const QString &path)
@@ -84,7 +56,7 @@ void KSecretCollectionManager::slotDirectoryChanged(const QString \
&path) QString errorMessage;
KSecretCollection *coll = KSecretCollection::deserialize(file, this, \
errorMessage); if (coll) {
- m_collections.insert(file, coll);
+ addCollection(coll);
}
}
}
@@ -96,4 +68,14 @@ void KSecretCollectionManager::slotStartupDiscovery()
slotDirectoryChanged(m_watcher.directories().at(0));
}
+void KSecretCollectionManager::createCollectionJobResult(QueuedJob *job)
+{
+ KSecretCreateCollectionJob *ccj = qobject_cast<KSecretCreateCollectionJob*>(job);
+ Q_ASSERT(ccj);
+
+ connect(ccj->collection(), SIGNAL(collectionDeleted(BackendCollection*)),
+ SIGNAL(collectionDeleted(BackendCollection*)));
+ emit collectionCreated(ccj->collection());
+}
+
#include "ksecretcollectionmanager.moc"
diff --git a/backend/ksecret/ksecretcollectionmanager.h \
b/backend/ksecret/ksecretcollectionmanager.h index 4633dc8..5c0e57a 100644
--- a/backend/ksecret/ksecretcollectionmanager.h
+++ b/backend/ksecret/ksecretcollectionmanager.h
@@ -23,9 +23,11 @@
#include "../backendcollectionmanager.h"
+#include <QtCore/QMap>
#include <QtCore/QFileSystemWatcher>
class KSecretCollection;
+class KSecretCreateCollectionJob;
/**
* Manager for collections stored in ksecret files.
@@ -49,25 +51,23 @@ public:
virtual ~KSecretCollectionManager();
/**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
- *
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is required.
- */
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
-
- /**
- * Create a new collection.
+ * Create a call for creating a new collection.
*
* @param label the label of the new collection
* @param lock if true, the collection should be locked after creation,
* if false it should stay unlocked
- * @return the collection or 0 on error
*/
- virtual BackendReturn<BackendCollection*> createCollection(const QString &label, \
bool locked); + virtual CreateCollectionJob *createCreateCollectionJob(const \
QString &label, + bool \
locked);
+protected:
+ /**
+ * This methods adds a newly created collection to the manager.
+ *
+ * @param collection collection to add
+ */
+ void addCollection(KSecretCollection *coll);
+
private Q_SLOTS:
/**
* Connected to a filesystem watcher this slot is called whenever
@@ -81,8 +81,17 @@ private Q_SLOTS:
* Collection discovery method which can be called using a single-shot timer.
*/
void slotStartupDiscovery();
+
+ /**
+ * Called when a CreateCollectionJob run by this manager finishes.
+ *
+ * @param job the job that finished
+ */
+ void createCollectionJobResult(QueuedJob *job);
private:
+ friend class KSecretCreateCollectionJob;
+
// filesystem watcher to detect new/removed ksecret files
QFileSystemWatcher m_watcher;
diff --git a/backend/ksecret/ksecretitem.cpp b/backend/ksecret/ksecretitem.cpp
index 8d63d34..d6415db 100644
--- a/backend/ksecret/ksecretitem.cpp
+++ b/backend/ksecret/ksecretitem.cpp
@@ -20,8 +20,12 @@
#include "ksecretitem.h"
#include "ksecretcollection.h"
+#include "ksecretjobs.h"
#include "../securebuffer.h"
+#include <QtCore/QPointer>
+#include <QtCore/QTimer>
+
KSecretItem::KSecretItem(const QString &id, KSecretCollection *parent)
: BackendItem(parent), m_collection(parent), m_id(id)
{
@@ -118,31 +122,21 @@ bool KSecretItem::isLocked() const
return m_collection->isLocked();
}
-bool KSecretItem::isCallImmediate(AsyncCall::AsyncType type) const
+UnlockItemJob *KSecretItem::createUnlockJob()
{
Q_ASSERT(m_collection);
-
- if (type == AsyncCall::AsyncDeleteItem) {
- // delete item calls are always immediate
- return true;
- }
-
- // all other relevant async calls are forwarded to the collection.
- return m_collection->isCallImmediate(type);
+ return new KSecretUnlockItemJob(this, m_collection);
}
-BackendReturn<bool> KSecretItem::unlock()
+LockItemJob *KSecretItem::createLockJob()
{
Q_ASSERT(m_collection);
- // pass the unlock call on to the collection
- return m_collection->unlock();
+ return new KSecretLockItemJob(this, m_collection);
}
-BackendReturn<bool> KSecretItem::lock()
+DeleteItemJob *KSecretItem::createDeleteJob()
{
- Q_ASSERT(m_collection);
- // pass the lock call on to the collection
- return m_collection->lock();
+ return new KSecretDeleteItemJob(this);
}
BackendReturn<bool> KSecretItem::deleteItem()
@@ -152,10 +146,9 @@ BackendReturn<bool> KSecretItem::deleteItem()
return true;
}
-BackendReturn<bool> KSecretItem::changeAuthentication()
+ChangeAuthenticationItemJob *KSecretItem::createChangeAuthenticationJob()
{
- // changing individual items' authentication is not supported
- return BackendReturn<bool>(false, ErrorNotSupported);
+ return new KSecretChangeAuthenticationItemJob(this);
}
bool KSecretItem::matches(const QMap<QString, QString> &attributes)
diff --git a/backend/ksecret/ksecretitem.h b/backend/ksecret/ksecretitem.h
index 678db96..b1cfd59 100644
--- a/backend/ksecret/ksecretitem.h
+++ b/backend/ksecret/ksecretitem.h
@@ -27,6 +27,7 @@
#include <QtCore/QSet>
class KSecretCollection;
+class KSecretDeleteItemJob;
/**
* Represents an item stored inside a ksecret file.
@@ -116,51 +117,24 @@ public:
virtual bool isLocked() const;
/**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
- *
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is
- * required.
+ * Create a job for unlocking this item.
*/
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
+ virtual UnlockItemJob *createUnlockJob();
/**
- * Unlock this item.
- *
- * @return true if the item was unlocked successfully, false if unlocking failed
- * or an error occurred.
- * @remarks this is only called by processCall. To set an unlock call
- * erroneous, use the Base::setError() call.
+ * Create a job for locking this item.
*/
- virtual BackendReturn<bool> unlock();
+ virtual LockItemJob *createLockJob();
/**
- * Lock this item.
- *
- * @return true if the item was locked successfully, false if locking failed
- * or an error occurred.
- * @remarks this is only called by processCall. To set a lock call
- * erroneous, use the Base::setError() call.
+ * Create a job for deleting this item.
*/
- virtual BackendReturn<bool> lock();
+ virtual DeleteItemJob *createDeleteJob();
/**
- * Delete this item.
- *
- * @return true if the item was deleted, false if it wasn't or an error occurred.
- * @remarks this is only called by processCall. To set a delete call
- * erroneous, use the Base::setError() call.
+ * Create a job for changing this item's authentication.
*/
- virtual BackendReturn<bool> deleteItem();
-
- /**
- * Change this item's authentication.
- *
- * @return always false as TemporaryItem doesn't support authentication
- */
- virtual BackendReturn<bool> changeAuthentication();
+ virtual ChangeAuthenticationItemJob *createChangeAuthenticationJob();
/**
* Check whether this item matches the attributes given.
@@ -206,6 +180,13 @@ protected:
*/
static QSet<QByteArray> createHashes(const QMap<QString, QString> &attributes,
QCA::Hash *hash);
+
+ /**
+ * Delete the item.
+ *
+ * @remarks this is called by KSecretDeleteItemJob
+ */
+ BackendReturn<bool> deleteItem();
Q_SIGNALS:
/**
@@ -228,6 +209,7 @@ Q_SIGNALS:
private:
friend class KSecretCollection;
+ friend class KSecretDeleteItemJob;
/**
* Mark this item as modified and emit the \sa itemChanged signal.
diff --git a/backend/ksecret/ksecretjobs.cpp b/backend/ksecret/ksecretjobs.cpp
new file mode 100644
index 0000000..d6da49c
--- /dev/null
+++ b/backend/ksecret/ksecretjobs.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ksecretjobs.h"
+
+#include <secrettool.h>
+
+#include <QtCore/QTimer>
+
+KSecretCreateCollectionJob::KSecretCreateCollectionJob(const QString &label, bool \
locked, + \
KSecretCollectionManager *manager) + : CreateCollectionJob(label, locked, manager), \
m_manager(manager) +{
+}
+
+bool KSecretCreateCollectionJob::isImmediate() const
+{
+ // TODO: depending on available authentiation methods this may return
+ // true.
+ return false;
+}
+
+void KSecretCreateCollectionJob::exec()
+{
+ Q_ASSERT(false);
+}
+
+void KSecretCreateCollectionJob::start()
+{
+ // TODO: collection needs authentication methods, filenames, ...
+ QString errorMessage;
+ KSecretCollection *coll = KSecretCollection::create(createId(), manager(),
+ errorMessage);
+ coll->setLabel(label());
+
+ // NOTE: coll has to be added to m_collections before serializing it for the
+ // first time, so when slotDirectoryChanged is called, the collection
+ // is already known.
+ m_manager->addCollection(coll);
+
+ if (locked()) {
+ // TODO: lock
+ }
+
+ setCollection(coll);
+ emitResult();
+}
+
+KSecretUnlockCollectionJob::KSecretUnlockCollectionJob(KSecretCollection *coll)
+ : UnlockCollectionJob(coll), m_collection(coll)
+{
+}
+
+bool KSecretUnlockCollectionJob::isImmediate() const
+{
+ // unlocked collections don't need a job to open
+ if (!m_collection->isLocked()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void KSecretUnlockCollectionJob::exec()
+{
+ Q_ASSERT(!collection()->isLocked());
+ setResult(true);
+ emitResult();
+}
+
+void KSecretUnlockCollectionJob::start()
+{
+ QTimer::singleShot(0, this, SLOT(doWork()));
+}
+
+void KSecretUnlockCollectionJob::doWork()
+{
+ if (!collection()->isLocked()) {
+ setResult(true);
+ emitResult();
+ return;
+ }
+
+ // TODO: make it actually unlock, needs UI
+
+ // TODO: check authenticated parts
+
+ // TODO: check if the key is actually correct
+
+ // FIXME: this is bogus
+
+ // create a key to unlock the actual symmetric key
+ QCA::SymmetricKey *symkey = new QCA::SymmetricKey;
+ QCA::SymmetricKey *keyUnlockKey = new \
QCA::SymmetricKey(QByteArray("12345678901234567890")); + Q_FOREACH(EncryptedKey \
*key, m_collection->encryptedSymKeys()) { + if (key->m_type == \
KSecretFile::KeyBogus) { + QCA::Cipher keyCipher("blowfish", \
QCA::Cipher::CBC); + keyCipher.setup(QCA::Decode, *keyUnlockKey);
+ *symkey += QCA::SecureArray(keyCipher.update(key->m_key));
+ *symkey += QCA::SecureArray(keyCipher.final());
+ break;
+ }
+ }
+ Q_ASSERT(symkey);
+ m_collection->setSymKey(symkey);
+
+ // clear symmetric key if unlocking failed
+ if (m_collection->tryUnlock()) {
+ setResult(true);
+ } else {
+ m_collection->setSymKey(0);
+ delete symkey;
+ setResult(false);
+ }
+ emitResult();
+}
+
+KSecretLockCollectionJob::KSecretLockCollectionJob(KSecretCollection *coll)
+ : LockCollectionJob(coll), m_collection(coll)
+{
+}
+
+void KSecretLockCollectionJob::exec()
+{
+ // nothing to do if already locked
+ if (collection()->isLocked()) {
+ setResult(true);
+ emitResult();
+ return;
+ }
+
+ BackendReturn<bool> rc = m_collection->lock();
+ if (rc.isError()) {
+ setError(rc.error(), rc.errorMessage());
+ setResult(false);
+ } else {
+ setResult(true);
+ emitResult();
+ }
+}
+
+KSecretDeleteCollectionJob::KSecretDeleteCollectionJob(KSecretCollection \
*collection) + : DeleteCollectionJob(collection), m_collection(collection)
+{
+}
+
+void KSecretDeleteCollectionJob::exec()
+{
+ BackendReturn<bool> rc = m_collection->deleteCollection();
+ if (rc.isError()) {
+ setError(rc.error(), rc.errorMessage());
+ setResult(false);
+ } else {
+ setResult(true);
+ }
+ emitResult();
+}
+
+KSecretCreateItemJob::KSecretCreateItemJob(const QString& label, const QMap< \
QString, QString >& attributes, + const \
QCA::SecureArray& secret, bool locked, bool replace, + \
KSecretCollection* collection) + : CreateItemJob(label, attributes, secret, locked, \
replace, collection), + m_collection(collection)
+{
+}
+
+void KSecretCreateItemJob::exec()
+{
+ BackendReturn<BackendItem*> rc = m_collection->createItem(label(), attributes(),
+ secret(), locked(), \
replace()); + if (rc.isError()) {
+ setError(rc.error(), rc.errorMessage());
+ setItem(0);
+ } else {
+ setItem(rc.value());
+ }
+ emitResult();
+}
+
+KSecretChangeAuthenticationCollectionJob::KSecretChangeAuthenticationCollectionJob(BackendCollection \
*coll) + : ChangeAuthenticationCollectionJob(coll)
+{
+}
+
+void KSecretChangeAuthenticationCollectionJob::exec()
+{
+ setError(ErrorOther, "Not implemented.");
+ setResult(false);
+ emitResult();
+}
+
+KSecretUnlockItemJob::KSecretUnlockItemJob(KSecretItem *item,
+ KSecretCollection *collection)
+ : UnlockItemJob(item)
+{
+ // delegate to an unlock job on the collection
+ m_subJob = collection->createUnlockJob();
+}
+
+KSecretUnlockItemJob::~KSecretUnlockItemJob()
+{
+ // delete the subjob if it wasn't executed.
+ if (!m_subJob.isNull()) {
+ m_subJob->deleteLater();
+ }
+}
+
+bool KSecretUnlockItemJob::isImmediate() const
+{
+ Q_ASSERT(!m_subJob.isNull());
+ return m_subJob->isImmediate();
+}
+
+void KSecretUnlockItemJob::exec()
+{
+ Q_ASSERT(!m_subJob.isNull());
+ m_subJob->exec();
+ handleSubJobResult(m_subJob);
+}
+
+void KSecretUnlockItemJob::start()
+{
+ connect(m_subJob, SIGNAL(result(QueuedJob*)),
+ SLOT(handleSubJobResult(QueuedJob*)));
+ m_subJob->start();
+}
+
+void KSecretUnlockItemJob::handleSubJobResult(QueuedJob *job)
+{
+ Q_UNUSED(job);
+ Q_ASSERT(!m_subJob.isNull());
+ Q_ASSERT(m_subJob == job);
+ Q_ASSERT(m_subJob->isFinished());
+ setError(m_subJob->error(), m_subJob->errorMessage());
+ setResult(m_subJob->result());
+ emitResult();
+}
+
+KSecretLockItemJob::KSecretLockItemJob(KSecretItem *item,
+ KSecretCollection *collection)
+ : LockItemJob(item)
+{
+ // delegate to a lock job on the collection
+ m_subJob = collection->createLockJob();
+}
+
+KSecretLockItemJob::~KSecretLockItemJob()
+{
+ // delete the subjob if it wasn't executed.
+ if (!m_subJob.isNull()) {
+ m_subJob->deleteLater();
+ }
+}
+
+bool KSecretLockItemJob::isImmediate() const
+{
+ Q_ASSERT(!m_subJob.isNull());
+ return m_subJob->isImmediate();
+}
+
+void KSecretLockItemJob::exec()
+{
+ Q_ASSERT(!m_subJob.isNull());
+ m_subJob->exec();
+ handleSubJobResult(m_subJob);
+}
+
+void KSecretLockItemJob::start()
+{
+ connect(m_subJob, SIGNAL(result(QueuedJob*)),
+ SLOT(handleSubJobResult(QueuedJob*)));
+ m_subJob->start();
+}
+
+void KSecretLockItemJob::handleSubJobResult(QueuedJob *job)
+{
+ Q_UNUSED(job);
+ Q_ASSERT(!m_subJob.isNull());
+ Q_ASSERT(m_subJob == job);
+ Q_ASSERT(m_subJob->isFinished());
+ setError(m_subJob->error(), m_subJob->errorMessage());
+ setResult(m_subJob->result());
+ emitResult();
+}
+
+KSecretDeleteItemJob::KSecretDeleteItemJob(KSecretItem *item)
+ : DeleteItemJob(item), m_item(item)
+{
+}
+
+void KSecretDeleteItemJob::exec()
+{
+ // TODO: this could easily be delegated to the collection
+ BackendReturn<bool> rc = m_item->deleteItem();
+ if (rc.isError()) {
+ setError(rc.error(), rc.errorMessage());
+ setResult(false);
+ } else {
+ setResult(true);
+ }
+ emitResult();
+}
+
+KSecretChangeAuthenticationItemJob::KSecretChangeAuthenticationItemJob(BackendItem \
*item) + : ChangeAuthenticationItemJob(item)
+{
+}
+
+void KSecretChangeAuthenticationItemJob::exec()
+{
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+
+#include "ksecretjobs.moc"
diff --git a/backend/ksecret/ksecretjobs.h b/backend/ksecret/ksecretjobs.h
new file mode 100644
index 0000000..c418d9f
--- /dev/null
+++ b/backend/ksecret/ksecretjobs.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KSECRETJOBS_H
+#define KSECRETJOBS_H
+
+#include "ksecretcollectionmanager.h"
+#include "ksecretcollection.h"
+#include "ksecretitem.h"
+#include "../backendjob.h"
+
+#include <QtCore/QPointer>
+
+/**
+ * Job for creating a new ksecret collection.
+ */
+class KSecretCreateCollectionJob : public CreateCollectionJob
+{
+ Q_OBJECT
+
+public:
+ KSecretCreateCollectionJob(const QString &label, bool locked,
+ KSecretCollectionManager *manager);
+ virtual bool isImmediate() const;
+ virtual void exec();
+ virtual void start();
+
+private:
+ KSecretCollectionManager *m_manager;
+};
+
+/**
+ * Job for unlocking a ksecret collection.
+ */
+class KSecretUnlockCollectionJob : public UnlockCollectionJob
+{
+ Q_OBJECT
+
+public:
+ KSecretUnlockCollectionJob(KSecretCollection *coll);
+ virtual bool isImmediate() const;
+ virtual void exec();
+ virtual void start();
+
+private Q_SLOTS:
+ void doWork();
+
+private:
+ KSecretCollection *m_collection;
+};
+
+/**
+ * Job for locking a ksecret collection.
+ */
+class KSecretLockCollectionJob : public LockCollectionJob
+{
+ Q_OBJECT
+
+public:
+ KSecretLockCollectionJob(KSecretCollection *coll);
+ virtual void exec();
+
+private:
+ KSecretCollection *m_collection;
+};
+
+/**
+ * Job for deleting a ksecret collection.
+ */
+class KSecretDeleteCollectionJob : public DeleteCollectionJob
+{
+ Q_OBJECT
+
+public:
+ KSecretDeleteCollectionJob(KSecretCollection *collection);
+ virtual void exec();
+
+private:
+ KSecretCollection *m_collection;
+};
+
+/**
+ * Job for creating a new item inside a ksecret collection.
+ */
+class KSecretCreateItemJob : public CreateItemJob
+{
+ Q_OBJECT
+
+public:
+ KSecretCreateItemJob(const QString& label, const QMap< QString, QString >& \
attributes, + const QCA::SecureArray& secret, bool locked, \
bool replace, + KSecretCollection* collection);
+ virtual void exec();
+
+private:
+ KSecretCollection *m_collection;
+};
+
+/**
+ * Job for changing a ksecret collection's authentication.
+ *
+ * @todo implement changing the authentication. in order to achieve this the UI
+ * framework has to be in place.
+ */
+class KSecretChangeAuthenticationCollectionJob : public \
ChangeAuthenticationCollectionJob +{
+ Q_OBJECT
+
+public:
+ KSecretChangeAuthenticationCollectionJob(BackendCollection *coll);
+ virtual void exec();
+};
+
+/**
+ * Job for unlocking an item inside a ksecret collection.
+ */
+class KSecretUnlockItemJob : public UnlockItemJob
+{
+ Q_OBJECT
+
+public:
+ KSecretUnlockItemJob(KSecretItem *item, KSecretCollection *collection);
+ virtual ~KSecretUnlockItemJob();
+ virtual bool isImmediate() const;
+ virtual void exec();
+ virtual void start();
+
+private Q_SLOTS:
+ void handleSubJobResult(QueuedJob *job);
+
+private:
+ QPointer<UnlockCollectionJob> m_subJob;
+};
+
+/**
+ * Job for locking an item inside a ksecret collection.
+ */
+class KSecretLockItemJob : public LockItemJob
+{
+ Q_OBJECT
+
+public:
+ KSecretLockItemJob(KSecretItem *item, KSecretCollection *collection);
+ virtual ~KSecretLockItemJob();
+ virtual bool isImmediate() const;
+ virtual void exec();
+ virtual void start();
+
+private Q_SLOTS:
+ void handleSubJobResult(QueuedJob *job);
+
+private:
+ QPointer<LockCollectionJob> m_subJob;
+};
+
+/**
+ * Job for deleting an item inside a ksecret collection.
+ */
+class KSecretDeleteItemJob : public DeleteItemJob
+{
+ Q_OBJECT
+
+public:
+ KSecretDeleteItemJob(KSecretItem *item);
+ virtual void exec();
+
+private:
+ KSecretItem *m_item;
+};
+
+/**
+ * Job for changing a ksecret collection's authentication.
+ */
+class KSecretChangeAuthenticationItemJob : public ChangeAuthenticationItemJob
+{
+ Q_OBJECT
+
+public:
+ KSecretChangeAuthenticationItemJob(BackendItem *item);
+ virtual void exec();
+};
+
+#endif
diff --git a/backend/temporary/temporarycollection.cpp \
b/backend/temporary/temporarycollection.cpp index d8cddba..00cd4d9 100644
--- a/backend/temporary/temporarycollection.cpp
+++ b/backend/temporary/temporarycollection.cpp
@@ -20,10 +20,15 @@
#include "temporarycollection.h"
#include "temporaryitem.h"
+#include "temporaryjobs.h"
#include <secrettool.h>
-TemporaryCollection::TemporaryCollection(const QString &id, BackendCollectionManager \
*parent) +#include <klocalizedstring.h>
+#include <QtCore/QTimer>
+
+TemporaryCollection::TemporaryCollection(const QString &id,
+ BackendCollectionManager *parent)
: BackendCollection(parent)
{
m_id = id;
@@ -88,33 +93,36 @@ BackendReturn<QList<BackendItem*> > \
TemporaryCollection::searchItems( return foundItems;
}
-bool TemporaryCollection::isCallImmediate(AsyncCall::AsyncType type) const
+UnlockCollectionJob *TemporaryCollection::createUnlockJob()
{
- Q_UNUSED(type);
- return true;
+ return new TemporaryUnlockCollectionJob(this);
}
-BackendReturn<bool> TemporaryCollection::unlock()
+LockCollectionJob *TemporaryCollection::createLockJob()
{
- return true;
+ return new TemporaryLockCollectionJob(this);
}
-BackendReturn<bool> TemporaryCollection::lock()
+DeleteCollectionJob *TemporaryCollection::createDeleteJob()
{
- return BackendReturn<bool>(false, ErrorNotSupported);
+ TemporaryDeleteCollectionJob *job = new TemporaryDeleteCollectionJob(this);
+ connect(job, SIGNAL(result(QueuedJob*)),
+ SLOT(deleteCollectionJobResult(QueuedJob*)));
+ return job;
}
-BackendReturn<bool> TemporaryCollection::deleteCollection()
+CreateItemJob *TemporaryCollection::createCreateItemJob(const QString &label,
+ const QMap<QString, QString> \
&attributes, + const \
QCA::SecureArray &secret, + \
bool locked, bool replace) {
- emit collectionDeleted(this);
- deleteLater();
- return true;
+ return new TemporaryCreateItemJob(label, attributes, secret, locked, replace, \
this); }
BackendReturn<BackendItem*> TemporaryCollection::createItem(const QString &label,
const QMap<QString, \
QString> &attributes,
const QCA::SecureArray \
&secret,
- bool replace, bool \
locked) + bool locked, \
bool replace) {
Q_UNUSED(locked);
@@ -143,9 +151,12 @@ BackendReturn<BackendItem*> \
TemporaryCollection::createItem(const QString &label if (!item) {
item = new TemporaryItem(createId(), this);
}
+ // block signals while changing label, secret and attributes
+ item->blockSignals(true);
item->setLabel(label);
item->setAttributes(attributes);
item->setSecret(secret);
+ item->blockSignals(false);
if (replacing) {
emit itemChanged(item);
@@ -160,10 +171,9 @@ BackendReturn<BackendItem*> \
TemporaryCollection::createItem(const QString &label return item;
}
-BackendReturn<bool> TemporaryCollection::changeAuthentication()
+ChangeAuthenticationCollectionJob \
*TemporaryCollection::createChangeAuthenticationJob() {
- // TODO: an error might actually be better
- return false;
+ return new TemporaryChangeAuthenticationCollectionJob(this);
}
void TemporaryCollection::slotItemDeleted(BackendItem *item)
@@ -172,4 +182,14 @@ void TemporaryCollection::slotItemDeleted(BackendItem *item)
emit itemDeleted(item);
}
+void TemporaryCollection::deleteCollectionJobResult(QueuedJob *job)
+{
+ TemporaryDeleteCollectionJob *dcj = \
qobject_cast<TemporaryDeleteCollectionJob*>(job); + Q_ASSERT(dcj);
+ if (!dcj->result()) {
+ return;
+ }
+ emit collectionDeleted(this);
+}
+
#include "temporarycollection.moc"
diff --git a/backend/temporary/temporarycollection.h \
b/backend/temporary/temporarycollection.h index 1c942e6..a6e90e7 100644
--- a/backend/temporary/temporarycollection.h
+++ b/backend/temporary/temporarycollection.h
@@ -23,6 +23,9 @@
#include "../backendcollection.h"
+// forward declarations
+class TemporaryCreateItemJob;
+
/**
* A temporary collection stored in memory.
*/
@@ -104,44 +107,22 @@ public:
const QMap<QString, QString> &attributes) const;
/**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
- *
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is
- * required.
- * @remarks always returns true as all calls on temporary
- * items are immediate
- */
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
-
- /**
- * Unlock this collection.
- *
- * @return true if the collection is now unlocked, false if unlocking
- * failed.
+ * Create a job for unlocking this collection.
*/
- virtual BackendReturn<bool> unlock();
+ virtual UnlockCollectionJob *createUnlockJob();
/**
- * Lock this collection.
- *
- * @return true if the collection is now locked, false if locking
- * failed (the collection couldn't be locked or unlocking is not
- * supported by this backend).
+ * Create a job for locking this collection.
*/
- virtual BackendReturn<bool> lock();
+ virtual LockCollectionJob *createLockJob();
/**
- * Delete this collection.
- *
- * @return true if the collection was deleted, false if it wasn't.
+ * Create a job for deleting this collection.
*/
- virtual BackendReturn<bool> deleteCollection();
+ virtual DeleteCollectionJob *createDeleteJob();
/**
- * Create an item.
+ * Create a job for creating an item.
*
* @param label label to assign to the new item
* @param attributes attributes to store for the new item
@@ -150,20 +131,24 @@ public:
* will be replaced, if false no item will be created
* if one with the same attributes already exists
* @param locked if true, the item will be locked after creation
- * @return the item created or 0 if an error occurred.
*/
- virtual BackendReturn<BackendItem*> createItem(const QString &label,
- const QMap<QString, QString> \
&attributes,
- const QCA::SecureArray &secret, \
bool replace,
- bool locked);
+ virtual CreateItemJob *createCreateItemJob(const QString &label,
+ const QMap<QString, QString> \
&attributes, + const QCA::SecureArray \
&secret, bool replace, + bool locked);
/**
- * Change this collection's authentication.
- *
- * @return Always false as TemporaryCollection doesn't support authentication
+ * Create a job for changingcoll this collection's authentication.
*/
- virtual BackendReturn<bool> changeAuthentication();
+ virtual ChangeAuthenticationCollectionJob *createChangeAuthenticationJob();
+protected:
+ // Method for creating items. This is only called by TemporaryCreateItemJobs.
+ BackendReturn<BackendItem*> createItem(const QString &label,
+ const QMap<QString, QString> &attributes,
+ const QCA::SecureArray &secret, bool \
replace, + bool locked);
+
private Q_SLOTS:
/**
* Remove an item from our list of known items.
@@ -171,8 +156,17 @@ private Q_SLOTS:
* @param item Item to remove
*/
void slotItemDeleted(BackendItem *item);
+
+ /**
+ * Called when a DeleteCollectionJob signals its result.
+ *
+ * @param job the job that finished
+ */
+ void deleteCollectionJobResult(QueuedJob *job);
private:
+ friend class TemporaryCreateItemJob;
+
QString m_id;
QString m_label;
QDateTime m_created;
diff --git a/backend/temporary/temporarycollectionmanager.cpp \
b/backend/temporary/temporarycollectionmanager.cpp index 008cdc6..cdb8559 100644
--- a/backend/temporary/temporarycollectionmanager.cpp
+++ b/backend/temporary/temporarycollectionmanager.cpp
@@ -20,9 +20,12 @@
#include "temporarycollectionmanager.h"
#include "temporarycollection.h"
+#include "temporaryjobs.h"
#include <secrettool.h>
+#include <QtCore/QTimer>
+
TemporaryCollectionManager::TemporaryCollectionManager(QObject *parent)
: BackendCollectionManager(parent)
{
@@ -32,26 +35,30 @@ TemporaryCollectionManager::~TemporaryCollectionManager()
{
}
-bool TemporaryCollectionManager::isCallImmediate(AsyncCall::AsyncType type) const
+CreateCollectionJob *TemporaryCollectionManager::createCreateCollectionJob(
+ const QString &label, bool locked)
{
- Q_UNUSED(type);
- return true;
+ TemporaryCreateCollectionJob *job = new TemporaryCreateCollectionJob(label,
+ locked,
+ this);
+ connect(job, SIGNAL(result(QueuedJob*)),
+ SLOT(createCollectionJobResult(QueuedJob*)));
+ return job;
}
-BackendReturn<BackendCollection *> TemporaryCollectionManager::createCollection(
- const QString &label, bool locked)
+void TemporaryCollectionManager::createCollectionJobResult(QueuedJob *job)
{
- Q_UNUSED(locked);
+ CreateCollectionJob *ccj = qobject_cast<CreateCollectionJob*>(job);
+ Q_ASSERT(ccj);
+
+ if (!ccj->collection()) {
+ return;
+ }
- TemporaryCollection *coll = new TemporaryCollection(createId(), this);
- coll->setLabel(label);
-
// connect signals
- connect(coll, SIGNAL(collectionDeleted(BackendCollection*)),
- SIGNAL(collectionDeleted(BackendCollection*)));
- emit collectionCreated(coll);
-
- return coll;
+ connect(ccj->collection(), SIGNAL(collectionDeleted(BackendCollection*)),
+ SIGNAL(collectionDeleted(BackendCollection*)));
+ emit collectionCreated(ccj->collection());
}
#include "temporarycollectionmanager.moc"
diff --git a/backend/temporary/temporarycollectionmanager.h \
b/backend/temporary/temporarycollectionmanager.h index 0ca2835..bb41a6c 100644
--- a/backend/temporary/temporarycollectionmanager.h
+++ b/backend/temporary/temporarycollectionmanager.h
@@ -23,8 +23,6 @@
#include "../backendcollectionmanager.h"
-class TemporaryCollection;
-
/**
* Manager for temporary collections.
*/
@@ -46,26 +44,21 @@ public:
virtual ~TemporaryCollectionManager();
/**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
+ * Create a job for creating a new collection.
*
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is
- * required.
- * @remarks always returns true as all calls on temporary
- * items are immediate
+ * @param label the label of the new collection
+ * @param lock ignored. Temporary collections can't be locked.
*/
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
-
+ virtual CreateCollectionJob *createCreateCollectionJob(const QString &label,
+ bool locked);
+
+private Q_SLOTS:
/**
- * Create a new collection.
+ * Called when a CreateCollectionJob created by this manager finishes.
*
- * @param label the label of the new collection
- * @param lock ignored. Temporary collections can't be locked.
- * @return the collection or 0 on error
+ * @param job the job that finished
*/
- virtual BackendReturn<BackendCollection*> createCollection(const QString &label, \
bool locked); + void createCollectionJobResult(QueuedJob *job);
};
#endif
diff --git a/backend/temporary/temporaryitem.cpp \
b/backend/temporary/temporaryitem.cpp index 0449164..74f95dc 100644
--- a/backend/temporary/temporaryitem.cpp
+++ b/backend/temporary/temporaryitem.cpp
@@ -20,6 +20,9 @@
#include "temporaryitem.h"
#include "temporarycollection.h"
+#include "temporaryjobs.h"
+
+#include <QtCore/QTimer>
TemporaryItem::TemporaryItem(const QString &id, TemporaryCollection *parent)
: BackendItem(parent), m_id(id)
@@ -89,33 +92,26 @@ bool TemporaryItem::isLocked() const
return false;
}
-bool TemporaryItem::isCallImmediate(AsyncCall::AsyncType type) const
+UnlockItemJob *TemporaryItem::createUnlockJob()
{
- Q_UNUSED(type);
- return true;
+ return new TemporaryUnlockItemJob(this);
}
-BackendReturn<bool> TemporaryItem::unlock()
+LockItemJob *TemporaryItem::createLockJob()
{
- return true;
+ return new TemporaryLockItemJob(this);
}
-BackendReturn<bool> TemporaryItem::lock()
+DeleteItemJob *TemporaryItem::createDeleteJob()
{
- return BackendReturn<bool>(false, ErrorNotSupported);
-}
-
-BackendReturn<bool> TemporaryItem::deleteItem()
-{
- emit itemDeleted(this);
- deleteLater();
- return true;
+ TemporaryDeleteItemJob *job = new TemporaryDeleteItemJob(this);
+ connect(job, SIGNAL(result(QueuedJob*)), SLOT(deleteItemJobResult(QueuedJob*)));
+ return job;
}
-BackendReturn<bool> TemporaryItem::changeAuthentication()
+ChangeAuthenticationItemJob *TemporaryItem::createChangeAuthenticationJob()
{
- // TODO: error might be better
- return false;
+ return new TemporaryChangeAuthenticationItemJob(this);
}
bool TemporaryItem::matches(const QMap<QString, QString> &attributes)
@@ -132,6 +128,16 @@ bool TemporaryItem::matches(const QMap<QString, QString> \
&attributes) return true;
}
+void TemporaryItem::deleteItemJobResult(QueuedJob *job)
+{
+ TemporaryDeleteItemJob *dij = qobject_cast<TemporaryDeleteItemJob*>(job);
+ Q_ASSERT(dij);
+ if (!dij->result()) {
+ return;
+ }
+ emit itemDeleted(this);
+}
+
void TemporaryItem::markAsModified()
{
m_modified = QDateTime::currentDateTime();
diff --git a/backend/temporary/temporaryitem.h b/backend/temporary/temporaryitem.h
index 2817219..6a67532 100644
--- a/backend/temporary/temporaryitem.h
+++ b/backend/temporary/temporaryitem.h
@@ -112,53 +112,24 @@ public:
virtual bool isLocked() const;
/**
- * Check if a type of call can be handled immediately
- * (synchronously) without requiring an async call.
- *
- * @param type the type of call to check
- * @return true if the type of call can be handled
- * immediately, false if an async call is
- * required.
- * @remarks always returns true as all calls on temporary
- * items are immediate
- */
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
-
- /**
- * Unlock this item.
- *
- * @return true if the item was unlocked successfully, false if unlocking failed
- * or an error occurred.
- * @remarks this is only called by processCall. To set an unlock call
- * erroneous, use the Base::setError() call.
+ * Create a job for unlocking this item.
*/
- virtual BackendReturn<bool> unlock();
+ virtual UnlockItemJob *createUnlockJob();
/**
- * Lock this item.
- *
- * @return true if the item was locked successfully, false if locking failed
- * or an error occurred.
- * @remarks this is only called by processCall. To set a lock call
- * erroneous, use the Base::setError() call.
+ * Create a job for locking this item.
*/
- virtual BackendReturn<bool> lock();
+ virtual LockItemJob *createLockJob();
/**
- * Delete this item.
- *
- * @return true if the item was deleted, false if it wasn't or an error occurred.
- * @remarks this is only called by processCall. To set a delete call
- * erroneous, use the Base::setError() call.
+ * Create a job for deleting this item.
*/
- virtual BackendReturn<bool> deleteItem();
+ virtual DeleteItemJob *createDeleteJob();
/**
- * Change this item's authentication.
- *
- * @return always false as TemporaryItem doesn't support authentication
+ * Create a job for changing this item's authentication.
*/
- virtual BackendReturn<bool> changeAuthentication();
+ virtual ChangeAuthenticationItemJob *createChangeAuthenticationJob();
/**
* Check whether this item matches the attributes given.
@@ -169,6 +140,14 @@ public:
*/
bool matches(const QMap<QString, QString> &attributes);
+private Q_SLOTS:
+ /**
+ * Called when a DeleteItemJob signals its result.
+ *
+ * @param job the job that finished
+ */
+ void deleteItemJobResult(QueuedJob *job);
+
private:
/**
* Mark this item as modified and emit the \sa itemChanged signal.
diff --git a/backend/temporary/temporaryjobs.cpp \
b/backend/temporary/temporaryjobs.cpp new file mode 100644
index 0000000..4c772de
--- /dev/null
+++ b/backend/temporary/temporaryjobs.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "temporaryjobs.h"
+
+#include <secrettool.h>
+
+TemporaryCreateCollectionJob::TemporaryCreateCollectionJob(const QString &label,
+ bool locked,
+ \
TemporaryCollectionManager *manager) + : CreateCollectionJob(label, locked, manager)
+{
+}
+
+void TemporaryCreateCollectionJob::exec()
+{
+ TemporaryCollection *coll = new TemporaryCollection(createId(), manager());
+ coll->setLabel(label());
+
+ setCollection(coll);
+ emitResult();
+}
+
+TemporaryUnlockCollectionJob::TemporaryUnlockCollectionJob(BackendCollection *coll)
+ : UnlockCollectionJob(coll)
+{
+}
+
+void TemporaryUnlockCollectionJob::exec()
+{
+ // collection is always unlocked.
+ setResult(true);
+ emitResult();
+}
+
+TemporaryLockCollectionJob::TemporaryLockCollectionJob(BackendCollection *coll)
+ : LockCollectionJob(coll)
+{
+}
+
+void TemporaryLockCollectionJob::exec()
+{
+ // collection can not be locked as that's not supported for this backend.
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+TemporaryDeleteCollectionJob::TemporaryDeleteCollectionJob(BackendCollection *coll)
+ : DeleteCollectionJob(coll)
+{
+}
+
+void TemporaryDeleteCollectionJob::exec()
+{
+ setResult(true);
+ collection()->deleteLater();
+ emitResult();
+}
+
+TemporaryChangeAuthenticationCollectionJob::TemporaryChangeAuthenticationCollectionJob(BackendCollection \
*coll) + : ChangeAuthenticationCollectionJob(coll)
+{
+}
+
+void TemporaryChangeAuthenticationCollectionJob::exec()
+{
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+TemporaryCreateItemJob::TemporaryCreateItemJob(const QString &label,
+ const QMap<QString, QString> \
&attributes, + const QCA::SecureArray \
&secret, + bool locked, bool replace,
+ TemporaryCollection *collection)
+ : CreateItemJob(label, attributes, secret, locked, replace, collection),
+ m_tempColl(collection)
+{
+}
+
+void TemporaryCreateItemJob::exec()
+{
+ // let the collection do all the work.
+ BackendReturn<BackendItem*> rc = m_tempColl->createItem(label(), attributes(),
+ secret(), locked(),
+ replace());
+ if (rc.isError()) {
+ setError(rc.error(), rc.errorMessage());
+ } else {
+ setItem(rc.value());
+ }
+ emitResult();
+}
+
+TemporaryUnlockItemJob::TemporaryUnlockItemJob(BackendItem *item) : \
UnlockItemJob(item) +{
+}
+
+void TemporaryUnlockItemJob::exec()
+{
+ // item is always unlocked.
+ setResult(true);
+ emitResult();
+}
+
+TemporaryLockItemJob::TemporaryLockItemJob(BackendItem *item) : LockItemJob(item)
+{
+}
+
+void TemporaryLockItemJob::exec()
+{
+ // item can not be locked as that's not supported for this backend.
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+TemporaryDeleteItemJob::TemporaryDeleteItemJob(BackendItem *item) : \
DeleteItemJob(item) +{
+}
+
+void TemporaryDeleteItemJob::exec()
+{
+ setResult(true);
+ item()->deleteLater();
+ emitResult();
+}
+
+TemporaryChangeAuthenticationItemJob::TemporaryChangeAuthenticationItemJob(BackendItem \
*item) + : ChangeAuthenticationItemJob(item)
+{
+}
+
+void TemporaryChangeAuthenticationItemJob::exec()
+{
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+#include "temporaryjobs.moc"
diff --git a/backend/temporary/temporaryjobs.h b/backend/temporary/temporaryjobs.h
new file mode 100644
index 0000000..0b6e74a
--- /dev/null
+++ b/backend/temporary/temporaryjobs.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TEMPORARYJOBS_H
+#define TEMPORARYJOBS_H
+
+#include "temporarycollectionmanager.h"
+#include "temporarycollection.h"
+#include "temporaryitem.h"
+#include "../backendjob.h"
+
+#include <QtCore/QString>
+
+/**
+ * Job for creating a new temporary collection.
+ */
+class TemporaryCreateCollectionJob : public CreateCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryCreateCollectionJob(const QString &label, bool locked,
+ TemporaryCollectionManager *manager);
+ virtual void exec();
+};
+
+/**
+ * Job for unlocking a temporary collection.
+ */
+class TemporaryUnlockCollectionJob : public UnlockCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryUnlockCollectionJob(BackendCollection *coll);
+ virtual void exec();
+};
+
+/**
+ * Job for locking a temporary collection.
+ */
+class TemporaryLockCollectionJob : public LockCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryLockCollectionJob(BackendCollection *coll);
+ virtual void exec();
+};
+
+/**
+ * Job for deleting a temporary collection.
+ */
+class TemporaryDeleteCollectionJob : public DeleteCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryDeleteCollectionJob(BackendCollection *coll);
+ virtual void exec();
+};
+
+/**
+ * Job for changing a temporary collection's authentication.
+ */
+class TemporaryChangeAuthenticationCollectionJob : public \
ChangeAuthenticationCollectionJob +{
+ Q_OBJECT
+
+public:
+ TemporaryChangeAuthenticationCollectionJob(BackendCollection *coll);
+ virtual void exec();
+};
+
+/**
+ * Job for creating an item inside a temporary collection.
+ */
+class TemporaryCreateItemJob : public CreateItemJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryCreateItemJob(const QString &label, const QMap<QString, QString> \
&attributes, + const QCA::SecureArray &secret, bool locked, \
bool replace, + TemporaryCollection *collection);
+ virtual void exec();
+
+private:
+ TemporaryCollection *m_tempColl;
+};
+
+/**
+ * Job for unlocking an item inside a temporary collection.
+ */
+class TemporaryUnlockItemJob : public UnlockItemJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryUnlockItemJob(BackendItem *item);
+ virtual void exec();
+};
+
+/**
+ * Job for locking an item inside a temporary collection.
+ */
+class TemporaryLockItemJob : public LockItemJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryLockItemJob(BackendItem *item);
+ virtual void exec();
+};
+
+/**
+ * Job for deleting an item inside a temporary collection.
+ */
+class TemporaryDeleteItemJob : public DeleteItemJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryDeleteItemJob(BackendItem *item);
+ virtual void exec();
+};
+
+/**
+ * Job for changing a temporary item's authentication.
+ */
+class TemporaryChangeAuthenticationItemJob : public ChangeAuthenticationItemJob
+{
+ Q_OBJECT
+
+public:
+ TemporaryChangeAuthenticationItemJob(BackendItem *item);
+ virtual void exec();
+};
+
+#endif
diff --git a/backend/tests/backendtest.cpp b/backend/tests/backendtest.cpp
index 355420a..0a66fc3 100644
--- a/backend/tests/backendtest.cpp
+++ b/backend/tests/backendtest.cpp
@@ -47,135 +47,341 @@ void BackendTest::initTestCase()
m_master->addManager(m_manager);
}
-void BackendTest::testCreateCollection()
+void BackendTest::testCreateCollectionSync()
{
- QEventLoop e;
- AsyncCreateCollection *createColl = new AsyncCreateCollection("test", false, \
m_manager); + CreateCollectionJob *createColl = \
m_manager->createCreateCollectionJob("test", false);
QSignalSpy managerSpy(m_manager, SIGNAL(collectionCreated(BackendCollection*)));
QSignalSpy masterSpy(m_master, SIGNAL(collectionCreated(BackendCollection*)));
- QVERIFY(connect(createColl, SIGNAL(completed(AsyncCall*,bool)), &e, \
SLOT(quit())));
- createColl->enqueue();
- e.exec();
+ QVERIFY(createColl->isImmediate());
+ createColl->exec();
+
+ QVERIFY(createColl->isFinished());
QCOMPARE(createColl->error(), NoError);
- QVERIFY(createColl->isCompleted());
QVERIFY(!createColl->isDismissed());
+ QVERIFY(createColl->collection() != 0);
// Verify signals
QCOMPARE(managerSpy.count(), 1);
QCOMPARE(managerSpy.takeFirst().at(0).value<BackendCollection*>()->label().value(), \
QString("test")); QCOMPARE(masterSpy.count(), 1);
- QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>()->label().value(), \
QString("test")); + \
QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>(), \
createColl->collection());
// Check the collection is present and alive
QCOMPARE(m_master->collections().size(), 1);
- QCOMPARE(m_master->collections().first()->label().value(), QString("test"));
+ QCOMPARE(m_master->collections().first(), createColl->collection());
+ QCOMPARE(m_master->collections().first()->label().value(), \
QLatin1String("test")); }
-void BackendTest::testCreateItem()
+void BackendTest::testCreateItemSync()
{
- QEventLoop e;
BackendCollection *collection = m_master->collections().first();
QMap<QString,QString> attr;
attr["mainattr"] = "haha";
QCA::SecureArray array(4, 'c');
- AsyncCreateItem *createItem = new AsyncCreateItem("testitem", attr, array,
- false, false, \
m_master->collections().first());
-
+ CreateItemJob *createItem = collection->createCreateItemJob("testitem", attr, \
array, + false, \
false);
QSignalSpy collectionSpy(collection, SIGNAL(itemCreated(BackendItem*)));
- QVERIFY(connect(createItem, SIGNAL(completed(AsyncCall*,bool)), &e, \
SLOT(quit())));
- createItem->enqueue();
- e.exec();
+ QVERIFY(createItem->isImmediate());
+
+ createItem->exec();
+
+ QVERIFY(createItem->isFinished());
QCOMPARE(createItem->error(), NoError);
- QVERIFY(createItem->isCompleted());
QVERIFY(!createItem->isDismissed());
+ QVERIFY(createItem->item() != 0);
// Verify signals
QCOMPARE(collectionSpy.count(), 1);
- QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>()->label().value(), \
QString("testitem")); + \
QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>(), createItem->item()); \
// Check the item is present and alive
QCOMPARE(collection->items().value().size(), 1);
+ QCOMPARE(collection->items().value().first(), createItem->item());
QCOMPARE(collection->items().value().first()->secret().value().toByteArray(), \
QByteArray("cccc")); }
-void BackendTest::testChangeItem()
+void BackendTest::testReplaceItemSync()
{
- QEventLoop e;
BackendCollection *collection = m_master->collections().first();
QMap<QString,QString> attr;
attr["mainattr"] = "haha";
QCA::SecureArray array(QByteArray("arealsecrete243"));
- AsyncCreateItem *createItem = new AsyncCreateItem("testitem", attr, array,
- false, true, \
m_master->collections().first()); + CreateItemJob *createItem = \
collection->createCreateItemJob("testitem2", attr, array, + \
false, true);
QSignalSpy collectionSpy(collection, SIGNAL(itemChanged(BackendItem*)));
- QVERIFY(connect(createItem, SIGNAL(completed(AsyncCall*,bool)), &e, \
SLOT(quit())));
- createItem->enqueue();
- e.exec();
+ QVERIFY(createItem->isImmediate());
+
+ createItem->exec();
+
+ QVERIFY(createItem->isFinished());
QCOMPARE(createItem->error(), NoError);
- QVERIFY(createItem->isCompleted());
QVERIFY(!createItem->isDismissed());
+ QVERIFY(createItem->item() != 0);
// Verify signals
- QCOMPARE(collectionSpy.count(), 4);
- QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>()->label().value(), \
QString("testitem")); + QCOMPARE(collectionSpy.count(), 1);
+ QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>(), \
createItem->item());
// Check the item is present and alive
QCOMPARE(collection->items().value().size(), 1);
+ QCOMPARE(collection->items().value().first(), createItem->item());
QCOMPARE(collection->items().value().first()->secret().value().toByteArray(), \
QByteArray("arealsecrete243")); }
-void BackendTest::testDeleteItem()
+void BackendTest::testDoNotReplaceItemSync()
{
- QEventLoop e;
BackendCollection *collection = m_master->collections().first();
- BackendItem *item = collection->items().value().first();
- AsyncSimpleBooleanCall *call = new \
AsyncSimpleBooleanCall(AsyncCall::AsyncDeleteItem, item); + QMap<QString,QString> \
attr; + attr["mainattr"] = "haha";
+ QCA::SecureArray array(QByteArray("anothersecret"));
+ CreateItemJob *createItem = collection->createCreateItemJob("testitem3", attr, \
array, + false, \
false);
+ QSignalSpy collectionSpy(collection, SIGNAL(itemChanged(BackendItem*)));
+
+ QVERIFY(createItem->isImmediate());
+
+ createItem->exec();
+
+ QVERIFY(createItem->isFinished());
+ QCOMPARE(createItem->error(), ErrorAlreadyExists);
+ QVERIFY(!createItem->isDismissed());
+ QVERIFY(createItem->item() == 0);
+
+ // Verify signals
+ QCOMPARE(collectionSpy.count(), 0);
+
+ // Check the item is present and alive
+ QCOMPARE(collection->items().value().size(), 1);
+ QCOMPARE(collection->items().value().first()->secret().value().toByteArray(), \
QByteArray("arealsecrete243")); +}
+
+void BackendTest::testDeleteItemSync()
+{
+ BackendCollection *collection = m_master->collections().first();
+ BackendItem *item = collection->items().value().first();
+ DeleteItemJob *deleteItem = item->createDeleteJob();
QSignalSpy collectionSpy(collection, SIGNAL(itemDeleted(BackendItem*)));
- QVERIFY(connect(call, SIGNAL(completed(AsyncCall*,bool)), &e, SLOT(quit())));
- call->enqueue();
- e.exec();
+
+ QVERIFY(deleteItem->isImmediate());
- QVERIFY(call->result());
- QCOMPARE(call->error(), NoError);
- QVERIFY(call->isCompleted());
- QVERIFY(!call->isDismissed());
+ deleteItem->exec();
+
+ QVERIFY(deleteItem->isFinished());
+ QCOMPARE(deleteItem->error(), NoError);
+ QVERIFY(deleteItem->result());
+ QVERIFY(!deleteItem->isDismissed());
// Verify signals
QCOMPARE(collectionSpy.count(), 1);
- QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>()->label().value(), \
QString("testitem")); + \
QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>()->label().value(), \
QString("testitem2"));
// Check the item is present and alive
QVERIFY(collection->items().value().isEmpty());
}
-void BackendTest::testDeleteCollection()
+void BackendTest::testDeleteCollectionSync()
{
- QEventLoop e;
BackendCollection *collection = m_master->collections().first();
- AsyncSimpleBooleanCall *call = new \
AsyncSimpleBooleanCall(AsyncCall::AsyncDeleteCollection, collection);
-
+ DeleteCollectionJob *deleteCollection = collection->createDeleteJob();
QSignalSpy managerSpy(m_manager, SIGNAL(collectionDeleted(BackendCollection*)));
QSignalSpy masterSpy(m_master, SIGNAL(collectionDeleted(BackendCollection*)));
- QVERIFY(connect(call, SIGNAL(completed(AsyncCall*,bool)), &e, SLOT(quit())));
- call->enqueue();
- e.exec();
- QVERIFY(call->result());
- QCOMPARE(call->error(), NoError);
- QVERIFY(call->isCompleted());
- QVERIFY(!call->isDismissed());
+ QVERIFY(deleteCollection->isImmediate());
+
+ deleteCollection->exec();
+
+ QVERIFY(deleteCollection->isFinished());
+ QCOMPARE(deleteCollection->error(), NoError);
+ QVERIFY(deleteCollection->result());
+ QVERIFY(!deleteCollection->isDismissed());
+
+ // Verify signals
+ QCOMPARE(managerSpy.count(), 1);
+ QCOMPARE(managerSpy.takeFirst().at(0).value<BackendCollection*>(), collection);
+ QCOMPARE(masterSpy.count(), 1);
+ QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>(), collection);
+
+ // Check the collection is dead
+ QVERIFY(m_master->collections().isEmpty());
+}
+
+void BackendTest::testCreateCollectionAsync()
+{
+ CreateCollectionJob *createColl = m_manager->createCreateCollectionJob("test", \
false); + QSignalSpy managerSpy(m_manager, \
SIGNAL(collectionCreated(BackendCollection*))); + QSignalSpy masterSpy(m_master, \
SIGNAL(collectionCreated(BackendCollection*))); + QEventLoop loop;
+ QVERIFY(loop.connect(createColl, SIGNAL(result(QueuedJob*)), SLOT(quit())));
+ createColl->start();
+ if (!createColl->isFinished()) {
+ loop.exec();
+ }
+
+ QVERIFY(createColl->isFinished());
+ QCOMPARE(createColl->error(), NoError);
+ QVERIFY(!createColl->isDismissed());
+ QVERIFY(createColl->collection() != 0);
// Verify signals
QCOMPARE(managerSpy.count(), 1);
QCOMPARE(managerSpy.takeFirst().at(0).value<BackendCollection*>()->label().value(), \
QString("test")); QCOMPARE(masterSpy.count(), 1);
- QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>()->label().value(), \
QString("test")); + \
QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>(), \
createColl->collection()); +
+ // Check the collection is present and alive
+ QCOMPARE(m_master->collections().size(), 1);
+ QCOMPARE(m_master->collections().first(), createColl->collection());
+ QCOMPARE(m_master->collections().first()->label().value(), \
QLatin1String("test")); +}
+
+void BackendTest::testCreateItemAsync()
+{
+ BackendCollection *collection = m_master->collections().first();
+ QMap<QString,QString> attr;
+ attr["mainattr"] = "haha";
+ QCA::SecureArray array(4, 'c');
+ CreateItemJob *createItem = collection->createCreateItemJob("testitem", attr, \
array, + false, \
false); + QSignalSpy collectionSpy(collection, SIGNAL(itemCreated(BackendItem*)));
+ QEventLoop loop;
+ QVERIFY(loop.connect(createItem, SIGNAL(result(QueuedJob*)), SLOT(quit())));
+ createItem->start();
+ if (!createItem->isFinished()) {
+ loop.exec();
+ }
+
+ QVERIFY(createItem->isFinished());
+ QCOMPARE(createItem->error(), NoError);
+ QVERIFY(!createItem->isDismissed());
+ QVERIFY(createItem->item() != 0);
+
+ // Verify signals
+ QCOMPARE(collectionSpy.count(), 1);
+ QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>(), \
createItem->item()); +
+ // Check the item is present and alive
+ QCOMPARE(collection->items().value().size(), 1);
+ QCOMPARE(collection->items().value().first(), createItem->item());
+ QCOMPARE(collection->items().value().first()->secret().value().toByteArray(), \
QByteArray("cccc")); +}
+
+void BackendTest::testReplaceItemAsync()
+{
+ BackendCollection *collection = m_master->collections().first();
+ QMap<QString,QString> attr;
+ attr["mainattr"] = "haha";
+ QCA::SecureArray array(QByteArray("arealsecrete243"));
+ CreateItemJob *createItem = collection->createCreateItemJob("testitem2", attr, \
array, + false, true);
+
+ QSignalSpy collectionSpy(collection, SIGNAL(itemChanged(BackendItem*)));
+ QEventLoop loop;
+ QVERIFY(loop.connect(createItem, SIGNAL(result(QueuedJob*)), SLOT(quit())));
+ createItem->start();
+ if (!createItem->isFinished()) {
+ loop.exec();
+ }
+
+ QVERIFY(createItem->isFinished());
+ QCOMPARE(createItem->error(), NoError);
+ QVERIFY(!createItem->isDismissed());
+ QVERIFY(createItem->item() != 0);
+
+ // Verify signals
+ QCOMPARE(collectionSpy.count(), 1);
+ QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>(), \
createItem->item()); +
+ // Check the item is present and alive
+ QCOMPARE(collection->items().value().size(), 1);
+ QCOMPARE(collection->items().value().first(), createItem->item());
+ QCOMPARE(collection->items().value().first()->secret().value().toByteArray(), \
QByteArray("arealsecrete243")); +}
+
+void BackendTest::testDoNotReplaceItemAsync()
+{
+ BackendCollection *collection = m_master->collections().first();
+ QMap<QString,QString> attr;
+ attr["mainattr"] = "haha";
+ QCA::SecureArray array(QByteArray("anothersecret"));
+ CreateItemJob *createItem = collection->createCreateItemJob("testitem3", attr, \
array, + false, \
false); +
+ QSignalSpy collectionSpy(collection, SIGNAL(itemChanged(BackendItem*)));
+ QEventLoop loop;
+ QVERIFY(loop.connect(createItem, SIGNAL(result(QueuedJob*)), SLOT(quit())));
+ createItem->start();
+ if (!createItem->isFinished()) {
+ loop.exec();
+ }
+
+ QVERIFY(createItem->isFinished());
+ QCOMPARE(createItem->error(), ErrorAlreadyExists);
+ QVERIFY(!createItem->isDismissed());
+ QVERIFY(createItem->item() == 0);
+
+ // Verify signals
+ QCOMPARE(collectionSpy.count(), 0);
+
+ // Check the item is present and alive
+ QCOMPARE(collection->items().value().size(), 1);
+ QCOMPARE(collection->items().value().first()->secret().value().toByteArray(), \
QByteArray("arealsecrete243")); +}
+
+void BackendTest::testDeleteItemAsync()
+{
+ BackendCollection *collection = m_master->collections().first();
+ BackendItem *item = collection->items().value().first();
+ DeleteItemJob *deleteItem = item->createDeleteJob();
+ QSignalSpy collectionSpy(collection, SIGNAL(itemDeleted(BackendItem*)));
+ QEventLoop loop;
+ QVERIFY(loop.connect(deleteItem, SIGNAL(result(QueuedJob*)), SLOT(quit())));
+ deleteItem->start();
+ if (!deleteItem->isFinished()) {
+ loop.exec();
+ }
+
+ QVERIFY(deleteItem->isFinished());
+ QCOMPARE(deleteItem->error(), NoError);
+ QVERIFY(deleteItem->result());
+ QVERIFY(!deleteItem->isDismissed());
+
+ // Verify signals
+ QCOMPARE(collectionSpy.count(), 1);
+ QCOMPARE(collectionSpy.takeFirst().at(0).value<BackendItem*>()->label().value(), \
QString("testitem2")); +
+ // Check the item is present and alive
+ QVERIFY(collection->items().value().isEmpty());
+}
+
+void BackendTest::testDeleteCollectionAsync()
+{
+ BackendCollection *collection = m_master->collections().first();
+ DeleteCollectionJob *deleteCollection = collection->createDeleteJob();
+ QSignalSpy managerSpy(m_manager, SIGNAL(collectionDeleted(BackendCollection*)));
+ QSignalSpy masterSpy(m_master, SIGNAL(collectionDeleted(BackendCollection*)));
+ QEventLoop loop;
+ QVERIFY(loop.connect(deleteCollection, SIGNAL(result(QueuedJob*)), \
SLOT(quit()))); + deleteCollection->start();
+ if (!deleteCollection->isFinished()) {
+ loop.exec();
+ }
+
+ QVERIFY(deleteCollection->isFinished());
+ QCOMPARE(deleteCollection->error(), NoError);
+ QVERIFY(deleteCollection->result());
+ QVERIFY(!deleteCollection->isDismissed());
+
+ // Verify signals
+ QCOMPARE(managerSpy.count(), 1);
+ QCOMPARE(managerSpy.takeFirst().at(0).value<BackendCollection*>(), collection);
+ QCOMPARE(masterSpy.count(), 1);
+ QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>(), collection);
// Check the collection is dead
QVERIFY(m_master->collections().isEmpty());
@@ -183,7 +389,7 @@ void BackendTest::testDeleteCollection()
void BackendTest::cleanupTestCase()
{
-
+ // TODO: delete stuff so this can also be used for valgrind leak-checking.
}
diff --git a/backend/tests/backendtest.h b/backend/tests/backendtest.h
index 437ab45..39111f1 100644
--- a/backend/tests/backendtest.h
+++ b/backend/tests/backendtest.h
@@ -36,11 +36,19 @@ class BackendTest : public QObject
private Q_SLOTS:
void initTestCase();
- void testCreateCollection();
- void testCreateItem();
- void testChangeItem();
- void testDeleteItem();
- void testDeleteCollection();
+ void testCreateCollectionSync();
+ void testCreateItemSync();
+ void testReplaceItemSync();
+ void testDoNotReplaceItemSync();
+ void testDeleteItemSync();
+ void testDeleteCollectionSync();
+
+ void testCreateCollectionAsync();
+ void testCreateItemAsync();
+ void testReplaceItemAsync();
+ void testDoNotReplaceItemAsync();
+ void testDeleteItemAsync();
+ void testDeleteCollectionAsync();
void cleanupTestCase();
diff --git a/daemon/collection.cpp b/daemon/collection.cpp
index 6cef29d..15d8ce6 100644
--- a/daemon/collection.cpp
+++ b/daemon/collection.cpp
@@ -93,12 +93,12 @@ qulonglong Collection::modified() const
QDBusObjectPath Collection::deleteCollection()
{
- // bypass prompt?
- if (m_collection->isCallImmediate(AsyncCall::AsyncDeleteCollection)) {
- m_collection->deleteCollection();
+ DeleteCollectionJob *dcj = m_collection->createDeleteJob();
+ if (dcj->isImmediate()) {
+ dcj->exec();
return QDBusObjectPath("/");
} else {
- PromptCollectionDelete *p = new PromptCollectionDelete(m_collection, \
m_service); + SingleJobPrompt *p = new SingleJobPrompt(m_service, dcj, this);
return p->objectPath();
}
}
@@ -122,7 +122,7 @@ QDBusObjectPath Collection::createItem(const QMap<QString, \
QVariant> &properties
const Secret &secret, bool replace,
QDBusObjectPath &prompt)
{
- // TODO: bypass prompt
+ // default label?
QString label;
QMap<QString, QString> attributes;
bool locked = false;
@@ -150,21 +150,20 @@ QDBusObjectPath Collection::createItem(const QMap<QString, \
QVariant> &properties if (!ok) {
// TODO: invalid session
}
- if (m_collection->isCallImmediate(AsyncCall::AsyncCreateItem)) {
- BackendReturn<BackendItem*> rc = m_collection->createItem(label, attributes, \
secretValue,
- replace, locked);
- if (rc.isError()) {
+ CreateItemJob *cij = m_collection->createCreateItemJob(label, attributes, \
secretValue, + replace, \
locked); + if (cij->isImmediate()) {
+ cij->exec();
+ if (cij->error() != NoError || !cij->item()) {
// TODO: error creating the item
}
- // the item is already created inside slotItemCreated()
+ // the Item is already created inside slotItemCreated()
prompt.setPath("/");
- QDBusObjectPath itemPath(m_objectPath.path() + "/" + rc.value()->id());
+ QDBusObjectPath itemPath(m_objectPath.path() + "/" + cij->item()->id());
return itemPath;
} else {
- PromptBase *p = new PromptCollectionCreateItem(m_collection, label, \
attributes, locked,
- secret.value(), replace, \
m_service, this);
-
+ SingleJobPrompt *p = new SingleJobPrompt(m_service, cij, this);
prompt = p->objectPath();
return QDBusObjectPath("/");
}
diff --git a/daemon/item.cpp b/daemon/item.cpp
index bfb2747..93e1b09 100644
--- a/daemon/item.cpp
+++ b/daemon/item.cpp
@@ -95,15 +95,13 @@ qulonglong Item::modified() const
QDBusObjectPath Item::deleteItem()
{
- // bypass prompt?
- if (m_item->isCallImmediate(AsyncCall::AsyncDeleteItem)) {
- m_item->deleteItem();
+ DeleteItemJob *dij = m_item->createDeleteJob();
+ if (dij->isImmediate()) {
+ dij->exec();
return QDBusObjectPath("/");
} else {
- // FIXME: needs the service as well as some QObject.
- // I'd say the whole constructor should be checked
- // and its signature changed.
- PromptItemDelete *p = new PromptItemDelete(m_item, 0, 0);
+ // FIXME: needs the service!
+ SingleJobPrompt *p = new SingleJobPrompt(0, dij, this);
return p->objectPath();
}
}
diff --git a/daemon/prompt.cpp b/daemon/prompt.cpp
index 9c3e21b..0258293 100644
--- a/daemon/prompt.cpp
+++ b/daemon/prompt.cpp
@@ -30,7 +30,7 @@
#include <QtDBus/QDBusObjectPath>
PromptBase::PromptBase(Service *service, QObject *parent)
- : QObject(parent), m_prompted(false), m_serviceObjectPath(service->objectPath())
+ : QObject(parent), m_serviceObjectPath(service->objectPath())
{
Q_ASSERT(service);
m_objectPath.setPath(service->objectPath().path() + "/prompts/" + createId());
@@ -39,34 +39,13 @@ PromptBase::PromptBase(Service *service, QObject *parent)
QDBusConnection::sessionBus().registerObject(m_objectPath.path(), this);
}
-const QDBusObjectPath &PromptBase::objectPath() const
-{
- return m_objectPath;
-}
-
-void PromptBase::prompt(const QString &windowId)
+PromptBase::~PromptBase()
{
- Q_ASSERT(!m_prompted);
- Q_ASSERT(!m_pendingCalls.isEmpty());
-
- m_prompted = true;
-
- // TODO: convert windowId to a WId
- Q_FOREACH(AsyncCall *call, m_pendingCalls) {
- call->enqueue(windowId);
- }
}
-void PromptBase::dismiss()
+const QDBusObjectPath &PromptBase::objectPath() const
{
- Q_ASSERT(!m_prompted);
- Q_ASSERT(!m_pendingCalls.isEmpty());
-
- m_prompted = true;
-
- Q_FOREACH(AsyncCall *call, m_pendingCalls) {
- call->dismiss();
- }
+ return m_objectPath;
}
const QDBusObjectPath &PromptBase::serviceObjectPath() const
@@ -74,156 +53,261 @@ const QDBusObjectPath &PromptBase::serviceObjectPath() const
return m_serviceObjectPath;
}
-void PromptBase::addCall(AsyncCall *call)
+void PromptBase::emitCompleted(bool dismissed, const QVariant &result)
{
- Q_ASSERT(call);
- Q_ASSERT(!m_prompted);
-
- m_pendingCalls.append(call);
- connect(call, SIGNAL(completed(AsyncCall*, bool)), SLOT(slotCompleted(AsyncCall*, \
bool))); + emit completed(dismissed, result);
}
-void PromptBase::slotCompleted(AsyncCall *call, bool dismissed)
+SingleJobPrompt::SingleJobPrompt(Service* service, BackendJob* job, QObject* parent)
+ : PromptBase(service, parent), m_prompted(false), m_job(job)
{
- Q_ASSERT(m_pendingCalls.contains(call));
- m_pendingCalls.removeAll(call);
- if (m_pendingCalls.size() > 0) {
- return; // still waiting for more calls to complete
- }
-
- // TODO: handle errors
- if (dismissed) {
- emit completed(true, QVariant(""));
- } else {
- emit completed(false, getResult());
- }
-
- deleteLater();
+ connect(job, SIGNAL(result(QueuedJob*)), SLOT(jobResult(QueuedJob*)));
}
-PromptServiceCreateCollection::PromptServiceCreateCollection(const QString &label, \
bool locked,
- BackendMaster *master,
- Service *service, \
QObject *parent)
- : PromptBase(service, parent)
+SingleJobPrompt::~SingleJobPrompt()
{
- m_call = new AsyncCreateCollectionMaster(label, locked, master);
- addCall(m_call);
+ // TODO: delete the job?
}
-QVariant PromptServiceCreateCollection::getResult() const
+void SingleJobPrompt::prompt(const QString &windowId)
{
- QDBusObjectPath result("/");
- if (m_call->result()) {
- result.setPath(serviceObjectPath().path() + "/collection/" + \
m_call->result()->id()); + Q_UNUSED(windowId);
+ if (m_prompted) {
+ return;
}
+ m_prompted = true;
- return qVariantFromValue(result);
+ // TODO: convert windowId to a WId and pass it to the job
+ m_job->start();
}
-PromptServiceUnlock::PromptServiceUnlock(const QMap<BackendBase*, QDBusObjectPath> \
&objects,
- Service *service, QObject *parent)
- : PromptBase(service, parent), m_objects(objects)
+void SingleJobPrompt::dismiss()
{
- AsyncSimpleBooleanCall *call;
-
- // TODO: get rid of the cast
- Q_FOREACH(BackendBase *object, objects.keys()) {
- call = new AsyncSimpleBooleanCall(AsyncCall::AsyncUnlock, object);
- addCall(call);
- m_calls.append(call);
+ if (m_prompted) {
+ return;
}
+ m_prompted = true;
+
+ m_job->dismiss();
}
-QVariant PromptServiceUnlock::getResult() const
+void SingleJobPrompt::jobResult(QueuedJob *job)
{
- QList<QDBusObjectPath> paths;
-
- Q_FOREACH(AsyncSimpleBooleanCall *call, m_calls) {
- if (call->result()) {
- if (m_objects.contains(call->destination())) {
- paths.append(m_objects[call->destination()]);
+ Q_ASSERT(job == m_job);
+ // check for errors first
+ if (m_job->isDismissed()) {
+ emit completed(true, QVariant(""));
+ } else if (m_job->error() != NoError) {
+ // TODO: figure out how to handle errors gracefully.
+ emit completed(false, QVariant(""));
+ } else {
+ switch (m_job->type()) {
+
+ case BackendJob::TypeUnlockCollection:
+ case BackendJob::TypeLockCollection:
+ case BackendJob::TypeDeleteCollection:
+ case BackendJob::TypeChangeAuthenticationCollection:
+ case BackendJob::TypeDeleteItem:
+ case BackendJob::TypeLockItem:
+ case BackendJob::TypeUnlockItem:
+ case BackendJob::TypeChangeAuthenticationItem:
+ {
+ BooleanResultJob *brj = qobject_cast<BooleanResultJob*>(m_job);
+ Q_ASSERT(brj);
+ emitCompleted(false, QVariant(brj->result()));
}
+ break;
+
+ case BackendJob::TypeCreateCollectionMaster:
+ {
+ CreateCollectionMasterJob *ccmj = \
qobject_cast<CreateCollectionMasterJob*>(m_job); + Q_ASSERT(ccmj);
+ QDBusObjectPath result("/");
+ if (ccmj->collection()) {
+ BackendCollection *coll = ccmj->collection();
+ result.setPath(serviceObjectPath().path() + "/collection/" + \
coll->id()); + }
+
+ emitCompleted(false, qVariantFromValue(result));
+ }
+ break;
+
+ case BackendJob::TypeCreateCollection:
+ {
+ CreateCollectionJob *ccj = qobject_cast<CreateCollectionJob*>(m_job);
+ Q_ASSERT(ccj);
+ QDBusObjectPath result("/");
+ if (ccj->collection()) {
+ BackendCollection *coll = ccj->collection();
+ result.setPath(serviceObjectPath().path() + "/collection/" + \
coll->id()); + }
+
+ emitCompleted(false, qVariantFromValue(result));
+ }
+ break;
+
+ case BackendJob::TypeCreateItem:
+ {
+ CreateItemJob *cij = qobject_cast<CreateItemJob*>(m_job);
+ Q_ASSERT(cij);
+ QDBusObjectPath result("/");
+ if (cij->item()) {
+ BackendItem *item = cij->item();
+ result.setPath(serviceObjectPath().path() + "/collection/" +
+ cij->collection()->id() + "/" + item->id());
+ }
+
+ emitCompleted(false, qVariantFromValue(result));
+ }
+ break;
+
+ default:
+ // should not happen!
+ Q_ASSERT(false);
}
}
-
- return qVariantFromValue(paths);
-}
-
-PromptServiceLock::PromptServiceLock(
- const QMap<BackendBase*, QDBusObjectPath> &objects,
- Service *service, QObject *parent)
- : PromptBase(service, parent), m_objects(objects)
-{
- AsyncSimpleBooleanCall *call;
-
- Q_FOREACH(BackendBase *object, objects.keys()) {
- call = new AsyncSimpleBooleanCall(AsyncCall::AsyncLock, object);
- addCall(call);
- m_calls.append(call);
- }
+
+ deleteLater();
}
-QVariant PromptServiceLock::getResult() const
+ServiceMultiPrompt::ServiceMultiPrompt(Service *service, const QSet<BackendJob*> \
jobs, + QObject *parent)
+ : PromptBase(service, parent), m_prompted(false), m_jobs(jobs)
{
- QList<QDBusObjectPath> paths;
-
- Q_FOREACH(AsyncSimpleBooleanCall *call, m_calls) {
- if (call->result()) {
- if (m_objects.contains(call->destination())) {
- paths.append(m_objects[call->destination()]);
- }
+ bool jobTypeDetermined = false;
+ bool jobTypeUnlock = false;
+
+ Q_FOREACH(BackendJob *job, m_jobs) {
+ // make sure the subjobs are either all unlock or all lock calls
+ bool currentJobTypeUnlock = (job->type() == BackendJob::TypeUnlockCollection \
|| + job->type() == BackendJob::TypeUnlockItem);
+ if (jobTypeDetermined && jobTypeUnlock != currentJobTypeUnlock) {
+ Q_ASSERT(false);
+ } else if (!jobTypeDetermined) {
+ jobTypeUnlock = currentJobTypeUnlock;
+ jobTypeDetermined = true;
}
+ connect(job, SIGNAL(result(QueuedJob*)), SLOT(jobResult(QueuedJob*)));
}
-
- return qVariantFromValue(paths);
-}
-
-PromptCollectionDelete::PromptCollectionDelete(BackendCollection *collection, \
Service *service,
- QObject *parent)
- : PromptBase(service, parent)
-{
- m_call = new AsyncSimpleBooleanCall(AsyncCall::AsyncDeleteCollection, \
collection);
- addCall(m_call);
}
-QVariant PromptCollectionDelete::getResult() const
+ServiceMultiPrompt::~ServiceMultiPrompt()
{
- return m_call->result();
+ // TODO: delete jobs if not started?
}
-PromptCollectionCreateItem::PromptCollectionCreateItem(BackendCollection \
*collection,
- const QString &label,
- const QMap<QString, QString> \
&attributes,
- bool locked, const \
QCA::SecureArray &secret,
- bool replace, Service \
*service,
- QObject *parent)
- : PromptBase(service, parent)
+void ServiceMultiPrompt::prompt(const QString &windowId)
{
- m_call = new AsyncCreateItem(label, attributes, secret, locked, replace, \
collection);
- addCall(m_call);
+ Q_UNUSED(windowId);
+ if (m_prompted) {
+ return;
+ }
+ m_prompted = true;
+
+ // TODO: convert windowId to a WId and pass it to the job
+ Q_FOREACH(BackendJob *job, m_jobs) {
+ job->start();
+ }
}
-QVariant PromptCollectionCreateItem::getResult() const
+void ServiceMultiPrompt::dismiss()
{
- if (!m_call->result()) {
- // no item created
- return qVariantFromValue(QDBusObjectPath("/"));
- } else {
- return qVariantFromValue(QDBusObjectPath(serviceObjectPath().path() + \
"/collection/" +
- m_call->collection()->id() + "/" + m_call->result()->id()));
+ if (m_prompted) {
+ return;
+ }
+ m_prompted = true;
+
+ Q_FOREACH(BackendJob *job, m_jobs) {
+ disconnect(job, SIGNAL(result(QueuedJob*)), this, \
SLOT(jobResult(QueuedJob*))); + job->dismiss();
}
-}
-PromptItemDelete::PromptItemDelete(BackendItem *item, Service *service, QObject \
*parent)
- : PromptBase(service, parent)
-{
- m_call = new AsyncSimpleBooleanCall(AsyncCall::AsyncDeleteItem, item);
- addCall(m_call);
+ // emit result right away so we don't have to catch all result() signals
+ // from individual jobs.
+ emitCompleted(true, qVariantFromValue(QList<QDBusObjectPath>()));
+ deleteLater();
}
-QVariant PromptItemDelete::getResult() const
+void ServiceMultiPrompt::jobResult(QueuedJob *job)
{
- return m_call->result();
+ BackendJob *bj = qobject_cast<BackendJob*>(job);
+ Q_ASSERT(bj);
+ Q_ASSERT(m_jobs.contains(bj));
+ // remove job from the set of jobs we're waiting for
+ m_jobs.remove(bj);
+ if (bj->error() != NoError) {
+ // TODO: figure out what to do with erroneous jobs
+ } else {
+ switch (bj->type()) {
+
+ case BackendJob::TypeUnlockCollection:
+ {
+ UnlockCollectionJob *ucj = qobject_cast<UnlockCollectionJob*>(bj);
+ Q_ASSERT(ucj);
+ if (ucj->result()) {
+ BackendCollection *coll = ucj->collection();
+ QDBusObjectPath path;
+ path.setPath(serviceObjectPath().path() + "/collection/" + \
coll->id()); + m_result.append(path);
+ }
+ }
+ break;
+
+ case BackendJob::TypeLockCollection:
+ {
+ LockCollectionJob *lcj = qobject_cast<LockCollectionJob*>(bj);
+ Q_ASSERT(lcj);
+ if (lcj->result()) {
+ BackendCollection *coll = lcj->collection();
+ QDBusObjectPath path;
+ path.setPath(serviceObjectPath().path() + "/collection/" + \
coll->id()); + m_result.append(path);
+ }
+ }
+ break;
+
+ case BackendJob::TypeUnlockItem:
+ {
+ UnlockItemJob *uij = qobject_cast<UnlockItemJob*>(bj);
+ Q_ASSERT(uij);
+ if (uij->result()) {
+ BackendItem *item = uij->item();
+ BackendCollection *coll = 0;
+ // TODO: I NEED THE COLLECTION DAMMIT
+ QDBusObjectPath path;
+ path.setPath(serviceObjectPath().path() + "/collection/" + coll->id() \
+ + "/" + item->id());
+ m_result.append(path);
+ }
+ }
+ break;
+
+ case BackendJob::TypeLockItem:
+ {
+ LockItemJob *lij = qobject_cast<LockItemJob*>(bj);
+ Q_ASSERT(lij);
+ if (lij->result()) {
+ BackendItem *item = lij->item();
+ BackendCollection *coll = 0;
+ // TODO: I NEED THE COLLECTION DAMMIT
+ QDBusObjectPath path;
+ path.setPath(serviceObjectPath().path() + "/collection/" + coll->id() \
+ + "/" + item->id());
+ m_result.append(path);
+ }
+ }
+ break;
+
+ default:
+ Q_ASSERT(false);
+ }
+ }
+
+ if (m_jobs.isEmpty()) {
+ // all jobs finished
+ emitCompleted(false, qVariantFromValue(m_result));
+ deleteLater();
+ }
}
#include "prompt.moc"
diff --git a/daemon/prompt.h b/daemon/prompt.h
index 3298575..b5aac66 100644
--- a/daemon/prompt.h
+++ b/daemon/prompt.h
@@ -21,301 +21,185 @@
#ifndef DAEMON_PROMPT_H
#define DAEMON_PROMPT_H
-#include <backend/asynccall.h>
+#include <backend/backendjob.h>
#include <QtCore/QObject>
+#include <QtCore/QSet>
#include <QtDBus/QDBusObjectPath>
#include <QtDBus/QDBusContext>
-// TODO: when doing getResult() calls, be sure to check for errors!!!
-
class Service;
/**
- * Implemention of prompt objects according to the org.freedesktop.Secret.Prompt
+ * Implementation of prompt objects according to the org.freedesktop.Secret.Prompt
* interface.
- *
- * @remarks a Prompt can contain several PendingCall objects which are all executed
- * when prompt() is called.
*/
class PromptBase : public QObject, protected QDBusContext
{
Q_OBJECT
-
+
public:
/**
* Constructor.
*
* @param service Service object (used to derive the object path of the prompt)
- * @param parent Parent object (the object that created the call)
+ * @param job the job encapsulated by the prompt
+ * @param parent Parent object
*/
- PromptBase(Service *service, QObject *parent = 0);
-
+ PromptBase(Service *service, QObject *parent);
+
+ /**
+ * Destructor.
+ */
+ virtual ~PromptBase();
+
/**
* Return the prompt's path on the D-Bus.
*
* @return the Prompt object's path
*/
const QDBusObjectPath &objectPath() const;
-
+
+ /**
+ * Return the service object's path on the D-Bus.
+ *
+ * @return the Service object's path
+ */
+ const QDBusObjectPath &serviceObjectPath() const;
+
/**
* Perform the prompt.
*
* @param windowId Platform specific window handle to use for showing the prompt
* @todo implement window handle handling
*/
- void prompt(const QString &windowId);
-
+ virtual void prompt(const QString &windowId) = 0;
+
/**
* Dismiss the prompt.
*/
- void dismiss();
-
+ virtual void dismiss() = 0;
+
Q_SIGNALS:
/**
* Emitted when the operation performed by the prompt was completed
*
* @param dismissed if true the prompt was dismissed, if false it was completed
- * @param result result of the operation encapsulated by the prompt object
+ * @param result result of the operation encapulated by the prompt object
*/
void completed(bool dismissed, QVariant result);
-
+
protected:
/**
- * This method is called after all pending calls this prompt is attached to
- * have completed. It extracts the results from the pending calls and marshalls
- * them into a result variant to transmit to the client.
- *
- * @return the result of the call marshalled as a variant
- * @remarks implemented in inherited classes only
- */
- virtual QVariant getResult() const = 0;
-
- /**
- * Get the service's object path.
- *
- * @return the objectpath of the service that created the call
- * @remarks called by inherited classes
- */
- const QDBusObjectPath &serviceObjectPath() const;
-
- /**
- * Add a call to the list of pending calls to wait for.
- *
- * @param call the call to add
- * @remarks each inherited class must call this for every pending call it creates
- */
- void addCall(AsyncCall *call);
-
-private Q_SLOTS:
- /**
- * Connected to the pending call's completed() signal this notifies about
- * the call's completion.
+ * Used to emit completed() signals in derived classes.
*
- * @param call the pending call
- * @param dismissed true if the call was dismissed, false else
+ * @param dismissed if true the prompt was dismissed, if false it was completed
+ * @param result result of the operation encapsulated by the prompt object
*/
- void slotCompleted(AsyncCall *call, bool dismissed);
+ void emitCompleted(bool dismissed, const QVariant &result);
private:
- bool m_prompted;
- QDBusObjectPath m_objectPath;
- QDBusObjectPath m_serviceObjectPath;
- QList<AsyncCall*> m_pendingCalls; // calls we are still waiting for
+ QDBusObjectPath m_objectPath; // the prompt object's objectpath
+ QDBusObjectPath m_serviceObjectPath; // the service's objectpath
};
/**
- * Prompt for the Service::createCollection() call.
+ * Prompt object encapsulating a single BackendJob.
*/
-class PromptServiceCreateCollection : public PromptBase
+class SingleJobPrompt : public PromptBase
{
Q_OBJECT
-
+
public:
/**
* Constructor.
*
- * @param label Label to use for the new collection
- * @param locked if true, lock the new collection after creating it, if false,
- * keep it open
- * @param master the master object that will be called to create the collection
- * (the master has to figure out which BackendManager to use)
* @param service Service object (used to derive the object path of the prompt)
- * @param parent Parent object (the object that created the call)
- */
- PromptServiceCreateCollection(const QString &label, bool locked, BackendMaster \
*master,
- Service *service, QObject *parent = 0);
-
-protected:
- /**
- * Returns the results of the pending createCollection call as a variant.
- *
- * @return the result of the call marshalled as a variant
+ * @param job the job encapsulated by the prompt
+ * @param parent Parent object
*/
- virtual QVariant getResult() const;
-
-private:
- AsyncCreateCollectionMaster *m_call;
-};
-
-/**
- * Prompt for the Service::unlock() call.
- */
-class PromptServiceUnlock : public PromptBase
-{
- Q_OBJECT
-
-public:
+ SingleJobPrompt(Service *service, BackendJob *job, QObject *parent = 0);
+
/**
- * Constructor.
- *
- * @param objects map of backend objects to corresponding dbus paths to unlock
- * @param service Service object (used to derive the object path of the prompt)
- * @param parent Parent object (the object that created the call)
- * @remarks collections and items in the objectMap so when the pending calls \
finish the
- * backend objects can be mapped back to the corresponding D-Bus paths
+ * Destructor.
*/
- PromptServiceUnlock(const QMap<BackendBase*, QDBusObjectPath> &objects,
- Service *service, QObject *parent = 0);
-
-protected:
+ virtual ~SingleJobPrompt();
+
/**
- * Returns the results of the pending unlock call as a variant.
+ * Perform the prompt.
*
- * @return the result of the call marshalled as a variant
+ * @param windowId Platform specific window handle to use for showing the prompt
+ * @todo implement window handle handling
*/
- virtual QVariant getResult() const;
-
-private:
- QMap<BackendBase*, QDBusObjectPath> m_objects;
- QList<AsyncSimpleBooleanCall*> m_calls;
-};
-
-/**
- * Prompt for the Service::lock() call.
- */
-class PromptServiceLock : public PromptBase
-{
- Q_OBJECT
-
-public:
+ virtual void prompt(const QString &windowId);
+
/**
- * Constructor.
- *
- * @param objects map of backend objects to corresponding dbus paths to lock
- * @param service Service object (used to derive the object path of the prompt)
- * @param parent Parent object (the object that created the call)
+ * Dismiss the prompt.
*/
- PromptServiceLock(const QMap<BackendBase*, QDBusObjectPath> &objects,
- Service *service, QObject *parent = 0);
-
-protected:
+ virtual void dismiss();
+
+private Q_SLOTS:
/**
- * Returns the results of the pending lock call as a variant.
+ * Connected to the backend job's result() signal this notifies about
+ * the job's completion.
*
- * @return the result of the call marshalled as a variant
+ * @param job the job that finished
*/
- virtual QVariant getResult() const;
+ void jobResult(QueuedJob *job);
private:
- QMap<BackendBase*, QDBusObjectPath> m_objects;
- QList<AsyncSimpleBooleanCall*> m_calls;
+ bool m_prompted; // true if one of the prompt()/dismiss() methods has been called \
already + BackendJob *m_job; // the encapulated job
};
/**
- * Prompt for the Collection::delete() call.
+ * Prompt object encapsulating a Service.Unlock or a Service.Lock call with multiple \
targets.
*/
-class PromptCollectionDelete : public PromptBase
+class ServiceMultiPrompt : public PromptBase
{
Q_OBJECT
-
+
public:
/**
* Constructor.
*
- * @param collection the backend collection to delete
* @param service Service object (used to derive the object path of the prompt)
- * @param parent Parent object
+ * @param jobs the unlock jobs to encapsulate
+ * @param parent parent object
*/
- PromptCollectionDelete(BackendCollection *collection, Service *service, QObject \
*parent = 0);
-
-protected:
- /**
- * Returns the results of the pending delete call as a variant.
- *
- * @return the result of the call marshalled as a variant
- */
- virtual QVariant getResult() const;
-
-private:
- AsyncSimpleBooleanCall *m_call;
-};
-
-/**
- * Prompt for the Collection::createItem() call.
- */
-class PromptCollectionCreateItem : public PromptBase
-{
- Q_OBJECT
-
-public:
+ ServiceMultiPrompt(Service *service, const QSet<BackendJob*> jobs, QObject \
*parent = 0); +
/**
- * Constructor.
- *
- * @param collection the backend collection to create the item in
- * @param label label for the new item
- * @param attributes attributes for the new item
- * @param locked if true, try to lock the item after creation, if false try to \
unlock the
- * item after creation
- * @param secret secret to store
- * @param replace if true an existing item with the same attributes will be \
replaced
- * @param service Service object (used to derive the object path of the prompt)
- * @param parent Parent object
+ * Destructor.
*/
- PromptCollectionCreateItem(BackendCollection *collection,
- const QString &label, const QMap<QString, QString> \
&attributes,
- bool locked, const QCA::SecureArray &secret, bool \
replace,
- Service *service, QObject *parent = 0);
-
-protected:
+ virtual ~ServiceMultiPrompt();
+
/**
- * Returns the results of the pending createItem call as a variant.
+ * Perform the prompt.
*
- * @return the result of the call marshalled as a variant
+ * @pararm windowId Platform specific window handle to use for showing the prompt
+ * @todo implement window handling
*/
- virtual QVariant getResult() const;
-
-private:
- AsyncCreateItem *m_call;
-};
-
-/**
- * Prompt for the Item::delete() call.
- */
-class PromptItemDelete : public PromptBase
-{
- Q_OBJECT
-
-public:
+ virtual void prompt(const QString &windowId);
+
/**
- * Constructor.
- *
- * @param item the backend item to delete
- * @param service Service object (used to derive the object path of the prompt)
- * @param parent Parent object
+ * Dismiss this prompt.
*/
- PromptItemDelete(BackendItem *item, Service *service, QObject *parent = 0);
-
-protected:
+ virtual void dismiss();
+
+private Q_SLOTS:
/**
- * Returns the results of the pending deleteItem call as a variant.
+ * Connected to the backend jobs' result() signals this notifies about a
+ * job's completion.
*
- * @return the result of the call marshalled as a variant
+ * @param job the job that finished
*/
- virtual QVariant getResult() const;
-
+ void jobResult(QueuedJob *job);
+
private:
- AsyncSimpleBooleanCall *m_call;
+ bool m_prompted; // true if one of the prompt()/dismiss() methods has been called \
already + QList<QDBusObjectPath> m_result; // resulting unlocked/locked object \
paths + QSet<BackendJob*> m_jobs; // encapsulated jobs
};
#endif
diff --git a/daemon/service.cpp b/daemon/service.cpp
index 65377c8..280435d 100644
--- a/daemon/service.cpp
+++ b/daemon/service.cpp
@@ -87,6 +87,7 @@ QVariant Service::openSession(const QString &algorithm, const \
QVariant &input, QDBusObjectPath Service::createCollection(const QMap<QString, \
QVariant> &properties, QDBusObjectPath &prompt)
{
+ // TODO: default label
QString label;
bool locked = false;
@@ -97,17 +98,20 @@ QDBusObjectPath Service::createCollection(const QMap<QString, \
QVariant> &propert locked = properties["Locked"].toBool();
}
- if (m_master->isCallImmediate(AsyncCall::AsyncCreateCollectionMaster)) {
- BackendReturn<BackendCollection*> rc = m_master->createCollection(label, \
locked);
- if (rc.isError()) {
+ CreateCollectionMasterJob *job = m_master->createCreateCollectionMasterJob(label, \
locked); + if (job->isImmediate()) {
+ job->exec();
+ if (job->error() != NoError || !job->collection()) {
// TODO: error creating the collection
+ return QDBusObjectPath("/");
+ } else {
+ BackendCollection *coll = job->collection();
+ prompt.setPath("/");
+ QDBusObjectPath collPath(m_basePath.path() + "/collection/" + coll->id());
+ return collPath;
}
-
- prompt.setPath("/");
- QDBusObjectPath collPath(m_basePath.path() + "/collection/" + \
rc.value()->id());
- return collPath;
} else {
- PromptBase *p = new PromptServiceCreateCollection(label, locked, m_master, \
this, this); + PromptBase *p = new SingleJobPrompt(this, job, this);
prompt = p->objectPath();
return QDBusObjectPath("/");
}
@@ -144,8 +148,8 @@ QList<QDBusObjectPath> Service::unlock(const \
QList<QDBusObjectPath> &objects,
// objects already unlocked
QList<QDBusObjectPath> rc;
- // objects to unlock
- QMap<BackendBase*, QDBusObjectPath> unlockObjects;
+ // jobs to call asynchronously
+ QSet<BackendJob*> unlockJobs;
QObject *object;
Item *item;
Collection *collection;
@@ -158,40 +162,42 @@ QList<QDBusObjectPath> Service::unlock(const \
QList<QDBusObjectPath> &objects, continue;
}
if ((collection = qobject_cast<Collection*>(object))) {
- if ((bc = collection->backendCollection())) {
+ bc = collection->backendCollection();
+ if (bc) {
if (!bc->isLocked()) {
rc.append(path);
} else {
- if (bc->isCallImmediate(AsyncCall::AsyncUnlock)) {
- // unlock without prompt?
- BackendReturn<bool> br = bc->unlock();
- if (!br.isError() && br.value()) {
- rc.append(path);
+ UnlockCollectionJob *ucj = bc->createUnlockJob();
+ if (ucj->isImmediate()) {
+ ucj->exec();
+ if (ucj->error() != NoError || !ucj->result()) {
+ // not unlocked, maybe due to an error.
+ // There's not much to do about it. Silently ignore.
} else {
- // fallback: try async unlocking
- unlockObjects.insert(bc, path);
+ rc.append(path);
}
} else {
- unlockObjects.insert(bc, path);
+ unlockJobs.insert(ucj);
}
}
}
} else if ((item = qobject_cast<Item*>(object))) {
- if ((bi = item->backendItem())) {
+ bi = item->backendItem();
+ if (bi) {
if (!bi->isLocked()) {
rc.append(path);
} else {
- if (bi->isCallImmediate(AsyncCall::AsyncUnlock)) {
- // unlock without prompt?
- BackendReturn<bool> br = bi->unlock();
- if (!br.isError() && br.value()) {
- rc.append(path);
+ UnlockItemJob *uij = bi->createUnlockJob();
+ if (uij->isImmediate()) {
+ uij->exec();
+ if (uij->error() != NoError ||!uij->result()) {
+ // not unlocked, maybe due to an error.
+ // There's not much to do about it. Silently ignore.
} else {
- // fallback: try async unlocking
- unlockObjects.insert(bi, path);
+ rc.append(path);
}
} else {
- unlockObjects.insert(bi, path);
+ unlockJobs.insert(uij);
}
}
}
@@ -199,8 +205,8 @@ QList<QDBusObjectPath> Service::unlock(const \
QList<QDBusObjectPath> &objects,
// NOTE: objects which either don't exist or whose type is wrong are silently \
ignored. }
- if (unlockObjects.size() > 0) {
- PromptServiceUnlock *p = new PromptServiceUnlock(unlockObjects, this, this);
+ if (!unlockJobs.isEmpty()) {
+ ServiceMultiPrompt *p = new ServiceMultiPrompt(this, unlockJobs, this);
prompt = p->objectPath();
} else {
prompt.setPath("/");
@@ -213,12 +219,11 @@ QList<QDBusObjectPath> Service::lock(const \
QList<QDBusObjectPath> &objects, QDBusObjectPath &prompt)
{
// TODO: check is session exists
- // TODO: bypass prompt
// objects already locked
QList<QDBusObjectPath> rc;
- // objects to lock
- QMap<BackendBase*, QDBusObjectPath> lockObjects;
+ // jobs to call asynchronously
+ QSet<BackendJob*> lockJobs;
QObject *object;
Item *item;
Collection *collection;
@@ -231,40 +236,42 @@ QList<QDBusObjectPath> Service::lock(const \
QList<QDBusObjectPath> &objects, continue;
}
if ((collection = qobject_cast<Collection*>(object))) {
- if ((bc = collection->backendCollection())) {
+ bc = collection->backendCollection();
+ if (bc) {
if (bc->isLocked()) {
rc.append(path);
} else {
- if (bc->isCallImmediate(AsyncCall::AsyncLock)) {
- // lock without prompt?
- BackendReturn<bool> br = bc->lock();
- if (!br.isError() && br.value()) {
- rc.append(path);
+ LockCollectionJob *lcj = bc->createLockJob();
+ if (lcj->isImmediate()) {
+ lcj->exec();
+ if (lcj->error() != NoError || !lcj->result()) {
+ // not locked, maybe due to an error.
+ // There's not much to do about it. Silently ignore.
} else {
- // fallback: try async unlocking
- lockObjects.insert(bc, path);
+ rc.append(path);
}
} else {
- lockObjects.insert(bc, path);
+ lockJobs.insert(lcj);
}
}
}
} else if ((item = qobject_cast<Item*>(object))) {
- if ((bi = item->backendItem())) {
+ bi = item->backendItem();
+ if (bi) {
if (bi->isLocked()) {
rc.append(path);
} else {
- if (bi->isCallImmediate(AsyncCall::AsyncLock)) {
- // unlock without prompt?
- BackendReturn<bool> br = bi->lock();
- if (!br.isError() && br.value()) {
- rc.append(path);
+ LockItemJob *lij = bi->createLockJob();
+ if (lij->isImmediate()) {
+ lij->exec();
+ if (lij->error() != NoError || !lij->result()) {
+ // not locked, maybe due to an error.
+ // There's not much to do about it. Silently ignore.
} else {
- // fallback: try async unlocking
- lockObjects.insert(bi, path);
+ rc.append(path);
}
} else {
- lockObjects.insert(bi, path);
+ lockJobs.insert(lij);
}
}
}
@@ -272,8 +279,8 @@ QList<QDBusObjectPath> Service::lock(const QList<QDBusObjectPath> \
&objects,
// NOTE: objects which either don't exist or whose type is wrong are silently \
ignored. }
- if (lockObjects.size() > 0) {
- PromptServiceLock *p = new PromptServiceLock(lockObjects, this, this);
+ if (!lockJobs.isEmpty()) {
+ ServiceMultiPrompt *p = new ServiceMultiPrompt(this, lockJobs, this);
prompt = p->objectPath();
} else {
prompt.setPath("/");
diff --git a/daemon/tests/CMakeLists.txt b/daemon/tests/CMakeLists.txt
index 42b54ab..04029ff 100644
--- a/daemon/tests/CMakeLists.txt
+++ b/daemon/tests/CMakeLists.txt
@@ -12,6 +12,7 @@ KDE4_ADD_EXECUTABLE (ksecretservice_daemon_test
tempblockingcollectionmanager.cpp
tempblockingcollection.cpp
tempblockingitem.cpp
+ tempblockingjobs.cpp
)
TARGET_LINK_LIBRARIES (ksecretservice_daemon_test
ksecretservicebackend
diff --git a/daemon/tests/servicetest.cpp b/daemon/tests/servicetest.cpp
index a6cf383..000dcc4 100644
--- a/daemon/tests/servicetest.cpp
+++ b/daemon/tests/servicetest.cpp
@@ -162,19 +162,31 @@ void ServiceTest::nonBlockingCollection()
createInput << QVariant::fromValue(createProperties);
QDBusMessage createReply = ifaceService.callWithArgumentList(QDBus::Block, \
"CreateCollection",
createInput);
+
QCOMPARE(createReply.type(), QDBusMessage::ReplyMessage);
QList<QVariant> createArgs = createReply.arguments();
QCOMPARE(createArgs.size(), 2);
QCOMPARE(createArgs.at(0).userType(), qMetaTypeId<QDBusObjectPath>());
QCOMPARE(createArgs.at(1).userType(), qMetaTypeId<QDBusObjectPath>());
- // TemporaryCollection is non-blocking, so the second output (prompt) should be \
"/".
- QCOMPARE(createArgs.at(1).value<QDBusObjectPath>().path(), QLatin1String("/"));
- collectionPath = createArgs.at(0).value<QDBusObjectPath>();
+ // CreateCollection is blocking, so the first output (path) should be "/".
+ QCOMPARE(createArgs.at(0).value<QDBusObjectPath>().path(), QLatin1String("/"));
+ QDBusObjectPath promptPath = createArgs.at(1).value<QDBusObjectPath>();
+ QVERIFY(promptPath.path().startsWith(
+ QLatin1String("/org/freedesktop/secrets/prompts/")));
+
+ // prompt and wait for the result.
+ ClientPrompt *prompt = new ClientPrompt(promptPath);
+ prompt->promptAndWait(5000);
+ QVERIFY(prompt->completed());
+ QVERIFY(!prompt->dismissed());
+ QCOMPARE(prompt->result().userType(), qMetaTypeId<QDBusObjectPath>());
+ collectionPath = prompt->result().value<QDBusObjectPath>();
QVERIFY(collectionPath.path().startsWith(
QLatin1String("/org/freedesktop/secrets/collection/")));
QDBusInterface ifaceCollection("org.freedesktop.Secret", collectionPath.path(),
"org.freedesktop.Secret.Collection");
QVERIFY(ifaceCollection.isValid());
+ delete prompt;
// make sure the CollectionCreated signal was sent
if (createdSpy.size() < 1) {
@@ -263,7 +275,12 @@ void ServiceTest::nonBlockingItem()
collInput << QVariant::fromValue(collProperties);
QDBusMessage collReply = ifaceService.callWithArgumentList(QDBus::Block, \
"CreateCollection", collInput);
- collectionPath = collReply.arguments()[0].value<QDBusObjectPath>();
+ QDBusObjectPath promptPath = \
collReply.arguments().at(1).value<QDBusObjectPath>(); + ClientPrompt *prompt = new \
ClientPrompt(promptPath); + prompt->promptAndWait(5000);
+ QVERIFY(prompt->completed());
+ collectionPath = prompt->result().value<QDBusObjectPath>();
+ delete prompt;
QDBusInterface ifaceColl("org.freedesktop.Secret", collectionPath.path());
ObjectPathSignalSpy createdSpy(&ifaceColl, SIGNAL(ItemCreated(QDBusObjectPath)));
diff --git a/daemon/tests/tempblockingcollection.cpp \
b/daemon/tests/tempblockingcollection.cpp index 2ea28c3..8169aaa 100644
--- a/daemon/tests/tempblockingcollection.cpp
+++ b/daemon/tests/tempblockingcollection.cpp
@@ -20,18 +20,55 @@
#include "tempblockingcollection.h"
#include "tempblockingitem.h"
+#include "tempblockingjobs.h"
#include <secrettool.h>
TempBlockingCollection::TempBlockingCollection(const QString &id, \
BackendCollectionManager *parent)
- : TemporaryCollection(id, parent)
+ : BackendCollection(parent)
{
+ m_id = id;
+ QDateTime now = QDateTime::currentDateTime();
+ m_created = now;
+ m_modified = now;
}
TempBlockingCollection::~TempBlockingCollection()
{
}
+QString TempBlockingCollection::id() const
+{
+ return m_id;
+}
+
+BackendReturn<QString> TempBlockingCollection::label() const
+{
+ return m_label;
+}
+
+BackendReturn<void> TempBlockingCollection::setLabel(const QString &label)
+{
+ m_label = label;
+ emit collectionChanged(this);
+ return BackendReturn<void>();
+}
+
+QDateTime TempBlockingCollection::created() const
+{
+ return m_created;
+}
+
+QDateTime TempBlockingCollection::modified() const
+{
+ return m_modified;
+}
+
+bool TempBlockingCollection::isLocked() const
+{
+ return false;
+}
+
BackendReturn<QList<BackendItem*> > TempBlockingCollection::items() const
{
return m_items;
@@ -51,16 +88,41 @@ BackendReturn<QList<BackendItem*> > \
TempBlockingCollection::searchItems( return foundItems;
}
-bool TempBlockingCollection::isCallImmediate(AsyncCall::AsyncType type) const
+UnlockCollectionJob *TempBlockingCollection::createUnlockJob()
{
- Q_UNUSED(type);
- return false;
+ return new TempBlockingUnlockCollectionJob(this);
+}
+
+LockCollectionJob *TempBlockingCollection::createLockJob()
+{
+ return new TempBlockingLockCollectionJob(this);
+}
+
+DeleteCollectionJob *TempBlockingCollection::createDeleteJob()
+{
+ TempBlockingDeleteCollectionJob *job = new TempBlockingDeleteCollectionJob(this);
+ connect(job, SIGNAL(result(QueuedJob*)),
+ SLOT(deleteCollectionJobResult(QueuedJob*)));
+ return job;
+}
+
+CreateItemJob *TempBlockingCollection::createCreateItemJob(const QString &label,
+ const QMap<QString, \
QString> &attributes, + \
const QCA::SecureArray &secret, + \
bool locked, bool replace) +{
+ return new TempBlockingCreateItemJob(label, attributes, secret, locked, replace, \
this); +}
+
+ChangeAuthenticationCollectionJob \
*TempBlockingCollection::createChangeAuthenticationJob() +{
+ return new TempBlockingChangeAuthenticationCollectionJob(this);
}
BackendReturn<BackendItem*> TempBlockingCollection::createItem(const QString &label,
const QMap<QString, \
QString> &attributes,
const \
QCA::SecureArray &secret,
- bool replace, bool \
locked) + bool locked, \
bool replace) {
Q_UNUSED(locked);
@@ -89,9 +151,11 @@ BackendReturn<BackendItem*> \
TempBlockingCollection::createItem(const QString &la if (!item) {
item = new TempBlockingItem(createId(), this);
}
+ item->blockSignals(true);
item->setLabel(label);
item->setAttributes(attributes);
item->setSecret(secret);
+ item->blockSignals(false);
if (replacing) {
emit itemChanged(item);
@@ -112,4 +176,14 @@ void TempBlockingCollection::slotItemDeleted(BackendItem *item)
emit itemDeleted(item);
}
+void TempBlockingCollection::deleteCollectionJobResult(QueuedJob *job)
+{
+ TempBlockingDeleteCollectionJob * dcj = \
qobject_cast<TempBlockingDeleteCollectionJob*>(job); + Q_ASSERT(dcj);
+ if (!dcj->result()) {
+ return;
+ }
+ emit collectionDeleted(this);
+}
+
#include "tempblockingcollection.moc"
diff --git a/daemon/tests/tempblockingcollection.h \
b/daemon/tests/tempblockingcollection.h index bd5df65..7a71c2b 100644
--- a/daemon/tests/tempblockingcollection.h
+++ b/daemon/tests/tempblockingcollection.h
@@ -21,29 +21,51 @@
#ifndef TEMPBLOCKINGCOLLECTION_H
#define TEMPBLOCKINGCOLLECTION_H
-#include "backend/temporary/temporarycollection.h"
+#include "backend/backendcollection.h"
// implement a temporary collection that blocks every call.
-class TempBlockingCollection : public TemporaryCollection
+class TempBlockingCollection : public BackendCollection
{
Q_OBJECT
public:
TempBlockingCollection(const QString &id, BackendCollectionManager *parent);
virtual ~TempBlockingCollection();
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
+ virtual QString id() const;
+ virtual BackendReturn<QString> label() const;
+ virtual BackendReturn<void> setLabel(const QString &label);
+ virtual QDateTime created() const;
+ virtual QDateTime modified() const;
+ virtual bool isLocked() const;
virtual BackendReturn<QList<BackendItem*> > items() const;
virtual BackendReturn<QList<BackendItem*> > searchItems(const QMap<QString, \
QString> &attributes) const;
-
- virtual BackendReturn<BackendItem*> createItem(const QString &label,
- const QMap<QString, QString> \
&attributes,
- const QCA::SecureArray &secret, \
bool replace,
- bool locked);
+ virtual UnlockCollectionJob *createUnlockJob();
+ virtual LockCollectionJob *createLockJob();
+ virtual DeleteCollectionJob *createDeleteJob();
+ virtual CreateItemJob *createCreateItemJob(const QString &label,
+ const QMap<QString, QString> \
&attributes, + const QCA::SecureArray \
&secret, bool locked, + bool replace);
+ virtual ChangeAuthenticationCollectionJob *createChangeAuthenticationJob();
+
+protected:
+ BackendReturn<BackendItem*> createItem(const QString &label,
+ const QMap<QString, QString> &attributes,
+ const QCA::SecureArray &secret, bool \
locked, + bool replace);
private Q_SLOTS:
void slotItemDeleted(BackendItem *item);
+ void deleteCollectionJobResult(QueuedJob *job);
private:
+ friend class TempBlockingCreateItemJob;
+
+ QString m_id;
+ QString m_label;
+ QDateTime m_created;
+ QDateTime m_modified;
+
QList<BackendItem*> m_items;
};
diff --git a/daemon/tests/tempblockingcollectionmanager.cpp \
b/daemon/tests/tempblockingcollectionmanager.cpp index fa935be..3c57fad 100644
--- a/daemon/tests/tempblockingcollectionmanager.cpp
+++ b/daemon/tests/tempblockingcollectionmanager.cpp
@@ -20,11 +20,12 @@
#include "tempblockingcollectionmanager.h"
#include "tempblockingcollection.h"
+#include "tempblockingjobs.h"
#include <secrettool.h>
TempBlockingCollectionManager::TempBlockingCollectionManager(QObject *parent)
- : TemporaryCollectionManager(parent)
+ : BackendCollectionManager(parent)
{
}
@@ -32,26 +33,30 @@ TempBlockingCollectionManager::~TempBlockingCollectionManager()
{
}
-bool TempBlockingCollectionManager::isCallImmediate(AsyncCall::AsyncType type) const
+CreateCollectionJob *TempBlockingCollectionManager::createCreateCollectionJob(const \
QString &label, + \
bool locked) {
- Q_UNUSED(type);
- return false;
+ TempBlockingCreateCollectionJob *job = new TempBlockingCreateCollectionJob(label,
+ \
locked, + \
this); + connect(job, SIGNAL(result(QueuedJob*)),
+ SLOT(createCollectionJobResult(QueuedJob*)));
+ return job;
}
-BackendReturn<BackendCollection*> TempBlockingCollectionManager::createCollection(
- const QString &label, bool locked)
+void TempBlockingCollectionManager::createCollectionJobResult(QueuedJob *job)
{
- Q_UNUSED(locked);
-
- TempBlockingCollection *coll = new TempBlockingCollection(createId(), this);
- coll->setLabel(label);
-
+ CreateCollectionJob *ccj = qobject_cast<CreateCollectionJob*>(job);
+ Q_ASSERT(ccj);
+
+ if (!ccj->collection()) {
+ return;
+ }
+
// connect signals
- connect(coll, SIGNAL(collectionDeleted(BackendCollection*)),
- SIGNAL(collectionDeleted(BackendCollection*)));
- emit collectionCreated(coll);
-
- return coll;
+ connect(ccj->collection(), SIGNAL(collectionDeleted(BackendCollection*)),
+ SIGNAL(collectionDeleted(BackendCollection*)));
+ emit collectionCreated(ccj->collection());
}
#include "tempblockingcollectionmanager.moc"
diff --git a/daemon/tests/tempblockingcollectionmanager.h \
b/daemon/tests/tempblockingcollectionmanager.h index 22f914d..4272d29 100644
--- a/daemon/tests/tempblockingcollectionmanager.h
+++ b/daemon/tests/tempblockingcollectionmanager.h
@@ -21,12 +21,12 @@
#ifndef TEMPBLOCKINGCOLLECTIONMANAGER_H
#define TEMPBLOCKINGCOLLECTIONMANAGER_H
-#include "backend/temporary/temporarycollectionmanager.h"
+#include "backend/backendcollectionmanager.h"
class TempBlockingCollection;
// implement a temporary collection manager that blocks every call.
-class TempBlockingCollectionManager : public TemporaryCollectionManager
+class TempBlockingCollectionManager : public BackendCollectionManager
{
Q_OBJECT
@@ -36,8 +36,11 @@ public:
public:
TempBlockingCollectionManager(QObject *parent = 0);
virtual ~TempBlockingCollectionManager();
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
- virtual BackendReturn<BackendCollection*> createCollection(const QString &label, \
bool locked); + virtual CreateCollectionJob *createCreateCollectionJob(const \
QString &label, + bool \
locked); +
+private Q_SLOTS:
+ void createCollectionJobResult(QueuedJob *job);
};
#endif
diff --git a/daemon/tests/tempblockingitem.cpp b/daemon/tests/tempblockingitem.cpp
index 69eed27..b819bd3 100644
--- a/daemon/tests/tempblockingitem.cpp
+++ b/daemon/tests/tempblockingitem.cpp
@@ -20,20 +20,126 @@
#include "tempblockingitem.h"
#include "tempblockingcollection.h"
+#include "tempblockingjobs.h"
TempBlockingItem::TempBlockingItem(const QString &id, TempBlockingCollection \
*parent)
- : TemporaryItem(id, parent)
+ : BackendItem(parent), m_id(id)
{
+ QDateTime now = QDateTime::currentDateTime();
+ m_created = now;
+ m_modified = now;
}
TempBlockingItem::~TempBlockingItem()
{
}
-bool TempBlockingItem::isCallImmediate(AsyncCall::AsyncType type) const
+QString TempBlockingItem::id() const
+{
+ return m_id;
+}
+
+BackendReturn<QString> TempBlockingItem::label() const
+{
+ return m_label;
+}
+
+BackendReturn<void> TempBlockingItem::setLabel(const QString &label)
+{
+ m_label = label;
+ markAsModified();
+ return BackendReturn<void>();
+}
+
+BackendReturn<QCA::SecureArray> TempBlockingItem::secret() const
+{
+ return m_secret;
+}
+
+BackendReturn<void> TempBlockingItem::setSecret(const QCA::SecureArray &secret)
+{
+ m_secret = secret;
+ markAsModified();
+ return BackendReturn<void>();
+}
+
+BackendReturn<QMap<QString, QString> > TempBlockingItem::attributes() const
+{
+ return m_attributes;
+}
+
+BackendReturn<void> TempBlockingItem::setAttributes(const QMap<QString, QString> \
&attributes) +{
+ m_attributes = attributes;
+ markAsModified();
+ return BackendReturn<void>();
+}
+
+QDateTime TempBlockingItem::created() const
+{
+ return m_created;
+}
+
+QDateTime TempBlockingItem::modified() const
+{
+ return m_modified;
+}
+
+bool TempBlockingItem::isLocked() const
{
- Q_UNUSED(type);
return false;
}
+UnlockItemJob *TempBlockingItem::createUnlockJob()
+{
+ return new TempBlockingUnlockItemJob(this);
+}
+
+LockItemJob *TempBlockingItem::createLockJob()
+{
+ return new TempBlockingLockItemJob(this);
+}
+
+DeleteItemJob *TempBlockingItem::createDeleteJob()
+{
+ TempBlockingDeleteItemJob *job = new TempBlockingDeleteItemJob(this);
+ connect(job, SIGNAL(result(QueuedJob*)), SLOT(deleteItemJobResult(QueuedJob*)));
+ return job;
+}
+
+ChangeAuthenticationItemJob *TempBlockingItem::createChangeAuthenticationJob()
+{
+ return new TempBlockingChangeAuthenticationItemJob(this);
+}
+
+bool TempBlockingItem::matches(const QMap<QString, QString> &attributes)
+{
+ QMap<QString, QString>::const_iterator it = attributes.constBegin();
+ QMap<QString, QString>::const_iterator end = attributes.constEnd();
+ for ( ; it != end; ++it) {
+ if (!m_attributes.contains(it.key()) ||
+ m_attributes.value(it.key()) != it.value()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TempBlockingItem::deleteItemJobResult(QueuedJob *job)
+{
+ TempBlockingDeleteItemJob *dij = qobject_cast<TempBlockingDeleteItemJob*>(job);
+ Q_ASSERT(dij);
+ if (!dij->result()) {
+ return;
+ }
+ emit itemDeleted(this);
+}
+
+void TempBlockingItem::markAsModified()
+{
+ m_modified = QDateTime::currentDateTime();
+ emit itemChanged(this);
+}
+
#include "tempblockingitem.moc"
diff --git a/daemon/tests/tempblockingitem.h b/daemon/tests/tempblockingitem.h
index 6df1990..1b16a0c 100644
--- a/daemon/tests/tempblockingitem.h
+++ b/daemon/tests/tempblockingitem.h
@@ -21,12 +21,12 @@
#ifndef TEMPBLOCKINGITEM_H
#define TEMPBLOCKINGITEM_H
-#include "backend/temporary/temporaryitem.h"
+#include "backend/backenditem.h"
class TempBlockingCollection;
// temporary item that blocks every call
-class TempBlockingItem : public TemporaryItem
+class TempBlockingItem : public BackendItem
{
Q_OBJECT
@@ -35,7 +35,35 @@ public:
TempBlockingItem(const QString &id, TempBlockingCollection *parent);
~TempBlockingItem();
- virtual bool isCallImmediate(AsyncCall::AsyncType type) const;
+ virtual QString id() const;
+ virtual BackendReturn<QString> label() const;
+ virtual BackendReturn<void> setLabel(const QString &label);
+ virtual BackendReturn<QCA::SecureArray> secret() const;
+ virtual BackendReturn<void> setSecret(const QCA::SecureArray &secret);
+ virtual BackendReturn<QMap<QString, QString> > attributes() const;
+ virtual BackendReturn<void> setAttributes(const QMap<QString, QString> \
&attributes); + virtual QDateTime created() const;
+ virtual QDateTime modified() const;
+ virtual bool isLocked() const;
+ virtual UnlockItemJob *createUnlockJob();
+ virtual LockItemJob *createLockJob();
+ virtual DeleteItemJob *createDeleteJob();
+ virtual ChangeAuthenticationItemJob *createChangeAuthenticationJob();
+ bool matches(const QMap<QString, QString> &attributes);
+
+private Q_SLOTS:
+ void deleteItemJobResult(QueuedJob *job);
+
+private:
+ void markAsModified();
+
+ QString m_id;
+ QString m_label;
+ QDateTime m_created;
+ QDateTime m_modified;
+ QMap<QString, QString> m_attributes;
+
+ QCA::SecureArray m_secret;
};
#endif
diff --git a/daemon/tests/tempblockingjobs.cpp b/daemon/tests/tempblockingjobs.cpp
new file mode 100644
index 0000000..47382e2
--- /dev/null
+++ b/daemon/tests/tempblockingjobs.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tempblockingjobs.h"
+
+#include <secrettool.h>
+
+#include <QtCore/QTimer>
+
+TempBlockingCreateCollectionJob::TempBlockingCreateCollectionJob(const QString \
&label, bool locked, + \
TempBlockingCollectionManager *manager) + : CreateCollectionJob(label, locked, \
manager) +{
+}
+
+void TempBlockingCreateCollectionJob::perform()
+{
+ TempBlockingCollection *coll = new TempBlockingCollection(createId(), manager());
+ coll->setLabel(label());
+
+ setCollection(coll);
+ emitResult();
+}
+
+TempBlockingUnlockCollectionJob::TempBlockingUnlockCollectionJob(BackendCollection* \
coll) + : UnlockCollectionJob(coll)
+{
+}
+
+void TempBlockingUnlockCollectionJob::perform()
+{
+ setResult(true);
+ emitResult();
+}
+
+TempBlockingLockCollectionJob::TempBlockingLockCollectionJob(BackendCollection* \
coll) + : LockCollectionJob(coll)
+{
+}
+
+void TempBlockingLockCollectionJob::perform()
+{
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+TempBlockingDeleteCollectionJob::TempBlockingDeleteCollectionJob(BackendCollection* \
coll) + : DeleteCollectionJob(coll)
+{
+}
+
+void TempBlockingDeleteCollectionJob::perform()
+{
+ setResult(true);
+ collection()->deleteLater();
+ emitResult();
+}
+
+TempBlockingChangeAuthenticationCollectionJob::TempBlockingChangeAuthenticationCollectionJob(BackendCollection* \
coll) + : ChangeAuthenticationCollectionJob(coll)
+{
+}
+
+void TempBlockingChangeAuthenticationCollectionJob::perform()
+{
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+TempBlockingCreateItemJob::TempBlockingCreateItemJob(const QString& label,
+ const QMap< QString, QString >& \
attributes, + const \
QCA::SecureArray& secret, bool locked, + \
bool replace, + \
TempBlockingCollection* collection) + : CreateItemJob(label, attributes, secret, \
locked, replace, collection), + m_tempColl(collection)
+{
+}
+
+void TempBlockingCreateItemJob::perform()
+{
+ BackendReturn<BackendItem*> rc = m_tempColl->createItem(label(), attributes(),
+ secret(), locked(),
+ replace());
+
+ if (rc.isError()) {
+ setError(rc.error(), rc.errorMessage());
+ } else {
+ setItem(rc.value());
+ }
+ emitResult();
+}
+
+TempBlockingUnlockItemJob::TempBlockingUnlockItemJob(BackendItem* item)
+ : UnlockItemJob(item)
+{
+}
+
+void TempBlockingUnlockItemJob::perform()
+{
+ setResult(true);
+ emitResult();
+}
+
+TempBlockingLockItemJob::TempBlockingLockItemJob(BackendItem* item)
+ : LockItemJob(item)
+{
+}
+
+void TempBlockingLockItemJob::perform()
+{
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+TempBlockingDeleteItemJob::TempBlockingDeleteItemJob(BackendItem* item)
+ : DeleteItemJob(item)
+{
+}
+
+void TempBlockingDeleteItemJob::perform()
+{
+ setResult(true);
+ item()->deleteLater();
+ emitResult();
+}
+
+TempBlockingChangeAuthenticationItemJob::TempBlockingChangeAuthenticationItemJob(BackendItem* \
item) + : ChangeAuthenticationItemJob(item)
+{
+}
+
+void TempBlockingChangeAuthenticationItemJob::perform()
+{
+ setError(ErrorNotSupported);
+ setResult(false);
+ emitResult();
+}
+
+#include "tempblockingjobs.moc"
diff --git a/daemon/tests/tempblockingjobs.h b/daemon/tests/tempblockingjobs.h
new file mode 100644
index 0000000..bf04014
--- /dev/null
+++ b/daemon/tests/tempblockingjobs.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2010, Michael Leupold <lemma@confuego.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) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TEMPBLOCKINGJOBS_H
+#define TEMPBLOCKINGJOBS_H
+
+#include "tempblockingcollectionmanager.h"
+#include "tempblockingcollection.h"
+#include "tempblockingitem.h"
+
+#include <QtCore/QTimer>
+
+class TempBlockingCreateCollectionJob : public CreateCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingCreateCollectionJob(const QString &label, bool locked,
+ TempBlockingCollectionManager *manager);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingUnlockCollectionJob : public UnlockCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingUnlockCollectionJob(BackendCollection *coll);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingDeleteCollectionJob : public DeleteCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingDeleteCollectionJob(BackendCollection *coll);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingLockCollectionJob : public LockCollectionJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingLockCollectionJob(BackendCollection *coll);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingChangeAuthenticationCollectionJob : public \
ChangeAuthenticationCollectionJob +{
+ Q_OBJECT
+
+public:
+ TempBlockingChangeAuthenticationCollectionJob(BackendCollection *coll);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingCreateItemJob : public CreateItemJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingCreateItemJob(const QString &label, const QMap<QString, QString> \
&attributes, + const QCA::SecureArray &secret, bool \
locked, bool replace, + TempBlockingCollection \
*collection); + virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+
+private:
+ TempBlockingCollection* m_tempColl;
+};
+
+class TempBlockingUnlockItemJob : public UnlockItemJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingUnlockItemJob(BackendItem *item);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingLockItemJob : public LockItemJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingLockItemJob(BackendItem *item);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingDeleteItemJob : public DeleteItemJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingDeleteItemJob(BackendItem *item);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+class TempBlockingChangeAuthenticationItemJob : public ChangeAuthenticationItemJob
+{
+ Q_OBJECT
+
+public:
+ TempBlockingChangeAuthenticationItemJob(BackendItem *item);
+ virtual bool isImmediate() const { return false; }
+ virtual void exec() { Q_ASSERT(false); }
+ virtual void start() { QTimer::singleShot(0, this, SLOT(perform())); }
+
+private Q_SLOTS:
+ void perform();
+};
+
+#endif
diff --git a/lib/queuedjob.h b/lib/queuedjob.h
index 59dcb75..b9e5520 100644
--- a/lib/queuedjob.h
+++ b/lib/queuedjob.h
@@ -82,8 +82,8 @@ public:
* advertised that it can be called immediately.
*
* @note This method has to call emitResult() before returning. Even if
- * noone is interested in the signal it's used to set mark this
- * job as finished.
+ * noone is interested in the signal it's used to mark this job
+ * as finished and call deleteLater().
*/
virtual void exec() = 0;
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic