Branch 'kolab/integration/4.13.0' - 38 commits - accountwizard/CMakeLists.txt accountwizard/ispdb CMakeLists.txt kcm/configmodule.cpp resources/google resources/imap resources/kolab resources/maildir resources/mbox resources/mixedmaildir resources/shared

Christian Mollekopf mollekopf at kolabsys.com
Mon Aug 11 11:07:07 CEST 2014


 CMakeLists.txt                                               |    2 
 accountwizard/CMakeLists.txt                                 |    1 
 accountwizard/ispdb/ispdb.cpp                                |   18 
 accountwizard/ispdb/main.cpp                                 |   81 +
 kcm/configmodule.cpp                                         |    3 
 resources/google/CMakeLists.txt                              |    4 
 resources/google/contacts/contactsresource.cpp               |    2 
 resources/imap/CMakeLists.txt                                |   36 
 resources/imap/addcollectiontask.cpp                         |    4 
 resources/imap/batchfetcher.cpp                              |  205 ++
 resources/imap/batchfetcher.h                                |   76 +
 resources/imap/changecollectiontask.cpp                      |   23 
 resources/imap/changecollectiontask.h                        |    3 
 resources/imap/changeitemsflagstask.h                        |   10 
 resources/imap/collectionmetadatahelper.cpp                  |   89 +
 resources/imap/collectionmetadatahelper.h                    |   32 
 resources/imap/imapidlemanager.cpp                           |    2 
 resources/imap/imapidlemanager.h                             |    6 
 resources/imap/imapresource.cpp                              |  748 ----------
 resources/imap/imapresource.h                                |  142 -
 resources/imap/imapresourcebase.cpp                          |  807 +++++++++++
 resources/imap/imapresourcebase.h                            |  173 ++
 resources/imap/messagehelper.cpp                             |   10 
 resources/imap/messagehelper.h                               |   10 
 resources/imap/resourcestate.cpp                             |   44 
 resources/imap/resourcestate.h                               |    9 
 resources/imap/resourcestateinterface.h                      |    3 
 resources/imap/resourcetask.cpp                              |   16 
 resources/imap/resourcetask.h                                |    7 
 resources/imap/retrievecollectionmetadatatask.cpp            |   74 -
 resources/imap/retrievecollectionmetadatatask.h              |    1 
 resources/imap/retrievecollectionstask.h                     |    2 
 resources/imap/retrieveitemstask.cpp                         |  222 ---
 resources/imap/retrieveitemstask.h                           |    4 
 resources/imap/retrieveitemtask.cpp                          |   16 
 resources/imap/retrieveitemtask.h                            |    4 
 resources/imap/serverinfodialog.cpp                          |    2 
 resources/imap/serverinfodialog.h                            |    4 
 resources/imap/sessionpool.cpp                               |   24 
 resources/imap/sessionpool.h                                 |    9 
 resources/imap/settings.cpp                                  |   40 
 resources/imap/settings.h                                    |   28 
 resources/imap/settingspasswordrequester.cpp                 |   16 
 resources/imap/settingspasswordrequester.h                   |    6 
 resources/imap/setupserver.cpp                               |  112 -
 resources/imap/setupserver.h                                 |    6 
 resources/imap/tests/dummyresourcestate.cpp                  |   15 
 resources/imap/tests/dummyresourcestate.h                    |    3 
 resources/imap/tests/testretrievecollectionmetadatatask.cpp  |   65 
 resources/kolab/CMakeLists.txt                               |   17 
 resources/kolab/kolabhelpers.cpp                             |    7 
 resources/kolab/kolabmessagehelper.cpp                       |   10 
 resources/kolab/kolabmessagehelper.h                         |   10 
 resources/kolab/kolabresource.cpp                            |   16 
 resources/kolab/kolabresource.h                              |    1 
 resources/kolab/kolabresourcestate.cpp                       |   37 
 resources/kolab/kolabresourcestate.h                         |    1 
 resources/kolab/kolabretrievecollectionstask.cpp             |  255 +++
 resources/kolab/kolabretrievecollectionstask.h               |   33 
 resources/maildir/libmaildir/maildir.cpp                     |   28 
 resources/maildir/libmaildir/tests/testmaildir.cpp           |    4 
 resources/mbox/mboxresource.cpp                              |    2 
 resources/mixedmaildir/kmindexreader/kmindexreader.cpp       |    2 
 resources/mixedmaildir/kmindexreader/kmindexreader_support.h |   43 
 resources/mixedmaildir/tests/itemfetchtest.cpp               |   12 
 resources/shared/getcredentialsjob.cpp                       |    2 
 resources/shared/imapaclattribute.cpp                        |   44 
 resources/shared/imapaclattribute.h                          |    3 
 resources/shared/tests/imapaclattributetest.cpp              |   43 
 69 files changed, 2307 insertions(+), 1482 deletions(-)

New commits:
commit ebbe365edab2b98a9d701c750ec6f54e94045338
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Sun Aug 10 20:54:35 2014 +0200

    Remove password from kwallet when we remove resource
    
    Conflicts:
    	resources/imap/imapresource.cpp
    	resources/imap/imapresource.h
    	resources/imap/settings.h

diff --git a/resources/imap/imapresource.cpp b/resources/imap/imapresource.cpp
index c388a1f..e78768a 100644
--- a/resources/imap/imapresource.cpp
+++ b/resources/imap/imapresource.cpp
@@ -70,3 +70,8 @@ void ImapResource::onConfigurationDone(int result)
   }
   dlg->deleteLater();
 }
+
+void ImapResource::cleanup()
+{
+    settings()->cleanup();
+}
diff --git a/resources/imap/imapresource.h b/resources/imap/imapresource.h
index 43e3892..2101341 100644
--- a/resources/imap/imapresource.h
+++ b/resources/imap/imapresource.h
@@ -38,6 +38,7 @@ public:
     virtual ~ImapResource();
 
     virtual KDialog *createConfigureDialog ( WId windowId );
+    virtual void cleanup();
 
 protected:
     virtual QString defaultName() const;
diff --git a/resources/imap/settings.cpp b/resources/imap/settings.cpp
index a47ed1a..2671a8c 100644
--- a/resources/imap/settings.cpp
+++ b/resources/imap/settings.cpp
@@ -88,6 +88,18 @@ void Settings::clearCachedPassword()
     m_password.clear();
 }
 
