[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