+void Settings::cleanup()
+{
+    Wallet* wallet = Wallet::openWallet( Wallet::NetworkWallet(), m_winId );
+    if ( wallet && wallet->isOpen() ) {
+        if ( wallet->hasFolder( QLatin1String("imap") ) ) {
+            wallet->setFolder( QLatin1String("imap") );
+            wallet->removeEntry( config()->name() );
+        }
+        delete wallet;
+    }
+}
+
 void Settings::requestPassword()
 {
   if ( !m_password.isEmpty() ||


commit 8d8335f6c854db4493e96c3a53c886c32af7dd99
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Sun Aug 10 18:00:59 2014 +0200

    Kolab-Resource/IMAP-Resource: Retrieve metadata as part of collectionretrieval

diff --git a/resources/imap/CMakeLists.txt b/resources/imap/CMakeLists.txt
index 89bbf65..e22a242 100644
--- a/resources/imap/CMakeLists.txt
+++ b/resources/imap/CMakeLists.txt
@@ -48,6 +48,7 @@ set( imapresource_LIB_SRCS
   subscriptiondialog.cpp
   imapidlemanager.cpp
   resourcestate.cpp
+  collectionmetadatahelper.cpp
   ${AKONADI_COLLECTIONATTRIBUTES_SHARED_SOURCES}
   ${AKONADI_IMAPATTRIBUTES_SHARED_SOURCES}
 )
diff --git a/resources/imap/collectionmetadatahelper.cpp b/resources/imap/collectionmetadatahelper.cpp
new file mode 100644
index 0000000..92eefbc
--- /dev/null
+++ b/resources/imap/collectionmetadatahelper.cpp
@@ -0,0 +1,89 @@
+/*
+    Copyright (c) 2014 Christian Mollekopf <mollekopf at kolabsys.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#include "collectionmetadatahelper.h"
+#include <imapaclattribute.h>
+#include <timestampattribute.h>
+
+Akonadi::Collection::Rights CollectionMetadataHelper::convertRights(const KIMAP::Acl::Rights imapRights, KIMAP::Acl::Rights parentRights)
+{
+    Akonadi::Collection::Rights newRights = Akonadi::Collection::ReadOnly;
+
+    // For renaming, the parent folder needs to have the CreateMailbox or Create permission.
+    // We map renaming to CanChangeCollection here, which is not entirely correct, but we have no
+    // CanRenameCollection flag.
+    if (parentRights & KIMAP::Acl::CreateMailbox ||
+        parentRights & KIMAP::Acl::Create) {
+        newRights|= Akonadi::Collection::CanChangeCollection;
+    }
+
+    if (imapRights & KIMAP::Acl::Write) {
+        newRights|= Akonadi::Collection::CanChangeItem;
+    }
+
+    if (imapRights & KIMAP::Acl::Insert) {
+        newRights|= Akonadi::Collection::CanCreateItem;
+    }
+
+    if (imapRights & (KIMAP::Acl::DeleteMessage | KIMAP::Acl::Delete)) {
+        newRights|= Akonadi::Collection::CanDeleteItem;
+    }
+
+    if (imapRights & (KIMAP::Acl::CreateMailbox | KIMAP::Acl::Create)) {
+        newRights|= Akonadi::Collection::CanCreateCollection;
+    }
+
+    if (imapRights & (KIMAP::Acl::DeleteMailbox | KIMAP::Acl::Delete)) {
+        newRights|= Akonadi::Collection::CanDeleteCollection;
+    }
+    return newRights;
+}
+
+bool CollectionMetadataHelper::applyRights(Akonadi::Collection &collection, const KIMAP::Acl::Rights imapRights, KIMAP::Acl::Rights parentRights)
+{
+    Akonadi::Collection::Rights newRights = convertRights(imapRights, parentRights);
+
+    if (collection.hasAttribute("noinferiors")) {
+        newRights &= ~Akonadi::Collection::CanCreateCollection;
+    }
+
+    if (collection.parentCollection().hasAttribute("noselect")) {
+        newRights &= ~Akonadi::Collection::CanChangeCollection;
+    }
+
+    const bool isNewCollection = !collection.hasAttribute<TimestampAttribute>();
+    bool accessRevoked = false;
+    if ((collection.rights() & Akonadi::Collection::CanCreateItem) &&
+        !(newRights & Akonadi::Collection::CanCreateItem) &&
+        !isNewCollection) {
+        // write access revoked
+        accessRevoked = true;
+    }
+
+    kDebug(5327) << collection.remoteId()
+                << "imapRights:" << imapRights
+                << "newRights:" << newRights
+                << "oldRights:" << collection.rights();
+
+    if (newRights != collection.rights()) {
+        collection.setRights(newRights);
+    }
+    return accessRevoked;
+}
+
diff --git a/resources/imap/collectionmetadatahelper.h b/resources/imap/collectionmetadatahelper.h
new file mode 100644
index 0000000..4849116
--- /dev/null
+++ b/resources/imap/collectionmetadatahelper.h
@@ -0,0 +1,32 @@
+/*
+    Copyright (c) 2014 Christian Mollekopf <mollekopf at kolabsys.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+#ifndef COLLECTIONMETADATAHELPER_H
+#define COLLECTIONMETADATAHELPER_H
+
+#include <akonadi/collection.h>
+#include <kimap/acl.h>
+
+class CollectionMetadataHelper
+{
+public:
+    static Akonadi::Collection::Rights convertRights(const KIMAP::Acl::Rights imapRights, KIMAP::Acl::Rights parentRights);
+    static bool applyRights(Akonadi::Collection &collection, const KIMAP::Acl::Rights imapRights, KIMAP::Acl::Rights parentRights);
+};
+
+#endif
diff --git a/resources/imap/imapresourcebase.h b/resources/imap/imapresourcebase.h
index 4f07a44..0ab176a 100644
--- a/resources/imap/imapresourcebase.h
+++ b/resources/imap/imapresourcebase.h
@@ -87,6 +87,7 @@ protected Q_SLOTS:
 
   virtual void retrieveItems( const Akonadi::Collection &col );
   virtual bool retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts );
+  virtual void delayedInit();
 
 protected:
   virtual void itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection );
@@ -147,8 +148,6 @@ private Q_SLOTS:
 
   void onCollectionModifyDone( KJob *job );
 
-  void delayedInit();
-
 protected:
   //Starts and queues a task
   void startTask( ResourceTask *task );
diff --git a/resources/imap/resourcestate.cpp b/resources/imap/resourcestate.cpp
index 90083b0..fbff0ce 100644
--- a/resources/imap/resourcestate.cpp
+++ b/resources/imap/resourcestate.cpp
@@ -224,6 +224,7 @@ void ResourceState::collectionsRetrieved( const Akonadi::Collection::List &colle
 {
   m_resource->collectionsRetrieved( collections );
 
+  //FIXME get rid of this. If we retrieve metadata before syncing a folder I think we can live without this code.
   if ( m_resource->settings()->retrieveMetadataOnFolderListing() ) {
     QStringList oldMailBoxes = m_resource->settings()->knownMailBoxes();
     QStringList newMailBoxes;
diff --git a/resources/imap/retrievecollectionmetadatatask.cpp b/resources/imap/retrievecollectionmetadatatask.cpp
index 27c666a..a891861 100644
--- a/resources/imap/retrievecollectionmetadatatask.cpp
+++ b/resources/imap/retrievecollectionmetadatatask.cpp
@@ -38,6 +38,7 @@
 #include "imapquotaattribute.h"
 #include "noselectattribute.h"
 #include "timestampattribute.h"
+#include "collectionmetadatahelper.h"
 
 RetrieveCollectionMetadataTask::RetrieveCollectionMetadataTask( ResourceStateInterface::Ptr resource, QObject *parent )
   : ResourceTask( CancelIfNoSession, resource, parent ),
@@ -174,47 +175,15 @@ void RetrieveCollectionMetadataTask::onRightsReceived( KJob *job )
 
   KIMAP::MyRightsJob *rightsJob = qobject_cast<KIMAP::MyRightsJob*>( job );
 
-  Akonadi::ImapAclAttribute * const parentAclAttribute =
-        collection().parentCollection().attribute<Akonadi::ImapAclAttribute>();
-  KIMAP::Acl::Rights parentRights = 0;
-  if ( parentAclAttribute ) {
-    parentRights = parentAclAttribute->rights()[userName().toUtf8()];
-  }
-
-  const KIMAP::Acl::Rights imapRights = rightsJob->rights();
-  Akonadi::Collection::Rights newRights = Akonadi::Collection::ReadOnly;
-
-  // For renaming, the parent folder needs to have the CreateMailbox or Create permission.
-  // We map renaming to CanChangeCollection here, which is not entirely correct, but we have no
-  // CanRenameCollection flag.
-  // If the ACL of the parent folder hasn't been retrieved yet, allow changing, since we don't know
-  // better. If the parent folder is a noselect folder though, don't allow it, since for those we have
-  // no CreateMailbox right.
-  if ( ( !parentAclAttribute && !collection().parentCollection().hasAttribute( "noselect" ) ) ||
-       parentRights & KIMAP::Acl::CreateMailbox ||
-       parentRights & KIMAP::Acl::Create ) {
-    newRights|= Akonadi::Collection::CanChangeCollection;
-  }
-
-  if ( imapRights & KIMAP::Acl::Write ) {
-    newRights|= Akonadi::Collection::CanChangeItem;
-  }
-
-  if ( imapRights & KIMAP::Acl::Insert ) {
-    newRights|= Akonadi::Collection::CanCreateItem;
-  }
+  //Default value in case we have nothing better available
+  KIMAP::Acl::Rights parentRights = KIMAP::Acl::CreateMailbox | KIMAP::Acl::Create;
 
-  if ( imapRights & ( KIMAP::Acl::DeleteMessage | KIMAP::Acl::Delete ) ) {
-    newRights|= Akonadi::Collection::CanDeleteItem;
+  //FIXME I don't think we have the parent's acl's available
+  if (collection().parentCollection().attribute<Akonadi::ImapAclAttribute>()) {
+    parentRights = myRights(collection().parentCollection());
   }
 
-  if ( !m_collection.hasAttribute( "noinferiors" ) && imapRights & ( KIMAP::Acl::CreateMailbox | KIMAP::Acl::Create ) ) {
-    newRights|= Akonadi::Collection::CanCreateCollection;
-  }
-
-  if ( imapRights & ( KIMAP::Acl::DeleteMailbox | KIMAP::Acl::Delete ) ) {
-    newRights|= Akonadi::Collection::CanDeleteCollection;
-  }
+  const KIMAP::Acl::Rights imapRights = rightsJob->rights();
 
 //  kDebug( 5327 ) << collection.remoteId()
 //                 << "imapRights:" << imapRights
@@ -222,9 +191,8 @@ void RetrieveCollectionMetadataTask::onRightsReceived( KJob *job )
 //                 << "oldRights:" << collection.rights();
 
   const bool isNewCollection = !m_collection.hasAttribute<TimestampAttribute>();
-  if ( (m_collection.rights() & Akonadi::Collection::CanCreateItem) &&
-       !(newRights & Akonadi::Collection::CanCreateItem) &&
-       !isNewCollection ) {
+  const bool accessRevoked = CollectionMetadataHelper::applyRights(m_collection, imapRights, parentRights);
+  if ( accessRevoked && !isNewCollection ) {
     // write access revoked
     const QString collectionName = m_collection.displayName();
 
@@ -234,8 +202,12 @@ void RetrieveCollectionMetadataTask::onRightsReceived( KJob *job )
                            i18n( "Access rights revoked" ), QLatin1String("ShowRightsRevokedWarning") );
   }
 
-  if ( newRights != m_collection.rights() ) {
-    m_collection.setRights( newRights );
+  // Store the mailbox ACLs
+  Akonadi::ImapAclAttribute *aclAttribute
+    = m_collection.attribute<Akonadi::ImapAclAttribute>( Akonadi::Collection::AddIfMissing );
+  const KIMAP::Acl::Rights oldRights = aclAttribute->myRights();
+  if ( oldRights != imapRights ) {
+    aclAttribute->setMyRights( imapRights );
   }
 
   //The a right is required to list acl's
diff --git a/resources/imap/tests/testretrievecollectionmetadatatask.cpp b/resources/imap/tests/testretrievecollectionmetadatatask.cpp
index c6113f8..a05a2fb 100644
--- a/resources/imap/tests/testretrievecollectionmetadatatask.cpp
+++ b/resources/imap/tests/testretrievecollectionmetadatatask.cpp
@@ -74,16 +74,16 @@ private slots:
              << "C: A000003 GETANNOTATION \"INBOX/Foo\" \"*\" \"value.shared\""
              << "S: * ANNOTATION INBOX/Foo /vendor/kolab/folder-test ( value.shared true )"
              << "S: A000003 OK annotations retrieved"
-             << "C: A000004 GETACL \"INBOX/Foo\""
-             << "S: * ACL INBOX/Foo foo at kde.org lrswipcda"
-             << "S: A000004 OK acl retrieved"
-             << "C: A000005 MYRIGHTS \"INBOX/Foo\""
+             << "C: A000004 MYRIGHTS \"INBOX/Foo\""
              << "S: * MYRIGHTS \"INBOX/Foo\" lrswipkxtecda"
-             << "S: A000005 OK rights retrieved"
-             << "C: A000006 GETQUOTAROOT \"INBOX/Foo\""
+             << "S: A000004 OK rights retrieved"
+             << "C: A000005 GETQUOTAROOT \"INBOX/Foo\""
              << "S: * QUOTAROOT INBOX/Foo user/foo"
              << "S: * QUOTA user/foo ( )"
-             << "S: A000006 OK quota retrieved";
+             << "S: A000005 OK quota retrieved"
+             << "C: A000006 GETACL \"INBOX/Foo\""
+             << "S: * ACL INBOX/Foo foo at kde.org lrswipcda"
+             << "S: A000006 OK acl retrieved";
 
     callNames.clear();
     callNames << "collectionAttributesRetrieved";
@@ -122,7 +122,7 @@ private slots:
     NoSelectAttribute *noSelectAttribute = new NoSelectAttribute();
     parentCollection.addAttribute( noSelectAttribute );
     collection.setParentCollection( parentCollection );
-    QTest::newRow( "parent wit noselect" ) << collection << capabilities << scenario
+    QTest::newRow( "parent with noselect" ) << collection << capabilities << scenario
                                            << callNames << rights << expectedAnnotations;
     parentCollection.removeAttribute<NoSelectAttribute>();
 
@@ -136,16 +136,13 @@ private slots:
              << "C: A000003 GETANNOTATION \"INBOX/Foo\" \"*\" \"value.shared\""
              << "S: * ANNOTATION INBOX/Foo /vendor/kolab/folder-test ( value.shared true )"
              << "S: A000003 OK annotations retrieved"
-             << "C: A000004 GETACL \"INBOX/Foo\""
-             << "S: * ACL INBOX/Foo foo at kde.org wi"
-             << "S: A000004 OK acl retrieved"
-             << "C: A000005 MYRIGHTS \"INBOX/Foo\""
+             << "C: A000004 MYRIGHTS \"INBOX/Foo\""
              << "S: * MYRIGHTS \"INBOX/Foo\" wi"
-             << "S: A000005 OK rights retrieved"
-             << "C: A000006 GETQUOTAROOT \"INBOX/Foo\""
+             << "S: A000004 OK rights retrieved"
+             << "C: A000005 GETQUOTAROOT \"INBOX/Foo\""
              << "S: * QUOTAROOT INBOX/Foo user/foo"
              << "S: * QUOTA user/foo ( )"
-             << "S: A000006 OK quota retrieved";
+             << "S: A000005 OK quota retrieved";
     rights = Akonadi::Collection::CanCreateItem | Akonadi::Collection::CanChangeItem |
              Akonadi::Collection::CanChangeCollection;
     QTest::newRow( "only some rights" ) << collection << capabilities << scenario
@@ -167,16 +164,13 @@ private slots:
              << "C: A000003 GETANNOTATION \"INBOX/Foo\" \"*\" \"value.shared\""
              << "S: * ANNOTATION INBOX/Foo /vendor/kolab/folder-test ( value.shared true )"
              << "S: A000003 OK annotations retrieved"
-             << "C: A000004 GETACL \"INBOX/Foo\""
-             << "S: * ACL INBOX/Foo foo at kde.org wi"
-             << "S: A000004 OK acl retrieved"
-             << "C: A000005 MYRIGHTS \"INBOX/Foo\""
+             << "C: A000004 MYRIGHTS \"INBOX/Foo\""
              << "S: * MYRIGHTS \"INBOX/Foo\" w"
-             << "S: A000005 OK rights retrieved"
-             << "C: A000006 GETQUOTAROOT \"INBOX/Foo\""
+             << "S: A000004 OK rights retrieved"
+             << "C: A000005 GETQUOTAROOT \"INBOX/Foo\""
              << "S: * QUOTAROOT INBOX/Foo user/foo"
              << "S: * QUOTA user/foo ( )"
-             << "S: A000006 OK quota retrieved";
+             << "S: A000005 OK quota retrieved";
 
     callNames.clear();
     callNames << "showInformationDialog";
@@ -199,16 +193,13 @@ private slots:
              << "C: A000003 GETANNOTATION \"INBOX\" \"*\" \"value.shared\""
              << "S: * ANNOTATION INBOX /vendor/kolab/folder-test ( value.shared true )"
              << "S: A000003 OK annotations retrieved"
-             << "C: A000004 GETACL \"INBOX\""
-             << "S: * ACL INBOX foo at kde.org wik"
-             << "S: A000004 OK acl retrieved"
-             << "C: A000005 MYRIGHTS \"INBOX\""
+             << "C: A000004 MYRIGHTS \"INBOX\""
              << "S: * MYRIGHTS \"INBOX\" wk"
-             << "S: A000005 OK rights retrieved"
-             << "C: A000006 GETQUOTAROOT \"INBOX\""
+             << "S: A000004 OK rights retrieved"
+             << "C: A000005 GETQUOTAROOT \"INBOX\""
              << "S: * QUOTAROOT INBOX user"
              << "S: * QUOTA user ( )"
-             << "S: A000006 OK quota retrieved";
+             << "S: A000005 OK quota retrieved";
 
     callNames.clear();
     callNames << "collectionAttributesRetrieved";
@@ -236,16 +227,16 @@ private slots:
              << "S: * METADATA \"INBOX/Foo\" (/shared/vendor/kolab/folder-test2 \"NIL\")"
              << "S: * METADATA \"INBOX/Foo\" (/shared/vendor/cmu/cyrus-imapd/lastupdate \"true\")"
              << "S: A000003 OK GETMETADATA complete"
-             << "C: A000004 GETACL \"INBOX/Foo\""
-             << "S: * ACL INBOX/Foo foo at kde.org lrswipcda"
-             << "S: A000004 OK acl retrieved"
-             << "C: A000005 MYRIGHTS \"INBOX/Foo\""
+             << "C: A000004 MYRIGHTS \"INBOX/Foo\""
              << "S: * MYRIGHTS \"INBOX/Foo\" lrswipkxtecda"
-             << "S: A000005 OK rights retrieved"
-             << "C: A000006 GETQUOTAROOT \"INBOX/Foo\""
+             << "S: A000004 OK rights retrieved"
+             << "C: A000005 GETQUOTAROOT \"INBOX/Foo\""
              << "S: * QUOTAROOT INBOX/Foo user/Foo"
              << "S: * QUOTA user/Foo ( )"
-             << "S: A000006 OK quota retrieved";
+             << "S: A000005 OK quota retrieved"
+             << "C: A000006 GETACL \"INBOX/Foo\""
+             << "S: * ACL INBOX/Foo foo at kde.org lrswipcda"
+             << "S: A000006 OK acl retrieved";
 
     callNames.clear();
     callNames << "collectionAttributesRetrieved";
diff --git a/resources/kolab/kolabresource.cpp b/resources/kolab/kolabresource.cpp
index a5e051a..6348e20 100644
--- a/resources/kolab/kolabresource.cpp
+++ b/resources/kolab/kolabresource.cpp
@@ -34,6 +34,7 @@
 #include "kolabretrievecollectionstask.h"
 #include "kolabresourcestate.h"
 #include "kolabhelpers.h"
+#include "settings.h"
 
 KolabResource::KolabResource(const QString& id)
     :ImapResource(id)
@@ -47,6 +48,13 @@ KolabResource::~KolabResource()
 
 }
 
+void KolabResource::delayedInit()
+{
+    ImapResource::delayedInit();
+    settings()->setRetrieveMetadataOnFolderListing(false);
+    Q_ASSERT(!settings()->retrieveMetadataOnFolderListing());
+}
+
 QString KolabResource::defaultName()
 {
     return i18n("Kolab Resource");
diff --git a/resources/kolab/kolabresource.h b/resources/kolab/kolabresource.h
index 38889ad..2604d98 100644
--- a/resources/kolab/kolabresource.h
+++ b/resources/kolab/kolabresource.h
@@ -36,6 +36,7 @@ public:
 protected Q_SLOTS:
     virtual void retrieveCollections();
     virtual void retrieveItems(const Akonadi::Collection& col);
+    virtual void delayedInit();
 
 protected:
     virtual ResourceStateInterface::Ptr createResourceState(const TaskArguments &);
diff --git a/resources/kolab/kolabretrievecollectionstask.cpp b/resources/kolab/kolabretrievecollectionstask.cpp
index 4be0268..915409b 100644
--- a/resources/kolab/kolabretrievecollectionstask.cpp
+++ b/resources/kolab/kolabretrievecollectionstask.cpp
@@ -26,7 +26,10 @@
 #include <noselectattribute.h>
 #include <noinferiorsattribute.h>
 #include <collectionannotationsattribute.h>
+#include <collectionmetadatahelper.h>
+#include <imapaclattribute.h>
 #include <kimap/getmetadatajob.h>
+#include <kimap/myrightsjob.h>
 
 #include <akonadi/cachepolicy.h>
 #include <akonadi/entitydisplayattribute.h>
@@ -38,6 +41,104 @@
 #include <KDE/KDebug>
 #include <KDE/KLocale>
 
+RetrieveMetadataJob::RetrieveMetadataJob(KIMAP::Session *session, const QStringList &mailboxes, const QStringList &serverCapabilities, const QSet<QByteArray> &requestedMetadata, const QString &separator, QObject *parent)
+    : KJob(parent)
+    , mJobs(0)
+    , mRequestedMetadata(requestedMetadata)
+    , mServerCapabilities(serverCapabilities)
+    , mMailboxes(mailboxes)
+    , mSession(session)
+    , mSeparator(separator)
+{
+
+}
+
+void RetrieveMetadataJob::start()
+{
+    QSet<QString> toplevelMailboxes;
+    Q_FOREACH (const QString &mailbox, mMailboxes) {
+        const QStringList parts = mailbox.split(mSeparator);
+        if (!parts.isEmpty()) {
+            toplevelMailboxes << parts.first();
+        }
+    }
+
+    if ( mServerCapabilities.contains( QLatin1String("METADATA") ) || mServerCapabilities.contains( QLatin1String("ANNOTATEMORE") ) ) {
+        //TODO perhaps exclude the shared and other users namespaces by listing only toplevel (with %), and then only getting metadata of the toplevel folders.
+        Q_FOREACH (const QString &mailbox, toplevelMailboxes) {
+            {
+                KIMAP::GetMetaDataJob *meta = new KIMAP::GetMetaDataJob(mSession);
+                meta->setMailBox(mailbox + QLatin1String("*"));
+                if ( mServerCapabilities.contains( QLatin1String("METADATA") ) ) {
+                    meta->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
+                } else {
+                    meta->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
+                }
+                meta->setDepth( KIMAP::GetMetaDataJob::AllLevels );
+                Q_FOREACH (const QByteArray &requestedEntry, mRequestedMetadata) {
+                    meta->addRequestedEntry(requestedEntry);
+                }
+                connect( meta, SIGNAL(result(KJob*)), SLOT(onGetMetaDataDone(KJob*)) );
+                mJobs++;
+                meta->start();
+            }
+        }
+    }
+
+
+    // Get the ACLs from the mailbox if it's supported
+    if ( mServerCapabilities.contains( QLatin1String("ACL") ) ) {
+
+        Q_FOREACH (const QString &mailbox, mMailboxes) {
+            KIMAP::MyRightsJob *rights = new KIMAP::MyRightsJob( mSession );
+            rights->setMailBox(mailbox);
+            connect( rights, SIGNAL(result(KJob*)), SLOT(onRightsReceived(KJob*)) );
+            mJobs++;
+            rights->start();
+        }
+    }
+    checkDone();
+}
+
+void RetrieveMetadataJob::onGetMetaDataDone( KJob *job )
+{
+    mJobs--;
+    if ( job->error() ) {
+        kWarning() << "Get metadata failed: " << job->errorString();
+        setError(KJob::UserDefinedError);
+        checkDone();
+        return;
+    }
+
+    KIMAP::GetMetaDataJob *meta = qobject_cast<KIMAP::GetMetaDataJob*>( job );
+    mMetadata = meta->allMetaDataForMailboxes();
+    checkDone();
+}
+
+void RetrieveMetadataJob::onRightsReceived( KJob *job )
+{
+    mJobs--;
+    if ( job->error() ) {
+        kWarning() << "MyRights failed: " << job->errorString();
+        setError(KJob::UserDefinedError);
+        checkDone();
+        return; // Well, no metadata for us then...
+    }
+
+    KIMAP::MyRightsJob *rightsJob = qobject_cast<KIMAP::MyRightsJob*>( job );
+    const KIMAP::Acl::Rights imapRights = rightsJob->rights();
+    mRights.insert(rightsJob->mailBox(), imapRights);
+    checkDone();
+}
+
+void RetrieveMetadataJob::checkDone()
+{
+    if (!mJobs) {
+        kDebug() << "done";
+        emitResult();
+    }
+}
+
 KolabRetrieveCollectionsTask::KolabRetrieveCollectionsTask(ResourceStateInterface::Ptr resource, QObject* parent)
     : ResourceTask(CancelIfNoSession, resource, parent),
     mJobs(0)
@@ -53,6 +154,8 @@ KolabRetrieveCollectionsTask::~KolabRetrieveCollectionsTask()
 
 void KolabRetrieveCollectionsTask::doStart(KIMAP::Session *session)
 {
+    mSession = session;
+
     Akonadi::Collection root;
     root.setName(resourceName());
     root.setRemoteId(rootRemoteId());
@@ -97,23 +200,6 @@ void KolabRetrieveCollectionsTask::doStart(KIMAP::Session *session)
         fullListJob->start();
     }
 
-    if ( resourceState()->serverCapabilities().contains( QLatin1String("METADATA") ) || resourceState()->serverCapabilities().contains( QLatin1String("ANNOTATEMORE") ) ) {
-        //TODO perhaps exclude the shared and other users namespaces by listing only toplevel (with %), and then only getting metadata of the toplevel folders.
-        KIMAP::GetMetaDataJob *meta = new KIMAP::GetMetaDataJob(session);
-        meta->setMailBox(QLatin1String("*"));
-        if ( resourceState()->serverCapabilities().contains( QLatin1String("METADATA") ) ) {
-            meta->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
-        } else {
-            meta->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
-        }
-        meta->setDepth( KIMAP::GetMetaDataJob::AllLevels );
-        Q_FOREACH (const QByteArray &requestedEntry, mRequestedMetadata) {
-            meta->addRequestedEntry(requestedEntry);
-        }
-        connect( meta, SIGNAL(result(KJob*)), SLOT(onGetMetaDataDone(KJob*)) );
-        meta->start();
-    }
-
     KIMAP::ListJob *listJob = new KIMAP::ListJob(session);
     listJob->setOption(KIMAP::ListJob::IncludeUnsubscribed);
     listJob->setQueriedNamespaces(serverNamespaces());
@@ -124,17 +210,6 @@ void KolabRetrieveCollectionsTask::doStart(KIMAP::Session *session)
     listJob->start();
 }
 
-void KolabRetrieveCollectionsTask::onGetMetaDataDone( KJob *job )
-{
-    if ( job->error() ) {
-            kWarning() << "Get metadata failed: " << job->errorString();
-            return;
-    }
-
-    KIMAP::GetMetaDataJob *meta = qobject_cast<KIMAP::GetMetaDataJob*>( job );
-    mMetadata = meta->allMetaDataForMailboxes();
-}
-
 void KolabRetrieveCollectionsTask::onMailBoxesReceived(const QList< KIMAP::MailBoxDescriptor > &descriptors,
                                                    const QList< QList<QByteArray> > &flags)
 {
@@ -171,10 +246,10 @@ Akonadi::Collection KolabRetrieveCollectionsTask::getOrCreateParent(const QStrin
     return c;
 }
 
-bool KolabRetrieveCollectionsTask::isNamespaceFolder(const QStringList &pathParts, const QList<KIMAP::MailBoxDescriptor> &namespaces)
+bool KolabRetrieveCollectionsTask::isNamespaceFolder(const QString &path, const QList<KIMAP::MailBoxDescriptor> &namespaces) const
 {
     Q_FOREACH (const KIMAP::MailBoxDescriptor &desc, namespaces) {
-        if (desc.name.contains(pathParts.first())) { //Namespace ends with path separator and pathPart doesn't
+        if (path.startsWith(desc.name.left(desc.name.size() - 1))) { //Namespace ends with path separator and pathPart doesn't
             return true;
         }
     }
@@ -188,36 +263,35 @@ void KolabRetrieveCollectionsTask::setAttributes(Akonadi::Collection &c, const Q
     attr->setIdentifier(path.toLatin1());
 
     // If the folder is a other users top-level folder mark it accordingly
-    if (pathParts.size() == 1 && isNamespaceFolder(pathParts, resourceState()->userNamespaces())) {
+    if (pathParts.size() == 1 && isNamespaceFolder(path, resourceState()->userNamespaces())) {
         Akonadi::EntityDisplayAttribute *attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
         attr->setDisplayName(i18n("Other Users"));
         attr->setIconName(QLatin1String("x-mail-distribution-list"));
     }
 
     //Mark user folders for searching
-    if (pathParts.size() == 2 && isNamespaceFolder(pathParts, resourceState()->userNamespaces())) {
+    if (pathParts.size() >= 2 && isNamespaceFolder(path, resourceState()->userNamespaces())) {
         CollectionIdentificationAttribute *attr = c.attribute<CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing);
-        attr->setCollectionNamespace("user");
+        if (pathParts.size() == 2) {
+            attr->setCollectionNamespace("usertoplevel");
+        } else {
+            attr->setCollectionNamespace("user");
+        }
     }
 
     // If the folder is a shared folders top-level folder mark it accordingly
-    if (pathParts.size() == 1 && isNamespaceFolder(pathParts, resourceState()->sharedNamespaces())) {
+    if (pathParts.size() == 1 && isNamespaceFolder(path, resourceState()->sharedNamespaces())) {
         Akonadi::EntityDisplayAttribute *attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
         attr->setDisplayName(i18n("Shared Folders"));
         attr->setIconName(QLatin1String("x-mail-distribution-list"));
     }
 
     //Mark shared folders for searching
-    if (pathParts.size() >= 2 && isNamespaceFolder(pathParts, resourceState()->sharedNamespaces())) {
+    if (pathParts.size() >= 2 && isNamespaceFolder(path, resourceState()->sharedNamespaces())) {
         CollectionIdentificationAttribute *attr = c.attribute<CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing);
         attr->setCollectionNamespace("shared");
     }
 
-    const QMap<QByteArray, QByteArray> metadata = mMetadata.value(path);
-    if (!metadata.isEmpty()) {
-        c.attribute<Akonadi::CollectionAnnotationsAttribute>(Akonadi::Collection::AddIfMissing)->setAnnotations(metadata);
-    }
-
 }
 
 void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, const QList<QByteArray> &currentFlags, bool isSubscribed)
@@ -291,6 +365,78 @@ void KolabRetrieveCollectionsTask::onMailBoxesReceiveDone(KJob* job)
     if (job->error()) {
         cancelTask(job->errorString());
     } else {
+        QStringList personalMailboxes;
+        Q_FOREACH(const QString &mailbox, mMailCollections.keys()) {
+            if (!isNamespaceFolder(mailbox, resourceState()->userNamespaces() + resourceState()->sharedNamespaces())) {
+                if (mailbox.isEmpty()) {
+                    continue;
+                }
+                personalMailboxes << mailbox;
+            }
+        }
+
+        RetrieveMetadataJob *metadata = new RetrieveMetadataJob(mSession, personalMailboxes, serverCapabilities(), mRequestedMetadata, separatorCharacter(), this);
+        connect(metadata, SIGNAL(result(KJob*)), this, SLOT(onMetadataRetrieved(KJob*)));
+        mJobs++;
+        metadata->start();
+    }
+}
+
+void KolabRetrieveCollectionsTask::applyRights(QHash<QString, KIMAP::Acl::Rights> rights)
+{
+    // kDebug() << rights;
+    Q_FOREACH(const QString &mailbox, rights.keys()) {
+        if (mMailCollections.contains(mailbox)) {
+            const KIMAP::Acl::Rights imapRights = rights.value(mailbox);
+            QStringList parts = mailbox.split(separatorCharacter());
+            parts.removeLast();
+            QString parentMailbox = parts.join(separatorCharacter());
+            if (!parentMailbox.isEmpty() &&!rights.contains(parentMailbox)) {
+                kWarning() << "Couldn't find parent mailbox rights";
+            }
+
+            const KIMAP::Acl::Rights parentImapRights = rights.value(parentMailbox);
+            // kDebug() << mailbox << parentMailbox << imapRights << parentImapRights;
+
+            Akonadi::Collection &collection = mMailCollections[mailbox];
+            CollectionMetadataHelper::applyRights(collection, imapRights, parentImapRights);
+
+            // Store the mailbox ACLs
+            Akonadi::ImapAclAttribute *aclAttribute = collection.attribute<Akonadi::ImapAclAttribute>( Akonadi::Collection::AddIfMissing );
+            const KIMAP::Acl::Rights oldRights = aclAttribute->myRights();
+            if ( oldRights != imapRights ) {
+                aclAttribute->setMyRights( imapRights );
+            }
+        } else {
+            kWarning() << "Can't find mailbox " << mailbox;
+        }
+    }
+}
+
+void KolabRetrieveCollectionsTask::applyMetadata(QHash<QString, QMap<QByteArray, QByteArray> > metadataMap)
+{
+    kDebug() << metadataMap;
+    Q_FOREACH(const QString &mailbox, metadataMap.keys()) {
+        const QMap<QByteArray, QByteArray> metadata  = metadataMap.value(mailbox);
+        if (mMailCollections.contains(mailbox)) {
+            Akonadi::Collection &collection = mMailCollections[mailbox];
+            kDebug() << "setting metadata: " << mailbox << metadata;
+            collection.attribute<Akonadi::CollectionAnnotationsAttribute>(Akonadi::Collection::AddIfMissing)->setAnnotations(metadata);
+        }
+    }
+}
+
+void KolabRetrieveCollectionsTask::onMetadataRetrieved(KJob *job)
+{
+    kDebug();
+    mJobs--;
+    if (job->error()) {
+        kWarning() << job->errorString();
+        cancelTask(job->errorString());
+    } else {
+        RetrieveMetadataJob *metadata = static_cast<RetrieveMetadataJob*>(job);
+        applyRights(metadata->mRights);
+        applyMetadata(metadata->mMetadata);
         checkDone();
     }
 }
diff --git a/resources/kolab/kolabretrievecollectionstask.h b/resources/kolab/kolabretrievecollectionstask.h
index a8e421d..6e568f4 100644
--- a/resources/kolab/kolabretrievecollectionstask.h
+++ b/resources/kolab/kolabretrievecollectionstask.h
@@ -43,7 +43,7 @@ private slots:
     void onMailBoxesReceiveDone(KJob *job);
     void onFullMailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList<QList<QByteArray> > &flags);
     void onFullMailBoxesReceiveDone(KJob *job);
-    void onGetMetaDataDone(KJob *job);
+    void onMetadataRetrieved(KJob *job);
 
 protected:
     virtual void doStart(KIMAP::Session *session);
@@ -52,14 +52,40 @@ private:
     void checkDone();
     Akonadi::Collection getOrCreateParent(const QString &parentPath);
     void createCollection(const QString &mailbox, const QList<QByteArray> &flags, bool isSubscribed);
-    bool isNamespaceFolder(const QStringList &pathParts, const QList<KIMAP::MailBoxDescriptor> &namespaces);
+    bool isNamespaceFolder(const QString &path, const QList<KIMAP::MailBoxDescriptor> &namespaces) const;
     void setAttributes(Akonadi::Collection &c, const QStringList &pathParts, const QString &path);
+    void applyRights(QHash<QString, KIMAP::Acl::Rights> rights);
+    void applyMetadata(QHash<QString, QMap<QByteArray, QByteArray> > metadata);
 
     int mJobs;
     QHash<QString, Akonadi::Collection> mMailCollections;
     QSet<QString> mSubscribedMailboxes;
     QSet<QByteArray> mRequestedMetadata;
+    KIMAP::Session *mSession;
+};
+
+class RetrieveMetadataJob : public KJob
+{
+    Q_OBJECT
+public:
+    RetrieveMetadataJob(KIMAP::Session *session, const QStringList &mailboxes, const QStringList &serverCapabilities, const QSet<QByteArray> &requestedMetadata, const QString &separator, QObject *parent = 0);
+    void start();
+
     QHash<QString, QMap<QByteArray, QByteArray> > mMetadata;
+    QHash<QString, KIMAP::Acl::Rights> mRights;
+
+private:
+    void checkDone();
+    int mJobs;
+    QSet<QByteArray> mRequestedMetadata;
+    QStringList mServerCapabilities;
+    QStringList mMailboxes;
+    KIMAP::Session *mSession;
+    QString mSeparator;
+
+private Q_SLOTS:
+    void onGetMetaDataDone(KJob *job);
+    void onRightsReceived(KJob *job);
 };
 
 #endif


commit 5fc16d5564d7a14a37bd6d17abae5a64e5b771c7
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Fri Aug 8 10:47:29 2014 +0200

    IMAP-Resource: Print warnings

diff --git a/resources/imap/addcollectiontask.cpp b/resources/imap/addcollectiontask.cpp
index 7e8e8e9..7e86450 100644
--- a/resources/imap/addcollectiontask.cpp
+++ b/resources/imap/addcollectiontask.cpp
@@ -45,6 +45,7 @@ AddCollectionTask::~AddCollectionTask()
 void AddCollectionTask::doStart( KIMAP::Session *session )
 {
   if ( parentCollection().remoteId().isEmpty() ) {
+    kWarning() << "Parent collection has no remote id, aborting." << collection().name() << parentCollection().name();
     emitError( i18n( "Cannot add IMAP folder '%1' for a non-existing parent folder '%2'.",
                     collection().name(),
                     parentCollection().name() ) );
@@ -81,6 +82,7 @@ void AddCollectionTask::doStart( KIMAP::Session *session )
 void AddCollectionTask::onCreateDone( KJob *job )
 {
   if ( job->error() ) {
+    kWarning() << "Failed to create folder on server: " << job->errorString();
     emitError( i18n( "Failed to create the folder '%1' on the IMAP server. ",
                       m_collection.name() ) );
     cancelTask( job->errorString() );
@@ -101,6 +103,7 @@ void AddCollectionTask::onCreateDone( KJob *job )
 void AddCollectionTask::onSubscribeDone( KJob *job )
 {
   if ( job->error() && isSubscriptionEnabled() ) {
+    kWarning() << "Failed to subscribe to the new folder: " << job->errorString();
     emitWarning( i18n( "Failed to subscribe to the folder '%1' on the IMAP server. "
                        "It will disappear on next sync. Use the subscription dialog to overcome that",
                        m_collection.name() ) );
@@ -144,6 +147,7 @@ void AddCollectionTask::onSubscribeDone( KJob *job )
 void AddCollectionTask::onSetMetaDataDone( KJob *job )
 {
   if ( job->error() ) {
+    kWarning() << "Failed to write annotations: " << job->errorString();
     emitWarning( i18n( "Failed to write some annotations for '%1' on the IMAP server. %2",
                        collection().name(), job->errorText() ) );
   }


commit 119557bc05c42f319833c307877fc887a4011062
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Wed Aug 6 16:47:22 2014 +0200

    Kolab-Resource: Fetch folder-type annotation directly during collection sync.

diff --git a/resources/kolab/kolabresourcestate.cpp b/resources/kolab/kolabresourcestate.cpp
index 00f0a46..60b0478 100644
--- a/resources/kolab/kolabresourcestate.cpp
+++ b/resources/kolab/kolabresourcestate.cpp
@@ -36,14 +36,10 @@ KolabResourceState::KolabResourceState(ImapResource* resource, const TaskArgumen
 
 }
 
-void KolabResourceState::collectionAttributesRetrieved(const Akonadi::Collection& collection)
+static Akonadi::Collection processAnnotations(const Akonadi::Collection &collection)
 {
-    if (!collection.isValid() && collection.remoteId().isEmpty()) {
-        ResourceState::collectionAttributesRetrieved(collection);
-        return;
-    }
-    Akonadi::Collection col = collection;
-    if (col.attribute<Akonadi::CollectionAnnotationsAttribute>()) {
+    if (collection.attribute<Akonadi::CollectionAnnotationsAttribute>()) {
+        Akonadi::Collection col = collection;
         const QMap<QByteArray, QByteArray> rawAnnotations = col.attribute<Akonadi::CollectionAnnotationsAttribute>()->annotations();
         const QByteArray type = KolabHelpers::getFolderTypeAnnotation(rawAnnotations);
         const Kolab::FolderType folderType = KolabHelpers::folderTypeFromString(type);
@@ -72,10 +68,30 @@ void KolabResourceState::collectionAttributesRetrieved(const Akonadi::Collection
             //If we don't handle the folder, make sure we don't download the messages
             col.attribute<NoSelectAttribute>(Akonadi::Entity::AddIfMissing);
         }
+        return col;
     }
+    return collection;
+}
+
+void KolabResourceState::collectionAttributesRetrieved(const Akonadi::Collection& collection)
+{
+    if (!collection.isValid() && collection.remoteId().isEmpty()) {
+        ResourceState::collectionAttributesRetrieved(collection);
+        return;
+    }
+    const Akonadi::Collection col = processAnnotations(collection);
     ResourceState::collectionAttributesRetrieved(col);
 }
 
+void KolabResourceState::collectionsRetrieved(const Akonadi::Collection::List &collections)
+{
+    Akonadi::Collection::List modifiedCollections;
+    Q_FOREACH (const Akonadi::Collection &col, collections) {
+        modifiedCollections << processAnnotations(col);
+    }
+    ResourceState::collectionsRetrieved(modifiedCollections);
+}
+
 MessageHelper::Ptr KolabResourceState::messageHelper() const
 {
     return MessageHelper::Ptr(new KolabMessageHelper(collection()));
diff --git a/resources/kolab/kolabresourcestate.h b/resources/kolab/kolabresourcestate.h
index 2d37f29..501c46d 100644
--- a/resources/kolab/kolabresourcestate.h
+++ b/resources/kolab/kolabresourcestate.h
@@ -31,6 +31,7 @@ public:
 
 private:
     virtual void collectionAttributesRetrieved(const Akonadi::Collection& collection);
+    virtual void collectionsRetrieved(const Akonadi::Collection::List &collections);
     virtual MessageHelper::Ptr messageHelper() const;
 };
 
diff --git a/resources/kolab/kolabretrievecollectionstask.cpp b/resources/kolab/kolabretrievecollectionstask.cpp
index e0ae1c6..4be0268 100644
--- a/resources/kolab/kolabretrievecollectionstask.cpp
+++ b/resources/kolab/kolabretrievecollectionstask.cpp
@@ -26,6 +26,7 @@
 #include <noselectattribute.h>
 #include <noinferiorsattribute.h>
 #include <collectionannotationsattribute.h>
+#include <kimap/getmetadatajob.h>
 
 #include <akonadi/cachepolicy.h>
 #include <akonadi/entitydisplayattribute.h>
@@ -41,7 +42,8 @@ KolabRetrieveCollectionsTask::KolabRetrieveCollectionsTask(ResourceStateInterfac
     : ResourceTask(CancelIfNoSession, resource, parent),
     mJobs(0)
 {
-
+    mRequestedMetadata << "/shared/vendor/kolab/folder-type";
+    mRequestedMetadata << "/private/vendor/kolab/folder-type";
 }
 
 KolabRetrieveCollectionsTask::~KolabRetrieveCollectionsTask()
@@ -95,6 +97,23 @@ void KolabRetrieveCollectionsTask::doStart(KIMAP::Session *session)
         fullListJob->start();
     }
 
+    if ( resourceState()->serverCapabilities().contains( QLatin1String("METADATA") ) || resourceState()->serverCapabilities().contains( QLatin1String("ANNOTATEMORE") ) ) {
+        //TODO perhaps exclude the shared and other users namespaces by listing only toplevel (with %), and then only getting metadata of the toplevel folders.
+        KIMAP::GetMetaDataJob *meta = new KIMAP::GetMetaDataJob(session);
+        meta->setMailBox(QLatin1String("*"));
+        if ( resourceState()->serverCapabilities().contains( QLatin1String("METADATA") ) ) {
+            meta->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
+        } else {
+            meta->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
+        }
+        meta->setDepth( KIMAP::GetMetaDataJob::AllLevels );
+        Q_FOREACH (const QByteArray &requestedEntry, mRequestedMetadata) {
+            meta->addRequestedEntry(requestedEntry);
+        }
+        connect( meta, SIGNAL(result(KJob*)), SLOT(onGetMetaDataDone(KJob*)) );
+        meta->start();
+    }
+
     KIMAP::ListJob *listJob = new KIMAP::ListJob(session);
     listJob->setOption(KIMAP::ListJob::IncludeUnsubscribed);
     listJob->setQueriedNamespaces(serverNamespaces());
@@ -105,6 +124,17 @@ void KolabRetrieveCollectionsTask::doStart(KIMAP::Session *session)
     listJob->start();
 }
 
+void KolabRetrieveCollectionsTask::onGetMetaDataDone( KJob *job )
+{
+    if ( job->error() ) {
+            kWarning() << "Get metadata failed: " << job->errorString();
+            return;
+    }
+
+    KIMAP::GetMetaDataJob *meta = qobject_cast<KIMAP::GetMetaDataJob*>( job );
+    mMetadata = meta->allMetaDataForMailboxes();
+}
+
 void KolabRetrieveCollectionsTask::onMailBoxesReceived(const QList< KIMAP::MailBoxDescriptor > &descriptors,
                                                    const QList< QList<QByteArray> > &flags)
 {
@@ -183,6 +213,11 @@ void KolabRetrieveCollectionsTask::setAttributes(Akonadi::Collection &c, const Q
         attr->setCollectionNamespace("shared");
     }
 
+    const QMap<QByteArray, QByteArray> metadata = mMetadata.value(path);
+    if (!metadata.isEmpty()) {
+        c.attribute<Akonadi::CollectionAnnotationsAttribute>(Akonadi::Collection::AddIfMissing)->setAnnotations(metadata);
+    }
+
 }
 
 void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, const QList<QByteArray> &currentFlags, bool isSubscribed)
diff --git a/resources/kolab/kolabretrievecollectionstask.h b/resources/kolab/kolabretrievecollectionstask.h
index 5c7d26a..a8e421d 100644
--- a/resources/kolab/kolabretrievecollectionstask.h
+++ b/resources/kolab/kolabretrievecollectionstask.h
@@ -43,6 +43,7 @@ private slots:
     void onMailBoxesReceiveDone(KJob *job);
     void onFullMailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList<QList<QByteArray> > &flags);
     void onFullMailBoxesReceiveDone(KJob *job);
+    void onGetMetaDataDone(KJob *job);
 
 protected:
     virtual void doStart(KIMAP::Session *session);
@@ -57,6 +58,8 @@ private:
     int mJobs;
     QHash<QString, Akonadi::Collection> mMailCollections;
     QSet<QString> mSubscribedMailboxes;
+    QSet<QByteArray> mRequestedMetadata;
+    QHash<QString, QMap<QByteArray, QByteArray> > mMetadata;
 };
 
 #endif


commit 76bd4dcd11d22c5698983397de4fb91930f02579
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Tue Aug 5 22:50:19 2014 +0200

    IMAP-Resource: Avoid crashing on killSession
    
    This is a workaround for BUG xxxx. I don't know why, but this seems to prevent
    the occasional crash that occurs on QObject::disconnect, seemingly due to
    an invalid session pointer. Since the assert isn't triggered either with that
    code it could be a race condition.

diff --git a/resources/imap/sessionpool.cpp b/resources/imap/sessionpool.cpp
index d4ac710..8208599 100644
--- a/resources/imap/sessionpool.cpp
+++ b/resources/imap/sessionpool.cpp
@@ -194,6 +194,11 @@ QList<KIMAP::MailBoxDescriptor> SessionPool::serverNamespaces(Namespace ns) cons
 
 void SessionPool::killSession( KIMAP::Session *session, SessionTermination termination )
 {
+  if (!m_unusedPool.contains(session) && !m_reservedPool.contains(session) && !m_connectingPool.contains(session)) {
+    kWarning() << "Unmanaged session" << session;
+    Q_ASSERT(false);
+    return;
+  }
   QObject::disconnect( session, SIGNAL(stateChanged(KIMAP::Session::State,KIMAP::Session::State)),
                        this, SLOT(onSessionStateChanged(KIMAP::Session::State,KIMAP::Session::State)) );
   m_unusedPool.removeAll( session );


commit ebae2a61959fa15536b6188a82b7f256e6d4bc87
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Thu May 8 15:58:02 2014 +0200

    Use MyRights instead of the full acl.

diff --git a/resources/imap/resourcetask.cpp b/resources/imap/resourcetask.cpp
index 2f76423..d887cae 100644
--- a/resources/imap/resourcetask.cpp
+++ b/resources/imap/resourcetask.cpp
@@ -26,6 +26,7 @@
 #include <KDE/KLocale>
 
 #include "collectionflagsattribute.h"
+#include <imapaclattribute.h>
 #include "imapflags.h"
 #include "sessionpool.h"
 #include "resourcestateinterface.h"
@@ -500,3 +501,18 @@ ResourceStateInterface::Ptr ResourceTask::resourceState()
 {
     return m_resource;
 }
+
+KIMAP::Acl::Rights ResourceTask::myRights(const Akonadi::Collection &col)
+{
+    Akonadi::ImapAclAttribute *aclAttribute = col.attribute<Akonadi::ImapAclAttribute>();
+    if (aclAttribute) {
+        //HACK, only return myrights if they are available
+        if (aclAttribute->myRights() != KIMAP::Acl::None) {
+            return aclAttribute->myRights();
+        } else {
+            //This should be removed after 4.14, and myrights should be always used.
+            return aclAttribute->rights().value(userName().toUtf8());
+        }
+    }
+    return KIMAP::Acl::None;
+}
diff --git a/resources/imap/resourcetask.h b/resources/imap/resourcetask.h
index 2b09bcb..72280c8 100644
--- a/resources/imap/resourcetask.h
+++ b/resources/imap/resourcetask.h
@@ -28,6 +28,7 @@
 #include <Akonadi/Item>
 
 #include <kimap/listjob.h>
+#include <kimap/acl.h>
 
 #include "resourcestateinterface.h"
 
@@ -140,6 +141,8 @@ protected:
 
   ResourceStateInterface::Ptr resourceState();
 
+  KIMAP::Acl::Rights myRights(const Akonadi::Collection &);
+
 private:
 
   static QList<QByteArray> fromAkonadiFlags( const QList<QByteArray> &flags );
diff --git a/resources/imap/retrievecollectionmetadatatask.cpp b/resources/imap/retrievecollectionmetadatatask.cpp
index 355bfb8..27c666a 100644
--- a/resources/imap/retrievecollectionmetadatatask.cpp
+++ b/resources/imap/retrievecollectionmetadatatask.cpp
@@ -63,6 +63,7 @@ void RetrieveCollectionMetadataTask::doStart( KIMAP::Session *session )
     }
   }
 
+  m_session = session;
   m_collection = collection();
   const QString mailBox = mailBoxForCollection( m_collection );
   const QStringList capabilities = serverCapabilities();
@@ -88,12 +89,6 @@ void RetrieveCollectionMetadataTask::doStart( KIMAP::Session *session )
 
   // Get the ACLs from the mailbox if it's supported
   if ( capabilities.contains( QLatin1String("ACL") ) ) {
-    KIMAP::GetAclJob *acl = new KIMAP::GetAclJob( session );
-    acl->setMailBox( mailBox );
-    connect( acl, SIGNAL(result(KJob*)), SLOT(onGetAclDone(KJob*)) );
-    m_pendingMetaDataJobs++;
-    acl->start();
-
     KIMAP::MyRightsJob *rights = new KIMAP::MyRightsJob( session );
     rights->setMailBox( mailBox );
     connect( rights, SIGNAL(result(KJob*)), SLOT(onRightsReceived(KJob*)) );
@@ -186,7 +181,7 @@ void RetrieveCollectionMetadataTask::onRightsReceived( KJob *job )
     parentRights = parentAclAttribute->rights()[userName().toUtf8()];
   }
 
-  KIMAP::Acl::Rights imapRights = rightsJob->rights();
+  const KIMAP::Acl::Rights imapRights = rightsJob->rights();
   Akonadi::Collection::Rights newRights = Akonadi::Collection::ReadOnly;
 
   // For renaming, the parent folder needs to have the CreateMailbox or Create permission.
@@ -243,6 +238,15 @@ void RetrieveCollectionMetadataTask::onRightsReceived( KJob *job )
     m_collection.setRights( newRights );
   }
 
+  //The a right is required to list acl's
+  if ( imapRights & KIMAP::Acl::Admin ) {
+    KIMAP::GetAclJob *acl = new KIMAP::GetAclJob( m_session );
+    acl->setMailBox( mailBoxForCollection( m_collection ) );
+    connect( acl, SIGNAL(result(KJob*)), SLOT(onGetAclDone(KJob*)) );
+    m_pendingMetaDataJobs++;
+    acl->start();
+  }
+
   endTaskIfNeeded();
 }
 
diff --git a/resources/imap/retrievecollectionmetadatatask.h b/resources/imap/retrievecollectionmetadatatask.h
index 53eebfe..a093436 100644
--- a/resources/imap/retrievecollectionmetadatatask.h
+++ b/resources/imap/retrievecollectionmetadatatask.h
@@ -47,6 +47,7 @@ private:
   int m_pendingMetaDataJobs;
 
   Akonadi::Collection m_collection;
+  KIMAP::Session *m_session;
 };
 
 #endif
diff --git a/resources/imap/retrieveitemstask.cpp b/resources/imap/retrieveitemstask.cpp
index c345ad6..a90fc18 100644
--- a/resources/imap/retrieveitemstask.cpp
+++ b/resources/imap/retrieveitemstask.cpp
@@ -46,6 +46,7 @@
 #include <kimap/selectjob.h>
 #include <kimap/session.h>
 #include <kimap/searchjob.h>
+#include <kimap/acl.h>
 
 RetrieveItemsTask::RetrieveItemsTask(ResourceStateInterface::Ptr resource, QObject *parent)
     : ResourceTask(CancelIfNoSession, resource, parent),
@@ -146,7 +147,7 @@ void RetrieveItemsTask::startRetrievalTasks()
 
     // Now is the right time to expunge the messages marked \\Deleted from this mailbox.
     // We assume that we can only expunge if we can delete items (correct would be to check for "e" ACL right).
-    if (isAutomaticExpungeEnabled() && (collection().rights() & Akonadi::Collection::CanDeleteItem)) {
+    if (isAutomaticExpungeEnabled() && (!serverCapabilities().contains(QLatin1String("ACL")) || (myRights(collection()) & KIMAP::Acl::Expunge))) {
         if (m_session->selectedMailBox() != mailBox) {
             triggerPreExpungeSelect(mailBox);
         } else {
diff --git a/resources/shared/imapaclattribute.cpp b/resources/shared/imapaclattribute.cpp
index ad4fe2c..cd64f14 100644
--- a/resources/shared/imapaclattribute.cpp
+++ b/resources/shared/imapaclattribute.cpp
@@ -49,6 +49,16 @@ QMap<QByteArray, KIMAP::Acl::Rights> ImapAclAttribute::oldRights() const
   return mOldRights;
 }
 
+void ImapAclAttribute::setMyRights(KIMAP::Acl::Rights rights)
+{
+  mMyRights = rights;
+}
+
+KIMAP::Acl::Rights ImapAclAttribute::myRights() const
+{
+  return mMyRights;
+}
+
 QByteArray ImapAclAttribute::type() const
 {
   return "imapacl";
@@ -56,7 +66,9 @@ QByteArray ImapAclAttribute::type() const
 
 Akonadi::Attribute* ImapAclAttribute::clone() const
 {
-  return new ImapAclAttribute( mRights, mOldRights );
+  ImapAclAttribute *attr = new ImapAclAttribute( mRights, mOldRights );
+  attr->setMyRights( mMyRights );
+  return attr;
 }
 
 QByteArray ImapAclAttribute::serialized() const
@@ -89,6 +101,9 @@ QByteArray ImapAclAttribute::serialized() const
   if ( added )
     result.chop( 3 );
 
+  result+= " %% ";
+  result+= KIMAP::Acl::rightsToString( mMyRights );
+
   return result;
 }
 
@@ -114,12 +129,23 @@ void ImapAclAttribute::deserialize( const QByteArray &data )
 {
   mRights.clear();
   mOldRights.clear();
-  const int pos = data.indexOf( " %% " );
-  if ( pos == -1 )
-    return;
-
-  const QByteArray leftPart = data.left( pos );
-  const QByteArray rightPart = data.mid( pos + 4 );
-  fillRightsMap( leftPart.split( '%' ), mRights );
-  fillRightsMap( rightPart.split( '%' ), mOldRights );
+  mMyRights = KIMAP::Acl::None;
+
+  QList<QByteArray> parts;
+  int lastPos = 0;
+  int pos;
+  while ((pos = data.indexOf( " %% ", lastPos )) != -1) {
+      parts << data.mid(lastPos, pos-lastPos);
+      lastPos = pos + 4;
+  }
+  parts << data.right(lastPos + 4);
+
+  if (parts.size() < 2) {
+      return;
+  }
+  fillRightsMap( parts.at(0).split( '%' ), mRights );
+  fillRightsMap( parts.at(1).split( '%' ), mOldRights );
+  if (parts.size() >= 3) {
+    mMyRights = KIMAP::Acl::rightsFromString(parts.at(2));
+  }
 }
diff --git a/resources/shared/imapaclattribute.h b/resources/shared/imapaclattribute.h
index 8e4b83c..1c6fbcc 100644
--- a/resources/shared/imapaclattribute.h
+++ b/resources/shared/imapaclattribute.h
@@ -37,6 +37,8 @@ class ImapAclAttribute : public Akonadi::Attribute
     void setRights( const QMap<QByteArray, KIMAP::Acl::Rights> &rights );
     QMap<QByteArray, KIMAP::Acl::Rights> rights() const;
     QMap<QByteArray, KIMAP::Acl::Rights> oldRights() const;
+    void setMyRights( KIMAP::Acl::Rights rights );
+    KIMAP::Acl::Rights myRights() const;
     virtual QByteArray type() const;
     virtual Attribute *clone() const;
     virtual QByteArray serialized() const;
@@ -45,6 +47,7 @@ class ImapAclAttribute : public Akonadi::Attribute
   private:
     QMap<QByteArray, KIMAP::Acl::Rights> mRights;
     QMap<QByteArray, KIMAP::Acl::Rights> mOldRights;
+    KIMAP::Acl::Rights mMyRights;
 };
 
 }
diff --git a/resources/shared/tests/imapaclattributetest.cpp b/resources/shared/tests/imapaclattributetest.cpp
index 7e65a6f..838360e 100644
--- a/resources/shared/tests/imapaclattributetest.cpp
+++ b/resources/shared/tests/imapaclattributetest.cpp
@@ -32,6 +32,36 @@ class ImapAclAttributeTest : public QObject
   Q_OBJECT
 
   private Q_SLOTS:
+    void testDeserialize_data()
+    {
+      QTest::addColumn<ImapAcl>( "rights" );
+      QTest::addColumn<QByteArray>( "serialized" );
+
+      ImapAcl acl;
+      QTest::newRow( "empty" ) << acl << QByteArray( " %% " );
+
+      acl.insert( "user at host", KIMAP::Acl::None );
+      QTest::newRow( "none" ) << acl << QByteArray( "user at host  %% " );
+
+      acl.insert( "user at host", KIMAP::Acl::Lookup );
+      QTest::newRow( "lookup" ) << acl << QByteArray( "user at host l %% " );
+
+      acl.insert( "user at host", KIMAP::Acl::Lookup | KIMAP::Acl::Read );
+      QTest::newRow( "lookup/read" ) << acl << QByteArray( "user at host lr %% " );
+
+      acl.insert( "otheruser at host", KIMAP::Acl::Lookup | KIMAP::Acl::Read );
+      QTest::newRow( "lookup/read" ) << acl << QByteArray( "otheruser at host lr % user at host lr %% " );
+    }
+
+    void testDeserialize()
+    {
+      QFETCH( ImapAcl, rights );
+      QFETCH( QByteArray, serialized );
+
+      ImapAclAttribute deserializeAttr;
+      deserializeAttr.deserialize( serialized );
+      QCOMPARE( deserializeAttr.rights(), rights );
+    }
 
     void testSerializeDeserialize_data()
     {
@@ -40,20 +70,20 @@ class ImapAclAttributeTest : public QObject
       QTest::addColumn<QByteArray>( "oldSerialized" );
 
       ImapAcl acl;
-      QTest::newRow( "empty" ) << acl << QByteArray( " %% " ) << QByteArray( "testme at host l %% " );
+      QTest::newRow( "empty" ) << acl << QByteArray( " %%  %% " ) << QByteArray( "testme at host l %%  %% " );
 
       acl.insert( "user at host", KIMAP::Acl::None );
-      QTest::newRow( "none" ) << acl << QByteArray( "user at host  %% " ) << QByteArray( "testme at host l %% user at host " );
+      QTest::newRow( "none" ) << acl << QByteArray( "user at host  %%  %% " ) << QByteArray( "testme at host l %% user at host  %% " );
 
       acl.insert( "user at host", KIMAP::Acl::Lookup );
-      QTest::newRow( "lookup" ) << acl << QByteArray( "user at host l %% " ) << QByteArray( "testme at host l %% user at host l" );
+      QTest::newRow( "lookup" ) << acl << QByteArray( "user at host l %%  %% " ) << QByteArray( "testme at host l %% user at host l %% " );
 
       acl.insert( "user at host", KIMAP::Acl::Lookup | KIMAP::Acl::Read );
-      QTest::newRow( "lookup/read" ) << acl << QByteArray( "user at host lr %% " ) << QByteArray( "testme at host l %% user at host lr" );
+      QTest::newRow( "lookup/read" ) << acl << QByteArray( "user at host lr %%  %% " ) << QByteArray( "testme at host l %% user at host lr %% " );
 
       acl.insert( "otheruser at host", KIMAP::Acl::Lookup | KIMAP::Acl::Read );
-      QTest::newRow( "lookup/read" ) << acl << QByteArray( "otheruser at host lr % user at host lr %% " )
-                                     << QByteArray( "testme at host l %% otheruser at host lr % user at host lr" );
+      QTest::newRow( "lookup/read" ) << acl << QByteArray( "otheruser at host lr % user at host lr %%  %% " )
+                                     << QByteArray( "testme at host l %% otheruser at host lr % user at host lr %% " );
     }
 
     void testSerializeDeserialize()


commit 82480fcca7dcd1c6e481943efb8f9d4a1585461a
Author: Montel Laurent <montel at kde.org>
Date:   Mon Aug 4 13:03:35 2014 +0200

    Fix "server side subscription"

diff --git a/resources/imap/imapresourcebase.h b/resources/imap/imapresourcebase.h
index ae3187d..4f07a44 100644
--- a/resources/imap/imapresourcebase.h
+++ b/resources/imap/imapresourcebase.h
@@ -49,10 +49,10 @@ class Settings;
 
 class ImapResourceBase : public Akonadi::ResourceBase,
                          public Akonadi::AgentBase::ObserverV3,
-                         public Akonadi::AgentSearchInterface
+                        public Akonadi::AgentSearchInterface
 {
   Q_OBJECT
-
+  Q_CLASSINFO("D-Bus Interface", "org.kde.Akonadi.ImapResourceBase")
 protected:
   using Akonadi::AgentBase::Observer::collectionChanged;
 


commit 60664f002f1de3f28b6421f3ea9788e118f434d0
Author: Montel Laurent <montel at kde.org>
Date:   Mon Aug 4 09:45:00 2014 +0200

    Fix i18n

diff --git a/resources/maildir/libmaildir/maildir.cpp b/resources/maildir/libmaildir/maildir.cpp
index 36166ed..9ad4a66 100644
--- a/resources/maildir/libmaildir/maildir.cpp
+++ b/resources/maildir/libmaildir/maildir.cpp
@@ -476,13 +476,13 @@ QByteArray Maildir::readEntry( const QString& key ) const
     if ( realKey.isEmpty() ) {
         // FIXME error handling?
         qWarning() << "Maildir::readEntry unable to find: " << key;
-        d->lastError = i18n( "Cannot locate mail file %1." ).arg( key );
+        d->lastError = i18n( "Cannot locate mail file %1." ,key );
         return result;
     }
 
     QFile f( realKey );
     if ( !f.open( QIODevice::ReadOnly ) ) {
-      d->lastError = i18n( "Cannot open mail file %1." ).arg( realKey );
+      d->lastError = i18n( "Cannot open mail file %1.", realKey );
       return result;
     }
 
@@ -497,13 +497,13 @@ qint64 Maildir::size( const QString& key ) const
     if ( realKey.isEmpty() ) {
         // FIXME error handling?
         qWarning() << "Maildir::size unable to find: " << key;
-        d->lastError = i18n( "Cannot locate mail file %1." ).arg( key );
+        d->lastError = i18n( "Cannot locate mail file %1." , key );
         return -1;
     }
 
     QFileInfo info( realKey );
     if ( !info.exists() ) {
-        d->lastError = i18n( "Cannot open mail file %1." ).arg( realKey );
+        d->lastError = i18n( "Cannot open mail file %1." ,realKey );
         return -1;
     }
 
@@ -515,7 +515,7 @@ QDateTime Maildir::lastModified(const QString& key) const
     const QString realKey( d->findRealKey( key ) );
     if ( realKey.isEmpty() ) {
         qWarning() << "Maildir::lastModified unable to find: " << key;
-        d->lastError = i18n( "Cannot locate mail file %1." ).arg( key );
+        d->lastError = i18n( "Cannot locate mail file %1." , key );
         return QDateTime();
     }
 
@@ -534,7 +534,7 @@ QByteArray Maildir::readEntryHeadersFromFile( const QString& file ) const
     if ( !f.open( QIODevice::ReadOnly ) ) {
         // FIXME error handling?
         qWarning() << "Maildir::readEntryHeaders unable to find: " << file;
-        d->lastError = i18n( "Cannot locate mail file %1." ).arg( file );
+        d->lastError = i18n( "Cannot locate mail file %1." , file );
         return result;
     }
     f.map( 0, qMin( (qint64)8000, f.size() ) );
@@ -552,7 +552,7 @@ QByteArray Maildir::readEntryHeaders( const QString& key ) const
     const QString realKey( d->findRealKey( key ) );
     if ( realKey.isEmpty() ) {
         qWarning() << "Maildir::readEntryHeaders unable to find: " << key;
-        d->lastError = i18n( "Cannot locate mail file %1." ).arg( key );
+        d->lastError = i18n( "Cannot locate mail file %1." , key );
         return QByteArray();
     }
 
@@ -577,7 +577,7 @@ bool Maildir::writeEntry( const QString& key, const QByteArray& data )
     if ( realKey.isEmpty() ) {
         // FIXME error handling?
         qWarning() << "Maildir::writeEntry unable to find: " << key;
-        d->lastError = i18n( "Cannot locate mail file %1." ).arg( key );
+        d->lastError = i18n( "Cannot locate mail file %1." ,key );
         return false;
     }
     QFile f( realKey );
@@ -585,7 +585,7 @@ bool Maildir::writeEntry( const QString& key, const QByteArray& data )
     result = result & ( f.write( data ) != -1 );
     f.close();
     if ( !result) {
-       d->lastError = i18n( "Cannot write to mail file %1." ).arg( realKey );
+       d->lastError = i18n( "Cannot write to mail file %1." ,realKey );
        return false;
     }
     return true;
@@ -612,7 +612,7 @@ QString Maildir::addEntry( const QByteArray& data )
     result = result & ( f.write( data ) != -1 );
     f.close();
     if ( !result) {
-       d->lastError = i18n( "Cannot write to mail file %1." ).arg( key );
+       d->lastError = i18n( "Cannot write to mail file %1." , key );
        return QString();
     }
     /*
@@ -626,7 +626,7 @@ QString Maildir::addEntry( const QByteArray& data )
      */
     if ( !f.rename( finalKey ) ) {
         qWarning() << "Maildir: Failed to add entry: " << finalKey  << "! Error: " << f.errorString();
-        d->lastError = i18n( "Failed to create mail file %1. The error was: %2" ).arg( finalKey, f.errorString() );
+        d->lastError = i18n( "Failed to create mail file %1. The error was: %2" , finalKey, f.errorString() );
         return QString();
     }
     KeyCache *keyCache = KeyCache::self();
@@ -652,7 +652,7 @@ QString Maildir::changeEntryFlags(const QString& key, const Akonadi::Item::Flags
     QString realKey( d->findRealKey( key ) );
     if ( realKey.isEmpty() ) {
         qWarning() << "Maildir::changeEntryFlags unable to find: " << key;
-        d->lastError = i18n( "Cannot locate mail file %1." ).arg( key );
+        d->lastError = i18n( "Cannot locate mail file %1." , key );
         return QString();
     }
 
@@ -718,7 +718,7 @@ QString Maildir::changeEntryFlags(const QString& key, const Akonadi::Item::Flags
 
     if ( !f.rename( finalKey ) ) {
         qWarning() << "Maildir: Failed to rename entry: " << f.fileName() << " to "  << finalKey  << "! Error: " << f.errorString();
-        d->lastError = i18n( "Failed to update the file name %1 to %2 on the disk. The error was: %3." ).arg( f.fileName(), finalKey, f.errorString() );
+        d->lastError = i18n( "Failed to update the file name %1 to %2 on the disk. The error was: %3." , f.fileName(), finalKey, f.errorString() );
         return QString();
      }
 
@@ -794,7 +794,7 @@ QString Maildir::moveEntryTo( const QString &key, const Maildir &destination )
   const QString realKey( d->findRealKey( key ) );
   if ( realKey.isEmpty() ) {
     kWarning() << "Unable to find: " << key;
-    d->lastError = i18n( "Cannot locate mail file %1." ).arg( key );
+    d->lastError = i18n( "Cannot locate mail file %1." , key );
     return QString();
   }
   QFile f( realKey );


commit 63188a4dbc1215602561cb2ffd3c6a142cdd595e
Author: Montel Laurent <montel at kde.org>
Date:   Mon Aug 4 08:53:00 2014 +0200

    Revert "Fix kcm desktop file"
    
    This reverts commit 7cc4163078d598c8a307babaf8fd965d1f12b094.

diff --git a/kcm/kcm_akonadi.desktop b/kcm/kcm_akonadi.desktop
index edc83f4..7549a52 100644
--- a/kcm/kcm_akonadi.desktop
+++ b/kcm/kcm_akonadi.desktop
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Exec=kcmshell5 kcm_akonadi
+Exec=kcmshell4 kcm_akonadi
 Icon=akonadi
 Type=Service
 ServiceTypes=KCModule
diff --git a/kcm/kcm_akonadi_resources.desktop b/kcm/kcm_akonadi_resources.desktop
index 174a9b2..a5d8c8a 100644
--- a/kcm/kcm_akonadi_resources.desktop
+++ b/kcm/kcm_akonadi_resources.desktop
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Exec=kcmshell5 kcm_akonadi_resources
+Exec=kcmshell4 kcm_akonadi_resources
 Icon=akonadi
 Type=Service
 ServiceTypes=KCModule
diff --git a/kcm/kcm_akonadi_server.desktop b/kcm/kcm_akonadi_server.desktop
index caa6f16..796eec0 100644
--- a/kcm/kcm_akonadi_server.desktop
+++ b/kcm/kcm_akonadi_server.desktop
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Exec=kcmshell5 kcm_akonadi_server
+Exec=kcmshell4 kcm_akonadi_server
 Icon=akonadi
 Type=Service
 ServiceTypes=KCModule


commit cee880c09a916425a074477a867f37b777893133
Author: Montel Laurent <montel at kde.org>
Date:   Mon Aug 4 07:43:07 2014 +0200

    Fix kcm desktop file

diff --git a/kcm/kcm_akonadi.desktop b/kcm/kcm_akonadi.desktop
index 7549a52..edc83f4 100644
--- a/kcm/kcm_akonadi.desktop
+++ b/kcm/kcm_akonadi.desktop
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Exec=kcmshell4 kcm_akonadi
+Exec=kcmshell5 kcm_akonadi
 Icon=akonadi
 Type=Service
 ServiceTypes=KCModule
diff --git a/kcm/kcm_akonadi_resources.desktop b/kcm/kcm_akonadi_resources.desktop
index a5d8c8a..174a9b2 100644
--- a/kcm/kcm_akonadi_resources.desktop
+++ b/kcm/kcm_akonadi_resources.desktop
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Exec=kcmshell4 kcm_akonadi_resources
+Exec=kcmshell5 kcm_akonadi_resources
 Icon=akonadi
 Type=Service
 ServiceTypes=KCModule
diff --git a/kcm/kcm_akonadi_server.desktop b/kcm/kcm_akonadi_server.desktop
index 796eec0..caa6f16 100644
--- a/kcm/kcm_akonadi_server.desktop
+++ b/kcm/kcm_akonadi_server.desktop
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Exec=kcmshell4 kcm_akonadi_server
+Exec=kcmshell5 kcm_akonadi_server
 Icon=akonadi
 Type=Service
 ServiceTypes=KCModule


commit 6225c17988a70e6530408f327e8e22e1ee022495
Author: Montel Laurent <montel at kde.org>
Date:   Mon Aug 4 07:37:51 2014 +0200

    It needs akonadi

diff --git a/kcm/configmodule.cpp b/kcm/configmodule.cpp
index 2f94139..6cc4062 100644
--- a/kcm/configmodule.cpp
+++ b/kcm/configmodule.cpp
@@ -25,6 +25,7 @@
 #include <kpluginfactory.h>
 #include <kpluginloader.h>
 #include <qboxlayout.h>
+#include <akonadi/control.h>
 
 K_PLUGIN_FACTORY( ResourcesConfigFactory, registerPlugin<ConfigModule>(); )
 K_EXPORT_PLUGIN( ResourcesConfigFactory( "imaplib" ) )
@@ -34,7 +35,7 @@ ConfigModule::ConfigModule( QWidget * parent, const QVariantList & args ) :
 {
     KGlobal::locale()->insertCatalog( QLatin1String("kcm_akonadi") );
     KGlobal::locale()->insertCatalog( QLatin1String("libakonadi") );
-
+    Akonadi::Control::widgetNeedsAkonadi(this);
     setButtons( KCModule::Default | KCModule::Apply );
     QVBoxLayout *l = new QVBoxLayout( this );
     l->setMargin( 0 );


commit 63ef30e88dd0badb33efeb769b0760c4c430f996
Author: Sandro Knauß <mail at sandroknauss.de>
Date:   Wed Jul 2 20:20:25 2014 +0200

    compile ispdb as own binary.
    
    REVIEW: 119479

diff --git a/accountwizard/CMakeLists.txt b/accountwizard/CMakeLists.txt
index 7802aa0..1478ca0 100644
--- a/accountwizard/CMakeLists.txt
+++ b/accountwizard/CMakeLists.txt
@@ -69,3 +69,4 @@ install(FILES accountwizard-mime.xml DESTINATION ${XDG_MIME_INSTALL_DIR})
 update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR})
 
 add_subdirectory(wizards)
+add_subdirectory(ispdb)
\ No newline at end of file
diff --git a/accountwizard/ispdb/ispdb.cpp b/accountwizard/ispdb/ispdb.cpp
index ddc1664..7667259 100644
--- a/accountwizard/ispdb/ispdb.cpp
+++ b/accountwizard/ispdb/ispdb.cpp
@@ -163,24 +163,6 @@ void Ispdb::slotResult( KJob* job )
         n = n.nextSibling();
     }
 
-    // comment this section out when you are tired of it...
-    kDebug() << "------------------ summary --------------";
-    kDebug() << "Domains" << mDomains;
-    kDebug() << "Name" << mDisplayName << "(" << mDisplayShortName << ")";
-    kDebug() << "Imap servers:";
-    foreach ( const server& s, mImapServers ) {
-        kDebug() << s.hostname << s.port << s.socketType << s.username << s.authentication;
-    }
-    kDebug() << "pop3 servers:";
-    foreach ( const server& s, mPop3Servers ) {
-        kDebug() << s.hostname << s.port << s.socketType << s.username << s.authentication;
-    }
-    kDebug() << "smtp servers:";
-    foreach ( const server& s, mSmtpServers ) {
-        kDebug() << s.hostname << s.port << s.socketType << s.username << s.authentication;
-    }
-    // end section.
-
     emit finished( true );
 }
 
diff --git a/accountwizard/ispdb/main.cpp b/accountwizard/ispdb/main.cpp
index 0f76d7d..e1ed9a1 100644
--- a/accountwizard/ispdb/main.cpp
+++ b/accountwizard/ispdb/main.cpp
@@ -24,6 +24,44 @@
 #include <kcmdlineargs.h>
 #include <kglobal.h>
 
+#include <KDebug>
+
+QString socketTypeToStr( Ispdb::socketType socketType )
+{
+    QString enc = QLatin1String("None");
+    if ( socketType == Ispdb::SSL ) {
+        enc = QLatin1String("SSL");
+    } else if ( socketType == Ispdb::StartTLS ) {
+        enc = QLatin1String("TLS");
+    }
+    return enc;
+}
+
+QString authTypeToStr( Ispdb::authType authType )
+{
+    QString auth = QLatin1String("unknown");
+    switch ( authType ) {
+      case Ispdb::Plain:
+        auth = QLatin1String("plain");
+        break;
+      case Ispdb::CramMD5:
+        auth = QLatin1String("CramMD5");
+        break;
+      case Ispdb::NTLM:
+        auth = QLatin1String("NTLM");
+        break;
+      case Ispdb::GSSAPI:
+        auth = QLatin1String("GSSAPI");
+        break;
+      case Ispdb::ClientIP:
+        auth = QLatin1String("ClientIP");
+        break;
+      case Ispdb::NoAuth:
+        auth = QLatin1String("NoAuth");
+        break;
+    }
+    return auth;
+}
 int main( int argc, char **argv )
 {
     KAboutData aboutData( "ispdb", 0,
@@ -34,7 +72,7 @@ int main( int argc, char **argv )
                           ki18n( "(c) 2010 Omat Holding B.V." ),
                           KLocalizedString(),
                           "http://pim.kde.org/akonadi/" );
-    aboutData.setProgramIconName( "akonadi" );
+    aboutData.setProgramIconName( QLatin1String("akonadi") );
     aboutData.addAuthor( ki18n( "Tom Albers" ),  ki18n( "Author" ), "toma at kde.org" );
 
     KCmdLineArgs::init( argc, argv, &aboutData );
@@ -43,19 +81,48 @@ int main( int argc, char **argv )
     KCmdLineArgs::addCmdLineOptions( options );
     KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
 
-    QString email;
-    if ( !args->getOption( "email" ).isEmpty() )
+    QString email( QLatin1String("blablabla at gmail.com") );
+    if ( !args->getOption( "email" ).isEmpty() ) {
         email = args->getOption( "email" );
-    else
-        email = "blablabla at gmail.com";
-
+    }
 
     KApplication app;
 
+    QEventLoop loop;
     Ispdb ispdb;
     ispdb.setEmail( email );
+
+    loop.connect( &ispdb, SIGNAL(finished(bool)), SLOT(quit()) );
+
     ispdb.start();
 
-    return app.exec();
+    loop.exec();
+    kDebug() << "Domains" << ispdb.relevantDomains();
+    kDebug() << "Name" << ispdb.name( Ispdb::Long ) << "(" << ispdb.name( Ispdb::Short ) << ")";
+    kDebug() << "Imap servers:";
+    foreach ( const server &s, ispdb.imapServers() ) {
+        kDebug() << "\thostname:" << s.hostname
+                 << "- port:" << s.port
+                 << "- encryption:" << socketTypeToStr(s.socketType)
+                 << "- username:" << s.username
+                 << "- authentication:" << authTypeToStr(s.authentication);
+    }
+    kDebug() << "pop3 servers:";
+    foreach ( const server &s, ispdb.pop3Servers() ) {
+        kDebug() << "\thostname:" << s.hostname
+                 << "- port:" << s.port
+                 << "- encryption:" << socketTypeToStr(s.socketType)
+                 << "- username:" << s.username
+                 << "- authentication:" << authTypeToStr(s.authentication);
+    }
+    kDebug() << "smtp servers:";
+    foreach ( const server &s, ispdb.smtpServers() ) {
+        kDebug() << "\thostname:" << s.hostname
+                 << "- port:" << s.port
+                 << "- encryption:" << socketTypeToStr(s.socketType)
+                 << "- username:" << s.username
+                 << "- authentication:" << authTypeToStr(s.authentication);
+    }
 
+    return true;
 }


commit eb02b757acb4c6564e71d6752d0aa21b0e65bc10
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Wed Jul 23 16:51:17 2014 +0200

    Kolab-Resource: Set CollectionIdentificationAttribute based on namespace.
    
    This also fixes the identification of shared folders.

diff --git a/resources/kolab/kolabretrievecollectionstask.cpp b/resources/kolab/kolabretrievecollectionstask.cpp
index a3e2cd3..e0ae1c6 100644
--- a/resources/kolab/kolabretrievecollectionstask.cpp
+++ b/resources/kolab/kolabretrievecollectionstask.cpp
@@ -30,6 +30,7 @@
 #include <akonadi/cachepolicy.h>
 #include <akonadi/entitydisplayattribute.h>
 #include <akonadi/kmime/messageparts.h>
+#include <akonadi/collectionidentificationattribute.h>
 
 #include <kmime/kmime_message.h>
 
@@ -134,10 +135,56 @@ Akonadi::Collection KolabRetrieveCollectionsTask::getOrCreateParent(const QStrin
     c.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType());
     c.setRights(Akonadi::Collection::ReadOnly);
     c.setEnabled(false);
+    setAttributes(c, pathParts, path);
+
     mMailCollections.insert(path, c);
     return c;
 }
 
+bool KolabRetrieveCollectionsTask::isNamespaceFolder(const QStringList &pathParts, const QList<KIMAP::MailBoxDescriptor> &namespaces)
+{
+    Q_FOREACH (const KIMAP::MailBoxDescriptor &desc, namespaces) {
+        if (desc.name.contains(pathParts.first())) { //Namespace ends with path separator and pathPart doesn't
+            return true;
+        }
+    }
+    return false;
+}
+
+void KolabRetrieveCollectionsTask::setAttributes(Akonadi::Collection &c, const QStringList &pathParts, const QString &path)
+{
+
+    CollectionIdentificationAttribute *attr = c.attribute<CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing);
+    attr->setIdentifier(path.toLatin1());
+
+    // If the folder is a other users top-level folder mark it accordingly
+    if (pathParts.size() == 1 && isNamespaceFolder(pathParts, resourceState()->userNamespaces())) {
+        Akonadi::EntityDisplayAttribute *attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
+        attr->setDisplayName(i18n("Other Users"));
+        attr->setIconName(QLatin1String("x-mail-distribution-list"));
+    }
+
+    //Mark user folders for searching
+    if (pathParts.size() == 2 && isNamespaceFolder(pathParts, resourceState()->userNamespaces())) {
+        CollectionIdentificationAttribute *attr = c.attribute<CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing);
+        attr->setCollectionNamespace("user");
+    }
+
+    // If the folder is a shared folders top-level folder mark it accordingly
+    if (pathParts.size() == 1 && isNamespaceFolder(pathParts, resourceState()->sharedNamespaces())) {
+        Akonadi::EntityDisplayAttribute *attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
+        attr->setDisplayName(i18n("Shared Folders"));
+        attr->setIconName(QLatin1String("x-mail-distribution-list"));
+    }
+
+    //Mark shared folders for searching
+    if (pathParts.size() >= 2 && isNamespaceFolder(pathParts, resourceState()->sharedNamespaces())) {
+        CollectionIdentificationAttribute *attr = c.attribute<CollectionIdentificationAttribute>(Akonadi::Collection::AddIfMissing);
+        attr->setCollectionNamespace("shared");
+    }
+
+}
+
 void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, const QList<QByteArray> &currentFlags, bool isSubscribed)
 {
     const QString separator = separatorCharacter();
@@ -161,6 +208,7 @@ void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, cons
     //TODO get from ResourceState, and add KMime::Message::mimeType() for the normal imap resource by default
     //We add a dummy mimetype, otherwise the itemsync doesn't even work (action is disabled and resourcebase aborts the operation)
     c.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QLatin1String("application/x-kolab-objects"));
+
     //assume LRS, until myrights is executed
     if (serverCapabilities().contains(QLatin1String("ACL"))) {
         c.setRights(Akonadi::Collection::ReadOnly);
@@ -168,6 +216,8 @@ void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, cons
         c.setRights(Akonadi::Collection::AllRights);
     }
 
+    setAttributes(c, pathParts, mailbox);
+
     // If the folder is the Inbox, make some special settings.
     if (pathParts.size() == 1 && pathPart.compare(QLatin1String("inbox") , Qt::CaseInsensitive) == 0) {
         Akonadi::EntityDisplayAttribute *attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
@@ -176,13 +226,6 @@ void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, cons
         setIdleCollection(c);
     }
 
-    // If the folder is the user top-level folder, mark it as well, although it is not officially noted in the RFC
-    if (pathParts.size() == 1 && pathPart == QLatin1String("user") && currentFlags.contains("\\noselect")) {
-        Akonadi::EntityDisplayAttribute *attr = c.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
-        attr->setDisplayName(i18n("Shared Folders"));
-        attr->setIconName(QLatin1String("x-mail-distribution-list"));
-    }
-
     // If this folder is a noselect folder, make some special settings.
     if (currentFlags.contains("\\noselect")) {
         c.addAttribute(new NoSelectAttribute(true));
diff --git a/resources/kolab/kolabretrievecollectionstask.h b/resources/kolab/kolabretrievecollectionstask.h
index 2db1fcb..5c7d26a 100644
--- a/resources/kolab/kolabretrievecollectionstask.h
+++ b/resources/kolab/kolabretrievecollectionstask.h
@@ -51,6 +51,8 @@ private:
     void checkDone();
     Akonadi::Collection getOrCreateParent(const QString &parentPath);
     void createCollection(const QString &mailbox, const QList<QByteArray> &flags, bool isSubscribed);
+    bool isNamespaceFolder(const QStringList &pathParts, const QList<KIMAP::MailBoxDescriptor> &namespaces);
+    void setAttributes(Akonadi::Collection &c, const QStringList &pathParts, const QString &path);
 
     int mJobs;
     QHash<QString, Akonadi::Collection> mMailCollections;


commit 5b639a73827c6ae3f2251d172e8eac45e3ef359b
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Wed Jul 23 16:50:08 2014 +0200

    IMAP-Resource: Made retrieved namespaces available in resourcestate

diff --git a/resources/imap/resourcestate.cpp b/resources/imap/resourcestate.cpp
index e718768..90083b0 100644
--- a/resources/imap/resourcestate.cpp
+++ b/resources/imap/resourcestate.cpp
@@ -63,6 +63,21 @@ QList<KIMAP::MailBoxDescriptor> ResourceState::serverNamespaces() const
   return m_resource->m_pool->serverNamespaces();
 }
 
+QList<KIMAP::MailBoxDescriptor> ResourceState::personalNamespaces() const
+{
+    return m_resource->m_pool->serverNamespaces(SessionPool::Personal);
+}
+
+QList<KIMAP::MailBoxDescriptor> ResourceState::userNamespaces() const
+{
+    return m_resource->m_pool->serverNamespaces(SessionPool::User);
+}
+
+QList<KIMAP::MailBoxDescriptor> ResourceState::sharedNamespaces() const
+{
+    return m_resource->m_pool->serverNamespaces(SessionPool::Shared);
+}
+
 bool ResourceState::isAutomaticExpungeEnabled() const
 {
   return m_resource->settings()->automaticExpungeEnabled();
diff --git a/resources/imap/resourcestate.h b/resources/imap/resourcestate.h
index 4a61a11..f6026bb 100644
--- a/resources/imap/resourcestate.h
+++ b/resources/imap/resourcestate.h
@@ -61,6 +61,9 @@ public:
   virtual QString resourceName() const;
   virtual QStringList serverCapabilities() const;
   virtual QList<KIMAP::MailBoxDescriptor> serverNamespaces() const;
+  virtual QList<KIMAP::MailBoxDescriptor> personalNamespaces() const;
+  virtual QList<KIMAP::MailBoxDescriptor> userNamespaces() const;
+  virtual QList<KIMAP::MailBoxDescriptor> sharedNamespaces() const;
 
   virtual bool isAutomaticExpungeEnabled() const;
   virtual bool isSubscriptionEnabled() const;
diff --git a/resources/imap/resourcestateinterface.h b/resources/imap/resourcestateinterface.h
index 704038e..d61af67 100644
--- a/resources/imap/resourcestateinterface.h
+++ b/resources/imap/resourcestateinterface.h
@@ -43,6 +43,9 @@ public:
   virtual QString resourceName() const = 0;
   virtual QStringList serverCapabilities() const = 0;
   virtual QList<KIMAP::MailBoxDescriptor> serverNamespaces() const = 0;
+  virtual QList<KIMAP::MailBoxDescriptor> personalNamespaces() const = 0;
+  virtual QList<KIMAP::MailBoxDescriptor> userNamespaces() const = 0;
+  virtual QList<KIMAP::MailBoxDescriptor> sharedNamespaces() const = 0;
 
   virtual bool isAutomaticExpungeEnabled() const = 0;
   virtual bool isSubscriptionEnabled() const = 0;
diff --git a/resources/imap/sessionpool.cpp b/resources/imap/sessionpool.cpp
index c94069b..d4ac710 100644
--- a/resources/imap/sessionpool.cpp
+++ b/resources/imap/sessionpool.cpp
@@ -176,6 +176,22 @@ QList<KIMAP::MailBoxDescriptor> SessionPool::serverNamespaces() const
   return m_namespaces;
 }
 
+QList<KIMAP::MailBoxDescriptor> SessionPool::serverNamespaces(Namespace ns) const
+{
+    switch(ns) {
+        case Personal:
+            return m_personalNamespaces;
+        case User:
+            return m_userNamespaces;
+        case Shared:
+            return m_sharedNamespaces;
+        default:
+            break;
+    }
+    Q_ASSERT(false);
+    return QList<KIMAP::MailBoxDescriptor>();
+}
+
 void SessionPool::killSession( KIMAP::Session *session, SessionTermination termination )
 {
   QObject::disconnect( session, SIGNAL(stateChanged(KIMAP::Session::State,KIMAP::Session::State)),
@@ -443,6 +459,9 @@ void SessionPool::onCapabilitiesTestDone( KJob *job )
 void SessionPool::onNamespacesTestDone( KJob *job )
 {
   KIMAP::NamespaceJob *nsJob = qobject_cast<KIMAP::NamespaceJob*>( job );
+  m_personalNamespaces = nsJob->personalNamespaces();
+  m_userNamespaces = nsJob->userNamespaces();
+  m_sharedNamespaces = nsJob->sharedNamespaces();
 
   if ( nsJob->containsEmptyNamespace() ) {
     // When we got the empty namespace here, we assume that the other
diff --git a/resources/imap/sessionpool.h b/resources/imap/sessionpool.h
index 1959644..2af60b6 100644
--- a/resources/imap/sessionpool.h
+++ b/resources/imap/sessionpool.h
@@ -81,6 +81,12 @@ public:
   ImapAccount *account() const;
   QStringList serverCapabilities() const;
   QList<KIMAP::MailBoxDescriptor> serverNamespaces() const;
+  enum Namespace {
+      Personal,
+      User,
+      Shared
+  };
+  QList<KIMAP::MailBoxDescriptor> serverNamespaces(Namespace) const;
 
 signals:
   void connectionLost( KIMAP::Session *session );
@@ -123,6 +129,9 @@ private:
 
   QStringList m_capabilities;
   QList<KIMAP::MailBoxDescriptor> m_namespaces;
+  QList<KIMAP::MailBoxDescriptor> m_personalNamespaces;
+  QList<KIMAP::MailBoxDescriptor> m_userNamespaces;
+  QList<KIMAP::MailBoxDescriptor> m_sharedNamespaces;
 };
 
 #endif
diff --git a/resources/imap/tests/dummyresourcestate.cpp b/resources/imap/tests/dummyresourcestate.cpp
index b6d6e73..12a656a 100644
--- a/resources/imap/tests/dummyresourcestate.cpp
+++ b/resources/imap/tests/dummyresourcestate.cpp
@@ -77,6 +77,21 @@ QList<KIMAP::MailBoxDescriptor> DummyResourceState::serverNamespaces() const
   return m_namespaces;
 }
 
+QList<KIMAP::MailBoxDescriptor> DummyResourceState::personalNamespaces() const
+{
+  return QList<KIMAP::MailBoxDescriptor>();
+}
+
+QList<KIMAP::MailBoxDescriptor> DummyResourceState::userNamespaces() const
+{
+  return QList<KIMAP::MailBoxDescriptor>();
+}
+
+QList<KIMAP::MailBoxDescriptor> DummyResourceState::sharedNamespaces() const
+{
+  return QList<KIMAP::MailBoxDescriptor>();
+}
+
 void DummyResourceState::setAutomaticExpungeEnagled( bool enabled )
 {
   m_automaticExpunge = enabled;
diff --git a/resources/imap/tests/dummyresourcestate.h b/resources/imap/tests/dummyresourcestate.h
index 9e77a74..c12f8d5 100644
--- a/resources/imap/tests/dummyresourcestate.h
+++ b/resources/imap/tests/dummyresourcestate.h
@@ -46,6 +46,9 @@ public:
 
   void setServerNamespaces( const QList<KIMAP::MailBoxDescriptor> &namespaces );
   virtual QList<KIMAP::MailBoxDescriptor> serverNamespaces() const;
+  virtual QList<KIMAP::MailBoxDescriptor> personalNamespaces() const;
+  virtual QList<KIMAP::MailBoxDescriptor> userNamespaces() const;
+  virtual QList<KIMAP::MailBoxDescriptor> sharedNamespaces() const;
 
   void setAutomaticExpungeEnagled( bool enabled );
   virtual bool isAutomaticExpungeEnabled() const;


commit 671d2b7d70b20375a830b111d97fae4b47ec6310
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Wed Jul 23 17:33:56 2014 +0200

    Kolab-Resource: Synchronize enabled state with subscriptions.
    
    Instead of only getting the subscribed folders, we get all folders and
    set the enabled state based on the subscription state.

diff --git a/resources/kolab/kolabresource.cpp b/resources/kolab/kolabresource.cpp
index 18cfb55..a5e051a 100644
--- a/resources/kolab/kolabresource.cpp
+++ b/resources/kolab/kolabresource.cpp
@@ -24,6 +24,7 @@
 #include <timestampattribute.h>
 #include <retrieveitemstask.h>
 #include <collectionannotationsattribute.h>
+#include <changecollectiontask.h>
 
 #include <KLocalizedString>
 #include <Akonadi/CollectionFetchJob>
@@ -174,7 +175,10 @@ void KolabResource::collectionChanged(const Akonadi::Collection& collection, con
     //Update annotations if necessary
     const Akonadi::Collection col = updateAnnotations(collection);
     //TODO we need to save the collections as well if the annotations have changed
-    ImapResource::collectionChanged(col, parts);
+    emit status( AgentBase::Running, i18nc( "@info:status", "Updating folder '%1'", collection.name() ) );
+    ChangeCollectionTask *task = new ChangeCollectionTask( createResourceState(TaskArguments(collection, parts)), this );
+    task->syncEnabledState(true);
+    startTask(task);
 }
 
 AKONADI_RESOURCE_MAIN( KolabResource )
diff --git a/resources/kolab/kolabretrievecollectionstask.cpp b/resources/kolab/kolabretrievecollectionstask.cpp
index 5594b8f..a3e2cd3 100644
--- a/resources/kolab/kolabretrievecollectionstask.cpp
+++ b/resources/kolab/kolabretrievecollectionstask.cpp
@@ -109,14 +109,7 @@ void KolabRetrieveCollectionsTask::onMailBoxesReceived(const QList< KIMAP::MailB
 {
     for (int i=0; i<descriptors.size(); ++i) {
         const KIMAP::MailBoxDescriptor descriptor = descriptors[i];
-
-        //TODO Get all folders anyways, but locally unsubscribe from the ones we're not subscribed to online?
-        if (isSubscriptionEnabled() && !mSubscribedMailboxes.contains(descriptor.name)) {
-            // not subscribed, skipping
-            continue;
-        }
-
-        createCollection(descriptor.name, flags.at(i));
+        createCollection(descriptor.name, flags.at(i), !isSubscriptionEnabled() || mSubscribedMailboxes.contains(descriptor.name));
     }
     checkDone();
 }
@@ -140,11 +133,12 @@ Akonadi::Collection KolabRetrieveCollectionsTask::getOrCreateParent(const QStrin
     c.addAttribute(new NoSelectAttribute(true));
     c.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType());
     c.setRights(Akonadi::Collection::ReadOnly);
+    c.setEnabled(false);
     mMailCollections.insert(path, c);
     return c;
 }
 
-void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, const QList<QByteArray> &currentFlags)
+void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, const QList<QByteArray> &currentFlags, bool isSubscribed)
 {
     const QString separator = separatorCharacter();
     Q_ASSERT(separator.size() == 1);
@@ -205,6 +199,7 @@ void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, cons
         c.addAttribute(new NoInferiorsAttribute(true));
         c.setRights(c.rights() & ~Akonadi::Collection::CanCreateCollection);
     }
+    c.setEnabled(isSubscribed);
 
     kDebug() << "creating collection " << mailbox << " with parent " << parentPath;
     mMailCollections.insert(mailbox, c);
diff --git a/resources/kolab/kolabretrievecollectionstask.h b/resources/kolab/kolabretrievecollectionstask.h
index 3e9a14d..2db1fcb 100644
--- a/resources/kolab/kolabretrievecollectionstask.h
+++ b/resources/kolab/kolabretrievecollectionstask.h
@@ -50,7 +50,7 @@ protected:
 private:
     void checkDone();
     Akonadi::Collection getOrCreateParent(const QString &parentPath);
-    void createCollection(const QString &mailbox, const QList<QByteArray> &flags);
+    void createCollection(const QString &mailbox, const QList<QByteArray> &flags, bool isSubscribed);
 
     int mJobs;
     QHash<QString, Akonadi::Collection> mMailCollections;


commit c8104ef1a2e1dcce7a9df526841d1864c2540468
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Wed Jul 23 17:33:04 2014 +0200

    IMAP-Resource: Support setting subscription state based on enabled state.

diff --git a/resources/imap/changecollectiontask.cpp b/resources/imap/changecollectiontask.cpp
index 4372020..f43af47 100644
--- a/resources/imap/changecollectiontask.cpp
+++ b/resources/imap/changecollectiontask.cpp
@@ -26,6 +26,7 @@
 #include <kimap/setmetadatajob.h>
 #include <kimap/session.h>
 #include <kimap/subscribejob.h>
+#include <kimap/unsubscribejob.h>
 
 #include "collectionannotationsattribute.h"
 #include "imapaclattribute.h"
@@ -42,6 +43,11 @@ ChangeCollectionTask::~ChangeCollectionTask()
 {
 }
 
+void ChangeCollectionTask::syncEnabledState( bool enable )
+{
+    m_syncEnabledState = enable;
+}
+
 void ChangeCollectionTask::doStart( KIMAP::Session *session )
 {
   if ( collection().remoteId().isEmpty() ) {
@@ -222,6 +228,23 @@ void ChangeCollectionTask::doStart( KIMAP::Session *session )
     }
   }
 
+  if ( m_syncEnabledState && isSubscriptionEnabled() && parts().contains( "ENABLED" ) ) {
+    if ( collection().enabled() ) {
+        KIMAP::SubscribeJob *job = new KIMAP::SubscribeJob( session );
+        job->setMailBox( mailBoxForCollection( collection() ) );
+        connect( job, SIGNAL(result(KJob*)),
+                this, SLOT(onSubscribeDone(KJob*)) );
+        job->start();
+    } else {
+        KIMAP::UnsubscribeJob *job = new KIMAP::UnsubscribeJob( session );
+        job->setMailBox( mailBoxForCollection( collection() ) );
+        connect( job, SIGNAL(result(KJob*)),
+                this, SLOT(onSubscribeDone(KJob*)) );
+        job->start();
+    }
+    m_pendingJobs++;
+  }
+
   // we scheduled no change on the server side, probably we got only
   // unsupported part, so just declare the task done
   if ( m_pendingJobs == 0 ) {
diff --git a/resources/imap/changecollectiontask.h b/resources/imap/changecollectiontask.h
index 923590b..8222d22 100644
--- a/resources/imap/changecollectiontask.h
+++ b/resources/imap/changecollectiontask.h
@@ -32,6 +32,8 @@ public:
   explicit ChangeCollectionTask( ResourceStateInterface::Ptr resource, QObject *parent = 0 );
   virtual ~ChangeCollectionTask();
 
+  void syncEnabledState(bool);
+
 private slots:
   void onRenameDone( KJob *job );
   void onSubscribeDone( KJob *job );
@@ -46,6 +48,7 @@ private:
 
   int m_pendingJobs;
   Akonadi::Collection m_collection;
+  bool m_syncEnabledState;
 };
 
 #endif


commit ac0cd32671bd7b6056ac09ef88bae1d419b90b51
Author: Martin Koller <kollix at aon.at>
Date:   Mon Jul 21 15:31:35 2014 +0200

    make manual update work (reading the mbox file)
    
    When you have an mbox resource WITHOUT file watching, a "check mail" or
    "update folder" does NOTHING as MboxResource::retrieveItems() does
    not call reloadFile(). This patch does that.
    FIXED-IN: 4.14
    REVIEW: 116987

diff --git a/resources/mbox/mboxresource.cpp b/resources/mbox/mboxresource.cpp
index 36aef8b..3496f57 100644
--- a/resources/mbox/mboxresource.cpp
+++ b/resources/mbox/mboxresource.cpp
@@ -98,6 +98,8 @@ void MboxResource::retrieveItems( const Akonadi::Collection &col )
     return;
   }
 
+  reloadFile();
+
   KMBox::MBoxEntry::List entryList;
   if ( col.hasAttribute<DeletedItemsAttribute>() ) {
     DeletedItemsAttribute *attr = col.attribute<DeletedItemsAttribute>();


commit 2832f704f9a145bca4683cd94180c6a7d996064a
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Sun Aug 10 18:43:48 2014 +0200

    Gmail resource: fix resource not being able to authenticate
    
    This was caused by IMAP resource parts and Gmail resource parts using
    different instance of Settings, which caused mess in configuration.
    
    BUG: 336758
    FIXED-IN: 4.13.90
    
    Conflicts:
    	resources/imap/settings.h
    
    Conflicts:
    	resources/gmail/CMakeLists.txt
    	resources/gmail/gmailconfigdialog.cpp
    	resources/gmail/gmaillinkitemstask.cpp
    	resources/gmail/gmaillinkitemstask.h
    	resources/gmail/gmailpasswordrequester.cpp
    	resources/gmail/gmailpasswordrequester.h
    	resources/gmail/gmailresource.cpp
    	resources/gmail/gmailresource.h
    	resources/gmail/gmailsettings.cpp
    	resources/gmail/gmailsettings.h

diff --git a/resources/imap/settings.h b/resources/imap/settings.h
index 61c6683..31d17f9 100644
--- a/resources/imap/settings.h
+++ b/resources/imap/settings.h
@@ -39,32 +39,33 @@ public:
     explicit Settings( WId = 0 );
     void setWinId( WId );
 
-    void requestPassword();
-    void requestManualAuth();
+    virtual void requestPassword();
+    virtual void requestManualAuth();
 
-    void loadAccount( ImapAccount *account ) const;
+    virtual void loadAccount( ImapAccount *account ) const;
 
     QString rootRemoteId() const;
-    void renameRootCollection( const QString &newName );
+    virtual void renameRootCollection( const QString &newName );
 
-    void clearCachedPassword();
+    virtual void clearCachedPassword();
+    virtual void cleanup();
 
 signals:
     void passwordRequestCompleted( const QString &password, bool userRejected );
 
 public slots:
-    Q_SCRIPTABLE QString password( bool *userRejected = 0 ) const;
-    Q_SCRIPTABLE void setPassword( const QString &password );
-    Q_SCRIPTABLE void setSieveCustomPassword(const QString & password);
-    Q_SCRIPTABLE QString sieveCustomPassword( bool *userRejected = 0 ) const;
+    Q_SCRIPTABLE virtual QString password( bool *userRejected = 0 ) const;
+    Q_SCRIPTABLE virtual void setPassword( const QString &password );
+    Q_SCRIPTABLE virtual void setSieveCustomPassword(const QString & password);
+    Q_SCRIPTABLE virtual QString sieveCustomPassword( bool *userRejected = 0 ) const;
 
-private slots:
-    void onWalletOpened( bool success );
-    void onDialogFinished( int result );
+protected slots:
+    virtual void onWalletOpened( bool success );
+    virtual void onDialogFinished( int result );
 
     void onRootCollectionFetched( KJob *job );
 
-private:
+protected:
     WId m_winId;
     mutable QString m_password;
     mutable QString m_customSievePassword;


commit 7ac8cd804669520249d71c6d52c8090a298a5eba
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Wed Jul 16 13:46:22 2014 +0200

    IMAP Resource: let an instance of Settings be owned by ImapResource instead of being a singleton
    
    This makes it possible for IMAP Resource subclasses to override the
    Settings.
    
    REVIEW: 119298

diff --git a/resources/imap/imapresource.cpp b/resources/imap/imapresource.cpp
index 779f713..c388a1f 100644
--- a/resources/imap/imapresource.cpp
+++ b/resources/imap/imapresource.cpp
@@ -66,7 +66,7 @@ void ImapResource::onConfigurationDone(int result)
     if ( dlg->shouldClearCache() ) {
       clearCache();
     }
-    Settings::self()->writeConfig();
+    settings()->writeConfig();
   }
   dlg->deleteLater();
 }
diff --git a/resources/imap/imapresourcebase.cpp b/resources/imap/imapresourcebase.cpp
index fabe7e6..62d5031 100644
--- a/resources/imap/imapresourcebase.cpp
+++ b/resources/imap/imapresourcebase.cpp
@@ -97,7 +97,8 @@ ImapResourceBase::ImapResourceBase( const QString &id )
   : ResourceBase( id ),
     m_pool( new SessionPool( 2, this ) ),
     mSubscriptions( 0 ),
-    m_idle( 0 )
+    m_idle( 0 ),
+    m_settings( 0 )
 {
   QTimer::singleShot( 0, this, SLOT(updateResourceName()) );
 
@@ -140,26 +141,33 @@ ImapResourceBase::ImapResourceBase( const QString &id )
 
   connect( this, SIGNAL(reloadConfiguration()), SLOT(reconnect()) );
 
-  Settings::self(); // make sure the D-Bus settings interface is up
+
+  m_statusMessageTimer = new QTimer( this );
+  m_statusMessageTimer->setSingleShot( true );
+  connect( m_statusMessageTimer, SIGNAL(timeout()), SLOT(clearStatusMessage()) );
+  connect( this, SIGNAL(error(QString)), SLOT(showError(QString)) );
+
+  QMetaObject::invokeMethod( this, "delayedInit", Qt::QueuedConnection );
+}
+
+void ImapResourceBase::delayedInit()
+{
+  settings(); // make sure the D-Bus settings interface is up
   new ImapResourceBaseAdaptor( this );
   setNeedsNetwork( needsNetwork() );
 
   // Migration issue: trash folder had ID in config, but didn't have SpecialCollections attribute, fix that.
-  if (!Settings::self()->trashCollectionMigrated()) {
-    const Akonadi::Collection::Id trashCollection = Settings::self()->trashCollection();
+  if (!settings()->trashCollectionMigrated()) {
+    const Akonadi::Collection::Id trashCollection = settings()->trashCollection();
     if (trashCollection != -1) {
       Collection attributeCollection(trashCollection);
       SpecialCollections::setSpecialCollectionType("trash", attributeCollection);
     }
-    Settings::self()->setTrashCollectionMigrated(true);
+    settings()->setTrashCollectionMigrated(true);
   }
-
-  m_statusMessageTimer = new QTimer( this );
-  m_statusMessageTimer->setSingleShot( true );
-  connect( m_statusMessageTimer, SIGNAL(timeout()), SLOT(clearStatusMessage()) );
-  connect( this, SIGNAL(error(QString)), SLOT(showError(QString)) );
 }
 
+
 ImapResourceBase::~ImapResourceBase()
 {
   //Destroy everything that could cause callbacks immediately, otherwise the callbacks can result in a crash.
@@ -175,6 +183,7 @@ ImapResourceBase::~ImapResourceBase()
   m_taskList.clear();
 
   delete m_pool;
+  delete m_settings;
 }
 
 void ImapResourceBase::aboutToQuit()
@@ -227,7 +236,7 @@ void ImapResourceBase::configure( WId windowId )
 
 void ImapResourceBase::startConnect( const QVariant& )
 {
-  if ( Settings::self()->imapServer().isEmpty() ) {
+  if ( settings()->imapServer().isEmpty() ) {
     setOnline( false );
     emit status( NotConfigured, i18n( "No server configured yet." ) );
     taskDone();
@@ -236,7 +245,7 @@ void ImapResourceBase::startConnect( const QVariant& )
 
   m_pool->disconnect(); // reset all state, delete any old account
   ImapAccount *account = new ImapAccount;
-  Settings::self()->loadAccount( account );
+  settings()->loadAccount( account );
 
   const bool result = m_pool->connect( account );
   Q_ASSERT( result );
@@ -250,7 +259,7 @@ int ImapResourceBase::configureSubscription(qlonglong windowId)
 
   if ( !m_pool->account() )
      return -2;
-  const QString password = Settings::self()->password();
+  const QString password = settings()->password();
   if ( password.isEmpty() )
      return -1;
 
@@ -265,11 +274,11 @@ int ImapResourceBase::configureSubscription(qlonglong windowId)
   mSubscriptions->setCaption( i18nc( "@title:window", "Serverside Subscription" ) );
   mSubscriptions->setWindowIcon( KIcon( QLatin1String("network-server") ) );
   mSubscriptions->connectAccount( *m_pool->account(), password );
-  mSubscriptions->setSubscriptionEnabled( Settings::self()->subscriptionEnabled() );
+  mSubscriptions->setSubscriptionEnabled( settings()->subscriptionEnabled() );
 
   if ( mSubscriptions->exec() ) {
-    Settings::self()->setSubscriptionEnabled( mSubscriptions->subscriptionEnabled() );
-    Settings::self()->writeConfig();
+    settings()->setSubscriptionEnabled( mSubscriptions->subscriptionEnabled() );
+    settings()->writeConfig();
     emit configurationDialogAccepted();
     reconnect();
   }
@@ -327,6 +336,16 @@ ResourceStateInterface::Ptr ImapResourceBase::createResourceState(const TaskArgu
   return ResourceStateInterface::Ptr(new ResourceState(this, args));
 }
 
+Settings *ImapResourceBase::settings() const
+{
+  if (m_settings == 0) {
+    m_settings = new Settings;
+  }
+
+  return m_settings;
+}
+
+
 // ----------------------------------------------------------------------------------
 
 bool ImapResourceBase::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
@@ -560,7 +579,7 @@ void ImapResourceBase::doSetOnline(bool online)
       delete m_idle;
       m_idle = 0;
     }
-    Settings::self()->clearCachedPassword();
+    settings()->clearCachedPassword();
   } else if ( online && !m_pool->isConnected() ) {
     scheduleConnectionAttempt();
   }
@@ -579,7 +598,7 @@ void ImapResourceBase::setSeparatorCharacter( const QChar &separator )
 
 bool ImapResourceBase::needsNetwork() const
 {
-  const QString hostName = Settings::self()->imapServer().section( QLatin1Char(':'), 0, 0 );
+  const QString hostName = settings()->imapServer().section( QLatin1Char(':'), 0, 0 );
   // ### is there a better way to do this?
   if ( hostName == QLatin1String( "127.0.0.1" ) ||
        hostName == QLatin1String( "localhost" ) ||
@@ -616,11 +635,11 @@ void ImapResourceBase::startIdle()
     return;
 
   //Without password we don't even have to try
-  if (Settings::self()->password().isEmpty()) {
+  if (settings()->password().isEmpty()) {
     return;
   }
 
-  const QStringList ridPath = Settings::self()->idleRidPath();
+  const QStringList ridPath = settings()->idleRidPath();
   if ( ridPath.size() < 2 )
     return;
 
@@ -666,7 +685,7 @@ void ImapResourceBase::onIdleCollectionFetchDone( KJob *job )
 
 void ImapResourceBase::requestManualExpunge( qint64 collectionId )
 {
-  if ( !Settings::self()->automaticExpungeEnabled() ) {
+  if ( !settings()->automaticExpungeEnabled() ) {
     Collection collection( collectionId );
 
     Akonadi::CollectionFetchScope scope;
@@ -748,7 +767,7 @@ QStringList ImapResourceBase::serverCapabilities() const
 
 void ImapResourceBase::cleanup()
 {
-    Settings::self()->cleanup();
+    settings()->cleanup();
 }
 
 QString ImapResourceBase::dumpResourceToString() const
diff --git a/resources/imap/imapresourcebase.h b/resources/imap/imapresourcebase.h
index bc80ec5..ae3187d 100644
--- a/resources/imap/imapresourcebase.h
+++ b/resources/imap/imapresourcebase.h
@@ -45,6 +45,7 @@ class ImapIdleManager;
 class SessionPool;
 class ResourceState;
 class SubscriptionDialog;
+class Settings;
 
 class ImapResourceBase : public Akonadi::ResourceBase,
                          public Akonadi::AgentBase::ObserverV3,
@@ -64,6 +65,8 @@ public:
   QStringList serverCapabilities() const;
   void cleanup();
 
+  virtual Settings* settings() const;
+
 public Q_SLOTS:
   virtual void configure( WId windowId );
 
@@ -144,6 +147,8 @@ private Q_SLOTS:
 
   void onCollectionModifyDone( KJob *job );
 
+  void delayedInit();
+
 protected:
   //Starts and queues a task
   void startTask( ResourceTask *task );
@@ -163,6 +168,7 @@ private:
   ImapIdleManager *m_idle;
   QTimer *m_statusMessageTimer;
   QChar m_separatorCharacter;
+  mutable Settings *m_settings;
 };
 
 #endif
diff --git a/resources/imap/resourcestate.cpp b/resources/imap/resourcestate.cpp
index ef1111a..e718768 100644
--- a/resources/imap/resourcestate.cpp
+++ b/resources/imap/resourcestate.cpp
@@ -65,23 +65,23 @@ QList<KIMAP::MailBoxDescriptor> ResourceState::serverNamespaces() const
 
 bool ResourceState::isAutomaticExpungeEnabled() const
 {
-  return Settings::self()->automaticExpungeEnabled();
+  return m_resource->settings()->automaticExpungeEnabled();
 }
 
 bool ResourceState::isSubscriptionEnabled() const
 {
-  return Settings::self()->subscriptionEnabled();
+  return m_resource->settings()->subscriptionEnabled();
 }
 
 bool ResourceState::isDisconnectedModeEnabled() const
 {
-  return Settings::self()->disconnectedModeEnabled();
+  return m_resource->settings()->disconnectedModeEnabled();
 }
 
 int ResourceState::intervalCheckTime() const
 {
-  if ( Settings::self()->intervalCheckEnabled() )
-    return Settings::self()->intervalCheckTime();
+  if ( m_resource->settings()->intervalCheckEnabled() )
+    return m_resource->settings()->intervalCheckTime();
   else
     return -1; // -1 for never
 }
@@ -137,7 +137,7 @@ QSet<QByteArray> ResourceState::removedFlags() const
 
 QString ResourceState::rootRemoteId() const
 {
-  return Settings::self()->rootRemoteId();
+  return m_resource->settings()->rootRemoteId();
 }
 
 void ResourceState::setIdleCollection( const Akonadi::Collection &collection )
@@ -150,8 +150,8 @@ void ResourceState::setIdleCollection( const Akonadi::Collection &collection )
     curCol = curCol.parentCollection();
   }
 
-  Settings::self()->setIdleRidPath( ridPath );
-  Settings::self()->writeConfig();
+  m_resource->settings()->setIdleRidPath( ridPath );
+  m_resource->settings()->writeConfig();
 }
 
 void ResourceState::applyCollectionChanges( const Akonadi::Collection &collection )
@@ -209,8 +209,8 @@ void ResourceState::collectionsRetrieved( const Akonadi::Collection::List &colle
 {
   m_resource->collectionsRetrieved( collections );
 
-  if ( Settings::self()->retrieveMetadataOnFolderListing() ) {
-    QStringList oldMailBoxes = Settings::self()->knownMailBoxes();
+  if ( m_resource->settings()->retrieveMetadataOnFolderListing() ) {
+    QStringList oldMailBoxes = m_resource->settings()->knownMailBoxes();
     QStringList newMailBoxes;
 
     foreach ( const Akonadi::Collection &c, collections ) {
@@ -227,7 +227,7 @@ void ResourceState::collectionsRetrieved( const Akonadi::Collection::List &colle
       newMailBoxes << mailBox;
     }
 
-    Settings::self()->setKnownMailBoxes( newMailBoxes );
+    m_resource->settings()->setKnownMailBoxes( newMailBoxes );
   }
 
   m_resource->startIdleIfNeeded();
@@ -277,7 +277,7 @@ void ResourceState::cancelTask( const QString &errorString )
     collections << m_arguments.collection.parentCollection();
   }
 
-  const QStringList oldMailBoxes = Settings::self()->knownMailBoxes();
+  const QStringList oldMailBoxes = m_resource->settings()->knownMailBoxes();
   QStringList newMailBoxes = oldMailBoxes;
 
   foreach ( const Akonadi::Collection &collection, collections ) {
@@ -293,7 +293,7 @@ void ResourceState::cancelTask( const QString &errorString )
   }
 
   if ( oldMailBoxes.size()!=newMailBoxes.size() ) {
-    Settings::self()->setKnownMailBoxes( newMailBoxes );
+    m_resource->settings()->setKnownMailBoxes( newMailBoxes );
   }
 }
 
diff --git a/resources/imap/settings.cpp b/resources/imap/settings.cpp
index 1677686..a47ed1a 100644
--- a/resources/imap/settings.cpp
+++ b/resources/imap/settings.cpp
@@ -26,7 +26,6 @@
 #include <kwallet.h>
 using KWallet::Wallet;
 
-#include <kglobal.h>
 #include <klocale.h>
 #include <kpassworddialog.h>
 
@@ -36,28 +35,6 @@ using KWallet::Wallet;
 #include <KDE/Akonadi/CollectionFetchJob>
 #include <KDE/Akonadi/CollectionModifyJob>
 
-class SettingsHelper
-{
-public:
-    SettingsHelper() : q( 0 ) {}
-    ~SettingsHelper() {
-        delete q;
-    }
-    Settings *q;
-};
-
-K_GLOBAL_STATIC( SettingsHelper, s_globalSettings )
-
-Settings *Settings::self()
-{
-    if ( !s_globalSettings->q ) {
-        new Settings;
-        s_globalSettings->q->readConfig();
-    }
-
-    return s_globalSettings->q;
-}
-
 /**
  * Maps the enum used to represent authentication in MailTransport (kdepimlibs)
  * to the one used by the imap resource.
@@ -95,8 +72,7 @@ KIMAP::LoginJob::AuthenticationMode Settings::mapTransportAuthToKimap( MailTrans
 
 Settings::Settings( WId winId ) : SettingsBase(), m_winId( winId )
 {
-    Q_ASSERT( !s_globalSettings->q );
-    s_globalSettings->q = this;
+    readConfig();
 
     new SettingsAdaptor( this );
     QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ), this, QDBusConnection::ExportAdaptors | QDBusConnection::ExportScriptableContents );
@@ -312,7 +288,7 @@ void Settings::loadAccount( ImapAccount *account ) const
 
 QString Settings::rootRemoteId() const
 {
-  return QLatin1String("imap://") + Settings::self()->userName() + QLatin1Char('@') + Settings::self()->imapServer() + QLatin1Char('/');
+  return QLatin1String("imap://") + userName() + QLatin1Char('@') + imapServer() + QLatin1Char('/');
 }
 
 void Settings::renameRootCollection( const QString &newName )
diff --git a/resources/imap/settings.h b/resources/imap/settings.h
index 49c9108..61c6683 100644
--- a/resources/imap/settings.h
+++ b/resources/imap/settings.h
@@ -37,7 +37,6 @@ public:
     static KIMAP::LoginJob::AuthenticationMode mapTransportAuthToKimap( MailTransport::Transport::EnumAuthenticationType::type authType );
 
     explicit Settings( WId = 0 );
-    static Settings *self();
     void setWinId( WId );
 
     void requestPassword();
diff --git a/resources/imap/settingspasswordrequester.cpp b/resources/imap/settingspasswordrequester.cpp
index a4778e2..b795928 100644
--- a/resources/imap/settingspasswordrequester.cpp
+++ b/resources/imap/settingspasswordrequester.cpp
@@ -47,9 +47,9 @@ void SettingsPasswordRequester::requestPassword( RequestType request, const QStr
   if ( request == WrongPasswordRequest ) {
     QMetaObject::invokeMethod( this, "askUserInput", Qt::QueuedConnection, Q_ARG(QString, serverError) );
   } else {
-    connect( Settings::self(), SIGNAL(passwordRequestCompleted(QString,bool)),
+    connect( m_resource->settings(), SIGNAL(passwordRequestCompleted(QString,bool)),
              this, SLOT(onPasswordRequestCompleted(QString,bool)) );
-    Settings::self()->requestPassword();
+    m_resource->settings()->requestPassword();
   }
 }
 
@@ -99,9 +99,9 @@ void SettingsPasswordRequester::onButtonClicked(KDialog::ButtonCode result)
       dialog->show();
     }
   } else if ( result == KDialog::No ) {
-    connect( Settings::self(), SIGNAL(passwordRequestCompleted(QString,bool)),
+    connect( m_resource->settings(), SIGNAL(passwordRequestCompleted(QString,bool)),
              this, SLOT(onPasswordRequestCompleted(QString,bool)) );
-    Settings::self()->requestManualAuth();
+    m_resource->settings()->requestManualAuth();
   } else {
     emit done( UserRejected );
   }
@@ -129,12 +129,12 @@ void SettingsPasswordRequester::cancelPasswordRequests()
 
 void SettingsPasswordRequester::onPasswordRequestCompleted( const QString &password, bool userRejected )
 {
-  disconnect( Settings::self(), SIGNAL(passwordRequestCompleted(QString,bool)),
+  disconnect( m_resource->settings(), SIGNAL(passwordRequestCompleted(QString,bool)),
               this, SLOT(onPasswordRequestCompleted(QString,bool)) );
 
   if ( userRejected ) {
     emit done( UserRejected );
-  } else if ( password.isEmpty() && (Settings::self()->authentication() != MailTransport::Transport::EnumAuthenticationType::GSSAPI) ) {
+  } else if ( password.isEmpty() && (m_resource->settings()->authentication() != MailTransport::Transport::EnumAuthenticationType::GSSAPI) ) {
     emit done( EmptyPasswordEntered );
   } else {
     emit done( PasswordRetrieved, password );
diff --git a/resources/imap/setupserver.cpp b/resources/imap/setupserver.cpp
index c77e41f..26653f6 100644
--- a/resources/imap/setupserver.cpp
+++ b/resources/imap/setupserver.cpp
@@ -124,7 +124,7 @@ SetupServer::SetupServer( ImapResourceBase *parentResource, WId parent )
   : KDialog(), m_parentResource( parentResource ), m_ui(new Ui::SetupServerView), m_serverTest(0),
     m_subscriptionsChanged(false), m_shouldClearCache(false), mValidator( this )
 {
-  Settings::self()->setWinId( parent );
+  m_parentResource->settings()->setWinId( parent );
   m_ui->setupUi( mainWidget() );
   m_folderArchiveSettingPage = new FolderArchiveSettingPage(m_parentResource->identifier());
   m_ui->tabWidget->addTab(m_folderArchiveSettingPage, i18n("Folder Archive"));
@@ -256,14 +256,14 @@ void SetupServer::slotCustomSieveChanged()
 void SetupServer::applySettings()
 {
   m_folderArchiveSettingPage->writeSettings();
-  m_shouldClearCache = ( Settings::self()->imapServer() != m_ui->imapServer->text() )
-                    || ( Settings::self()->userName() != m_ui->userName->text() );
+  m_shouldClearCache = ( m_parentResource->settings()->imapServer() != m_ui->imapServer->text() )
+                    || ( m_parentResource->settings()->userName() != m_ui->userName->text() );
 
   m_parentResource->setName( m_ui->accountName->text() );
 
-  Settings::self()->setImapServer( m_ui->imapServer->text() );
-  Settings::self()->setImapPort( m_ui->portSpin->value() );
-  Settings::self()->setUserName( m_ui->userName->text() );
+  m_parentResource->settings()->setImapServer( m_ui->imapServer->text() );
+  m_parentResource->settings()->setImapPort( m_ui->portSpin->value() );
+  m_parentResource->settings()->setUserName( m_ui->userName->text() );
   QString encryption;
   switch ( m_ui->safeImapGroup->checkedId() ) {
   case KIMAP::LoginJob::Unencrypted :
@@ -278,22 +278,22 @@ void SetupServer::applySettings()
   default:
     kFatal() << "Shouldn't happen";
   }
-  Settings::self()->setSafety( encryption );
+  m_parentResource->settings()->setSafety( encryption );
   MailTransport::Transport::EnumAuthenticationType::type authtype = getCurrentAuthMode( m_ui->authenticationCombo );
   kDebug() << "saving IMAP auth mode: " << authenticationModeString( authtype );
-  Settings::self()->setAuthentication( authtype );
-  Settings::self()->setPassword( m_ui->password->text() );
-  Settings::self()->setSubscriptionEnabled( m_ui->subscriptionEnabled->isChecked() );
-  Settings::self()->setIntervalCheckTime( m_ui->checkInterval->value() );
-  Settings::self()->setDisconnectedModeEnabled( m_ui->disconnectedModeEnabled->isChecked() );
-
-  Settings::self()->setSieveSupport( m_ui->managesieveCheck->isChecked() );
-  Settings::self()->setSieveReuseConfig( m_ui->sameConfigCheck->isChecked() );
-  Settings::self()->setSievePort( m_ui->sievePortSpin->value() );
-  Settings::self()->setSieveAlternateUrl( m_ui->alternateURL->text() );
-  Settings::self()->setSieveVacationFilename( m_vacationFileName );
-
-  Settings::self()->setTrashCollection( m_ui->folderRequester->collection().id() );
+  m_parentResource->settings()->setAuthentication( authtype );
+  m_parentResource->settings()->setPassword( m_ui->password->text() );
+  m_parentResource->settings()->setSubscriptionEnabled( m_ui->subscriptionEnabled->isChecked() );
+  m_parentResource->settings()->setIntervalCheckTime( m_ui->checkInterval->value() );
+  m_parentResource->settings()->setDisconnectedModeEnabled( m_ui->disconnectedModeEnabled->isChecked() );
+
+  m_parentResource->settings()->setSieveSupport( m_ui->managesieveCheck->isChecked() );
+  m_parentResource->settings()->setSieveReuseConfig( m_ui->sameConfigCheck->isChecked() );
+  m_parentResource->settings()->setSievePort( m_ui->sievePortSpin->value() );
+  m_parentResource->settings()->setSieveAlternateUrl( m_ui->alternateURL->text() );
+  m_parentResource->settings()->setSieveVacationFilename( m_vacationFileName );
+
+  m_parentResource->settings()->setTrashCollection( m_ui->folderRequester->collection().id() );
   Akonadi::Collection trash = m_ui->folderRequester->collection();
   Akonadi::SpecialMailCollections::self()->registerCollection(Akonadi::SpecialMailCollections::Trash, trash);
   Akonadi::EntityDisplayAttribute *attribute =  trash.attribute<Akonadi::EntityDisplayAttribute>( Akonadi::Entity::AddIfMissing );
@@ -303,35 +303,35 @@ void SetupServer::applySettings()
       Akonadi::SpecialMailCollections::self()->unregisterCollection(mOldTrash);
   }
 
-  Settings::self()->setAutomaticExpungeEnabled( m_ui->autoExpungeCheck->isChecked() );
-  Settings::self()->setUseDefaultIdentity( m_ui->useDefaultIdentityCheck->isChecked() );
+  m_parentResource->settings()->setAutomaticExpungeEnabled( m_ui->autoExpungeCheck->isChecked() );
+  m_parentResource->settings()->setUseDefaultIdentity( m_ui->useDefaultIdentityCheck->isChecked() );
 
   if ( !m_ui->useDefaultIdentityCheck->isChecked() )
-    Settings::self()->setAccountIdentity( m_identityCombobox->currentIdentity() );
+    m_parentResource->settings()->setAccountIdentity( m_identityCombobox->currentIdentity() );
 
-  Settings::self()->setIntervalCheckEnabled( m_ui->enableMailCheckBox->isChecked() );
+  m_parentResource->settings()->setIntervalCheckEnabled( m_ui->enableMailCheckBox->isChecked() );
   if ( m_ui->enableMailCheckBox->isChecked() )
-    Settings::self()->setIntervalCheckTime( m_ui->checkInterval->value() );
+    m_parentResource->settings()->setIntervalCheckTime( m_ui->checkInterval->value() );
 
-  Settings::self()->setSieveCustomUsername(m_ui->customUsername->text());
+  m_parentResource->settings()->setSieveCustomUsername(m_ui->customUsername->text());
 
   QAbstractButton *checkedButton = m_ui->customSieveGroup->checkedButton();
 
   if (checkedButton == m_ui->imapUserPassword) {
-      Settings::self()->setSieveCustomAuthentification(QLatin1String("ImapUserPassword"));
+      m_parentResource->settings()->setSieveCustomAuthentification(QLatin1String("ImapUserPassword"));
   } else if (checkedButton == m_ui->noAuthentification) {
-      Settings::self()->setSieveCustomAuthentification(QLatin1String("NoAuthentification"));
+      m_parentResource->settings()->setSieveCustomAuthentification(QLatin1String("NoAuthentification"));
   } else if (checkedButton == m_ui->customUserPassword) {
-      Settings::self()->setSieveCustomAuthentification(QLatin1String("CustomUserPassword"));
+      m_parentResource->settings()->setSieveCustomAuthentification(QLatin1String("CustomUserPassword"));
   }
 
-  Settings::self()->setSieveCustomPassword( m_ui->customPassword->text() );
+  m_parentResource->settings()->setSieveCustomPassword( m_ui->customPassword->text() );
 
-  Settings::self()->writeConfig();
+  m_parentResource->settings()->writeConfig();
   kDebug() << "wrote" << m_ui->imapServer->text() << m_ui->userName->text() << m_ui->safeImapGroup->checkedId();
 
   if ( m_oldResourceName != m_ui->accountName->text() && !m_ui->accountName->text().isEmpty() ) {
-    Settings::self()->renameRootCollection( m_ui->accountName->text() );
+    m_parentResource->settings()->renameRootCollection( m_ui->accountName->text() );
   }
 }
 
@@ -345,16 +345,16 @@ void SetupServer::readSettings()
   KEMailSettings esetting;
 
   m_ui->imapServer->setText(
-    !Settings::self()->imapServer().isEmpty() ? Settings::self()->imapServer() :
+    !m_parentResource->settings()->imapServer().isEmpty() ? m_parentResource->settings()->imapServer() :
     esetting.getSetting( KEMailSettings::InServer ) );
 
-  m_ui->portSpin->setValue( Settings::self()->imapPort() );
+  m_ui->portSpin->setValue( m_parentResource->settings()->imapPort() );
 
   m_ui->userName->setText(
-    !Settings::self()->userName().isEmpty() ? Settings::self()->userName() :
+    !m_parentResource->settings()->userName().isEmpty() ? m_parentResource->settings()->userName() :
     currentUser->loginName() );
 
-  const QString safety = Settings::self()->safety();
+  const QString safety = m_parentResource->settings()->safety();
   int i = 0;
   if ( safety == QLatin1String( "SSL" ) )
     i = KIMAP::LoginJob::AnySslVersion;
@@ -368,12 +368,12 @@ void SetupServer::readSettings()
       safetyButton->setChecked( true );
 
   populateDefaultAuthenticationOptions();
-  i = Settings::self()->authentication();
+  i = m_parentResource->settings()->authentication();
   kDebug() << "read IMAP auth mode: " << authenticationModeString( (MailTransport::Transport::EnumAuthenticationType::type) i );
   setCurrentAuthMode( m_ui->authenticationCombo, (MailTransport::Transport::EnumAuthenticationType::type) i );
 
   bool rejected = false;
-  const QString password = Settings::self()->password( &rejected );
+  const QString password = m_parentResource->settings()->password( &rejected );
   if ( rejected ) {
     m_ui->password->setEnabled( false );
     KMessageBox::information( 0, i18n( "Could not access KWallet. "
@@ -386,19 +386,19 @@ void SetupServer::readSettings()
     m_ui->password->insert( password );
   }
 
-  m_ui->subscriptionEnabled->setChecked( Settings::self()->subscriptionEnabled() );
+  m_ui->subscriptionEnabled->setChecked( m_parentResource->settings()->subscriptionEnabled() );
 
-  m_ui->checkInterval->setValue( Settings::self()->intervalCheckTime() );
-  m_ui->disconnectedModeEnabled->setChecked( Settings::self()->disconnectedModeEnabled() );
+  m_ui->checkInterval->setValue( m_parentResource->settings()->intervalCheckTime() );
+  m_ui->disconnectedModeEnabled->setChecked( m_parentResource->settings()->disconnectedModeEnabled() );
 
-  m_ui->managesieveCheck->setChecked( Settings::self()->sieveSupport() );
-  m_ui->sameConfigCheck->setChecked( Settings::self()->sieveReuseConfig() );
-  m_ui->sievePortSpin->setValue( Settings::self()->sievePort() );
-  m_ui->alternateURL->setText( Settings::self()->sieveAlternateUrl() );
-  m_vacationFileName = Settings::self()->sieveVacationFilename();
+  m_ui->managesieveCheck->setChecked( m_parentResource->settings()->sieveSupport() );
+  m_ui->sameConfigCheck->setChecked( m_parentResource->settings()->sieveReuseConfig() );
+  m_ui->sievePortSpin->setValue( m_parentResource->settings()->sievePort() );
+  m_ui->alternateURL->setText( m_parentResource->settings()->sieveAlternateUrl() );
+  m_vacationFileName = m_parentResource->settings()->sieveVacationFilename();
 
 
-  Akonadi::Collection trashCollection( Settings::self()->trashCollection() );
+  Akonadi::Collection trashCollection( m_parentResource->settings()->trashCollection() );
   if ( trashCollection.isValid() ) {
     Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob( trashCollection,Akonadi::CollectionFetchJob::Base,this );
     connect( fetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)),
@@ -411,27 +411,27 @@ void SetupServer::readSettings()
     requestJob->start();
   }
 
-  m_ui->useDefaultIdentityCheck->setChecked( Settings::self()->useDefaultIdentity() );
+  m_ui->useDefaultIdentityCheck->setChecked( m_parentResource->settings()->useDefaultIdentity() );
   if ( !m_ui->useDefaultIdentityCheck->isChecked() )
-    m_identityCombobox->setCurrentIdentity( Settings::self()->accountIdentity() );
+    m_identityCombobox->setCurrentIdentity( m_parentResource->settings()->accountIdentity() );
 
-  m_ui->enableMailCheckBox->setChecked( Settings::self()->intervalCheckEnabled() );
+  m_ui->enableMailCheckBox->setChecked( m_parentResource->settings()->intervalCheckEnabled() );
   if ( m_ui->enableMailCheckBox->isChecked() )
-    m_ui->checkInterval->setValue( Settings::self()->intervalCheckTime() );
+    m_ui->checkInterval->setValue( m_parentResource->settings()->intervalCheckTime() );
   else
     m_ui->checkInterval->setEnabled( false );
 
-  m_ui->autoExpungeCheck->setChecked( Settings::self()->automaticExpungeEnabled() );
+  m_ui->autoExpungeCheck->setChecked( m_parentResource->settings()->automaticExpungeEnabled() );
 
   if ( m_vacationFileName.isEmpty() )
     m_vacationFileName = QLatin1String("kmail-vacation.siv");
 
-  m_ui->customUsername->setText(Settings::self()->sieveCustomUsername());
+  m_ui->customUsername->setText(m_parentResource->settings()->sieveCustomUsername());
 
-  m_ui->customPassword->setText(Settings::self()->sieveCustomPassword());
+  m_ui->customPassword->setText(m_parentResource->settings()->sieveCustomPassword());
 
 
-  const QString sieverCustomAuth(Settings::self()->sieveCustomAuthentification());
+  const QString sieverCustomAuth(m_parentResource->settings()->sieveCustomAuthentification());
   if (sieverCustomAuth == QLatin1String("ImapUserPassword"))
       m_ui->imapUserPassword->setChecked(true);
   else if (sieverCustomAuth == QLatin1String("NoAuthentification"))


commit 5bc7483abe1fd64a71ff8fca80d287fdbb478975
Author: Albert Astals Cid <aacid at kde.org>
Date:   Thu Jul 10 19:41:46 2014 +0200

    libkolab needed is really 0.5.2

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 276d7d5..ff2101a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,7 +71,7 @@ find_package(SharedMimeInfo 0.30)
 set_package_properties(SharedMimeInfo PROPERTIES DESCRIPTION "The shared-mime-info utility" URL "http://freedesktop.org/wiki/Software/shared-mime-info" TYPE REQUIRED PURPOSE "Information about filetypes")
 
 # Libkolab
-find_package(Libkolab 0.5 QUIET CONFIG)
+find_package(Libkolab 0.5.2 QUIET CONFIG)
 set_package_properties(Libkolab PROPERTIES DESCRIPTION "libkolab" URL "http://mirror.kolabsys.com/pub/releases" TYPE OPTIONAL PURPOSE "The Kolab Format libraries are required to build the Kolab Groupware Resource")
 
 # Libkolabxml


commit 1bf991f905025dc742923cfaaa1c6525556b33c4
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Sun Aug 10 18:42:56 2014 +0200

    Prepare 4.14beta1
    
    Conflicts:
    	CMakeLists.txt
    
    Conflicts:
    	CMakeLists.txt


commit f298d35d43835e5858f1e194efd3584426ab3b85
Author: Christophe Giboudeaux <cgiboudeaux at gmx.com>
Date:   Mon Jun 30 12:20:59 2014 +0200

    Fix build.

diff --git a/resources/shared/getcredentialsjob.cpp b/resources/shared/getcredentialsjob.cpp
index 2c972f2..7421a94 100644
--- a/resources/shared/getcredentialsjob.cpp
+++ b/resources/shared/getcredentialsjob.cpp
@@ -67,7 +67,7 @@ void GetCredentialsJob::getCredentials()
         return;
     }
 
-    m_authData["AccountUsername"] = acc->value(QLatin1String("username")).toString();
+    m_authData[QLatin1String("AccountUsername")] = acc->value(QLatin1String("username")).toString();
     QPointer<SignOn::AuthSession> authSession = identity->createSession(authData.method());
 
     connect(authSession, SIGNAL(response(SignOn::SessionData)),


commit 1b8fe768c4986f3001b1e0ac839524660aa8c4b3
Author: Montel Laurent <montel at kde.org>
Date:   Sat Jun 28 12:55:04 2014 +0200

    Make it compile with QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII

diff --git a/resources/google/CMakeLists.txt b/resources/google/CMakeLists.txt
index 664b5ce..92b8be8 100644
--- a/resources/google/CMakeLists.txt
+++ b/resources/google/CMakeLists.txt
@@ -1,5 +1,9 @@
 include_directories(${LibKGAPI2_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
 
+add_definitions( -DQT_NO_CAST_FROM_ASCII )
+add_definitions( -DQT_NO_CAST_TO_ASCII )
+
+
 if(${AccountsQt_FOUND} AND ${SignOnQt_FOUND})
   include_directories(${ACCOUNTSQT_INCLUDE_DIRS} ${SIGNONQT_INCLUDE_DIRS} ../)
   add_definitions(-DHAVE_ACCOUNTS)
diff --git a/resources/kolab/CMakeLists.txt b/resources/kolab/CMakeLists.txt
index f606ab1..0e8e237 100644
--- a/resources/kolab/CMakeLists.txt
+++ b/resources/kolab/CMakeLists.txt
@@ -7,6 +7,9 @@ include_directories(
     ${Libkolab_INCLUDES}
     ${Libkolabxml_INCLUDES}
 )
+add_definitions( -DQT_NO_CAST_FROM_ASCII )
+add_definitions( -DQT_NO_CAST_TO_ASCII )
+
 
 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" )
 
diff --git a/resources/kolab/kolabhelpers.cpp b/resources/kolab/kolabhelpers.cpp
index 56bfe20..084bcb5 100644
--- a/resources/kolab/kolabhelpers.cpp
+++ b/resources/kolab/kolabhelpers.cpp
@@ -97,7 +97,7 @@ Akonadi::Item KolabHelpers::translateFromImap(Kolab::FolderType folderType, cons
                 ok = false;
                 return Akonadi::Item();
             }
-            Akonadi::Item newItem("text/x-vnd.akonadi.note");
+            Akonadi::Item newItem(QLatin1String("text/x-vnd.akonadi.note"));
             newItem.setPayload(note);
             newItem.setRemoteId(imapItem.remoteId());
             const Akonadi::NoteUtils::NoteMessageWrapper wrapper(note);
diff --git a/resources/kolab/kolabresource.cpp b/resources/kolab/kolabresource.cpp
index c9b790d..18cfb55 100644
--- a/resources/kolab/kolabresource.cpp
+++ b/resources/kolab/kolabresource.cpp
@@ -38,7 +38,7 @@ KolabResource::KolabResource(const QString& id)
     :ImapResource(id)
 {
     //Load translations from imap resource
-    KGlobal::locale()->insertCatalog("akonadi_imap_resource");
+    KGlobal::locale()->insertCatalog(QLatin1String("akonadi_imap_resource"));
 }
 
 KolabResource::~KolabResource()
diff --git a/resources/kolab/kolabresourcestate.cpp b/resources/kolab/kolabresourcestate.cpp
index f4cf8b9..00f0a46 100644
--- a/resources/kolab/kolabresourcestate.cpp
+++ b/resources/kolab/kolabresourcestate.cpp
@@ -59,8 +59,8 @@ void KolabResourceState::collectionAttributesRetrieved(const Akonadi::Collection
             //Groupware data always requires the full message, because it cannot translate without the body
             Akonadi::CachePolicy cachePolicy = col.cachePolicy();
             QStringList localParts = cachePolicy.localParts();
-            if (!localParts.contains(Akonadi::MessagePart::Body)) {
-                localParts << Akonadi::MessagePart::Body;
+            if (!localParts.contains(QLatin1String(Akonadi::MessagePart::Body))) {
+                localParts << QLatin1String(Akonadi::MessagePart::Body);
                 cachePolicy.setLocalParts(localParts);
                 cachePolicy.setCacheTimeout(-1);
                 cachePolicy.setInheritFromParent(false);
diff --git a/resources/kolab/kolabretrievecollectionstask.cpp b/resources/kolab/kolabretrievecollectionstask.cpp
index d007cd1..5594b8f 100644
--- a/resources/kolab/kolabretrievecollectionstask.cpp
+++ b/resources/kolab/kolabretrievecollectionstask.cpp
@@ -168,7 +168,7 @@ void KolabRetrieveCollectionsTask::createCollection(const QString &mailbox, cons
     //We add a dummy mimetype, otherwise the itemsync doesn't even work (action is disabled and resourcebase aborts the operation)
     c.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QLatin1String("application/x-kolab-objects"));
     //assume LRS, until myrights is executed
-    if (serverCapabilities().contains("ACL")) {
+    if (serverCapabilities().contains(QLatin1String("ACL"))) {
         c.setRights(Akonadi::Collection::ReadOnly);
     } else {
         c.setRights(Akonadi::Collection::AllRights);


commit dcfcd85316ebc8130370c406138a673a32e305ef
Author: Montel Laurent <montel at kde.org>
Date:   Fri Jun 27 14:00:34 2014 +0200

    Remove not necessary

diff --git a/resources/mixedmaildir/kmindexreader/kmindexreader.cpp b/resources/mixedmaildir/kmindexreader/kmindexreader.cpp
index 996fd1d..5fed5a5 100644
--- a/resources/mixedmaildir/kmindexreader/kmindexreader.cpp
+++ b/resources/mixedmaildir/kmindexreader/kmindexreader.cpp
@@ -24,8 +24,6 @@
 
 #include "kmindexreader.h"
 
-#include "kmindexreader_support.h"
-
 #include <KDebug>
 #include <kde_file.h>
 #include <akonadi/kmime/messagestatus.h>
diff --git a/resources/mixedmaildir/kmindexreader/kmindexreader_support.h b/resources/mixedmaildir/kmindexreader/kmindexreader_support.h
deleted file mode 100644
index 3ac1bf9..0000000
--- a/resources/mixedmaildir/kmindexreader/kmindexreader_support.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *   Copyright (C) 2010 Casey Link <unnamedrambler at gmail.com>
- *   Copyright (c) 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company <info at kdab.net>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License along
- *   with this program; if not, write to the Free Software Foundation, Inc.,
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef KMINDEXREADER_SUPPORT
-#define KMINDEXREADER_SUPPORT
-
-#include <KShortcut>
-
-#include <QColor>
-#include <QFont>
-#include <QObject>
-
-class KMIndexTag
-{
-  public:
-    int priority;
-    QString tagName;
-    QColor backgroundColor;
-    QColor textColor;
-    QFont textFont;
-    bool inToolbar;
-    QString iconName;
-    KShortcut shortcut;
-    bool mEmpty;
-};
-#endif


commit 533c63c7b526203aaa256aa8894f4329d4d9d9a9
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Sun Aug 10 18:42:18 2014 +0200

    Try to make it compile
    
    Conflicts:
    	resources/gmail/CMakeLists.txt

diff --git a/resources/imap/CMakeLists.txt b/resources/imap/CMakeLists.txt
index 0a95d9d..89bbf65 100644
--- a/resources/imap/CMakeLists.txt
+++ b/resources/imap/CMakeLists.txt
@@ -44,10 +44,23 @@ set( imapresource_LIB_SRCS
   timestampattribute.cpp
   uidvalidityattribute.cpp
   uidnextattribute.cpp
+  settings.cpp
+  subscriptiondialog.cpp
+  imapidlemanager.cpp
+  resourcestate.cpp
   ${AKONADI_COLLECTIONATTRIBUTES_SHARED_SOURCES}
   ${AKONADI_IMAPATTRIBUTES_SHARED_SOURCES}
 )
 
+kcfg_generate_dbus_interface( ${CMAKE_CURRENT_SOURCE_DIR}/imapresource.kcfg org.kde.Akonadi.Imap.Settings )
+kde4_add_kcfg_files(imapresource_LIB_SRCS settingsbase.kcfgc)
+
+qt4_add_dbus_adaptor( imapresource_LIB_SRCS
+     ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Settings.xml settings.h Settings
+     )
+
+
+
 qt4_generate_dbus_interface( ${CMAKE_CURRENT_SOURCE_DIR}/imapresourcebase.h org.kde.Akonadi.Imap.Resource.xml OPTIONS -a )
 qt4_add_dbus_adaptor( imapresource_LIB_SRCS
      ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Resource.xml
@@ -65,14 +78,11 @@ endif()
 
 set( akonadi_imap_resource_SRCS
   main.cpp
-  imapidlemanager.cpp
   imapresource.cpp
   resourcestate.cpp
-  settings.cpp
   settingspasswordrequester.cpp
   setupserver.cpp
   serverinfodialog.cpp
-  subscriptiondialog.cpp
 )
 
 install( FILES imapresource.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents" )
@@ -84,11 +94,7 @@ kde4_add_ui_files(akonadi_imap_resource_SRCS setupserverview_desktop.ui)
 endif ()
 kde4_add_ui_files(akonadi_imap_resource_SRCS serverinfo.ui)
 
-kcfg_generate_dbus_interface( ${CMAKE_CURRENT_SOURCE_DIR}/imapresource.kcfg org.kde.Akonadi.Imap.Settings )
-qt4_add_dbus_adaptor( akonadi_imap_resource_SRCS
-     ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Settings.xml settings.h Settings
-     )
-kde4_add_kcfg_files(akonadi_imap_resource_SRCS settingsbase.kcfgc)
+
 
 if (RUNTIME_PLUGINS_STATIC)
     add_definitions(-DMAIL_SERIALIZER_PLUGIN_STATIC)
diff --git a/resources/kolab/CMakeLists.txt b/resources/kolab/CMakeLists.txt
index 875950b..f606ab1 100644
--- a/resources/kolab/CMakeLists.txt
+++ b/resources/kolab/CMakeLists.txt
@@ -13,14 +13,10 @@ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" )
 ########### next target ###############
 
 set(kolabresource_SRCS
-    ../imap/imapidlemanager.cpp
     ../imap/imapresource.cpp
-    ../imap/resourcestate.cpp
-    ../imap/settings.cpp
     ../imap/settingspasswordrequester.cpp
     ../imap/setupserver.cpp
     ../imap/serverinfodialog.cpp
-    ../imap/subscriptiondialog.cpp
     kolabretrievecollectionstask.cpp
     kolabresource.cpp
     kolabresourcestate.cpp
@@ -28,16 +24,6 @@ set(kolabresource_SRCS
     kolabmessagehelper.cpp
 )
 
-kcfg_generate_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/../imap/imapresource.kcfg org.kde.Akonadi.Imap.Settings)
-qt4_add_dbus_adaptor(kolabresource_SRCS
-    ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Settings.xml settings.h Settings
-)
-qt4_generate_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/../imap/imapresource.h org.kde.Akonadi.Imap.Resource.xml OPTIONS -a )
-qt4_add_dbus_adaptor(kolabresource_SRCS
-    ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Resource.xml
-    imapresource.h ImapResource
-)
-
 kde4_add_kcfg_files(kolabresource_SRCS ../imap/settingsbase.kcfgc)
 
 if (KDEPIM_MOBILE_UI)


commit 0bfd80206f5399c5b82090ae5526ff37f1f0f0d3
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Wed Jun 25 16:53:55 2014 +0200

    Fix build

diff --git a/resources/imap/imapresource.cpp b/resources/imap/imapresource.cpp
index 44fefd9..779f713 100644
--- a/resources/imap/imapresource.cpp
+++ b/resources/imap/imapresource.cpp
@@ -44,7 +44,7 @@ ImapResource::~ImapResource()
 {
 }
 
-QString ImapResource::defaultName()
+QString ImapResource::defaultName() const
 {
   return i18n( "IMAP Account" );
 }


commit 650819f8dfae26b96b12c808f955c892d1e07946
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Mon Jun 23 18:20:27 2014 +0200

    Google Contacts Resource: Use group ID instead of name for collection name
    
    Google allows multiple groups with the same name, which then breaks sync in
    Akonadi.
    
    This is using the same workaround like the Calendars resource - we use unique ID
    as collection name to make Akonadi happy, and we put the actual name into
    EntityDisplayAttribute.

diff --git a/resources/google/contacts/contactsresource.cpp b/resources/google/contacts/contactsresource.cpp
index 25a36ba..ac051ba 100644
--- a/resources/google/contacts/contactsresource.cpp
+++ b/resources/google/contacts/contactsresource.cpp
@@ -391,7 +391,7 @@ void ContactsResource::slotCollectionsRetrieved( KGAPI2::Job *job )
 
         Collection collection;
         collection.setContentMimeTypes( QStringList() << KABC::Addressee::mimeType() );
-        collection.setName( group->title() );
+        collection.setName( group->id() );
         collection.setParentCollection( m_rootCollection );
         collection.setRights( Collection::CanLinkItem |
                               Collection::CanUnlinkItem |


commit 2ce793a861a4b822a0ca57caa0752b94534452d4
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Fri Jun 20 13:23:33 2014 +0200

    Imap Resource: Make some methods in ChangeItemsFlagsTask virtual

diff --git a/resources/imap/changeitemsflagstask.h b/resources/imap/changeitemsflagstask.h
index 86a1c76..9a58652 100644
--- a/resources/imap/changeitemsflagstask.h
+++ b/resources/imap/changeitemsflagstask.h
@@ -35,18 +35,18 @@ public:
   explicit ChangeItemsFlagsTask( ResourceStateInterface::Ptr resource, QObject* parent = 0 );
   virtual ~ChangeItemsFlagsTask();
 
-private Q_SLOTS:
+protected Q_SLOTS:
   void onSelectDone( KJob *job );
   void onAppendFlagsDone( KJob *job );
   void onRemoveFlagsDone( KJob *job );
 
 protected:
+  KIMAP::StoreJob* prepareJob( KIMAP::Session *session );
+
   virtual void doStart( KIMAP::Session* session );
 
-private:
-  KIMAP::StoreJob* prepareJob( KIMAP::Session *session );
-  void triggerAppendFlagsJob( KIMAP::Session *session );
-  void triggerRemoveFlagsJob( KIMAP::Session *session );
+  virtual void triggerAppendFlagsJob( KIMAP::Session *session );
+  virtual void triggerRemoveFlagsJob( KIMAP::Session *session );
 
 };
 


commit 2158e5873eb7a5aa39fe438a66dd26bed53740c4
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Thu Jun 19 15:52:26 2014 +0200

    Split ImapResource to ImapResourceBase and ImapResource
    
    ImapResourceBase contains generic implementation (most of the code), and ImapResource
    contains code that links against specific classes, like configuration dialog etc.,
    which some more specialized IMAP subclasses might want to replace by their own
    implementation.
    
    Conflicts:
    	resources/imap/imapresource.cpp
    	resources/imap/imapresource.h

diff --git a/resources/imap/CMakeLists.txt b/resources/imap/CMakeLists.txt
index 0af8834..0a95d9d 100644
--- a/resources/imap/CMakeLists.txt
+++ b/resources/imap/CMakeLists.txt
@@ -24,6 +24,7 @@ set( imapresource_LIB_SRCS
   highestmodseqattribute.cpp
   imapaccount.cpp
   imapflags.cpp
+  imapresourcebase.cpp
   messagehelper.cpp
   movecollectiontask.cpp
   moveitemstask.cpp
@@ -47,6 +48,12 @@ set( imapresource_LIB_SRCS
   ${AKONADI_IMAPATTRIBUTES_SHARED_SOURCES}
 )
 
+qt4_generate_dbus_interface( ${CMAKE_CURRENT_SOURCE_DIR}/imapresourcebase.h org.kde.Akonadi.Imap.Resource.xml OPTIONS -a )
+qt4_add_dbus_adaptor( imapresource_LIB_SRCS
+     ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Resource.xml
+        imapresourcebase.h ImapResourceBase
+     )
+
 kde4_add_library(imapresource STATIC ${imapresource_LIB_SRCS})
 
 target_link_libraries(imapresource ${KDEPIMLIBS_AKONADI_LIBS} ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${KDEPIMLIBS_KIMAP_LIBS} ${KDEPIMLIBS_MAILTRANSPORT_LIBS} ${KDE4_KIO_LIBS} ${KDEPIMLIBS_KMIME_LIBS} ${KDEPIMLIBS_AKONADI_KMIME_LIBS} ${KDEPIMLIBS_KPIMIDENTITIES_LIBS})
@@ -81,11 +88,6 @@ kcfg_generate_dbus_interface( ${CMAKE_CURRENT_SOURCE_DIR}/imapresource.kcfg org.
 qt4_add_dbus_adaptor( akonadi_imap_resource_SRCS
      ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Settings.xml settings.h Settings
      )
-qt4_generate_dbus_interface( ${CMAKE_CURRENT_SOURCE_DIR}/imapresource.h org.kde.Akonadi.Imap.Resource.xml OPTIONS -a )
-qt4_add_dbus_adaptor( akonadi_imap_resource_SRCS
-     ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Imap.Resource.xml
-        imapresource.h ImapResource
-     )
 kde4_add_kcfg_files(akonadi_imap_resource_SRCS settingsbase.kcfgc)
 
 if (RUNTIME_PLUGINS_STATIC)
diff --git a/resources/imap/imapidlemanager.cpp b/resources/imap/imapidlemanager.cpp
index f5fb73b..db04b16 100644
--- a/resources/imap/imapidlemanager.cpp
+++ b/resources/imap/imapidlemanager.cpp
@@ -37,7 +37,7 @@
 #include "sessionpool.h"
 
 ImapIdleManager::ImapIdleManager( ResourceStateInterface::Ptr state,
-                                  SessionPool *pool, ImapResource *parent )
+                                  SessionPool *pool, ImapResourceBase *parent )
   : QObject( parent ), m_sessionRequestId( 0 ), m_pool( pool ), m_session( 0 ),
     m_idle( 0 ), m_resource( parent ), m_state( state ),
     m_lastMessageCount( -1 ), m_lastRecentCount( -1 )
diff --git a/resources/imap/imapidlemanager.h b/resources/imap/imapidlemanager.h
index f34a718..2016b14 100644
--- a/resources/imap/imapidlemanager.h
+++ b/resources/imap/imapidlemanager.h
@@ -39,7 +39,7 @@ namespace KIMAP
   class Session;
 }
 
-class ImapResource;
+class ImapResourceBase;
 class SessionPool;
 
 class KJob;
@@ -49,7 +49,7 @@ class ImapIdleManager : public QObject
   Q_OBJECT
 
 public:
-  ImapIdleManager( ResourceStateInterface::Ptr state, SessionPool *pool, ImapResource *parent );
+  ImapIdleManager( ResourceStateInterface::Ptr state, SessionPool *pool, ImapResourceBase *parent );
   ~ImapIdleManager();
   void stop();
 
@@ -73,7 +73,7 @@ private:
   SessionPool *m_pool;
   KIMAP::Session *m_session;
   QPointer<KIMAP::IdleJob> m_idle;
-  ImapResource *m_resource;
+  ImapResourceBase *m_resource;
   ResourceStateInterface::Ptr m_state;
   qint64 m_lastMessageCount;
   qint64 m_lastRecentCount;
diff --git a/resources/imap/imapresource.cpp b/resources/imap/imapresource.cpp
index 6b1371f..44fefd9 100644
--- a/resources/imap/imapresource.cpp
+++ b/resources/imap/imapresource.cpp
@@ -24,175 +24,24 @@
 */
 
 #include "imapresource.h"
-
-#include <QHostInfo>
-#include <QSettings>
-
-#include <kdebug.h>
-#include <klocale.h>
-#include <kstandarddirs.h>
-#include <KWindowSystem>
-#include <Akonadi/CollectionModifyJob>
-
-#include <akonadi/agentmanager.h>
-#include <akonadi/attributefactory.h>
-#include <akonadi/collectionfetchjob.h>
-#include <akonadi/collectionfetchscope.h>
-#include <akonadi/changerecorder.h>
-#include <akonadi/itemfetchscope.h>
-#include <akonadi/itemfetchjob.h>
-#include <akonadi/specialcollections.h>
-#include <akonadi/session.h>
-#include <akonadi/kmime/messageparts.h>
-
-#include "collectionannotationsattribute.h"
-#include "collectionflagsattribute.h"
-#include "imapaclattribute.h"
-#include "imapquotaattribute.h"
-#include "noselectattribute.h"
-#include "timestampattribute.h"
-#include "uidvalidityattribute.h"
-#include "uidnextattribute.h"
-#include "highestmodseqattribute.h"
-
 #include "setupserver.h"
 #include "settings.h"
-#include "imapaccount.h"
-#include "imapidlemanager.h"
-#include "resourcestate.h"
-#include "subscriptiondialog.h"
-
-#include "addcollectiontask.h"
-#include "additemtask.h"
-#include "changecollectiontask.h"
-#include "changeitemsflagstask.h"
-#include "changeitemtask.h"
-#include "expungecollectiontask.h"
-#include "movecollectiontask.h"
-#include "moveitemstask.h"
-#include "removecollectionrecursivetask.h"
-#include "removeitemstask.h"
-#include "retrievecollectionmetadatatask.h"
-#include "retrievecollectionstask.h"
-#include "retrieveitemtask.h"
-#include "retrieveitemstask.h"
-#include "searchtask.h"
-
-#include "settingspasswordrequester.h"
 #include "sessionpool.h"
+#include "settingspasswordrequester.h"
 #include "sessionuiproxy.h"
 
-#include "resourceadaptor.h"
-
-#ifdef MAIL_SERIALIZER_PLUGIN_STATIC
-
-Q_IMPORT_PLUGIN(akonadi_serializer_mail)
-#endif
-
-Q_DECLARE_METATYPE(QList<qint64>)
-Q_DECLARE_METATYPE(QWeakPointer<QObject>)
-
-using namespace Akonadi;
+#include <KWindowSystem>
+#include <KLocalizedString>
 
 ImapResource::ImapResource( const QString &id )
-  : ResourceBase( id ),
-    m_pool( new SessionPool( 2, this ) ),
-    mSubscriptions( 0 ),
-    m_idle( 0 )
+    : ImapResourceBase( id )
 {
-  if ( name() == identifier() ) {
-    const QString agentType = AgentManager::self()->instance( identifier() ).type().identifier();
-    const QString agentsrcFile = KGlobal::dirs()->localxdgconfdir() + QLatin1String("akonadi/agentsrc");
-
-    const QSettings agentsrc( agentsrcFile, QSettings::IniFormat );
-    const int instanceCounter = agentsrc.value(
-                                  QString::fromLatin1( "InstanceCounters/%1/InstanceCounter" ).arg( agentType ),
-                                  -1 ).toInt();
-
-    if ( instanceCounter > 0 ) {
-      setName( QString("%1 %2").arg(defaultName()).arg(instanceCounter) );
-    } else {
-      setName( defaultName() );
-    }
-  }
-
   m_pool->setPasswordRequester( new SettingsPasswordRequester( this, m_pool ) );
   m_pool->setSessionUiProxy( SessionUiProxy::Ptr( new SessionUiProxy ) );
-
-  connect( m_pool, SIGNAL(connectDone(int,QString)),
-           this, SLOT(onConnectDone(int,QString)) );
-  connect( m_pool, SIGNAL(connectionLost(KIMAP::Session*)),
-           this, SLOT(onConnectionLost(KIMAP::Session*)) );
-
-  Akonadi::AttributeFactory::registerAttribute<UidValidityAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<UidNextAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<NoSelectAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<TimestampAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<HighestModSeqAttribute>();
-
-  Akonadi::AttributeFactory::registerAttribute<CollectionAnnotationsAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<CollectionFlagsAttribute>();
-
-  Akonadi::AttributeFactory::registerAttribute<ImapAclAttribute>();
-  Akonadi::AttributeFactory::registerAttribute<ImapQuotaAttribute>();
-
-  // For QMetaObject::invokeMethod()
-  qRegisterMetaType<QList<qint64> >();
-
-  changeRecorder()->fetchCollection( true );
-  changeRecorder()->collectionFetchScope().setAncestorRetrieval( CollectionFetchScope::All );
-  changeRecorder()->collectionFetchScope().setIncludeStatistics( true );
-  changeRecorder()->itemFetchScope().fetchFullPayload( true );
-  changeRecorder()->itemFetchScope().setAncestorRetrieval( ItemFetchScope::All );
-  changeRecorder()->itemFetchScope().setFetchModificationTime( false );
- //(Andras) disable now, as tokoe reported problems with it and the mail filter: changeRecorder()->fetchChangedOnly( true );
-
-  setHierarchicalRemoteIdentifiersEnabled( true );
-  setItemTransactionMode( ItemSync::MultipleTransactions ); // we can recover from incomplete syncs, so we can use a faster mode
-  ItemFetchScope scope( changeRecorder()->itemFetchScope() );
-  scope.fetchFullPayload( false );
-  scope.setAncestorRetrieval( ItemFetchScope::None );
-  setItemSynchronizationFetchScope( scope );
-  setDisableAutomaticItemDeliveryDone( true );
-  setItemSyncBatchSize( 100 );
-
-  connect( this, SIGNAL(reloadConfiguration()), SLOT(reconnect()) );
-
-  Settings::self(); // make sure the D-Bus settings interface is up
-  new ResourceAdaptor( this );
-  setNeedsNetwork( needsNetwork() );
-
-  // Migration issue: trash folder had ID in config, but didn't have SpecialCollections attribute, fix that.
-  if (!Settings::self()->trashCollectionMigrated()) {
-    const Akonadi::Collection::Id trashCollection = Settings::self()->trashCollection();
-    if (trashCollection != -1) {
-      Collection attributeCollection(trashCollection);
-      SpecialCollections::setSpecialCollectionType("trash", attributeCollection);
-    }
-    Settings::self()->setTrashCollectionMigrated(true);
-  }
-
-  m_statusMessageTimer = new QTimer( this );
-  m_statusMessageTimer->setSingleShot( true );
-  connect( m_statusMessageTimer, SIGNAL(timeout()), SLOT(clearStatusMessage()) );
-  connect( this, SIGNAL(error(QString)), SLOT(showError(QString)) );
 }
 
 ImapResource::~ImapResource()
 {
-  //Destroy everything that could cause callbacks immediately, otherwise the callbacks can result in a crash.
-
-  if ( m_idle ) {
-    delete m_idle;
-    m_idle = 0;
-  }
-
-  Q_FOREACH (ResourceTask* task, m_taskList) {
-    delete task;
-  }
-  m_taskList.clear();
-
-  delete m_pool;
 }
 
 QString ImapResource::defaultName()
@@ -200,21 +49,6 @@ QString ImapResource::defaultName()
   return i18n( "IMAP Account" );
 }
 
-void ImapResource::aboutToQuit()
-{
-  //TODO the resource would ideally have to signal when it's done with logging out etc, before the destructor gets called
-  if ( m_idle ) {
-    m_idle->stop();
-  }
-
-  Q_FOREACH (ResourceTask* task, m_taskList) {
-    task->kill();
-  }
-
-  m_pool->disconnect();
-}
-
-// -----------------------------------------------------------------------------
 
 KDialog* ImapResource::createConfigureDialog(WId windowId)
 {
@@ -236,574 +70,3 @@ void ImapResource::onConfigurationDone(int result)
   }
   dlg->deleteLater();
 }
-
-void ImapResource::configure( WId windowId )
-{
-  if ( createConfigureDialog( windowId )->exec() == QDialog::Accepted ) {
-    emit configurationDialogAccepted();
-    reconnect();
-  } else {
-    emit configurationDialogRejected();
-  }
-}
-
-
-
-// ----------------------------------------------------------------------------------
-
-void ImapResource::startConnect( const QVariant& )
-{
-  if ( Settings::self()->imapServer().isEmpty() ) {
-    setOnline( false );
-    emit status( NotConfigured, i18n( "No server configured yet." ) );
-    taskDone();
-    return;
-  }
-
-  m_pool->disconnect(); // reset all state, delete any old account
-  ImapAccount *account = new ImapAccount;
-  Settings::self()->loadAccount( account );
-
-  const bool result = m_pool->connect( account );
-  Q_ASSERT( result );
-  Q_UNUSED( result );
-}
-
-int ImapResource::configureSubscription(qlonglong windowId)
-{
-  if (mSubscriptions)
-     return 0;
-
-  if ( !m_pool->account() )
-     return -2;
-  const QString password = Settings::self()->password();
-  if ( password.isEmpty() )
-     return -1;
-
-  mSubscriptions = new SubscriptionDialog( 0, SubscriptionDialog::AllowToEnableSubscription );
-  if(windowId) {
-#ifndef Q_WS_WIN
-    KWindowSystem::setMainWindow( mSubscriptions, windowId );
-#else
-    KWindowSystem::setMainWindow( mSubscriptions, (HWND)windowId );
-#endif
-  }
-  mSubscriptions->setCaption( i18nc( "@title:window", "Serverside Subscription" ) );
-  mSubscriptions->setWindowIcon( KIcon( QLatin1String("network-server") ) );
-  mSubscriptions->connectAccount( *m_pool->account(), password );
-  mSubscriptions->setSubscriptionEnabled( Settings::self()->subscriptionEnabled() );
-
-  if ( mSubscriptions->exec() ) {
-    Settings::self()->setSubscriptionEnabled( mSubscriptions->subscriptionEnabled() );
-    Settings::self()->writeConfig();
-    emit configurationDialogAccepted();
-    reconnect();
-  }
-  delete mSubscriptions;
-
-  return 0;
-}
-
-void ImapResource::onConnectDone( int errorCode, const QString &errorString )
-{
-  switch ( errorCode ) {
-  case SessionPool::NoError:
-    setOnline( true );
-    taskDone();
-    emit status( Idle, i18n( "Connection established." ) );
-
-    synchronizeCollectionTree();
-    break;
-
-  case SessionPool::PasswordRequestError:
-  case SessionPool::EncryptionError:
-  case SessionPool::LoginFailError:
-  case SessionPool::CapabilitiesTestError:
-  case SessionPool::IncompatibleServerError:
-    setOnline( false );
-    emit status( Broken, errorString );
-    cancelTask();
-    return;
-
-  case SessionPool::CouldNotConnectError:
-    emit status( Idle, i18n( "Server is not available." ) );
-    deferTask();
-    setTemporaryOffline((m_pool->account() && m_pool->account()->timeout() > 0) ? m_pool->account()->timeout() : 300);
-    return;
-
-  case SessionPool::ReconnectNeededError:
-    reconnect();
-    return;
-
-  case SessionPool::NoAvailableSessionError:
-    kFatal() << "Shouldn't happen";
-    return;
-  }
-}
-
-void ImapResource::onConnectionLost( KIMAP::Session */*session*/ )
-{
-  if ( !m_pool->isConnected() ) {
-    reconnect();
-  }
-}
-
-ResourceStateInterface::Ptr ImapResource::createResourceState(const TaskArguments &args)
-{
-  return ResourceStateInterface::Ptr(new ResourceState(this, args));
-}
-
-// ----------------------------------------------------------------------------------
-
-bool ImapResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
-{
-  // The collection name is empty here...
-  //emit status( AgentBase::Running, i18nc( "@info:status", "Retrieving item in '%1'", item.parentCollection().name() ) );
-
-  RetrieveItemTask *task = new RetrieveItemTask( createResourceState(TaskArguments(item, parts)), this );
-  task->start( m_pool );
-  queueTask( task );
-  return true;
-}
-
-void ImapResource::itemAdded( const Item &item, const Collection &collection )
-{
-  emit status( AgentBase::Running, i18nc( "@info:status", "Adding item in '%1'", collection.name() ) );
-
-  startTask(new AddItemTask( createResourceState(TaskArguments(item, collection)), this ));
-}
-
-void ImapResource::itemChanged( const Item &item, const QSet<QByteArray> &parts )
-{
-  emit status( AgentBase::Running, i18nc( "@info:status", "Updating item in '%1'", item.parentCollection().name() ) );
-
-  startTask(new ChangeItemTask( createResourceState(TaskArguments(item, parts)), this ));
-}
-
-void ImapResource::itemsFlagsChanged( const Item::List& items, const QSet< QByteArray >& addedFlags,
-                                      const QSet< QByteArray >& removedFlags )
-{
-  emit status( AgentBase::Running, i18nc( "@info:status", "Updating items" ) );
-
-  startTask(new ChangeItemsFlagsTask( createResourceState(TaskArguments(items, addedFlags, removedFlags)), this ));
-}
-
-void ImapResource::itemsRemoved( const Akonadi::Item::List &items )
-{
-  const QString mailBox = ResourceStateInterface::mailBoxForCollection( items.first().parentCollection(), false );
-  if ( mailBox.isEmpty() ) {
-    // this item will be removed soon by its parent collection
-    changeProcessed();
-    return;
-  }
-
-  emit status( AgentBase::Running, i18nc( "@info:status", "Removing items" ) );
-
-  startTask(new RemoveItemsTask( createResourceState(TaskArguments(items)), this ));
-}
-
-void ImapResource::itemsMoved( const Akonadi::Item::List &items, const Akonadi::Collection &source,
-                               const Akonadi::Collection &destination )
-{
-  if ( items.first().parentCollection() != destination ) { // should have been set by the server
-    kWarning() << "Collections don't match: destination=" << destination.id()
-               << "; items parent=" << items.first().parentCollection().id()
-               << "; source collection=" << source.id();
-    //Q_ASSERT( false );
-    //TODO: Find out why this happens
-    cancelTask();
-    return;
-  }
-
-  emit status( AgentBase::Running, i18nc( "@info:status", "Moving items from '%1' to '%2'", source.name(), destination.name() ) );
-
-  startTask(new MoveItemsTask( createResourceState(TaskArguments(items, source, destination)), this ));
-}
-
-
-
-// ----------------------------------------------------------------------------------
-
-void ImapResource::retrieveCollections()
-{
-  emit status( AgentBase::Running, i18nc( "@info:status", "Retrieving folders" ) );
-
-  startTask(new RetrieveCollectionsTask( createResourceState(TaskArguments()), this ));
-}
-
-void ImapResource::triggerCollectionExtraInfoJobs( const QVariant &collectionVariant )
-{
-  const Collection collection( collectionVariant.value<Collection>() );
-  emit status( AgentBase::Running, i18nc( "@info:status", "Retrieving extra folder information for '%1'", collection.name() ) );
-
-  //The collection that we received is potentially outdated.
-  //Using it would overwrite attributes with old values.
-  //FIXME: because this is async and not part of the resourcetask, it can't be killed. ResourceBase should just provide an up-to date copy of the collection.
-  Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(collection, CollectionFetchJob::Base, this);
-  fetchJob->fetchScope().setAncestorRetrieval( CollectionFetchScope::All );
-  fetchJob->fetchScope().setIncludeStatistics( true );
-  fetchJob->fetchScope().setIncludeUnsubscribed( true );
-  connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onMetadataCollectionFetchDone(KJob*)));
-}
-
-void ImapResource::onMetadataCollectionFetchDone(KJob *job)
-{
-  if (job->error()) {
-    kWarning() << "Failed to retrieve collection before RetrieveCollectionMetadataTask " << job->errorString();
-    cancelTask(i18n("Failed to collection metadata."));
-    return;
-  }
-
-  Akonadi::CollectionFetchJob *fetchJob = static_cast<Akonadi::CollectionFetchJob*>(job);
-  Q_ASSERT(fetchJob->collections().size() == 1);
-
-  startTask(new RetrieveCollectionMetadataTask( createResourceState(TaskArguments(fetchJob->collections().first())), this ));
-}
-
-void ImapResource::retrieveItems( const Collection &col )
-{
-  scheduleCustomTask( this, "triggerCollectionExtraInfoJobs", QVariant::fromValue( col ), ResourceBase::Append );
-
-  //The collection that we receive was fetched when the task was scheduled, it is therefore possible that it is outdated.
-  //We refetch the collection since we rely on up-to-date annotations.
-  //FIXME: because this is async and not part of the resourcetask, it can't be killed. ResourceBase should just provide an up-to date copy of the collection.
-  Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(col, CollectionFetchJob::Base, this);
-  fetchJob->fetchScope().setAncestorRetrieval( CollectionFetchScope::All );
-  fetchJob->fetchScope().setIncludeStatistics( true );
-  fetchJob->fetchScope().setIncludeUnsubscribed( true );
-  connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onItemRetrievalCollectionFetchDone(KJob*)));
-}
-
-void ImapResource::onItemRetrievalCollectionFetchDone(KJob *job)
-{
-  if (job->error()) {
-    kWarning() << "Failed to retrieve collection before RetrieveItemsTask: " << job->errorString();
-    cancelTask(i18n("Failed to retrieve items."));
-    return;
-  }
-
-  Akonadi::CollectionFetchJob *fetchJob = static_cast<Akonadi::CollectionFetchJob*>(job);
-  Q_ASSERT(fetchJob->collections().size() == 1);
-
-  setItemStreamingEnabled( true );
-
-  RetrieveItemsTask *task = new RetrieveItemsTask( createResourceState(TaskArguments(fetchJob->collections().first())), this);
-  connect(task, SIGNAL(status(int,QString)), SIGNAL(status(int,QString)));
-  connect(this, SIGNAL(retrieveNextItemSyncBatch(int)), task, SLOT(onReadyForNextBatch(int)));
-  startTask(task);
-}
-
-void ImapResource::collectionAdded( const Collection & collection, const Collection &parent )
-{
-  emit status( AgentBase::Running, i18nc( "@info:status", "Creating folder '%1'", collection.name() ) );
-  startTask(new AddCollectionTask( createResourceState(TaskArguments(collection, parent)), this ));
-}
-
-void ImapResource::collectionChanged( const Collection &collection, const QSet<QByteArray> &parts )
-{
-  emit status( AgentBase::Running, i18nc( "@info:status", "Updating folder '%1'", collection.name() ) );
-  startTask(new ChangeCollectionTask( createResourceState(TaskArguments(collection, parts)), this ));
-}
-
-void ImapResource::collectionRemoved( const Collection &collection )
-{
-  //TODO Move this to the task
-  const QString mailBox = ResourceStateInterface::mailBoxForCollection( collection, false );
-  if ( mailBox.isEmpty() ) {
-    // this collection will be removed soon by its parent collection
-    changeProcessed();
-    return;
-  }
-  emit status( AgentBase::Running, i18nc( "@info:status", "Removing folder '%1'", collection.name() ) );
-
-  startTask(new RemoveCollectionRecursiveTask( createResourceState(TaskArguments(collection)), this ));
-}
-
-void ImapResource::collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source,
-                                    const Akonadi::Collection &destination )
-{
-  emit status( AgentBase::Running, i18nc( "@info:status", "Moving folder '%1' from '%2' to '%3'",
-        collection.name(), source.name(), destination.name() ) );
-  startTask(new MoveCollectionTask( createResourceState(TaskArguments(collection, source, destination)), this ));
-}
-
-
-
-void ImapResource::addSearch(const QString& query, const QString& queryLanguage, const Collection& resultCollection)
-{
-}
-
-void ImapResource::removeSearch(const Collection& resultCollection)
-{
-}
-
-void ImapResource::search( const QString &query, const Collection &collection )
-{
-  QVariantMap arg;
-  arg[QLatin1String("query")] = query;
-  arg[QLatin1String("collection")] = QVariant::fromValue( collection );
-  scheduleCustomTask( this, "doSearch", arg );
-}
-
-void ImapResource::doSearch( const QVariant &arg )
-{
-  const QVariantMap map = arg.toMap();
-  const QString query = map[QLatin1String("query")].toString();
-  const Collection collection = map[QLatin1String("collection")].value<Collection>();
-
-  emit status( AgentBase::Running, i18nc( "@info:status", "Searching..." ) );
-  startTask(new SearchTask( createResourceState(TaskArguments(collection)), query, this ));
-}
-
-
-// -----
-
-// ----------------------------------------------------------------------------------
-
-void ImapResource::scheduleConnectionAttempt()
-{
-  // block all other tasks, until we are connected
-  scheduleCustomTask( this, "startConnect", QVariant(), ResourceBase::Prepend );
-}
-
-void ImapResource::doSetOnline(bool online)
-{
-#ifndef IMAPRESOURCE_NO_SOLID
-  kDebug() << "online=" << online;
-#endif
-  if ( !online ) {
-    Q_FOREACH(ResourceTask* task, m_taskList) {
-      task->kill();
-      delete task;
-    }
-    m_taskList.clear();
-    m_pool->cancelPasswordRequests();
-    if (m_pool->isConnected()) {
-        m_pool->disconnect();
-    }
-    if (m_idle) {
-      m_idle->stop();
-      delete m_idle;
-      m_idle = 0;
-    }
-    Settings::self()->clearCachedPassword();
-  } else if ( online && !m_pool->isConnected() ) {
-    scheduleConnectionAttempt();
-  }
-  ResourceBase::doSetOnline( online );
-}
-
-QChar ImapResource::separatorCharacter() const
-{
-    return m_separatorCharacter;
-}
-
-void ImapResource::setSeparatorCharacter( const QChar &separator )
-{
-    m_separatorCharacter = separator;
-}
-
-bool ImapResource::needsNetwork() const
-{
-  const QString hostName = Settings::self()->imapServer().section( QLatin1Char(':'), 0, 0 );
-  // ### is there a better way to do this?
-  if ( hostName == QLatin1String( "127.0.0.1" ) ||
-       hostName == QLatin1String( "localhost" ) ||
-       hostName == QHostInfo::localHostName() ) {
-    return false;
-  }
-  return true;
-}
-
-void ImapResource::reconnect()
-{
-  setNeedsNetwork( needsNetwork() );
-  setOnline( false ); // we are not connected initially
-  setOnline( true );
-}
-
-
-
-// ----------------------------------------------------------------------------------
-
-void ImapResource::startIdleIfNeeded()
-{
-  if ( !m_idle ) {
-    startIdle();
-  }
-}
-
-void ImapResource::startIdle()
-{
-  delete m_idle;
-  m_idle = 0;
-
-  if ( !m_pool->serverCapabilities().contains( QLatin1String("IDLE") ) )
-    return;
-
-  //Without password we don't even have to try
-  if (Settings::self()->password().isEmpty()) {
-    return;
-  }
-
-  const QStringList ridPath = Settings::self()->idleRidPath();
-  if ( ridPath.size() < 2 )
-    return;
-
-  Collection c, p;
-  p.setParentCollection( Collection::root() );
-  for ( int i = ridPath.size() - 1; i > 0; --i ) {
-    p.setRemoteId( ridPath.at( i ) );
-    c.setParentCollection( p );
-    p = c;
-  }
-  c.setRemoteId( ridPath.first() );
-
-  Akonadi::CollectionFetchScope scope;
-  scope.setResource( identifier() );
-  scope.setAncestorRetrieval( Akonadi::CollectionFetchScope::All );
-
-  Akonadi::CollectionFetchJob *fetch
-    = new Akonadi::CollectionFetchJob( c, Akonadi::CollectionFetchJob::Base, this );
-  fetch->setFetchScope( scope );
-
-  connect( fetch, SIGNAL(result(KJob*)),
-           this, SLOT(onIdleCollectionFetchDone(KJob*)) );
-}
-
-void ImapResource::onIdleCollectionFetchDone( KJob *job )
-{
-  if (job->error()) {
-    kWarning() << "CollectionFetch for idling failed."
-               << "error=" << job->error()
-               << ", errorString=" << job->errorString();
-    return;
-  }
-  Akonadi::CollectionFetchJob *fetch = static_cast<Akonadi::CollectionFetchJob*>(job);
-  //Can be empty if collection is not subscribed locally
-  if (!fetch->collections().isEmpty()) {
-    m_idle = new ImapIdleManager( createResourceState(TaskArguments(fetch->collections().first())), m_pool, this );
-  }
-}
-
-
-
-// ----------------------------------------------------------------------------------
-
-void ImapResource::requestManualExpunge( qint64 collectionId )
-{
-  if ( !Settings::self()->automaticExpungeEnabled() ) {
-    Collection collection( collectionId );
-
-    Akonadi::CollectionFetchScope scope;
-    scope.setResource( identifier() );
-    scope.setAncestorRetrieval( Akonadi::CollectionFetchScope::All );
-    scope.setIncludeUnsubscribed( true );
-
-    Akonadi::CollectionFetchJob *fetch
-      = new Akonadi::CollectionFetchJob( collection,
-                                         Akonadi::CollectionFetchJob::Base,
-                                         this );
-    fetch->setFetchScope( scope );
-
-    connect( fetch, SIGNAL(result(KJob*)),
-             this, SLOT(onExpungeCollectionFetchDone(KJob*)) );
-  }
-}
-
-void ImapResource::onExpungeCollectionFetchDone( KJob *job )
-{
-  if ( job->error() == 0 ) {
-    Akonadi::CollectionFetchJob *fetch = static_cast<Akonadi::CollectionFetchJob*>( job );
-    Akonadi::Collection collection = fetch->collections().first();
-
-    scheduleCustomTask( this, "triggerCollectionExpunge",
-                        QVariant::fromValue( collection ) );
-
-  } else {
-    kWarning() << "CollectionFetch for expunge failed."
-               << "error=" << job->error()
-               << ", errorString=" << job->errorString();
-  }
-}
-
-void ImapResource::triggerCollectionExpunge( const QVariant &collectionVariant )
-{
-  const Collection collection = collectionVariant.value<Collection>();
-
-  ExpungeCollectionTask *task = new ExpungeCollectionTask( createResourceState(TaskArguments(collection)), this );
-  task->start( m_pool );
-  queueTask( task );
-}
-
-
-
-// ----------------------------------------------------------------------------------
-
-void ImapResource::abortActivity()
-{
-  if ( !m_taskList.isEmpty() ) {
-    m_pool->disconnect( SessionPool::CloseSession );
-    scheduleConnectionAttempt();
-  }
-}
-
-void ImapResource::queueTask( ResourceTask *task )
-{
-  connect( task, SIGNAL(destroyed(QObject*)),
-           this, SLOT(taskDestroyed(QObject*)) );
-  m_taskList << task;
-}
-
-void ImapResource::startTask( ResourceTask* task )
-{
-  task->start(m_pool);
-  queueTask(task);
-}
-
-void ImapResource::taskDestroyed( QObject *task )
-{
-  m_taskList.removeAll( static_cast<ResourceTask *>( task ) );
-}
-
-
-QStringList ImapResource::serverCapabilities() const
-{
-  return m_pool->serverCapabilities();
-}
-
-QString ImapResource::dumpResourceToString() const
-{
-  QString ret;
-  Q_FOREACH(ResourceTask* task, m_taskList) {
-    if (!ret.isEmpty())
-      ret += QLatin1String(", ");
-    ret += QLatin1String(task->metaObject()->className());
-  }
-  return QLatin1String("IMAP tasks: ") + ret;
-}
-
-void ImapResource::showError( const QString &message )
-{
-  emit status( Akonadi::AgentBase::Idle, message );
-  m_statusMessageTimer->start( 1000*10 );
-}
-
-void ImapResource::clearStatusMessage()
-{
-  emit status( Akonadi::AgentBase::Idle, QString() );
-}
-
-void ImapResource::modifyCollection(const Collection &col)
-{
-    Akonadi::CollectionModifyJob *modJob = new Akonadi::CollectionModifyJob(col, this);
-    connect(modJob, SIGNAL(result(KJob*)), this, SLOT(onCollectionModifyDone(KJob*)));
-}
-
-void ImapResource::onCollectionModifyDone(KJob* job)
-{
-    if (job->error()) {
-        kWarning() << "Failed to modify collection: " << job->errorString();
-    }
-}
-
diff --git a/resources/imap/imapresource.h b/resources/imap/imapresource.h
index 0364a00..43e3892 100644
--- a/resources/imap/imapresource.h
+++ b/resources/imap/imapresource.h
@@ -23,144 +23,27 @@
     02110-1301, USA.
 */
 
-#ifndef RESOURCES_IMAP_IMAPRESOURCE_H
-#define RESOURCES_IMAP_IMAPRESOURCE_H
+#ifndef IMAPRESOURCE_H
+#define IMAPRESOURCE_H
 
-#include <akonadi/resourcebase.h>
-#include <akonadi/agentsearchinterface.h>
-#include <KDialog>
-#include <QPointer>
-#include "resourcestateinterface.h"
-#include "resourcestate.h"
+#include <imapresourcebase.h>
 
-class QTimer;
-
-class ResourceTask;
-namespace KIMAP
+class ImapResource : public ImapResourceBase
 {
-  class Session;
-}
-
-class ImapIdleManager;
-class SessionPool;
-class ResourceState;
-class SubscriptionDialog;
-
-class ImapResource : public Akonadi::ResourceBase,
-                     public Akonadi::AgentBase::ObserverV3,
-                     public Akonadi::AgentSearchInterface
-{
-  Q_OBJECT
-  Q_CLASSINFO( "D-Bus Interface", "org.kde.Akonadi.Imap.Resource" )
-protected:
-  using Akonadi::AgentBase::Observer::collectionChanged;
+    Q_OBJECT
+    Q_CLASSINFO( "D-Bus Interface", "org.kde.Akonadi.Imap.Resource" )
 
 public:
-  explicit ImapResource( const QString &id );
-  ~ImapResource();
-
-
-  KDialog *createConfigureDialog( WId windowId );
-  QStringList serverCapabilities() const;
-
-public Q_SLOTS:
-  virtual void configure( WId windowId );
-
-  // DBus methods
-  Q_SCRIPTABLE void requestManualExpunge( qint64 collectionId );
-  Q_SCRIPTABLE int configureSubscription( qlonglong windowId = 0 );
+    explicit ImapResource( const QString &id );
+    virtual ~ImapResource();
 
-  // pseudo-virtual called by ResourceBase
-  QString dumpResourceToString() const;
-
-protected Q_SLOTS:
-  void startIdleIfNeeded();
-  void startIdle();
-
-  void abortActivity();
-
-  virtual void retrieveCollections();
-
-  virtual void retrieveItems( const Akonadi::Collection &col );
-  virtual bool retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts );
+    virtual KDialog *createConfigureDialog ( WId windowId );
 
 protected:
-  virtual void itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection );
-  virtual void itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts );
-  virtual void itemsFlagsChanged( const Akonadi::Item::List &items, const QSet<QByteArray> &addedFlags, const QSet<QByteArray> &removedFlags );
-  virtual void itemsRemoved( const Akonadi::Item::List &items );
-  virtual void itemsMoved( const Akonadi::Item::List &item, const Akonadi::Collection &source,
-                           const Akonadi::Collection &destination );
-
-
-  virtual void collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent );
-  virtual void collectionChanged( const Akonadi::Collection &collection, const QSet<QByteArray> &parts );
-  virtual void collectionRemoved( const Akonadi::Collection &collection );
-  virtual void collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source,
-                                const Akonadi::Collection &destination );
-
-  virtual void addSearch( const QString &query, const QString &queryLanguage, const Akonadi::Collection &resultCollection );
-  virtual void removeSearch( const Akonadi::Collection &resultCollection );
-  virtual void search( const QString &query, const Akonadi::Collection &collection );
-
-  virtual void doSetOnline(bool online);
-
-  QChar separatorCharacter() const;
-  void setSeparatorCharacter( const QChar &separator );
-
-  virtual void aboutToQuit();
-
-  virtual ResourceStateInterface::Ptr createResourceState(const TaskArguments &);
-  virtual QString defaultName();
+    virtual QString defaultName() const;
 
 private Q_SLOTS:
-  void doSearch( const QVariant &arg );
-
-  void reconnect();
-
-  void scheduleConnectionAttempt();
-  void startConnect( const QVariant & ); // the parameter is necessary, since this method is used by the task scheduler
-  void onConnectDone( int errorCode, const QString &errorMessage );
-  void onConnectionLost( KIMAP::Session *session );
-
-
-  void onIdleCollectionFetchDone( KJob *job );
-  void onItemRetrievalCollectionFetchDone( KJob *job );
-  void onMetadataCollectionFetchDone( KJob *job );
-
-  void onExpungeCollectionFetchDone( KJob *job );
-  void triggerCollectionExpunge( const QVariant &collectionVariant );
-
-
-  void triggerCollectionExtraInfoJobs( const QVariant &collection );
-
-  void taskDestroyed( QObject *task );
-
-  void showError( const QString &message );
-  void clearStatusMessage();
-
-  void onConfigurationDone( int result );
-  void onCollectionModifyDone( KJob *job );
-
-protected:
-  //Starts and queues a task
-  void startTask( ResourceTask *task );
-  void queueTask( ResourceTask *task );
-  SessionPool *m_pool;
-
-private:
-  friend class ResourceState;
-
-  bool needsNetwork() const;
-  void modifyCollection(const Akonadi::Collection &);
-
-  friend class ImapIdleManager;
-
-  QList<ResourceTask*> m_taskList; //used to be able to kill tasks
-  QPointer<SubscriptionDialog> mSubscriptions;
-  ImapIdleManager *m_idle;
-  QTimer *m_statusMessageTimer;
-  QChar m_separatorCharacter;
+    void onConfigurationDone( int result );
 };
 
-#endif
+#endif // IMAPRESOURCE_H
diff --git a/resources/imap/imapresourcebase.cpp b/resources/imap/imapresourcebase.cpp
new file mode 100644
index 0000000..fabe7e6
--- /dev/null
+++ b/resources/imap/imapresourcebase.cpp
@@ -0,0 +1,788 @@
+/*
+    Copyright (c) 2007 Till Adam <adam at kde.org>
+    Copyright (C) 2008 Omat Holding B.V. <info at omat.nl>
+    Copyright (C) 2009 Kevin Ottens <ervin at kde.org>
+
+    Copyright (c) 2010 Klarälvdalens Datakonsult AB,
+                       a KDAB Group company <info at kdab.com>
+    Author: Kevin Ottens <kevin at kdab.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#include "imapresourcebase.h"
+
+#include <QHostInfo>
+#include <QSettings>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kwindowsystem.h>
+#include <Akonadi/CollectionModifyJob>
+
+#include <akonadi/agentmanager.h>
+#include <akonadi/attributefactory.h>
+#include <akonadi/collectionfetchjob.h>
+#include <akonadi/collectionfetchscope.h>
+#include <akonadi/changerecorder.h>
+#include <akonadi/itemfetchscope.h>
+#include <akonadi/itemfetchjob.h>
+#include <akonadi/specialcollections.h>
+#include <akonadi/session.h>
+#include <akonadi/kmime/messageparts.h>
+
+#include "collectionannotationsattribute.h"
+#include "collectionflagsattribute.h"
+#include "imapaclattribute.h"
+#include "imapquotaattribute.h"
+#include "noselectattribute.h"
+#include "timestampattribute.h"
+#include "uidvalidityattribute.h"
+#include "uidnextattribute.h"
+#include "highestmodseqattribute.h"
+
+#include "settings.h"
+#include "imapaccount.h"
+#include "imapidlemanager.h"
+#include "resourcestate.h"
+#include "subscriptiondialog.h"
+
+#include "addcollectiontask.h"
+#include "additemtask.h"
+#include "changecollectiontask.h"
+#include "changeitemsflagstask.h"
+#include "changeitemtask.h"
+#include "expungecollectiontask.h"
+#include "movecollectiontask.h"
+#include "moveitemstask.h"
+#include "removecollectionrecursivetask.h"
+#include "removeitemstask.h"
+#include "retrievecollectionmetadatatask.h"
+#include "retrievecollectionstask.h"
+#include "retrieveitemtask.h"
+#include "retrieveitemstask.h"
+#include "searchtask.h"
+
+#include "settingspasswordrequester.h"
+#include "sessionpool.h"
+#include "sessionuiproxy.h"
+
+#include "resourceadaptor.h"
+
+#ifdef MAIL_SERIALIZER_PLUGIN_STATIC
+
+Q_IMPORT_PLUGIN(akonadi_serializer_mail)
+#endif
+
+Q_DECLARE_METATYPE(QList<qint64>)
+Q_DECLARE_METATYPE(QWeakPointer<QObject>)
+
+using namespace Akonadi;
+
+ImapResourceBase::ImapResourceBase( const QString &id )
+  : ResourceBase( id ),
+    m_pool( new SessionPool( 2, this ) ),
+    mSubscriptions( 0 ),
+    m_idle( 0 )
+{
+  QTimer::singleShot( 0, this, SLOT(updateResourceName()) );
+
+  connect( m_pool, SIGNAL(connectDone(int,QString)),
+           this, SLOT(onConnectDone(int,QString)) );
+  connect( m_pool, SIGNAL(connectionLost(KIMAP::Session*)),
+           this, SLOT(onConnectionLost(KIMAP::Session*)) );
+
+  Akonadi::AttributeFactory::registerAttribute<UidValidityAttribute>();
+  Akonadi::AttributeFactory::registerAttribute<UidNextAttribute>();
+  Akonadi::AttributeFactory::registerAttribute<NoSelectAttribute>();
+  Akonadi::AttributeFactory::registerAttribute<TimestampAttribute>();
+  Akonadi::AttributeFactory::registerAttribute<HighestModSeqAttribute>();
+
+  Akonadi::AttributeFactory::registerAttribute<CollectionAnnotationsAttribute>();
+  Akonadi::AttributeFactory::registerAttribute<CollectionFlagsAttribute>();
+
+  Akonadi::AttributeFactory::registerAttribute<ImapAclAttribute>();
+  Akonadi::AttributeFactory::registerAttribute<ImapQuotaAttribute>();
+
+  // For QMetaObject::invokeMethod()
+  qRegisterMetaType<QList<qint64> >();
+
+  changeRecorder()->fetchCollection( true );
+  changeRecorder()->collectionFetchScope().setAncestorRetrieval( CollectionFetchScope::All );
+  changeRecorder()->collectionFetchScope().setIncludeStatistics( true );
+  changeRecorder()->itemFetchScope().fetchFullPayload( true );
+  changeRecorder()->itemFetchScope().setAncestorRetrieval( ItemFetchScope::All );
+  changeRecorder()->itemFetchScope().setFetchModificationTime( false );
+ //(Andras) disable now, as tokoe reported problems with it and the mail filter: changeRecorder()->fetchChangedOnly( true );
+
+  setHierarchicalRemoteIdentifiersEnabled( true );
+  setItemTransactionMode( ItemSync::MultipleTransactions ); // we can recover from incomplete syncs, so we can use a faster mode
+  ItemFetchScope scope( changeRecorder()->itemFetchScope() );
+  scope.fetchFullPayload( false );
+  scope.setAncestorRetrieval( ItemFetchScope::None );
+  setItemSynchronizationFetchScope( scope );
+  setDisableAutomaticItemDeliveryDone( true );
+  setItemSyncBatchSize( 100 );
+
+  connect( this, SIGNAL(reloadConfiguration()), SLOT(reconnect()) );
+
+  Settings::self(); // make sure the D-Bus settings interface is up
+  new ImapResourceBaseAdaptor( this );
+  setNeedsNetwork( needsNetwork() );
+
+  // Migration issue: trash folder had ID in config, but didn't have SpecialCollections attribute, fix that.
+  if (!Settings::self()->trashCollectionMigrated()) {
+    const Akonadi::Collection::Id trashCollection = Settings::self()->trashCollection();
+    if (trashCollection != -1) {
+      Collection attributeCollection(trashCollection);
+      SpecialCollections::setSpecialCollectionType("trash", attributeCollection);
+    }
+    Settings::self()->setTrashCollectionMigrated(true);
+  }
+
+  m_statusMessageTimer = new QTimer( this );
+  m_statusMessageTimer->setSingleShot( true );
+  connect( m_statusMessageTimer, SIGNAL(timeout()), SLOT(clearStatusMessage()) );
+  connect( this, SIGNAL(error(QString)), SLOT(showError(QString)) );
+}
+
+ImapResourceBase::~ImapResourceBase()
+{
+  //Destroy everything that could cause callbacks immediately, otherwise the callbacks can result in a crash.
+
+  if ( m_idle ) {
+    delete m_idle;
+    m_idle = 0;
+  }
+
+  Q_FOREACH (ResourceTask* task, m_taskList) {
+    delete task;
+  }
+  m_taskList.clear();
+
+  delete m_pool;
+}
+
+void ImapResourceBase::aboutToQuit()
+{
+  //TODO the resource would ideally have to signal when it's done with logging out etc, before the destructor gets called
+  if ( m_idle ) {
+    m_idle->stop();
+  }
+
+  Q_FOREACH (ResourceTask* task, m_taskList) {
+    task->kill();
+  }
+
+  m_pool->disconnect();
+}
+
+void ImapResourceBase::updateResourceName()
+{
+  if ( name() == identifier() ) {
+    const QString agentType = AgentManager::self()->instance( identifier() ).type().identifier();
+    const QString agentsrcFile = KGlobal::dirs()->localxdgconfdir() + QLatin1String("akonadi/agentsrc");
+
+    const QSettings agentsrc( agentsrcFile, QSettings::IniFormat );
+    const int instanceCounter = agentsrc.value(
+                                  QString::fromLatin1( "InstanceCounters/%1/InstanceCounter" ).arg( agentType ),
+                                  -1 ).toInt();
+
+    if ( instanceCounter > 0 ) {
+      setName( QString("%1 %2").arg(defaultName()).arg(instanceCounter) );
+    } else {
+      setName( defaultName() );
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+
+void ImapResourceBase::configure( WId windowId )
+{
+  if ( createConfigureDialog( windowId )->exec() == QDialog::Accepted ) {
+    emit configurationDialogAccepted();
+    reconnect();
+  } else {
+    emit configurationDialogRejected();
+  }
+}
+
+// ----------------------------------------------------------------------------------
+
+void ImapResourceBase::startConnect( const QVariant& )
+{
+  if ( Settings::self()->imapServer().isEmpty() ) {
+    setOnline( false );
+    emit status( NotConfigured, i18n( "No server configured yet." ) );
+    taskDone();
+    return;
+  }
+
+  m_pool->disconnect(); // reset all state, delete any old account
+  ImapAccount *account = new ImapAccount;
+  Settings::self()->loadAccount( account );
+
+  const bool result = m_pool->connect( account );
+  Q_ASSERT( result );
+  Q_UNUSED( result );
+}
+
+int ImapResourceBase::configureSubscription(qlonglong windowId)
+{
+  if (mSubscriptions)
+     return 0;
+
+  if ( !m_pool->account() )
+     return -2;
+  const QString password = Settings::self()->password();
+  if ( password.isEmpty() )
+     return -1;
+
+  mSubscriptions = new SubscriptionDialog( 0, SubscriptionDialog::AllowToEnableSubscription );
+  if(windowId) {
+#ifndef Q_WS_WIN
+    KWindowSystem::setMainWindow( mSubscriptions, windowId );
+#else
+    KWindowSystem::setMainWindow( mSubscriptions, (HWND)windowId );
+#endif
+  }
+  mSubscriptions->setCaption( i18nc( "@title:window", "Serverside Subscription" ) );
+  mSubscriptions->setWindowIcon( KIcon( QLatin1String("network-server") ) );
+  mSubscriptions->connectAccount( *m_pool->account(), password );
+  mSubscriptions->setSubscriptionEnabled( Settings::self()->subscriptionEnabled() );
+
+  if ( mSubscriptions->exec() ) {
+    Settings::self()->setSubscriptionEnabled( mSubscriptions->subscriptionEnabled() );
+    Settings::self()->writeConfig();
+    emit configurationDialogAccepted();
+    reconnect();
+  }
+  delete mSubscriptions;
+
+  return 0;
+}
+
+void ImapResourceBase::onConnectDone( int errorCode, const QString &errorString )
+{
+  switch ( errorCode ) {
+  case SessionPool::NoError:
+    setOnline( true );
+    taskDone();
+    emit status( Idle, i18n( "Connection established." ) );
+
+    synchronizeCollectionTree();
+    break;
+
+  case SessionPool::PasswordRequestError:
+  case SessionPool::EncryptionError:
+  case SessionPool::LoginFailError:
+  case SessionPool::CapabilitiesTestError:
+  case SessionPool::IncompatibleServerError:
+    setOnline( false );
+    emit status( Broken, errorString );
+    cancelTask();
+    return;
+
+  case SessionPool::CouldNotConnectError:
+    emit status( Idle, i18n( "Server is not available." ) );
+    deferTask();
+    setTemporaryOffline((m_pool->account() && m_pool->account()->timeout() > 0) ? m_pool->account()->timeout() : 300);
+    return;
+
+  case SessionPool::ReconnectNeededError:
+    reconnect();
+    return;
+
+  case SessionPool::NoAvailableSessionError:
+    kFatal() << "Shouldn't happen";
+    return;
+  }
+}
+
+void ImapResourceBase::onConnectionLost( KIMAP::Session */*session*/ )
+{
+  if ( !m_pool->isConnected() ) {
+    reconnect();
+  }
+}
+
+ResourceStateInterface::Ptr ImapResourceBase::createResourceState(const TaskArguments &args)
+{
+  return ResourceStateInterface::Ptr(new ResourceState(this, args));
+}
+
+// ----------------------------------------------------------------------------------
+
+bool ImapResourceBase::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
+{
+  // The collection name is empty here...
+  //emit status( AgentBase::Running, i18nc( "@info:status", "Retrieving item in '%1'", item.parentCollection().name() ) );
+
+  RetrieveItemTask *task = new RetrieveItemTask( createResourceState(TaskArguments(item, parts)), this );
+  task->start( m_pool );
+  queueTask( task );
+  return true;
+}
+
+void ImapResourceBase::itemAdded( const Item &item, const Collection &collection )
+{
+  emit status( AgentBase::Running, i18nc( "@info:status", "Adding item in '%1'", collection.name() ) );
+
+  startTask(new AddItemTask( createResourceState(TaskArguments(item, collection)), this ));
+}
+
+void ImapResourceBase::itemChanged( const Item &item, const QSet<QByteArray> &parts )
+{
+  emit status( AgentBase::Running, i18nc( "@info:status", "Updating item in '%1'", item.parentCollection().name() ) );
+
+  startTask(new ChangeItemTask( createResourceState(TaskArguments(item, parts)), this ));
+}
+
+void ImapResourceBase::itemsFlagsChanged( const Item::List& items, const QSet< QByteArray >& addedFlags,
+                                      const QSet< QByteArray >& removedFlags )
+{
+  emit status( AgentBase::Running, i18nc( "@info:status", "Updating items" ) );
+
+  startTask(new ChangeItemsFlagsTask( createResourceState(TaskArguments(items, addedFlags, removedFlags)), this ));
+}
+
+void ImapResourceBase::itemsRemoved( const Akonadi::Item::List &items )
+{
+  const QString mailBox = ResourceStateInterface::mailBoxForCollection( items.first().parentCollection(), false );
+  if ( mailBox.isEmpty() ) {
+    // this item will be removed soon by its parent collection
+    changeProcessed();
+    return;
+  }
+
+  emit status( AgentBase::Running, i18nc( "@info:status", "Removing items" ) );
+
+  startTask(new RemoveItemsTask( createResourceState(TaskArguments(items)), this ));
+}
+
+void ImapResourceBase::itemsMoved( const Akonadi::Item::List &items, const Akonadi::Collection &source,
+                               const Akonadi::Collection &destination )
+{
+  if ( items.first().parentCollection() != destination ) { // should have been set by the server
+    kWarning() << "Collections don't match: destination=" << destination.id()
+               << "; items parent=" << items.first().parentCollection().id()
+               << "; source collection=" << source.id();
+    //Q_ASSERT( false );
+    //TODO: Find out why this happens
+    cancelTask();
+    return;
+  }
+
+  emit status( AgentBase::Running, i18nc( "@info:status", "Moving items from '%1' to '%2'", source.name(), destination.name() ) );
+
+  startTask(new MoveItemsTask( createResourceState(TaskArguments(items, source, destination)), this ));
+}
+
+
+
+// ----------------------------------------------------------------------------------
+
+void ImapResourceBase::retrieveCollections()
+{
+  emit status( AgentBase::Running, i18nc( "@info:status", "Retrieving folders" ) );
+
+  startTask(new RetrieveCollectionsTask( createResourceState(TaskArguments()), this ));
+}
+
+void ImapResourceBase::triggerCollectionExtraInfoJobs( const QVariant &collectionVariant )
+{
+  const Collection collection( collectionVariant.value<Collection>() );
+  emit status( AgentBase::Running, i18nc( "@info:status", "Retrieving extra folder information for '%1'", collection.name() ) );
+
+  //The collection that we received is potentially outdated.
+  //Using it would overwrite attributes with old values.
+  //FIXME: because this is async and not part of the resourcetask, it can't be killed. ResourceBase should just provide an up-to date copy of the collection.
+  Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(collection, CollectionFetchJob::Base, this);
+  fetchJob->fetchScope().setAncestorRetrieval( CollectionFetchScope::All );
+  fetchJob->fetchScope().setIncludeStatistics( true );
+  fetchJob->fetchScope().setIncludeUnsubscribed( true );
+  connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onMetadataCollectionFetchDone(KJob*)));
+}
+
+void ImapResourceBase::onMetadataCollectionFetchDone(KJob *job)
+{
+  if (job->error()) {
+    kWarning() << "Failed to retrieve collection before RetrieveCollectionMetadataTask " << job->errorString();
+    cancelTask(i18n("Failed to collect metadata."));
+    return;
+  }
+
+  Akonadi::CollectionFetchJob *fetchJob = static_cast<Akonadi::CollectionFetchJob*>(job);
+  Q_ASSERT(fetchJob->collections().size() == 1);
+
+  startTask(new RetrieveCollectionMetadataTask( createResourceState(TaskArguments(fetchJob->collections().first())), this ));
+}
+
+void ImapResourceBase::retrieveItems( const Collection &col )
+{
+  scheduleCustomTask( this, "triggerCollectionExtraInfoJobs", QVariant::fromValue( col ), ResourceBase::Append );
+
+  //The collection that we receive was fetched when the task was scheduled, it is therefore possible that it is outdated.
+  //We refetch the collection since we rely on up-to-date annotations.
+  //FIXME: because this is async and not part of the resourcetask, it can't be killed. ResourceBase should just provide an up-to date copy of the collection.
+  Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(col, CollectionFetchJob::Base, this);
+  fetchJob->fetchScope().setAncestorRetrieval( CollectionFetchScope::All );
+  fetchJob->fetchScope().setIncludeStatistics( true );
+  fetchJob->fetchScope().setIncludeUnsubscribed( true );
+  connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onItemRetrievalCollectionFetchDone(KJob*)));
+}
+
+void ImapResourceBase::onItemRetrievalCollectionFetchDone(KJob *job)
+{
+  if (job->error()) {
+    kWarning() << "Failed to retrieve collection before RetrieveItemsTask: " << job->errorString();
+    cancelTask(i18n("Failed to retrieve items."));
+    return;
+  }
+
+  Akonadi::CollectionFetchJob *fetchJob = static_cast<Akonadi::CollectionFetchJob*>(job);
+  Q_ASSERT(fetchJob->collections().size() == 1);
+
+  setItemStreamingEnabled( true );
+
+  RetrieveItemsTask *task = new RetrieveItemsTask( createResourceState(TaskArguments(fetchJob->collections().first())), this);
+  connect(task, SIGNAL(status(int,QString)), SIGNAL(status(int,QString)));
+  connect(this, SIGNAL(retrieveNextItemSyncBatch(int)), task, SLOT(onReadyForNextBatch(int)));
+  startTask(task);
+}
+
+void ImapResourceBase::collectionAdded( const Collection & collection, const Collection &parent )
+{
+  emit status( AgentBase::Running, i18nc( "@info:status", "Creating folder '%1'", collection.name() ) );
+  startTask(new AddCollectionTask( createResourceState(TaskArguments(collection, parent)), this ));
+}
+
+void ImapResourceBase::collectionChanged( const Collection &collection, const QSet<QByteArray> &parts )
+{
+  emit status( AgentBase::Running, i18nc( "@info:status", "Updating folder '%1'", collection.name() ) );
+  startTask(new ChangeCollectionTask( createResourceState(TaskArguments(collection, parts)), this ));
+}
+
+void ImapResourceBase::collectionRemoved( const Collection &collection )
+{
+  //TODO Move this to the task
+  const QString mailBox = ResourceStateInterface::mailBoxForCollection( collection, false );
+  if ( mailBox.isEmpty() ) {
+    // this collection will be removed soon by its parent collection
+    changeProcessed();
+    return;
+  }
+  emit status( AgentBase::Running, i18nc( "@info:status", "Removing folder '%1'", collection.name() ) );
+
+  startTask(new RemoveCollectionRecursiveTask( createResourceState(TaskArguments(collection)), this ));
+}
+
+void ImapResourceBase::collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source,
+                                    const Akonadi::Collection &destination )
+{
+  emit status( AgentBase::Running, i18nc( "@info:status", "Moving folder '%1' from '%2' to '%3'",
+        collection.name(), source.name(), destination.name() ) );
+  startTask(new MoveCollectionTask( createResourceState(TaskArguments(collection, source, destination)), this ));
+}
+
+
+
+void ImapResourceBase::addSearch(const QString& query, const QString& queryLanguage, const Collection& resultCollection)
+{
+}
+
+void ImapResourceBase::removeSearch(const Collection& resultCollection)
+{
+}
+
+void ImapResourceBase::search( const QString &query, const Collection &collection )
+{
+  QVariantMap arg;
+  arg[QLatin1String("query")] = query;
+  arg[QLatin1String("collection")] = QVariant::fromValue( collection );
+  scheduleCustomTask( this, "doSearch", arg );
+}
+
+void ImapResourceBase::doSearch( const QVariant &arg )
+{
+  const QVariantMap map = arg.toMap();
+  const QString query = map[QLatin1String("query")].toString();
+  const Collection collection = map[QLatin1String("collection")].value<Collection>();
+
+  emit status( AgentBase::Running, i18nc( "@info:status", "Searching..." ) );
+  startTask(new SearchTask( createResourceState(TaskArguments(collection)), query, this ));
+}
+
+
+// -----
+
+// ----------------------------------------------------------------------------------
+
+void ImapResourceBase::scheduleConnectionAttempt()
+{
+  // block all other tasks, until we are connected
+  scheduleCustomTask( this, "startConnect", QVariant(), ResourceBase::Prepend );
+}
+
+void ImapResourceBase::doSetOnline(bool online)
+{
+#ifndef IMAPRESOURCE_NO_SOLID
+  kDebug() << "online=" << online;
+#endif
+  if ( !online ) {
+    Q_FOREACH(ResourceTask* task, m_taskList) {
+      task->kill();
+      delete task;
+    }
+    m_taskList.clear();
+    m_pool->cancelPasswordRequests();
+    if (m_pool->isConnected()) {
+        m_pool->disconnect();
+    }
+    if (m_idle) {
+      m_idle->stop();
+      delete m_idle;
+      m_idle = 0;
+    }
+    Settings::self()->clearCachedPassword();
+  } else if ( online && !m_pool->isConnected() ) {
+    scheduleConnectionAttempt();
+  }
+  ResourceBase::doSetOnline( online );
+}
+
+QChar ImapResourceBase::separatorCharacter() const
+{
+    return m_separatorCharacter;
+}
+
+void ImapResourceBase::setSeparatorCharacter( const QChar &separator )
+{
+    m_separatorCharacter = separator;
+}
+
+bool ImapResourceBase::needsNetwork() const
+{
+  const QString hostName = Settings::self()->imapServer().section( QLatin1Char(':'), 0, 0 );
+  // ### is there a better way to do this?
+  if ( hostName == QLatin1String( "127.0.0.1" ) ||
+       hostName == QLatin1String( "localhost" ) ||
+       hostName == QHostInfo::localHostName() ) {
+    return false;
+  }
+  return true;
+}
+
+void ImapResourceBase::reconnect()
+{
+  setNeedsNetwork( needsNetwork() );
+  setOnline( false ); // we are not connected initially
+  setOnline( true );
+}
+
+
+
+// ----------------------------------------------------------------------------------
+
+void ImapResourceBase::startIdleIfNeeded()
+{
+  if ( !m_idle ) {
+    startIdle();
+  }
+}
+
+void ImapResourceBase::startIdle()
+{
+  delete m_idle;
+  m_idle = 0;
+
+  if ( !m_pool->serverCapabilities().contains( QLatin1String("IDLE") ) )
+    return;
+
+  //Without password we don't even have to try
+  if (Settings::self()->password().isEmpty()) {
+    return;
+  }
+
+  const QStringList ridPath = Settings::self()->idleRidPath();
+  if ( ridPath.size() < 2 )
+    return;
+
+  Collection c, p;
+  p.setParentCollection( Collection::root() );
+  for ( int i = ridPath.size() - 1; i > 0; --i ) {
+    p.setRemoteId( ridPath.at( i ) );
+    c.setParentCollection( p );
+    p = c;
+  }
+  c.setRemoteId( ridPath.first() );
+
+  Akonadi::CollectionFetchScope scope;
+  scope.setResource( identifier() );
+  scope.setAncestorRetrieval( Akonadi::CollectionFetchScope::All );
+
+  Akonadi::CollectionFetchJob *fetch
+    = new Akonadi::CollectionFetchJob( c, Akonadi::CollectionFetchJob::Base, this );
+  fetch->setFetchScope( scope );
+
+  connect( fetch, SIGNAL(result(KJob*)),
+           this, SLOT(onIdleCollectionFetchDone(KJob*)) );
+}
+
+void ImapResourceBase::onIdleCollectionFetchDone( KJob *job )
+{
+  if (job->error()) {
+    kWarning() << "CollectionFetch for idling failed."
+               << "error=" << job->error()
+               << ", errorString=" << job->errorString();
+    return;
+  }
+  Akonadi::CollectionFetchJob *fetch = static_cast<Akonadi::CollectionFetchJob*>(job);
+  //Can be empty if collection is not subscribed locally
+  if (!fetch->collections().isEmpty()) {
+    m_idle = new ImapIdleManager( createResourceState(TaskArguments(fetch->collections().first())), m_pool, this );
+  }
+}
+
+
+
+// ----------------------------------------------------------------------------------
+
+void ImapResourceBase::requestManualExpunge( qint64 collectionId )
+{
+  if ( !Settings::self()->automaticExpungeEnabled() ) {
+    Collection collection( collectionId );
+
+    Akonadi::CollectionFetchScope scope;
+    scope.setResource( identifier() );
+    scope.setAncestorRetrieval( Akonadi::CollectionFetchScope::All );
+    scope.setIncludeUnsubscribed( true );
+
+    Akonadi::CollectionFetchJob *fetch
+      = new Akonadi::CollectionFetchJob( collection,
+                                         Akonadi::CollectionFetchJob::Base,
+                                         this );
+    fetch->setFetchScope( scope );
+
+    connect( fetch, SIGNAL(result(KJob*)),
+             this, SLOT(onExpungeCollectionFetchDone(KJob*)) );
+  }
+}
+
+void ImapResourceBase::onExpungeCollectionFetchDone( KJob *job )
+{
+  if ( job->error() == 0 ) {
+    Akonadi::CollectionFetchJob *fetch = static_cast<Akonadi::CollectionFetchJob*>( job );
+    Akonadi::Collection collection = fetch->collections().first();
+
+    scheduleCustomTask( this, "triggerCollectionExpunge",
+                        QVariant::fromValue( collection ) );
+
+  } else {
+    kWarning() << "CollectionFetch for expunge failed."
+               << "error=" << job->error()
+               << ", errorString=" << job->errorString();
+  }
+}
+
+void ImapResourceBase::triggerCollectionExpunge( const QVariant &collectionVariant )
+{
+  const Collection collection = collectionVariant.value<Collection>();
+
+  ExpungeCollectionTask *task = new ExpungeCollectionTask( createResourceState(TaskArguments(collection)), this );
+  task->start( m_pool );
+  queueTask( task );
+}
+
+
+
+// ----------------------------------------------------------------------------------
+
+void ImapResourceBase::abortActivity()
+{
+  if ( !m_taskList.isEmpty() ) {
+    m_pool->disconnect( SessionPool::CloseSession );
+    scheduleConnectionAttempt();
+  }
+}
+
+void ImapResourceBase::queueTask( ResourceTask *task )
+{
+  connect( task, SIGNAL(destroyed(QObject*)),
+           this, SLOT(taskDestroyed(QObject*)) );
+  m_taskList << task;
+}
+
+void ImapResourceBase::startTask( ResourceTask* task )
+{
+  task->start(m_pool);
+  queueTask(task);
+}
+
+void ImapResourceBase::taskDestroyed( QObject *task )
+{
+  m_taskList.removeAll( static_cast<ResourceTask *>( task ) );
+}
+
+
+QStringList ImapResourceBase::serverCapabilities() const
+{
+    return m_pool->serverCapabilities();
+}
+
+void ImapResourceBase::cleanup()
+{
+    Settings::self()->cleanup();
+}
+
+QString ImapResourceBase::dumpResourceToString() const
+{
+  QString ret;
+  Q_FOREACH(ResourceTask* task, m_taskList) {
+    if (!ret.isEmpty())
+      ret += QLatin1String(", ");
+    ret += QLatin1String(task->metaObject()->className());
+  }
+  return QLatin1String("IMAP tasks: ") + ret;
+}
+
+void ImapResourceBase::showError( const QString &message )
+{
+  emit status( Akonadi::AgentBase::Idle, message );
+  m_statusMessageTimer->start( 1000*10 );
+}
+
+void ImapResourceBase::clearStatusMessage()
+{
+  emit status( Akonadi::AgentBase::Idle, QString() );
+}
+
+void ImapResourceBase::modifyCollection(const Collection &col)
+{
+    Akonadi::CollectionModifyJob *modJob = new Akonadi::CollectionModifyJob(col, this);
+    connect(modJob, SIGNAL(result(KJob*)), this, SLOT(onCollectionModifyDone(KJob*)));
+}
+
+void ImapResourceBase::onCollectionModifyDone(KJob* job)
+{
+    if (job->error()) {
+        kWarning() << "Failed to modify collection: " << job->errorString();
+    }
+}
+
diff --git a/resources/imap/imapresourcebase.h b/resources/imap/imapresourcebase.h
new file mode 100644
index 0000000..bc80ec5
--- /dev/null
+++ b/resources/imap/imapresourcebase.h
@@ -0,0 +1,168 @@
+/*
+    Copyright (c) 2007 Till Adam <adam at kde.org>
+    Copyright (C) 2008 Omat Holding B.V. <info at omat.nl>
+    Copyright (C) 2009 Kevin Ottens <ervin at kde.org>
+
+    Copyright (c) 2010 Klarälvdalens Datakonsult AB,
+                       a KDAB Group company <info at kdab.com>
+    Author: Kevin Ottens <kevin at kdab.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#ifndef RESOURCES_IMAP_IMAPRESOURCEBASE_H
+#define RESOURCES_IMAP_IMAPRESOURCEBASE_H
+
+#include <akonadi/resourcebase.h>
+#include <akonadi/agentsearchinterface.h>
+#include <KDialog>
+#include <QPointer>
+#include "resourcestateinterface.h"
+#include "resourcestate.h"
+
+class QTimer;
+
+class ResourceTask;
+namespace KIMAP
+{
+  class Session;
+}
+
+class ImapIdleManager;
+class SessionPool;
+class ResourceState;
+class SubscriptionDialog;
+
+class ImapResourceBase : public Akonadi::ResourceBase,
+                         public Akonadi::AgentBase::ObserverV3,
+                         public Akonadi::AgentSearchInterface
+{
+  Q_OBJECT
+
+protected:
+  using Akonadi::AgentBase::Observer::collectionChanged;
+
+public:
+  explicit ImapResourceBase( const QString &id );
+  ~ImapResourceBase();
+
+  virtual KDialog *createConfigureDialog( WId windowId ) = 0;
+
+  QStringList serverCapabilities() const;
+  void cleanup();
+
+public Q_SLOTS:
+  virtual void configure( WId windowId );
+
+  // DBus methods
+  Q_SCRIPTABLE void requestManualExpunge( qint64 collectionId );
+  Q_SCRIPTABLE int configureSubscription( qlonglong windowId = 0 );
+
+  // pseudo-virtual called by ResourceBase
+  QString dumpResourceToString() const;
+
+protected Q_SLOTS:
+  void startIdleIfNeeded();
+  void startIdle();
+
+  void abortActivity();
+
+  virtual void retrieveCollections();
+
+  virtual void retrieveItems( const Akonadi::Collection &col );
+  virtual bool retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts );
+
+protected:
+  virtual void itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection );
+  virtual void itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts );
+  virtual void itemsFlagsChanged( const Akonadi::Item::List &items, const QSet<QByteArray> &addedFlags, const QSet<QByteArray> &removedFlags );
+  virtual void itemsRemoved( const Akonadi::Item::List &items );
+  virtual void itemsMoved( const Akonadi::Item::List &item, const Akonadi::Collection &source,
+                           const Akonadi::Collection &destination );
+
+
+  virtual void collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent );
+  virtual void collectionChanged( const Akonadi::Collection &collection, const QSet<QByteArray> &parts );
+  virtual void collectionRemoved( const Akonadi::Collection &collection );
+  virtual void collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source,
+                                const Akonadi::Collection &destination );
+
+  virtual void addSearch( const QString &query, const QString &queryLanguage, const Akonadi::Collection &resultCollection );
+  virtual void removeSearch( const Akonadi::Collection &resultCollection );
+  virtual void search( const QString &query, const Akonadi::Collection &collection );
+
+  virtual void doSetOnline(bool online);
+
+  QChar separatorCharacter() const;
+  void setSeparatorCharacter( const QChar &separator );
+
+  virtual void aboutToQuit();
+
+  virtual ResourceStateInterface::Ptr createResourceState(const TaskArguments &);
+  virtual QString defaultName() const = 0;
+
+private Q_SLOTS:
+  void doSearch( const QVariant &arg );
+
+  void reconnect();
+
+  void scheduleConnectionAttempt();
+  void startConnect( const QVariant & ); // the parameter is necessary, since this method is used by the task scheduler
+  void onConnectDone( int errorCode, const QString &errorMessage );
+  void onConnectionLost( KIMAP::Session *session );
+
+
+  void onIdleCollectionFetchDone( KJob *job );
+  void onItemRetrievalCollectionFetchDone( KJob *job );
+  void onMetadataCollectionFetchDone( KJob *job );
+
+  void onExpungeCollectionFetchDone( KJob *job );
+  void triggerCollectionExpunge( const QVariant &collectionVariant );
+
+
+  void triggerCollectionExtraInfoJobs( const QVariant &collection );
+
+  void taskDestroyed( QObject *task );
+
+  void showError( const QString &message );
+  void clearStatusMessage();
+
+  void updateResourceName();
+
+  void onCollectionModifyDone( KJob *job );
+
+protected:
+  //Starts and queues a task
+  void startTask( ResourceTask *task );
+  void queueTask( ResourceTask *task );
+  SessionPool *m_pool;
+
+private:
+  friend class ResourceState;
+
+  bool needsNetwork() const;
+  void modifyCollection(const Akonadi::Collection &);
+
+  friend class ImapIdleManager;
+
+  QList<ResourceTask*> m_taskList; //used to be able to kill tasks
+  QPointer<SubscriptionDialog> mSubscriptions;
+  ImapIdleManager *m_idle;
+  QTimer *m_statusMessageTimer;
+  QChar m_separatorCharacter;
+};
+
+#endif
diff --git a/resources/imap/resourcestate.cpp b/resources/imap/resourcestate.cpp
index 3f09a21..ef1111a 100644
--- a/resources/imap/resourcestate.cpp
+++ b/resources/imap/resourcestate.cpp
@@ -31,7 +31,7 @@
 #include <akonadi/agentsearchinterface.h>
 #include <kmessagebox.h>
 
-ResourceState::ResourceState( ImapResource *resource, const TaskArguments &args )
+ResourceState::ResourceState( ImapResourceBase *resource, const TaskArguments &args )
   : m_resource( resource ),
   m_arguments( args )
 {
diff --git a/resources/imap/resourcestate.h b/resources/imap/resourcestate.h
index 02c8ff8..4a61a11 100644
--- a/resources/imap/resourcestate.h
+++ b/resources/imap/resourcestate.h
@@ -25,7 +25,7 @@
 #include "resourcestateinterface.h"
 #include "messagehelper.h"
 
-class ImapResource;
+class ImapResourceBase;
 
 struct TaskArguments {
     TaskArguments(){}
@@ -52,7 +52,7 @@ struct TaskArguments {
 class ResourceState : public ResourceStateInterface
 {
 public:
-  explicit ResourceState( ImapResource *resource, const TaskArguments &arguments );
+  explicit ResourceState( ImapResourceBase *resource, const TaskArguments &arguments );
 
 public:
   ~ResourceState();
@@ -130,7 +130,7 @@ public:
   virtual MessageHelper::Ptr messageHelper() const;
 
 private:
-  ImapResource *m_resource;
+  ImapResourceBase *m_resource;
   const TaskArguments m_arguments;
 };
 
diff --git a/resources/imap/retrieveitemstask.cpp b/resources/imap/retrieveitemstask.cpp
index 2d007ac..c345ad6 100644
--- a/resources/imap/retrieveitemstask.cpp
+++ b/resources/imap/retrieveitemstask.cpp
@@ -524,7 +524,7 @@ void RetrieveItemsTask::listFlagsForImapSet(const KIMAP::ImapSet& set)
       }
   }
 
-  m_batchFetcher = createBatchFetcher(resourceState()->messageHelper(), set, scope, 50 * batchSize(), m_session);
+  m_batchFetcher = createBatchFetcher(resourceState()->messageHelper(), set, scope, 10 * batchSize(), m_session);
   m_batchFetcher->setUidBased(m_uidBasedFetch);
   if (m_uidBasedFetch && scope.changedSince == 0 && set.intervals().size() == 1) {
       m_batchFetcher->setSearchTerm(KIMAP::Term(KIMAP::Term::Uid, set));
diff --git a/resources/imap/serverinfodialog.cpp b/resources/imap/serverinfodialog.cpp
index 4508e56..140bfc0 100644
--- a/resources/imap/serverinfodialog.cpp
+++ b/resources/imap/serverinfodialog.cpp
@@ -24,7 +24,7 @@
 
 #include <KLocalizedString>
 
-ServerInfoDialog::ServerInfoDialog(ImapResource *parentResource, QWidget *parent)
+ServerInfoDialog::ServerInfoDialog(ImapResourceBase *parentResource, QWidget *parent)
     : KDialog(parent)
 {
     setCaption(
diff --git a/resources/imap/serverinfodialog.h b/resources/imap/serverinfodialog.h
index 6cc9646..32cee08 100644
--- a/resources/imap/serverinfodialog.h
+++ b/resources/imap/serverinfodialog.h
@@ -23,7 +23,7 @@
 
 #include <KDialog>
 
-class ImapResource;
+class ImapResourceBase;
 namespace Ui {
 class ServerInfo;
 }
@@ -32,7 +32,7 @@ class ServerInfoDialog : public KDialog
 {
     Q_OBJECT
 public:
-    explicit ServerInfoDialog(ImapResource *parentResource, QWidget *parent);
+    explicit ServerInfoDialog(ImapResourceBase *parentResource, QWidget *parent);
     ~ServerInfoDialog();
 private:
     Ui::ServerInfo *mServerInfoWidget;
diff --git a/resources/imap/settingspasswordrequester.cpp b/resources/imap/settingspasswordrequester.cpp
index 8d46dec..a4778e2 100644
--- a/resources/imap/settingspasswordrequester.cpp
+++ b/resources/imap/settingspasswordrequester.cpp
@@ -28,10 +28,10 @@
 #include <mailtransport/transportbase.h>
 #include <kwindowsystem.h>
 
-#include "imapresource.h"
+#include "imapresourcebase.h"
 #include "settings.h"
 
-SettingsPasswordRequester::SettingsPasswordRequester( ImapResource *resource, QObject *parent )
+SettingsPasswordRequester::SettingsPasswordRequester( ImapResourceBase *resource, QObject *parent )
   : PasswordRequesterInterface( parent ), m_resource( resource ), m_requestDialog( 0 ), m_settingsDialog( 0 )
 {
 
diff --git a/resources/imap/settingspasswordrequester.h b/resources/imap/settingspasswordrequester.h
index 671ec16..9f9791b 100644
--- a/resources/imap/settingspasswordrequester.h
+++ b/resources/imap/settingspasswordrequester.h
@@ -25,14 +25,14 @@
 #include <passwordrequesterinterface.h>
 #include <KDialog>
 
-class ImapResource;
+class ImapResourceBase;
 
 class SettingsPasswordRequester : public PasswordRequesterInterface
 {
   Q_OBJECT
 
 public:
-  explicit SettingsPasswordRequester( ImapResource *resource, QObject *parent = 0 );
+  explicit SettingsPasswordRequester( ImapResourceBase *resource, QObject *parent = 0 );
   virtual ~SettingsPasswordRequester();
 
   virtual void requestPassword( RequestType request = StandardRequest,
@@ -47,7 +47,7 @@ private slots:
   void onSettingsDialogFinished(int result);
 
 private:
-  ImapResource *m_resource;
+  ImapResourceBase *m_resource;
   KDialog *m_requestDialog;
   KDialog *m_settingsDialog;
 };
diff --git a/resources/imap/setupserver.cpp b/resources/imap/setupserver.cpp
index 0dae9ed..c77e41f 100644
--- a/resources/imap/setupserver.cpp
+++ b/resources/imap/setupserver.cpp
@@ -120,7 +120,7 @@ static void addAuthenticationItem( QComboBox* authCombo, MailTransport::Transpor
     authCombo->addItem( authenticationModeString( authtype ), QVariant( authtype ) );
 }
 
-SetupServer::SetupServer( ImapResource *parentResource, WId parent )
+SetupServer::SetupServer( ImapResourceBase *parentResource, WId parent )
   : KDialog(), m_parentResource( parentResource ), m_ui(new Ui::SetupServerView), m_serverTest(0),
     m_subscriptionsChanged(false), m_shouldClearCache(false), mValidator( this )
 {
diff --git a/resources/imap/setupserver.h b/resources/imap/setupserver.h
index cfc2ed7..c5650f3 100644
--- a/resources/imap/setupserver.h
+++ b/resources/imap/setupserver.h
@@ -43,7 +43,7 @@ class IdentityCombo;
 class IdentityManager;
 }
 class FolderArchiveSettingPage;
-class ImapResource;
+class ImapResourceBase;
 
 /**
  * @class SetupServer
@@ -60,7 +60,7 @@ public:
    * @param parentResource The resource this dialog belongs to
    * @param parent Parent WId
    */
-  SetupServer( ImapResource *parentResource, WId parent );
+  SetupServer( ImapResourceBase *parentResource, WId parent );
 
   /**
    * Destructor
@@ -83,7 +83,7 @@ private:
   void readSettings();
   void populateDefaultAuthenticationOptions();
 
-  ImapResource *m_parentResource;
+  ImapResourceBase *m_parentResource;
   Ui::SetupServerView *m_ui;
   MailTransport::ServerTest *m_serverTest;
   bool m_subscriptionsChanged;


commit 042a4b91434cd819ea08f2a4f85693b301088c71
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Thu Jun 19 15:50:31 2014 +0200

    ResourceTask: Make serverSupports* virtual methods

diff --git a/resources/imap/resourcetask.h b/resources/imap/resourcetask.h
index d012f17..2b09bcb 100644
--- a/resources/imap/resourcetask.h
+++ b/resources/imap/resourcetask.h
@@ -133,8 +133,8 @@ protected:
   const QChar separatorCharacter() const;
   void setSeparatorCharacter( const QChar &separator );
 
-  bool serverSupportsAnnotations() const;
-  bool serverSupportsCondstore() const;
+  virtual bool serverSupportsAnnotations() const;
+  virtual bool serverSupportsCondstore() const;
 
   int batchSize() const;
 


commit 80498b6a98f776ff2d164c4dcb918dccd55e4965
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Wed Jun 18 15:08:27 2014 +0200

    Make private members of RetrieveCollectionsTask protected to allow subclassing

diff --git a/resources/imap/retrievecollectionstask.h b/resources/imap/retrievecollectionstask.h
index a3d1541..1173105 100644
--- a/resources/imap/retrievecollectionstask.h
+++ b/resources/imap/retrievecollectionstask.h
@@ -46,7 +46,7 @@ private slots:
 protected:
   virtual void doStart( KIMAP::Session *session );
 
-private:
+protected:
   QHash<QString, Akonadi::Collection> m_reportedCollections;
   QHash<QString, Akonadi::Collection> m_dummyCollections;
   QSet<QString> m_fullReportedCollections;


commit f49c91ed7a346ca4bbfaf6df6b84daa2037e007c
Author: Dan Vrátil <dvratil at redhat.com>
Date:   Wed Jun 18 15:08:02 2014 +0200

    Move BatchFether to it's own file and port to extended KIMAP signals

diff --git a/resources/imap/CMakeLists.txt b/resources/imap/CMakeLists.txt
index 053d715..0af8834 100644
--- a/resources/imap/CMakeLists.txt
+++ b/resources/imap/CMakeLists.txt
@@ -16,6 +16,7 @@ endif()
 set( imapresource_LIB_SRCS
   addcollectiontask.cpp
   additemtask.cpp
+  batchfetcher.cpp
   changecollectiontask.cpp
   changeitemsflagstask.cpp
   changeitemtask.cpp
diff --git a/resources/imap/batchfetcher.cpp b/resources/imap/batchfetcher.cpp
new file mode 100644
index 0000000..d250326
--- /dev/null
+++ b/resources/imap/batchfetcher.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2014 Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "batchfetcher.h"
+
+#include <KIMAP/Session>
+
+BatchFetcher::BatchFetcher(MessageHelper::Ptr messageHelper,
+                           const KIMAP::ImapSet &set,
+                           const KIMAP::FetchJob::FetchScope &scope,
+                           int batchSize,
+                           KIMAP::Session *session)
+    : KJob(session),
+    m_currentSet(set),
+    m_scope(scope),
+    m_session(session),
+    m_batchSize(batchSize),
+    m_uidBased(false),
+    m_fetchedItemsInCurrentBatch(0),
+    m_messageHelper(messageHelper),
+    m_fetchInProgress(false),
+    m_continuationRequested(false)
+{
+}
+
+BatchFetcher::~BatchFetcher()
+{
+}
+
+void BatchFetcher::setUidBased(bool uidBased)
+{
+    m_uidBased = uidBased;
+}
+
+void BatchFetcher::setSearchTerm(const KIMAP::Term &searchTerm)
+{
+    m_searchTerm = searchTerm;
+}
+
+void BatchFetcher::start()
+{
+    if (!m_searchTerm.isNull()) {
+        //Resolve the uid to sequence numbers
+        KIMAP::SearchJob *search = new KIMAP::SearchJob(m_session);
+        search->setUidBased(true);
+        search->setTerm(m_searchTerm);
+        connect(search, SIGNAL(result(KJob*)), this, SLOT(onUidSearchDone(KJob*)));
+        search->start();
+    } else {
+        fetchNextBatch();
+    }
+}
+
+void BatchFetcher::onUidSearchDone(KJob* job)
+{
+    if (job->error()) {
+        kWarning() << "Search job failed: " << job->errorString();
+        setError(KJob::UserDefinedError);
+        emitResult();
+        return;
+    }
+    KIMAP::SearchJob *search = static_cast<KIMAP::SearchJob*>(job);
+    m_uidBased = search->isUidBased();
+
+    KIMAP::ImapSet set;
+    set.add(search->results());
+    m_currentSet = set;
+    fetchNextBatch();
+}
+
+void BatchFetcher::fetchNextBatch()
+{
+    if (m_fetchInProgress) {
+        m_continuationRequested = true;
+        return;
+    }
+    m_continuationRequested = false;
+    Q_ASSERT(m_batchSize > 0);
+    if (m_currentSet.isEmpty()) {
+        kDebug(5327) << "fetch complete";
+        emitResult();
+        return;
+    }
+
+    KIMAP::FetchJob *fetch = new KIMAP::FetchJob(m_session);
+    if (m_scope.changedSince != 0) {
+        kDebug(5327) << "Fetching all messages in one batch.";
+        fetch->setSequenceSet(m_currentSet);
+        m_currentSet = KIMAP::ImapSet();
+    } else {
+        KIMAP::ImapSet toFetch;
+        qint64 counter = 0;
+        KIMAP::ImapSet newSet;
+
+        //Take a chunk from the set
+        Q_FOREACH (const KIMAP::ImapInterval &interval, m_currentSet.intervals()) {
+            const qint64 wantedItems = m_batchSize - counter;
+            if (counter < m_batchSize) {
+                if (interval.size() <= wantedItems) {
+                    counter += interval.size();
+                    toFetch.add(interval);
+                } else {
+                    counter += wantedItems;
+                    toFetch.add(KIMAP::ImapInterval(interval.begin(), interval.begin() + wantedItems - 1));
+                    newSet.add(KIMAP::ImapInterval(interval.begin() + wantedItems, interval.end()));
+                }
+            } else {
+                newSet.add(interval);
+            }
+        }
+        kDebug(5327) << "Fetching " << toFetch.intervals().size() << " intervals";
+        fetch->setSequenceSet(toFetch);
+        m_currentSet = newSet;
+    }
+
+    fetch->setUidBased(m_uidBased);
+    fetch->setScope(m_scope);
+    connect(fetch, SIGNAL(headersReceived(QString,
+                                          QMap<qint64,qint64>,
+                                          QMap<qint64,qint64>,
+                                          QMap<qint64,KIMAP::MessageAttribute>,
+                                          QMap<qint64,KIMAP::MessageFlags>,
+                                          QMap<qint64,KIMAP::MessagePtr>)),
+            this, SLOT(onHeadersReceived(QString,
+                                         QMap<qint64,qint64>,
+                                         QMap<qint64,qint64>,
+                                         QMap<qint64,KIMAP::MessageAttribute>,
+                                         QMap<qint64,KIMAP::MessageFlags>,
+                                         QMap<qint64,KIMAP::MessagePtr>)) );
+    connect(fetch, SIGNAL(result(KJob*)),
+            this, SLOT(onHeadersFetchDone(KJob*)));
+    m_fetchInProgress = true;
+    fetch->start();
+}
+
+void BatchFetcher::onHeadersReceived(const QString &mailBox,
+                                     const QMap<qint64, qint64> &uids,
+                                     const QMap<qint64, qint64> &sizes,
+                                     const QMap<qint64, KIMAP::MessageAttribute> &attrs,
+                                     const QMap<qint64, KIMAP::MessageFlags> &flags,
+                                     const QMap<qint64, KIMAP::MessagePtr> &messages)
+{
+    KIMAP::FetchJob *fetch = static_cast<KIMAP::FetchJob*>( sender() );
+    Q_ASSERT( fetch );
+
+    Akonadi::Item::List addedItems;
+    foreach (qint64 number, uids.keys()) { //krazy:exclude=foreach
+        //kDebug( 5327 ) << "Flags: " << i.flags();
+        bool ok;
+        const Akonadi::Item item = m_messageHelper->createItemFromMessage(messages[number], uids[number], sizes[number], attrs.values(number), flags[number], fetch->scope(), ok);
+        if (ok) {
+            m_fetchedItemsInCurrentBatch++;
+            addedItems << item;
+        }
+    }
+//     kDebug() << addedItems.size();
+    if (!addedItems.isEmpty()) {
+        emit itemsRetrieved(addedItems);
+    }
+}
+
+void BatchFetcher::onHeadersFetchDone( KJob *job )
+{
+    m_fetchInProgress = false;
+    if (job->error()) {
+        kWarning() << "Fetch job failed " << job->errorString();
+        setError(KJob::UserDefinedError);
+        emitResult();
+        return;
+    }
+    if (m_currentSet.isEmpty()) {
+        emitResult();
+        return;
+    }
+    //Fetch more if we didn't deliver enough yet.
+    //This can happen because no message is in the fetched uid range, or if the translation failed
+    if (m_fetchedItemsInCurrentBatch < m_batchSize) {
+        fetchNextBatch();
+    } else {
+        m_fetchedItemsInCurrentBatch = 0;
+        //Also fetch more if we already got a continuation request during the fetch.
+        //This can happen if we deliver too many items during a previous batch (after using )
+        //Note that m_fetchedItemsInCurrentBatch will be off by the items that we delivered already.
+        if (m_continuationRequested) {
+            fetchNextBatch();
+        }
+    }
+}
+
diff --git a/resources/imap/batchfetcher.h b/resources/imap/batchfetcher.h
new file mode 100644
index 0000000..05bf07c
--- /dev/null
+++ b/resources/imap/batchfetcher.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014 Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef BATCHFETCHER_H
+#define BATCHFETCHER_H
+
+#include <KJob>
+#include <KIMAP/ImapSet>
+#include <KIMAP/FetchJob>
+#include <KIMAP/SearchJob>
+
+#include "messagehelper.h"
+
+/**
+ * A job that retrieves a set of messages in reverse-ordered batches.
+ * After each batch fetchNextBatch() needs to be called (for throttling the download speed)
+ */
+class BatchFetcher : public KJob {
+    Q_OBJECT
+public:
+    BatchFetcher(MessageHelper::Ptr messageHelper,
+                 const KIMAP::ImapSet &set,
+                 const KIMAP::FetchJob::FetchScope &scope,
+                 int batchSize,
+                 KIMAP::Session *session);
+    virtual ~BatchFetcher();
+    virtual void start();
+    void fetchNextBatch();
+    void setUidBased(bool);
+    void setSearchTerm(const KIMAP::Term &);
+
+Q_SIGNALS:
+    void itemsRetrieved(Akonadi::Item::List);
+
+private Q_SLOTS:
+    void onHeadersReceived(const QString &mailBox,
+                           const QMap<qint64, qint64> &uids,
+                           const QMap<qint64, qint64> &sizes,
+                           const QMap<qint64, KIMAP::MessageAttribute> &attrs,
+                           const QMap<qint64, KIMAP::MessageFlags> &flags,
+                           const QMap<qint64, KIMAP::MessagePtr> &messages);
+    void onHeadersFetchDone(KJob *job);
+    void onUidSearchDone(KJob* job);
+
+private:
+    //Batch fetching
+    KIMAP::ImapSet m_currentSet;
+    KIMAP::FetchJob::FetchScope m_scope;
+    KIMAP::Session *m_session;
+    int m_batchSize;
+    bool m_uidBased;
+    int m_fetchedItemsInCurrentBatch;
+    const MessageHelper::Ptr m_messageHelper;
+    bool m_fetchInProgress;
+    bool m_continuationRequested;
+    KIMAP::Term m_searchTerm;
+};
+
+
+#endif // BATCHFETCHER_H
diff --git a/resources/imap/messagehelper.cpp b/resources/imap/messagehelper.cpp
index 929c521..cf89315 100644
--- a/resources/imap/messagehelper.cpp
+++ b/resources/imap/messagehelper.cpp
@@ -27,8 +27,16 @@ MessageHelper::~MessageHelper()
 
 }
 
-Akonadi::Item MessageHelper::createItemFromMessage(KMime::Message::Ptr message, const qint64 uid, const qint64 size, const QList<QByteArray> &flags, const KIMAP::FetchJob::FetchScope &scope, bool &ok) const
+Akonadi::Item MessageHelper::createItemFromMessage(KMime::Message::Ptr message,
+                                                   const qint64 uid,
+                                                   const qint64 size,
+                                                   const QList<KIMAP::MessageAttribute> &attrs,
+                                                   const QList<QByteArray> &flags,
+                                                   const KIMAP::FetchJob::FetchScope &scope,
+                                                   bool &ok) const
 {
+    Q_UNUSED(attrs);
+
     Akonadi::Item i;
     if (scope.mode == KIMAP::FetchJob::FetchScope::Flags) {
         i.setRemoteId(QString::number(uid));
diff --git a/resources/imap/messagehelper.h b/resources/imap/messagehelper.h
index 96ce6b2..43874a4 100644
--- a/resources/imap/messagehelper.h
+++ b/resources/imap/messagehelper.h
@@ -30,7 +30,13 @@ public:
     typedef boost::shared_ptr<MessageHelper> Ptr;
 
     virtual ~MessageHelper();
-    virtual Akonadi::Item createItemFromMessage(KMime::Message::Ptr message, const qint64 uid, const qint64 size, const QList<QByteArray> &flags, const KIMAP::FetchJob::FetchScope &scope, bool &ok) const;
+    virtual Akonadi::Item createItemFromMessage(KMime::Message::Ptr message,
+                                                const qint64 uid,
+                                                const qint64 size,
+                                                const QList<KIMAP::MessageAttribute> &attrs,
+                                                const QList<QByteArray> &flags,
+                                                const KIMAP::FetchJob::FetchScope &scope,
+                                                bool &ok) const;
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/resources/imap/retrieveitemstask.cpp b/resources/imap/retrieveitemstask.cpp
index 5697fe6..2d007ac 100644
--- a/resources/imap/retrieveitemstask.cpp
+++ b/resources/imap/retrieveitemstask.cpp
@@ -28,6 +28,7 @@
 #include "uidnextattribute.h"
 #include "highestmodseqattribute.h"
 #include "messagehelper.h"
+#include "batchfetcher.h"
 
 #include <akonadi/cachepolicy.h>
 #include <akonadi/collectionstatistics.h>
@@ -46,212 +47,6 @@
 #include <kimap/session.h>
 #include <kimap/searchjob.h>
 
-/**
- * A job that retrieves a set of messages in reverse-ordered batches.
- * After each batch fetchNextBatch() needs to be called (for throttling the download speed)
- */
-class BatchFetcher : public KJob {
-    Q_OBJECT
-public:
-    BatchFetcher(MessageHelper::Ptr messageHelper, const KIMAP::ImapSet &set, const KIMAP::FetchJob::FetchScope &scope, int batchSize, KIMAP::Session *session);
-    virtual ~BatchFetcher();
-    virtual void start();
-    void fetchNextBatch();
-    void setUidBased(bool);
-    void setSearchTerm(const KIMAP::Term &);
-
-Q_SIGNALS:
-    void itemsRetrieved(Akonadi::Item::List);
-
-private Q_SLOTS:
-    void onHeadersReceived(const QString &mailBox, const QMap<qint64, qint64> &uids,
-                                           const QMap<qint64, qint64> &sizes,
-                                           const QMap<qint64, KIMAP::MessageFlags> &flags,
-                                           const QMap<qint64, KIMAP::MessagePtr> &messages);
-    void onHeadersFetchDone(KJob *job);
-    void onUidSearchDone(KJob* job);
-
-private:
-    //Batch fetching
-    KIMAP::ImapSet m_currentSet;
-    KIMAP::FetchJob::FetchScope m_scope;
-    KIMAP::Session *m_session;
-    int m_batchSize;
-    bool m_uidBased;
-    int m_fetchedItemsInCurrentBatch;
-    const MessageHelper::Ptr m_messageHelper;
-    bool m_fetchInProgress;
-    bool m_continuationRequested;
-    KIMAP::Term m_searchTerm;
-};
-
-BatchFetcher::BatchFetcher(MessageHelper::Ptr messageHelper, const KIMAP::ImapSet &set, const KIMAP::FetchJob::FetchScope& scope, int batchSize, KIMAP::Session* session)
-    : KJob(session),
-    m_currentSet(set),
-    m_scope(scope),
-    m_session(session),
-    m_batchSize(batchSize),
-    m_uidBased(false),
-    m_fetchedItemsInCurrentBatch(0),
-    m_messageHelper(messageHelper),
-    m_fetchInProgress(false),
-    m_continuationRequested(false)
-{
-}
-
-BatchFetcher::~BatchFetcher()
-{
-}
-
-void BatchFetcher::setUidBased(bool uidBased)
-{
-    m_uidBased = uidBased;
-}
-
-void BatchFetcher::setSearchTerm(const KIMAP::Term &searchTerm)
-{
-    m_searchTerm = searchTerm;
-}
-
-void BatchFetcher::start()
-{
-    if (!m_searchTerm.isNull()) {
-        //Resolve the uid to sequence numbers
-        KIMAP::SearchJob *search = new KIMAP::SearchJob(m_session);
-        search->setUidBased(true);
-        search->setTerm(m_searchTerm);
-        connect(search, SIGNAL(result(KJob*)), this, SLOT(onUidSearchDone(KJob*)));
-        search->start();
-    } else {
-        fetchNextBatch();
-    }
-}
-
-void BatchFetcher::onUidSearchDone(KJob* job)
-{
-    if (job->error()) {
-        kWarning() << "Search job failed: " << job->errorString();
-        setError(KJob::UserDefinedError);
-        emitResult();
-        return;
-    }
-    KIMAP::SearchJob *search = static_cast<KIMAP::SearchJob*>(job);
-    m_uidBased = search->isUidBased();
-
-    KIMAP::ImapSet set;
-    set.add(search->results());
-    m_currentSet = set;
-    fetchNextBatch();
-}
-
-void BatchFetcher::fetchNextBatch()
-{
-    if (m_fetchInProgress) {
-        m_continuationRequested = true;
-        return;
-    }
-    m_continuationRequested = false;
-    Q_ASSERT(m_batchSize > 0);
-    if (m_currentSet.isEmpty()) {
-        kDebug(5327) << "fetch complete";
-        emitResult();
-        return;
-    }
-
-    KIMAP::FetchJob *fetch = new KIMAP::FetchJob(m_session);
-    if (m_scope.changedSince != 0) {
-        kDebug(5327) << "Fetching all messages in one batch.";
-        fetch->setSequenceSet(m_currentSet);
-        m_currentSet = KIMAP::ImapSet();
-    } else {
-        KIMAP::ImapSet toFetch;
-        qint64 counter = 0;
-        KIMAP::ImapSet newSet;
-
-        //Take a chunk from the set
-        Q_FOREACH (const KIMAP::ImapInterval &interval, m_currentSet.intervals()) {
-            const qint64 wantedItems = m_batchSize - counter;
-            if (counter < m_batchSize) {
-                if (interval.size() <= wantedItems) {
-                    counter += interval.size();
-                    toFetch.add(interval);
-                } else {
-                    counter += wantedItems;
-                    toFetch.add(KIMAP::ImapInterval(interval.begin(), interval.begin() + wantedItems - 1));
-                    newSet.add(KIMAP::ImapInterval(interval.begin() + wantedItems, interval.end()));
-                }
-            } else {
-                newSet.add(interval);
-            }
-        }
-        kDebug(5327) << "Fetching " << toFetch.intervals().size() << " intervals";
-        fetch->setSequenceSet(toFetch);
-        m_currentSet = newSet;
-    }
-
-    fetch->setUidBased(m_uidBased);
-    fetch->setScope(m_scope);
-    connect(fetch, SIGNAL(headersReceived(QString,QMap<qint64,qint64>,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageFlags>,QMap<qint64,KIMAP::MessagePtr>)),
-            this, SLOT(onHeadersReceived(QString,QMap<qint64,qint64>,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageFlags>,QMap<qint64,KIMAP::MessagePtr>)) );
-    connect(fetch, SIGNAL(result(KJob*)),
-            this, SLOT(onHeadersFetchDone(KJob*)));
-    m_fetchInProgress = true;
-    fetch->start();
-}
-
-void BatchFetcher::onHeadersReceived(const QString &mailBox, const QMap<qint64, qint64> &uids,
-                                           const QMap<qint64, qint64> &sizes,
-                                           const QMap<qint64, KIMAP::MessageFlags> &flags,
-                                           const QMap<qint64, KIMAP::MessagePtr> &messages)
-{
-    KIMAP::FetchJob *fetch = static_cast<KIMAP::FetchJob*>( sender() );
-    Q_ASSERT( fetch );
-
-    Akonadi::Item::List addedItems;
-    foreach (qint64 number, uids.keys()) { //krazy:exclude=foreach
-        //kDebug( 5327 ) << "Flags: " << i.flags();
-        bool ok;
-        const Akonadi::Item item = m_messageHelper->createItemFromMessage(messages[number], uids[number], sizes[number], flags[number], fetch->scope(), ok);
-        if (ok) {
-            m_fetchedItemsInCurrentBatch++;
-            addedItems << item;
-        }
-    }
-//     kDebug() << addedItems.size();
-    if (!addedItems.isEmpty()) {
-        emit itemsRetrieved(addedItems);
-    }
-}
-
-void BatchFetcher::onHeadersFetchDone( KJob *job )
-{
-    m_fetchInProgress = false;
-    if (job->error()) {
-        kWarning() << "Fetch job failed " << job->errorString();
-        setError(KJob::UserDefinedError);
-        emitResult();
-        return;
-    }
-    if (m_currentSet.isEmpty()) {
-        emitResult();
-        return;
-    }
-    //Fetch more if we didn't deliver enough yet.
-    //This can happen because no message is in the fetched uid range, or if the translation failed
-    if (m_fetchedItemsInCurrentBatch < m_batchSize) {
-        fetchNextBatch();
-    } else {
-        m_fetchedItemsInCurrentBatch = 0;
-        //Also fetch more if we already got a continuation request during the fetch.
-        //This can happen if we deliver too many items during a previous batch (after using )
-        //Note that m_fetchedItemsInCurrentBatch will be off by the items that we delivered already.
-        if (m_continuationRequested) {
-            fetchNextBatch();
-        }
-    }
-}
-
-
 RetrieveItemsTask::RetrieveItemsTask(ResourceStateInterface::Ptr resource, QObject *parent)
     : ResourceTask(CancelIfNoSession, resource, parent),
     m_session(0),
@@ -304,6 +99,14 @@ void RetrieveItemsTask::doStart(KIMAP::Session *session)
     }
 }
 
+BatchFetcher* RetrieveItemsTask::createBatchFetcher(MessageHelper::Ptr messageHelper,
+                                                    const KIMAP::ImapSet &set,
+                                                    const KIMAP::FetchJob::FetchScope &scope,
+                                                    int batchSize, KIMAP::Session* session)
+{
+    return new BatchFetcher(messageHelper, set, scope, batchSize, session);
+}
+
 void RetrieveItemsTask::fetchItemsWithoutBodiesDone(KJob *job)
 {
     QList<qint64> uids;
@@ -637,7 +440,7 @@ void RetrieveItemsTask::retrieveItems(const KIMAP::ImapSet& set, const KIMAP::Fe
     m_incremental = incremental;
     m_uidBasedFetch = uidBased;
 
-    m_batchFetcher = new BatchFetcher(resourceState()->messageHelper(), set, scope, batchSize(), m_session);
+    m_batchFetcher = createBatchFetcher(resourceState()->messageHelper(), set, scope, batchSize(), m_session);
     m_batchFetcher->setUidBased(m_uidBasedFetch);
     if (m_uidBasedFetch && set.intervals().size() == 1) {
         m_batchFetcher->setSearchTerm(KIMAP::Term(KIMAP::Term::Uid, set));
@@ -721,7 +524,7 @@ void RetrieveItemsTask::listFlagsForImapSet(const KIMAP::ImapSet& set)
       }
   }
 
-  m_batchFetcher = new BatchFetcher(resourceState()->messageHelper(), set, scope, 50 * batchSize(), m_session);
+  m_batchFetcher = createBatchFetcher(resourceState()->messageHelper(), set, scope, 50 * batchSize(), m_session);
   m_batchFetcher->setUidBased(m_uidBasedFetch);
   if (m_uidBasedFetch && scope.changedSince == 0 && set.intervals().size() == 1) {
       m_batchFetcher->setSearchTerm(KIMAP::Term(KIMAP::Term::Uid, set));
diff --git a/resources/imap/retrieveitemstask.h b/resources/imap/retrieveitemstask.h
index 5cf4693..355e37b 100644
--- a/resources/imap/retrieveitemstask.h
+++ b/resources/imap/retrieveitemstask.h
@@ -57,6 +57,10 @@ private slots:
 protected:
     virtual void doStart(KIMAP::Session *session);
 
+    virtual BatchFetcher* createBatchFetcher(MessageHelper::Ptr messageHelper, const KIMAP::ImapSet &set,
+                                             const KIMAP::FetchJob::FetchScope &scope, int batchSize,
+                                             KIMAP::Session *session);
+
 private:
     void startRetrievalTasks();
     void triggerPreExpungeSelect(const QString &mailBox);
diff --git a/resources/imap/retrieveitemtask.cpp b/resources/imap/retrieveitemtask.cpp
index 0062c63..661b6c8 100644
--- a/resources/imap/retrieveitemtask.cpp
+++ b/resources/imap/retrieveitemtask.cpp
@@ -81,8 +81,14 @@ void RetrieveItemTask::triggerFetchJob()
   scope.parts.clear();// = parts.toList();
   scope.mode = KIMAP::FetchJob::FetchScope::Content;
   fetch->setScope( scope );
-  connect( fetch, SIGNAL(messagesReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessagePtr>)),
-           this, SLOT(onMessagesReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessagePtr>)) );
+  connect( fetch, SIGNAL(messagesReceived(QString,
+                                          QMap<qint64,qint64>,
+                                          QMap<qint64,KIMAP::MessageAttribute>,
+                                          QMap<qint64,KIMAP::MessagePtr>)),
+           this, SLOT(onMessagesReceived(QString,
+                                         QMap<qint64,qint64>,
+                                         QMap<qint64,KIMAP::MessageAttribute>,
+                                         QMap<qint64,KIMAP::MessagePtr>)) );
   //TODO: Handle parts retrieval
   //connect( fetch, SIGNAL(partsReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageParts>)),
   //         this, SLOT(onPartsReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageParts>)) );
@@ -91,7 +97,9 @@ void RetrieveItemTask::triggerFetchJob()
   fetch->start();
 }
 
-void RetrieveItemTask::onMessagesReceived( const QString &mailBox, const QMap<qint64, qint64> &uids,
+void RetrieveItemTask::onMessagesReceived( const QString &mailBox,
+                                           const QMap<qint64, qint64> &uids,
+                                           const QMap<qint64, KIMAP::MessageAttribute> &attrs,
                                            const QMap<qint64, KIMAP::MessagePtr> &messages )
 {
   Q_UNUSED( mailBox );
@@ -108,7 +116,7 @@ void RetrieveItemTask::onMessagesReceived( const QString &mailBox, const QMap<qi
 
   const qint64 number = uids.keys().first();
   bool ok;
-  const Akonadi::Item remoteItem = resourceState()->messageHelper()->createItemFromMessage(messages[number], uids[number], 0, QList<QByteArray>(), fetch->scope(), ok);
+  const Akonadi::Item remoteItem = resourceState()->messageHelper()->createItemFromMessage(messages[number], uids[number], 0, attrs.values(number), QList<QByteArray>(), fetch->scope(), ok);
   if (!ok) {
     kWarning() << "Failed to retrieve message " << uids[number];
     cancelTask( i18n( "No message retrieved, failed to read the message." ) );
diff --git a/resources/imap/retrieveitemtask.h b/resources/imap/retrieveitemtask.h
index d3c4fec..e44fd1e 100644
--- a/resources/imap/retrieveitemtask.h
+++ b/resources/imap/retrieveitemtask.h
@@ -36,7 +36,9 @@ public:
 
 private slots:
   void onSelectDone( KJob *job );
-  void onMessagesReceived( const QString &mailBox, const QMap<qint64, qint64> &uids,
+  void onMessagesReceived( const QString &mailBox,
+                           const QMap<qint64, qint64> &uids,
+                           const QMap<qint64, KIMAP::MessageAttribute> &attrs,
                            const QMap<qint64, KIMAP::MessagePtr> &messages );
   void onContentFetchDone( KJob *job );
 
diff --git a/resources/kolab/kolabmessagehelper.cpp b/resources/kolab/kolabmessagehelper.cpp
index b97be4f..777d48e 100644
--- a/resources/kolab/kolabmessagehelper.cpp
+++ b/resources/kolab/kolabmessagehelper.cpp
@@ -36,9 +36,15 @@ KolabMessageHelper::~KolabMessageHelper()
 
 }
 
-Akonadi::Item KolabMessageHelper::createItemFromMessage(KMime::Message::Ptr message, const qint64 uid, const qint64 size, const QList< QByteArray >& flags, const KIMAP::FetchJob::FetchScope& scope, bool& ok) const
+Akonadi::Item KolabMessageHelper::createItemFromMessage(KMime::Message::Ptr message,
+                                                        const qint64 uid,
+                                                        const qint64 size,
+                                                        const QList<KIMAP::MessageAttribute> &attrs,
+                                                        const QList<QByteArray> &flags,
+                                                        const KIMAP::FetchJob::FetchScope &scope,
+                                                        bool &ok) const
 {
-    const Akonadi::Item item = MessageHelper::createItemFromMessage(message, uid, size, flags, scope, ok);
+    const Akonadi::Item item = MessageHelper::createItemFromMessage(message, uid, size, attrs, flags, scope, ok);
     if (!ok) {
         kWarning() << "Failed to read imap message";
         return item;
diff --git a/resources/kolab/kolabmessagehelper.h b/resources/kolab/kolabmessagehelper.h
index ec978e6..bdc64f9 100644
--- a/resources/kolab/kolabmessagehelper.h
+++ b/resources/kolab/kolabmessagehelper.h
@@ -27,10 +27,16 @@ class KolabMessageHelper : public MessageHelper {
 public:
     explicit KolabMessageHelper(const Akonadi::Collection &collection);
     virtual ~KolabMessageHelper();
-    virtual Akonadi::Item createItemFromMessage(KMime::Message::Ptr message, const qint64 uid, const qint64 size, const QList<QByteArray> &flags, const KIMAP::FetchJob::FetchScope &scope, bool &ok) const;
+    virtual Akonadi::Item createItemFromMessage(KMime::Message::Ptr message,
+                                                const qint64 uid,
+                                                const qint64 size,
+                                                const QList<KIMAP::MessageAttribute> &attrs,
+                                                const QList<QByteArray> &flags,
+                                                const KIMAP::FetchJob::FetchScope &scope,
+                                                bool &ok) const;
 
 private:
     Akonadi::Collection mCollection;
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/resources/kolab/kolabresourcestate.cpp b/resources/kolab/kolabresourcestate.cpp
index 47981e7..f4cf8b9 100644
--- a/resources/kolab/kolabresourcestate.cpp
+++ b/resources/kolab/kolabresourcestate.cpp
@@ -20,6 +20,9 @@
 #include "kolabresourcestate.h"
 #include "kolabhelpers.h"
 #include "kolabmessagehelper.h"
+
+#include <imapresource.h>
+
 #include <collectionannotationsattribute.h>
 #include <noselectattribute.h>
 #include <Akonadi/EntityDisplayAttribute>


commit bba0685eba7ad1ec21b00fc16ff2186c6d734340
Author: Martin Steigerwald <martin at lichtvoll.de>
Date:   Sun Jun 8 18:34:18 2014 +0200

    Sort by filename, which is RemoteId, instead of item id to make test pass.
    
    Review request 118441 introduced sorting of items for ItemFetchJob
    testcase as due to an performance optimization mixedmaildir resource
    does not sort anymore. This fixed the testcase for me on BTRFS.
    
    However on the Jenkins server the test case was still not fixed and
    Kevin pointed out that qSort may sort by item id instead of RemoteId.
    The test relies on sorting by filename, which is basically the RemoteId.
    
    CCBUG: 334218
    
    REVIEW: 118619

diff --git a/resources/mixedmaildir/tests/itemfetchtest.cpp b/resources/mixedmaildir/tests/itemfetchtest.cpp
index fe034be..5372ce5 100644
--- a/resources/mixedmaildir/tests/itemfetchtest.cpp
+++ b/resources/mixedmaildir/tests/itemfetchtest.cpp
@@ -72,6 +72,13 @@ static QSet<QByteArray> messageParts( const KMime::Message::Ptr &msgPtr )
   return set;
 }
 
+// needed to sort maildir directory entries by filename which is their
+// remoteId. tagListHash.contains tests below need sorting of entries.
+static bool itemLessThanByRemoteId(const Item &item1, const Item &item2)
+{
+    return item1.remoteId() < item2.remoteId();
+}
+
 class ItemFetchTest : public QObject
 {
   Q_OBJECT
@@ -369,7 +376,7 @@ void ItemFetchTest::testListingMaildir()
   // tagListHash.contains tests below needs sorting of entries,
   // but libmaildir does not sort for performance reasons.
   // TODO: Check should not depend on any specific ordering.
-  qSort(items);
+  qSort(items.begin(), items.end(), itemLessThanByRemoteId);
 
   tagListHash = var.value< QHash<QString, QVariant> >();
   QCOMPARE( (int)tagListHash.count(), 3 );


commit 08cd5bc89874a42237aa831e02d97a8ea80bd523
Author: Martin Steigerwald <martin at lichtvoll.de>
Date:   Sat May 31 20:18:41 2014 +0200

    Manually sort the item list so that tagListHash.contains tests work
    
    Otherwise the individual tests in this testcase may work on the wrong
    mails as libmaildir doesn´t sort the entry list anymore.
    
    This is related to the nosorting change from review request 117975.
    
    This needs to go into 4.13 branch as well before release of 4.13.2.
    
    CCBUG: 334218
    
    REVIEW: 118441

diff --git a/resources/mixedmaildir/tests/itemfetchtest.cpp b/resources/mixedmaildir/tests/itemfetchtest.cpp
index 28a0f6e..fe034be 100644
--- a/resources/mixedmaildir/tests/itemfetchtest.cpp
+++ b/resources/mixedmaildir/tests/itemfetchtest.cpp
@@ -366,6 +366,11 @@ void ItemFetchTest::testListingMaildir()
   var = job->property( "remoteIdToTagList" );
   QVERIFY( var.isValid() );
 
+  // tagListHash.contains tests below needs sorting of entries,
+  // but libmaildir does not sort for performance reasons.
+  // TODO: Check should not depend on any specific ordering.
+  qSort(items);
+
   tagListHash = var.value< QHash<QString, QVariant> >();
   QCOMPARE( (int)tagListHash.count(), 3 );
   QVERIFY( !tagListHash.contains( items[ 0 ].remoteId() ) );


commit ced9ff99b3cd403db213a33ec5a81a0927294d19
Author: Martin Steigerwald <martin at lichtvoll.de>
Date:   Thu May 29 17:49:34 2014 +0200

    Manually sort the QStringList for the readEntryFlags test
    
    Otherwise the individual test in this testcase may work on the wrong
    mails as libmaildir doesn´t sort the entry list anymore.
    
    CCBUG: 334218
    
    REVIEW: 118400

diff --git a/resources/maildir/libmaildir/tests/testmaildir.cpp b/resources/maildir/libmaildir/tests/testmaildir.cpp
index 47bc5c9..aabe95c 100644
--- a/resources/maildir/libmaildir/tests/testmaildir.cpp
+++ b/resources/maildir/libmaildir/tests/testmaildir.cpp
@@ -357,6 +357,10 @@ void MaildirTest::testMaildirFlagsReading()
 
   Maildir d( m_temp->name() );
   QStringList entries = d.entryList();
+  // Maildir::entryList() doesn't sort for performance reasons,
+  // do it here to make test sequence reliable.
+  entries.sort();
+
   QCOMPARE( entries.count(), 6 );
 
   Akonadi::Item::Flags flags = d.readEntryFlags( entries[0] );


commit 1185fb707234330a67c5372fd976eb0eebd370a5
Author: Montel Laurent <montel at kde.org>
Date:   Fri Jun 6 13:58:32 2014 +0200

    Remove dead code

diff --git a/resources/kolab/kolabhelpers.cpp b/resources/kolab/kolabhelpers.cpp
index b4fb0c6..56bfe20 100644
--- a/resources/kolab/kolabhelpers.cpp
+++ b/resources/kolab/kolabhelpers.cpp
@@ -140,10 +140,9 @@ Akonadi::Item KolabHelpers::translateFromImap(Kolab::FolderType folderType, cons
         default:
             kWarning() << "Object type not handled";
             ok = false;
-            return Akonadi::Item();
+            break;
     }
-    ok = false;
-    return Akonadi::Item();
+   return Akonadi::Item();
 }
 
 Akonadi::Item::List KolabHelpers::translateToImap(const Akonadi::Item::List &items, bool &ok)


commit e09aff5394793be2eec327bd4b025e64863c21c8
Author: Montel Laurent <montel at kde.org>
Date:   Fri Jun 6 13:47:23 2014 +0200

    Fix mem leak

diff --git a/resources/shared/tests/imapaclattributetest.cpp b/resources/shared/tests/imapaclattributetest.cpp
index 8059641..7e65a6f 100644
--- a/resources/shared/tests/imapaclattributetest.cpp
+++ b/resources/shared/tests/imapaclattributetest.cpp
@@ -101,6 +101,7 @@ class ImapAclAttributeTest : public QObject
       attr->setRights( acls );
 
       QCOMPARE( attr->oldRights(), acls );
+      delete attr;
     }
 };
 


commit f100e9053337612826f44e9931b5453ed3c9f0a7
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Fri Jun 6 09:56:42 2014 +0200

    IMAP-Resource: Fixed TestRetrieveCollectionMetadataTask
    
    Adapted to to kimap change that fixed the GETMETADATA command.

diff --git a/resources/imap/tests/testretrievecollectionmetadatatask.cpp b/resources/imap/tests/testretrievecollectionmetadatatask.cpp
index ce0b027..c6113f8 100644
--- a/resources/imap/tests/testretrievecollectionmetadatatask.cpp
+++ b/resources/imap/tests/testretrievecollectionmetadatatask.cpp
@@ -231,7 +231,7 @@ private slots:
 
     scenario.clear();
     scenario << defaultPoolConnectionScenario()
-             << "C: A000003 GETMETADATA \"INBOX/Foo\" (DEPTH infinity) (/shared)"
+             << "C: A000003 GETMETADATA (DEPTH infinity) \"INBOX/Foo\" (/shared)"
              << "S: * METADATA \"INBOX/Foo\" (/shared/vendor/kolab/folder-test \"true\")"
              << "S: * METADATA \"INBOX/Foo\" (/shared/vendor/kolab/folder-test2 \"NIL\")"
              << "S: * METADATA \"INBOX/Foo\" (/shared/vendor/cmu/cyrus-imapd/lastupdate \"true\")"





More information about the commits mailing list