Page MenuHomePhorge

No OneTemporary

diff --git a/resources/kolabproxy/CMakeLists.txt b/resources/kolabproxy/CMakeLists.txt
index 69b72f529..6e6089b1e 100644
--- a/resources/kolabproxy/CMakeLists.txt
+++ b/resources/kolabproxy/CMakeLists.txt
@@ -1,99 +1,101 @@
project(kolabproxy)
include_directories(
${kdepim-runtime_SOURCE_DIR}
${QT_QTDBUS_INCLUDE_DIR}
${Boost_INCLUDE_DIR}
${Libkolab_INCLUDES}
${Libkolabxml_INCLUDES}
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS} -fPIC")
########### next target ###############
set(kolabproxyresource_shared_SRCS
kolabhandler.cpp
addressbookhandler.cpp
incidencehandler.cpp
calendarhandler.cpp
freebusyupdatehandler.cpp
taskshandler.cpp
journalhandler.cpp
notehandler.cpp
setupdefaultfoldersjob.cpp
kolabdefs.cpp
upgradejob.cpp
)
set(kolabproxyresource_SRCS
kolabproxyresource.cpp
collectiontreebuilder.cpp
setupkolab.cpp
${kolabproxyresource_shared_SRCS}
${AKONADI_COLLECTIONATTRIBUTES_SHARED_SOURCES}
)
+qt4_add_dbus_adaptor(kolabproxyresource_SRCS org.freedesktop.Akonadi.kolabproxy.xml kolabproxyresource.h KolabProxyResource)
+
install(FILES kolabproxyresource.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents")
kde4_add_kcfg_files(kolabproxyresource_SRCS settings.kcfgc)
kde4_add_ui_files(kolabproxyresource_SRCS kolabsettings.ui changeformat.ui)
kcfg_generate_dbus_interface(
${CMAKE_CURRENT_SOURCE_DIR}/kolabproxyresource.kcfg
org.kde.Akonadi.kolabproxy.Settings
)
qt4_add_dbus_adaptor(kolabproxyresource_SRCS
${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.kolabproxy.Settings.xml
settings.h Settings
)
if(RUNTIME_PLUGINS_STATIC)
add_definitions(-DRUNTIME_PLUGINS_STATIC)
endif()
kde4_add_executable(akonadi_kolabproxy_resource ${kolabproxyresource_SRCS})
if(Q_WS_MAC)
set_target_properties(akonadi_kolabproxy_resource PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/../Info.plist.template
)
set_target_properties(akonadi_kolabproxy_resource PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.Akonadi.kolabproxy"
)
set_target_properties(akonadi_kolabproxy_resource PROPERTIES
MACOSX_BUNDLE_BUNDLE_NAME "KDE Akonadi Kolabproxy Resource"
)
endif()
target_link_libraries(akonadi_kolabproxy_resource
kdepim-copy
${KDEPIMLIBS_AKONADI_KMIME_LIBS}
${KDEPIMLIBS_AKONADI_LIBS}
${KDEPIMLIBS_KABC_LIBS}
${KDEPIMLIBS_KCALCORE_LIBS}
${KDEPIMLIBS_KMIME_LIBS}
${KDE4_KIO_LIBS}
${QT_QTDBUS_LIBRARY}
${QT_QTXML_LIBRARY}
${Libkolab_LIBRARIES}
${Libkolabxml_LIBRARIES}
)
if(RUNTIME_PLUGINS_STATIC)
target_link_libraries(akonadi_kolabproxy_resource
akonadi_serializer_addressee
akonadi_serializer_contactgroup
akonadi_serializer_kcalcore
akonadi_serializer_mail
)
endif()
install(TARGETS akonadi_kolabproxy_resource ${INSTALL_TARGETS_DEFAULT_ARGS})
kde4_install_icons(${ICON_INSTALL_DIR})
add_subdirectory(tests)
add_subdirectory(wizard)
diff --git a/resources/kolabproxy/kolabproxyresource.cpp b/resources/kolabproxy/kolabproxyresource.cpp
index 7ba2cc397..1f3d9c76c 100644
--- a/resources/kolabproxy/kolabproxyresource.cpp
+++ b/resources/kolabproxy/kolabproxyresource.cpp
@@ -1,956 +1,969 @@
/*
Copyright (c) 2009 Andras Mantia <amantia@kde.org>
Copyright (c) 2012 Christian Mollekopf <mollekopf@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 "kolabproxyresource.h"
#include "collectiontreebuilder.h"
#include "freebusyupdatehandler.h"
#include "settings.h"
#include "settingsadaptor.h"
+#include "kolabproxyadaptor.h"
#include "setupkolab.h"
+#include <akonadi/dbusconnectionpool.h>
#include "collectionannotationsattribute.h" //from shared
#include <Akonadi/AttributeFactory>
#include <Akonadi/CachePolicy>
#include <Akonadi/ChangeRecorder>
#include <Akonadi/CollectionCreateJob>
#include <Akonadi/CollectionDeleteJob>
#include <Akonadi/CollectionFetchJob>
#include <Akonadi/CollectionFetchScope>
#include <Akonadi/CollectionModifyJob>
#include <Akonadi/CollectionMoveJob>
#include <Akonadi/EntityDisplayAttribute>
#include <Akonadi/EntityHiddenAttribute>
#include <Akonadi/ItemCreateJob>
#include <Akonadi/ItemDeleteJob>
#include <Akonadi/ItemFetchJob>
#include <Akonadi/ItemFetchScope>
#include <Akonadi/ItemModifyJob>
#include <Akonadi/ItemMoveJob>
#include <Akonadi/Session>
#include <Akonadi/KMime/MessageFlags>
#include <KLocale>
#include <KWindowSystem>
#include <QDBusInterface>
#include <QDBusReply>
#ifdef RUNTIME_PLUGINS_STATIC
#include <QtPlugin>
Q_IMPORT_PLUGIN(akonadi_serializer_mail)
Q_IMPORT_PLUGIN(akonadi_serializer_addressee)
Q_IMPORT_PLUGIN(akonadi_serializer_kcalcore)
Q_IMPORT_PLUGIN(akonadi_serializer_contactgroup)
#endif
static const char KOLAB_COLLECTION[] = "KolabCollection";
static const char KOLAB_ITEM[] = "KolabItem";
static const char IMAP_COLLECTION[] = "ImapCollection";
template <typename T>
static inline T kolabToImap( const T &kolabObject )
{
return T( kolabObject.remoteId().toLongLong() );
}
template <typename T>
static inline T imapToKolab( const T &imapObject )
{
T kolabObject;
kolabObject.setRemoteId( QString::number( imapObject.id() ) );
return kolabObject;
}
static QString mailBoxForImapCollection( const Akonadi::Collection &imapCollection,
bool showWarnings )
{
if ( imapCollection.remoteId().isEmpty() ) {
if ( showWarnings ) {
kWarning() << "Got incomplete ancestor chain:" << imapCollection;
}
return QString();
}
if ( imapCollection.parentCollection() == Akonadi::Collection::root() ) {
return QString( "" );
}
const QString parentMailbox =
mailBoxForImapCollection( imapCollection.parentCollection(), showWarnings );
if ( parentMailbox.isNull() ) {
// invalid, != isEmpty() here!
return QString();
}
const QString mailbox = parentMailbox + imapCollection.remoteId();
return mailbox;
}
KolabProxyResource::KolabProxyResource( const QString &id )
: ResourceBase( id )
{
Akonadi::AttributeFactory::registerAttribute<Akonadi::CollectionAnnotationsAttribute>();
-
new SettingsAdaptor( Settings::self() );
QDBusConnection::sessionBus().registerObject(
QLatin1String( "/Settings" ),
Settings::self(), QDBusConnection::ExportAdaptors );
+ new KolabproxyAdaptor( this );
+ Akonadi::DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/KolabProxy" ), this, QDBusConnection::ExportAdaptors );
+ Akonadi::DBusConnectionPool::threadConnection().registerService( QLatin1String( "Agent.akonadi_kolabproxy_resource" ) );
+
changeRecorder()->fetchCollection( true );
changeRecorder()->itemFetchScope().fetchFullPayload();
m_monitor = new Akonadi::Monitor( this );
m_monitor->itemFetchScope().fetchFullPayload();
m_monitor->itemFetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::All );
m_collectionMonitor = new Akonadi::Monitor( this );
m_collectionMonitor->fetchCollection( true );
m_collectionMonitor->setCollectionMonitored( Akonadi::Collection::root() );
m_collectionMonitor->ignoreSession( Akonadi::Session::defaultSession() );
m_collectionMonitor->collectionFetchScope().setAncestorRetrieval(
Akonadi::CollectionFetchScope::All );
m_freeBusyUpdateHandler = new FreeBusyUpdateHandler( this );
connect( m_monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)),
this, SLOT(imapItemAdded(Akonadi::Item,Akonadi::Collection)) );
connect( m_monitor, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)),
this, SLOT(imapItemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)) );
connect( m_monitor, SIGNAL(itemRemoved(Akonadi::Item)),
this, SLOT(imapItemRemoved(Akonadi::Item)) );
//We don't connect to changed because an edit results in a new item (append/delete) on imap
connect( m_collectionMonitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)),
this, SLOT(imapCollectionAdded(Akonadi::Collection,Akonadi::Collection)) );
connect( m_collectionMonitor, SIGNAL(collectionRemoved(Akonadi::Collection)),
this, SLOT(imapCollectionRemoved(Akonadi::Collection)) );
connect( m_collectionMonitor, SIGNAL(collectionChanged(Akonadi::Collection)),
this, SLOT(imapCollectionChanged(Akonadi::Collection)) );
connect( m_collectionMonitor,
SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection)),
this,
SLOT(imapCollectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection)) );
setName( i18n( "Kolab" ) );
// among other things, this ensures that m_root actually exists when a new imap folder is added
synchronizeCollectionTree();
}
KolabProxyResource::~KolabProxyResource()
{
}
KolabHandler::Ptr KolabProxyResource::getHandler(Akonadi::Entity::Id collectionId)
{
KolabHandler::Ptr handler = m_monitoredCollections.value(collectionId);
if ( !handler ) {
kWarning() << "No handler for collection available: " << collectionId;
return KolabHandler::Ptr();
}
return handler;
}
void KolabProxyResource::retrieveCollections()
{
kDebug() << "RETRIEVECOLLECTIONS ";
CollectionTreeBuilder *job = new CollectionTreeBuilder( this );
connect( job, SIGNAL(result(KJob*)), this, SLOT(retrieveCollectionsTreeDone(KJob*)) );
}
void KolabProxyResource::retrieveCollectionsTreeDone( KJob *job )
{
if ( job->error() ) {
kWarning( ) << "Error on collection fetch:" << job->errorText();
cancelTask( job->errorText() );
} else {
Akonadi::Collection::List imapCollections =
qobject_cast<CollectionTreeBuilder*>( job )->allCollections();
Akonadi::Collection::List kolabCollections;
Q_FOREACH ( const Akonadi::Collection &collection, imapCollections ) {
kolabCollections.append( createCollection( collection ) );
}
collectionsRetrieved( kolabCollections );
}
}
void KolabProxyResource::retrieveItems( const Akonadi::Collection &collection )
{
kDebug() << "RETRIEVEITEMS";
const Akonadi::Collection imapCollection = kolabToImap( collection );
const KolabHandler::Ptr handler = getHandler( imapCollection.id() );
Q_ASSERT( handler );
handler->reset();
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( imapCollection );
job->fetchScope().fetchFullPayload();
job->fetchScope().setIgnoreRetrievalErrors( true );
setItemStreamingEnabled( true );
connect( job, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(itemsReceived(Akonadi::Item::List)) );
connect( job, SIGNAL(result(KJob*)), this, SLOT(retrieveItemsFetchDone(KJob*)) );
}
void KolabProxyResource::itemsReceived(const Akonadi::Item::List &items)
{
if ( const KolabHandler::Ptr handler = getHandler( items[0].storageCollectionId() ) ) {
const Akonadi::Item::List newItems = handler->translateItems( items );
itemsRetrieved( newItems );
}
}
void KolabProxyResource::retrieveItemsFetchDone( KJob *job )
{
if ( job->error() ) {
kWarning( ) << "Error on item fetch:" << job->errorText();
cancelTask();
return;
}
itemsRetrievalDone();
kDebug() << "RETRIEVEITEM DONE";
}
bool KolabProxyResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
Q_UNUSED( parts );
kDebug() << "RETRIEVEITEM";
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( kolabToImap( item ) );
foreach (const QByteArray &part, parts) {
job->fetchScope().fetchPayloadPart( part );
}
job->setProperty( "itemId", item.id() );
connect( job, SIGNAL(result(KJob*)), this, SLOT(retrieveItemFetchDone(KJob*)) );
return true;
}
void KolabProxyResource::retrieveItemFetchDone( KJob *job )
{
if ( job->error() ) {
kWarning( ) << "Error on item fetch:" << job->errorText();
cancelTask();
return;
}
const Akonadi::Item::List items = qobject_cast<Akonadi::ItemFetchJob*>(job)->items();
if ( items.isEmpty() ) {
kWarning() << "Items is emtpy";
cancelTask();
return;
}
const KolabHandler::Ptr handler = getHandler( items[0].storageCollectionId() );
if ( !handler ) {
cancelTask();
return;
}
const Akonadi::Item::List newItems = handler->translateItems( items );
if ( newItems.isEmpty() ) {
kWarning() << "Could not translate item";
cancelTask();
return;
}
Akonadi::Item item = newItems[0];
item.setId(job->property("itemId").value<Akonadi::Item::Id>());
itemRetrieved( item );
kDebug() << "RETRIEVEITEM DONE";
}
void KolabProxyResource::aboutToQuit()
{
m_monitoredCollections.clear();
}
Kolab::Version readKolabVersion( const QString &resourceIdentifier )
{
KConfigGroup grp( KGlobal::mainComponent().config(), "KolabProxyResourceSettings" );
return static_cast<Kolab::Version>(
grp.readEntry<int>( "KolabFormatVersion" + resourceIdentifier,
static_cast<int>( Kolab::KolabV2 ) ) );
}
void KolabProxyResource::configure( WId windowId )
{
// TODO: this method is usually called when a new resource is being
// added to the Akonadi setup. You can do any kind of user interaction here,
// e.g. showing dialogs.
// The given window ID is usually useful to get the correct
// "on top of parent" behavior if the running window manager applies any kind
// of focus stealing prevention technique
QPointer<SetupKolab> kolabConfigDialog( new SetupKolab( this ) );
if ( windowId )
KWindowSystem::setMainWindow( kolabConfigDialog, windowId );
kolabConfigDialog->setWindowIcon( KIcon( "kolab" ) );
kolabConfigDialog->exec();
emit configurationDialogAccepted();
foreach ( Akonadi::Entity::Id id, m_monitoredCollections.keys() ) { //krazy:exclude=foreach
KolabHandler::Ptr handler = m_monitoredCollections.value( id );
Kolab::Version v = readKolabVersion( m_resourceIdentifier.value( id ) );
handler->setKolabFormatVersion( v );
}
delete kolabConfigDialog;
}
void KolabProxyResource::itemAdded( const Akonadi::Item &kolabItem,
const Akonadi::Collection &collection )
{
kDebug() << "ITEMADDED";
// kDebug() << "Item added " << item.id() << collection.remoteId() << collection.id();
const Akonadi::Collection imapCollection = kolabToImap( collection );
createItem( imapCollection, kolabItem );
}
void KolabProxyResource::createItem( const Akonadi::Collection &imapCollection, const Akonadi::Item &kolabItem )
{
KolabHandler::Ptr handler = getHandler( imapCollection.id() );
if ( !handler ) {
cancelTask();
return;
}
Akonadi::Item imapItem( handler->contentMimeTypes()[0] );
if (!handler->toKolabFormat( kolabItem, imapItem )) {
kWarning() << "Failed to convert item to kolab format: " << kolabItem.id();
cancelTask();
return;
}
imapItem.setFlag( Akonadi::MessageFlags::Seen );
Akonadi::ItemCreateJob *cjob = new Akonadi::ItemCreateJob( imapItem, imapCollection );
cjob->setProperty( KOLAB_ITEM, QVariant::fromValue( kolabItem ) );
cjob->setProperty( IMAP_COLLECTION, QVariant::fromValue( imapCollection ) );
connect( cjob, SIGNAL(result(KJob*)), SLOT(imapItemCreationResult(KJob*)) );
}
void KolabProxyResource::imapItemCreationResult( KJob *job )
{
if ( job->error() ) {
cancelTask( job->errorText() );
return;
}
Akonadi::ItemCreateJob *cjob = qobject_cast<Akonadi::ItemCreateJob*>( job );
const Akonadi::Item imapItem = cjob->item();
Akonadi::Item kolabItem = cjob->property( KOLAB_ITEM ).value<Akonadi::Item>();
// TODO add accessor to ItemCreateJob for the parent collection
const Akonadi::Collection imapCollection =
cjob->property( IMAP_COLLECTION ).value<Akonadi::Collection>();
KolabHandler::Ptr handler = m_monitoredCollections.value( imapCollection.id() );
Q_ASSERT( handler );
handler->itemAdded( imapItem );
m_excludeAppend << imapItem.id();
kolabItem.setRemoteId( QString::number( imapItem.id() ) );
changeCommitted( kolabItem );
}
void KolabProxyResource::itemChanged( const Akonadi::Item &kolabItem,
const QSet<QByteArray> &parts )
{
Q_UNUSED( parts );
kDebug() << "ITEMCHANGED" << kolabItem.id() << kolabItem.remoteId();
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( kolabToImap( kolabItem ), this );
job->setProperty( KOLAB_ITEM, QVariant::fromValue( kolabItem ) );
connect( job, SIGNAL(result(KJob*)), SLOT(imapItemUpdateFetchResult(KJob*)) );
}
void KolabProxyResource::imapItemUpdateFetchResult( KJob *job )
{
if ( job->error() ) {
cancelTask( job->errorText() );
return;
}
const Akonadi::Item kolabItem = job->property( KOLAB_ITEM ).value<Akonadi::Item>();
Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob*>( job );
if (fetchJob->items().isEmpty()) { //The corresponding imap item hasn't been created yet
Akonadi::CollectionFetchJob *fetch =
new Akonadi::CollectionFetchJob( Akonadi::Collection( kolabItem.storageCollectionId() ),
Akonadi::CollectionFetchJob::Base, this );
fetch->setProperty( KOLAB_ITEM, QVariant::fromValue( kolabItem ) );
connect( fetch, SIGNAL(result(KJob*)), SLOT(imapItemUpdateCollectionFetchResult(KJob*)) );
} else {
Akonadi::Item imapItem = fetchJob->items().first();
KolabHandler::Ptr handler = m_monitoredCollections.value( imapItem.storageCollectionId() );
if ( !handler ) {
kWarning() << "No handler found";
cancelTask();
return;
}
if (!handler->toKolabFormat( kolabItem, imapItem )) {
kWarning() << "Failed to convert item to kolab format: " << kolabItem.id();
cancelTask();
return;
}
Akonadi::ItemModifyJob *mjob = new Akonadi::ItemModifyJob( imapItem );
mjob->setProperty( KOLAB_ITEM, fetchJob->property( KOLAB_ITEM ) );
connect( mjob, SIGNAL(result(KJob*)), SLOT(imapItemUpdateResult(KJob*)) );
}
}
void KolabProxyResource::imapItemUpdateCollectionFetchResult( KJob *job )
{
Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob*>( job );
if ( job->error() || fetchJob->collections().isEmpty() ) {
cancelTask( job->errorText() );
return;
}
const Akonadi::Item kolabItem = job->property( KOLAB_ITEM ).value<Akonadi::Item>();
const Akonadi::Collection kolabCollection = fetchJob->collections().first();
const Akonadi::Collection imapCollection = kolabToImap( kolabCollection );
createItem( imapCollection, kolabItem );
}
void KolabProxyResource::imapItemUpdateResult( KJob *job )
{
if ( job->error() ) {
cancelTask( job->errorText() );
return;
}
const Akonadi::Item kolabItem = job->property( KOLAB_ITEM ).value<Akonadi::Item>();
changeCommitted( kolabItem );
}
void KolabProxyResource::itemMoved( const Akonadi::Item &item,
const Akonadi::Collection &collectionSource,
const Akonadi::Collection &collectionDestination )
{
Q_UNUSED( collectionSource );
new Akonadi::ItemMoveJob( kolabToImap( item ), kolabToImap( collectionDestination ), this );
changeCommitted( item );
}
void KolabProxyResource::itemRemoved( const Akonadi::Item &item )
{
kDebug() << "ITEMREMOVED";
kDebug() << "Item removed " << item.id() << item.remoteId();
const Akonadi::Item imapItem( item.remoteId().toUInt() );
Akonadi::ItemDeleteJob *djob = new Akonadi::ItemDeleteJob( imapItem );
changeCommitted( item );
Q_UNUSED(djob);
}
void KolabProxyResource::collectionAdded( const Akonadi::Collection &collection,
const Akonadi::Collection &parent )
{
if ( KolabHandler::kolabTypeForMimeType( collection.contentMimeTypes() ).isEmpty() ) {
kWarning() << "Collection " << collection.name() << collection.id() << collection.isValid()
<< "doesn't have kolab type set. isValid = "
<< "; parent is " << parent.name() << parent.id() << parent.isValid();
cancelTask( QLatin1String( "Collection doesn't have kolab type." ) );
Q_ASSERT_X( false, "collectionAdded", "Collection doesn't have kolab type set. Crashing..." );
return;
}
Akonadi::Collection imapCollection( collection );
imapCollection.setId( -1 );
imapCollection.setRemoteId( QString() );
imapCollection.setContentMimeTypes( QStringList()
<< Akonadi::Collection::mimeType()
<< QLatin1String( "message/rfc822" ) );
const Akonadi::Collection imapParent = kolabToImap( parent );
imapCollection.setParentCollection( imapParent );
Akonadi::CollectionAnnotationsAttribute *attr =
imapCollection.attribute<Akonadi::CollectionAnnotationsAttribute>(
Akonadi::Collection::AddIfMissing );
QMap<QByteArray, QByteArray> annotations = attr->annotations();
annotations[KOLAB_FOLDER_TYPE_ANNOTATION] =
KolabHandler::kolabTypeForMimeType( collection.contentMimeTypes() );
attr->setAnnotations( annotations );
Akonadi::CollectionCreateJob *job = new Akonadi::CollectionCreateJob( imapCollection, this );
job->setProperty( KOLAB_COLLECTION, QVariant::fromValue( collection ) );
connect( job, SIGNAL(result(KJob*)), SLOT(imapFolderCreateResult(KJob*)) );
}
void KolabProxyResource::imapFolderCreateResult( KJob *job )
{
if ( job->error() ) {
cancelTask( job->errorText() );
} else {
const Akonadi::Collection imapCollection =
qobject_cast<Akonadi::CollectionCreateJob*>( job )->collection();
registerHandlerForCollection( imapCollection );
Akonadi::Collection kolabCollection =
job->property( KOLAB_COLLECTION ).value<Akonadi::Collection>();
kolabCollection.setRemoteId( QString::number( imapCollection.id() ) );
changeCommitted( kolabCollection );
}
}
void KolabProxyResource::applyAttributesToImap( Akonadi::Collection &imapCollection,
const Akonadi::Collection &kolabCollection )
{
static const Akonadi::EntityDisplayAttribute eda;
static const Akonadi::EntityHiddenAttribute hidden;
foreach ( const Akonadi::Attribute *attr, kolabCollection.attributes() ) {
if ( attr->type() == hidden.type() ) {
// Don't propagate HIDDEN because that would hide collections in korg, kab too.
continue;
}
if ( attr->type() == eda.type() ) {
// Don't propagate DISPLAYATTRIBUTE because that would cause icons
// from the imap resource to use kolab icons.
Akonadi::EntityDisplayAttribute *imapEda =
imapCollection.attribute<Akonadi::EntityDisplayAttribute>( Akonadi::Entity::AddIfMissing );
const QString dName =
static_cast<const Akonadi::EntityDisplayAttribute*>( attr )->displayName();
imapEda->setDisplayName( dName );
continue;
}
if ( attr->type() == "AccessRights" ) {
continue;
}
//kDebug() << "cloning" << attr->type();
imapCollection.addAttribute( attr->clone() );
}
}
void KolabProxyResource::applyAttributesFromImap( Akonadi::Collection &kolabCollection,
const Akonadi::Collection &imapCollection )
{
static const Akonadi::EntityDisplayAttribute eda;
static const Akonadi::EntityHiddenAttribute hidden;
foreach ( const Akonadi::Attribute *attr, imapCollection.attributes() ) {
if ( attr->type() == hidden.type() ) {
continue;
}
if ( attr->type() == eda.type() ) {
continue;
}
if ( attr->type() == "AccessRights" ) {
continue;
}
//kDebug() << "cloning" << attr->type();
kolabCollection.addAttribute( attr->clone() );
}
}
void KolabProxyResource::updateFreeBusyInformation( const Akonadi::Collection &imapCollection )
{
const Akonadi::CollectionAnnotationsAttribute *annotationsAttribute =
imapCollection.attribute<Akonadi::CollectionAnnotationsAttribute>();
if ( annotationsAttribute ) {
const QMap<QByteArray, QByteArray> annotations = annotationsAttribute->annotations();
const QByteArray folderType = annotations[ KOLAB_FOLDER_TYPE_ANNOTATION ];
if ( folderType != KOLAB_FOLDER_TYPE_EVENT &&
folderType != KOLAB_FOLDER_TYPE_EVENT KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) {
return; // no kolab calendar collection
}
} else {
return; // no kolab collection
}
if ( !Settings::self()->updateFreeBusy() ) {
return; // disabled by user
}
Kolab::Version v = readKolabVersion( imapCollection.resource() );
if (v != Kolab::KolabV2) {
return;
}
const QString path = mailBoxForImapCollection( imapCollection, true );
if ( path.isEmpty() ) {
return;
}
const QString resourceId = imapCollection.resource();
QDBusInterface settingsInterface(
QString::fromLatin1( "org.freedesktop.Akonadi.Agent.%1" ).arg( resourceId ),
QLatin1String( "/Settings" ), QLatin1String( "org.kde.Akonadi.Imap.Settings" ) );
QDBusInterface walletInterface(
QString::fromLatin1( "org.freedesktop.Akonadi.Agent.%1" ).arg( resourceId ),
QLatin1String( "/Settings" ), QLatin1String( "org.kde.Akonadi.Imap.Wallet" ) );
if ( !settingsInterface.isValid() || !walletInterface.isValid() ) {
kWarning() << "unable to retrieve imap resource settings interface";
return;
}
const QDBusReply<QString> userNameReply = settingsInterface.call( QLatin1String( "userName" ) );
if ( !userNameReply.isValid() ) {
kWarning() << "unable to retrieve user name from imap resource settings";
return;
}
const QDBusReply<QString> passwordReply = walletInterface.call( QLatin1String( "password" ) );
if ( !passwordReply.isValid() ) {
kWarning() << "unable to retrieve password from imap resource settings";
return;
}
const QDBusReply<QString> hostReply = settingsInterface.call( QLatin1String( "imapServer" ) );
if ( !hostReply.isValid() ) {
kWarning() << "unable to retrieve host from imap resource settings";
return;
}
m_freeBusyUpdateHandler->updateFolder( path,
userNameReply.value(),
passwordReply.value(),
hostReply.value() );
}
void KolabProxyResource::collectionChanged( const Akonadi::Collection &collection )
{
Akonadi::Collection imapCollection;
imapCollection.setId( collection.remoteId().toLongLong() );
imapCollection.setName( collection.name() );
imapCollection.setCachePolicy( collection.cachePolicy() );
imapCollection.setRights( collection.rights() );
applyAttributesToImap( imapCollection, collection );
Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob( imapCollection, this );
Q_UNUSED( job );
// TODO wait for the result
changeCommitted( collection );
}
void KolabProxyResource::collectionMoved( const Akonadi::Collection &collection,
const Akonadi::Collection &source,
const Akonadi::Collection &destination )
{
Q_UNUSED( source );
new Akonadi::CollectionMoveJob( kolabToImap( collection ), kolabToImap( destination ), this );
changeCommitted( collection );
}
void KolabProxyResource::collectionRemoved( const Akonadi::Collection &collection )
{
Akonadi::Collection imapCollection = kolabToImap( collection );
Akonadi::CollectionDeleteJob *job = new Akonadi::CollectionDeleteJob( imapCollection, this );
Q_UNUSED( job );
// TODO wait for result
changeCommitted( collection );
}
void KolabProxyResource::deleteImapItem( const Akonadi::Item &item )
{
kDebug() << "DELETEIMAPITEM";
Akonadi::ItemDeleteJob *djob = new Akonadi::ItemDeleteJob( item );
Q_UNUSED( djob );
}
void KolabProxyResource::addImapItem( const Akonadi::Item &item,
Akonadi::Entity::Id collectionId )
{
kDebug() << "ADDITEMTOIMAP";
new Akonadi::ItemCreateJob( item, Akonadi::Collection( collectionId ) );
}
void KolabProxyResource::imapItemAdded( const Akonadi::Item &item,
const Akonadi::Collection &collection )
{
kDebug() << item.id() << collection.id() << Akonadi::Collection::root().id();
if ( m_excludeAppend.contains( item.id() ) ) {
kDebug() << "item already present";
m_excludeAppend.removeAll( item.id() );
return;
}
//TODO: slow, would be nice if ItemCreateJob would work with a Collection
// having only the remoteId set
const Akonadi::Collection kolabCol = imapToKolab( collection );
Akonadi::CollectionFetchJob *job =
new Akonadi::CollectionFetchJob( kolabCol, Akonadi::CollectionFetchJob::Base, this );
connect( job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchDone(KJob*)) );
job->setProperty( KOLAB_ITEM, QVariant::fromValue( item ) );
job->setProperty( "collectionId", QString::number( collection.id() ) );
}
void KolabProxyResource::collectionFetchDone( KJob *job )
{
if ( job->error() ) {
kWarning( ) << "Error on collection fetch:" << job->errorText();
return;
}
Akonadi::Collection::List collections =
qobject_cast<Akonadi::CollectionFetchJob*>(job)->collections();
Q_ASSERT(collections.size() == 1);
const Akonadi::Collection c = collections[0];
Q_ASSERT(c.remoteId() == job->property("collectionId").toString() );
if ( const KolabHandler::Ptr handler = getHandler( c.remoteId().toUInt() ) ) {
const Akonadi::Item item = job->property( KOLAB_ITEM ).value<Akonadi::Item>();
const Akonadi::Item::List newItems = handler->translateItems( Akonadi::Item::List() << item );
if ( !newItems.isEmpty() ) {
Akonadi::ItemCreateJob *cjob = new Akonadi::ItemCreateJob( newItems[0], c );
connect( cjob, SIGNAL(result(KJob*)), this, SLOT(itemCreatedDone(KJob*)) );
}
} else {
kWarning() << "No handler found";
}
}
void KolabProxyResource::itemCreatedDone( KJob *job )
{
if ( job->error() ) {
kWarning( ) << "Error on creating item:" << job->errorText();
}
}
void KolabProxyResource::imapItemRemoved( const Akonadi::Item &item )
{
kDebug() << "IMAPITEMREMOVED";
const Akonadi::Item kolabItem = imapToKolab( item );
Q_FOREACH ( KolabHandler::Ptr handler, m_monitoredCollections ) {
handler->itemDeleted( item );
}
Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob( kolabItem, this );
Q_UNUSED( job );
}
void KolabProxyResource::imapItemMoved( const Akonadi::Item &item,
const Akonadi::Collection &collectionSource,
const Akonadi::Collection &collectionDestination )
{
kDebug();
Q_UNUSED( collectionSource );
new Akonadi::ItemMoveJob( imapToKolab( item ), imapToKolab( collectionDestination ), this );
}
void KolabProxyResource::imapCollectionAdded( const Akonadi::Collection &collection,
const Akonadi::Collection &parent )
{
Q_UNUSED( parent );
if ( collection.resource() == identifier() ) {
// just to be sure...
return;
}
kDebug() << "IMAPCOLLECTIONADDED";
if ( m_monitoredCollections.contains( collection.id() ) ) {
// something is wrong, so better reload out collection tree
kDebug() << "IMAPCOLLECTIONADDED ABORT";
synchronizeCollectionTree();
return;
}
if ( registerHandlerForCollection( collection ) ) {
const Akonadi::Collection kolabCollection = createCollection( collection );
Akonadi::CollectionCreateJob *job = new Akonadi::CollectionCreateJob( kolabCollection, this );
connect( job, SIGNAL(result(KJob*)), SLOT(kolabFolderChangeResult(KJob*)) );
}
}
void KolabProxyResource::imapCollectionChanged( const Akonadi::Collection &collection )
{
if ( collection.resource() == identifier() ) {
// just to be sure...
return;
}
//kDebug() << "IMAPCOLLECTIONCHANGED";
if ( !m_monitoredCollections.contains( collection.id() ) ) {
// check if this is a Kolab folder at all, if yet something is wrong
Akonadi::CollectionAnnotationsAttribute *annotationsAttribute =
collection.attribute<Akonadi::CollectionAnnotationsAttribute>();
bool isKolabFolder = false;
if ( annotationsAttribute ) {
const QMap<QByteArray, QByteArray> annotations = annotationsAttribute->annotations();
QByteArray folderType = annotations[ KOLAB_FOLDER_TYPE_ANNOTATION ];
isKolabFolder = !folderType.isEmpty() && folderType != KOLAB_FOLDER_TYPE_MAIL;
}
if ( isKolabFolder ) {
synchronizeCollectionTree();
return;
}
// not a Kolab folder, no need to resync the tree.
// just try to update a possible structural collection.
// if that fails it's not in our tree -> we don't care
Akonadi::Collection kolabCollection = createCollection( collection );
Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob( kolabCollection, this );
Q_UNUSED( job );
} else {
// Kolab folder we already have in our tree, if the update fails, reload our tree
Akonadi::Collection kolabCollection = createCollection( collection );
Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob( kolabCollection, this );
connect( job, SIGNAL(result(KJob*)), SLOT(kolabFolderChangeResult(KJob*)) );
}
updateFreeBusyInformation( collection );
}
void KolabProxyResource::imapCollectionMoved( const Akonadi::Collection &collection,
const Akonadi::Collection &source,
const Akonadi::Collection &destination )
{
kDebug();
Q_UNUSED( source );
new Akonadi::CollectionMoveJob( imapToKolab( collection ), imapToKolab( destination ), this );
}
void KolabProxyResource::kolabFolderChangeResult( KJob *job )
{
if ( job->error() ) {
// something went wrong or the change was too complex to handle in the above slots,
// so re-sync the entire tree.
kDebug() << "Re-syncing collection tree as incremental changes did not succeed."
<< job->errorText();
synchronizeCollectionTree();
}
}
void KolabProxyResource::imapCollectionRemoved( const Akonadi::Collection &imapCollection )
{
if ( imapCollection.resource() == identifier() ) {
// just to be sure...
return;
}
kDebug() << "IMAPCOLLECTIONREMOVED";
Akonadi::Collection kolabCollection;
kolabCollection.setRemoteId( QString::number( imapCollection.id() ) );
new Akonadi::CollectionDeleteJob( kolabCollection );
m_monitoredCollections.remove( imapCollection.id() );
updateFreeBusyInformation( imapCollection );
}
Akonadi::Collection KolabProxyResource::createCollection(
const Akonadi::Collection &imapCollection )
{
Akonadi::Collection c;
QStringList contentTypes;
if ( imapCollection.parentCollection() == Akonadi::Collection::root() ) {
c.setParentCollection( Akonadi::Collection::root() );
Akonadi::CachePolicy policy;
policy.setInheritFromParent( false );
policy.setCacheTimeout( -1 );
policy.setLocalParts( QStringList() << QLatin1String( "ALL" ) );
c.setCachePolicy( policy );
} else {
c.parentCollection().setRemoteId( QString::number( imapCollection.parentCollection().id() ) );
}
c.setName( imapCollection.name() );
c.setRights( imapCollection.rights() );
Akonadi::EntityDisplayAttribute *imapAttr =
imapCollection.attribute<Akonadi::EntityDisplayAttribute>();
Akonadi::EntityDisplayAttribute *kolabAttr =
c.attribute<Akonadi::EntityDisplayAttribute>( Akonadi::Collection::AddIfMissing );
if ( imapAttr ) {
if ( imapAttr->iconName() == QLatin1String( "mail-folder-inbox" ) ) {
kolabAttr->setDisplayName( i18n( "My Data" ) );
kolabAttr->setIconName( QLatin1String( "view-pim-summary" ) );
//contentTypes << KolabHandler::allSupportedMimeTypes();
c.setRights( Akonadi::Collection::ReadOnly | Akonadi::Collection::CanCreateCollection );
} else if ( imapCollection.parentCollection() == Akonadi::Collection::root() ) {
c.setName( i18n( "Kolab (%1)", imapAttr->displayName() ) );
kolabAttr->setIconName( QLatin1String( "kolab" ) );
} else {
kolabAttr->setDisplayName( imapAttr->displayName() );
kolabAttr->setIconName( imapAttr->iconName() );
}
} else {
if ( imapCollection.parentCollection() == Akonadi::Collection::root() ) {
c.setName( i18n( "Kolab (%1)", imapCollection.name() ) );
kolabAttr->setIconName( QLatin1String( "kolab" ) );
}
}
applyAttributesFromImap( c, imapCollection );
KolabHandler::Ptr handler = m_monitoredCollections.value( imapCollection.id() );
contentTypes.append( Akonadi::Collection::mimeType() );
if ( handler ) {
contentTypes.append( handler->contentMimeTypes() );
kolabAttr->setIconName( handler->iconName() );
// hide Kolab folders on the IMAP server
if ( !imapCollection.hasAttribute<Akonadi::EntityHiddenAttribute>() ) {
Akonadi::Collection hiddenImapCol( imapCollection );
hiddenImapCol.attribute<Akonadi::EntityHiddenAttribute>( Akonadi::Collection::AddIfMissing );
new Akonadi::CollectionModifyJob( hiddenImapCol, this );
}
}
c.setContentMimeTypes( contentTypes );
c.setRemoteId( QString::number( imapCollection.id() ) );
return c;
}
bool KolabProxyResource::registerHandlerForCollection( const Akonadi::Collection &imapCollection )
{
Akonadi::CollectionAnnotationsAttribute *annotationsAttribute =
imapCollection.attribute<Akonadi::CollectionAnnotationsAttribute>();
if ( annotationsAttribute ) {
QMap<QByteArray, QByteArray> annotations = annotationsAttribute->annotations();
KolabHandler::Ptr handler =
KolabHandler::createHandler(
annotations[KOLAB_FOLDER_TYPE_ANNOTATION], imapCollection );
if ( handler ) {
Kolab::Version v = readKolabVersion( imapCollection.resource() );
handler->setKolabFormatVersion( v );
connect( handler.data(), SIGNAL(deleteItemFromImap(Akonadi::Item)),
this, SLOT(deleteImapItem(Akonadi::Item)));
connect( handler.data(), SIGNAL(addItemToImap(Akonadi::Item,Akonadi::Entity::Id)),
this, SLOT(addImapItem(Akonadi::Item,Akonadi::Entity::Id)));
m_monitor->setCollectionMonitored( imapCollection );
m_monitoredCollections.insert( imapCollection.id(), handler );
m_resourceIdentifier.insert( imapCollection.id(), imapCollection.resource() );
return true;
}
}
return false;
}
+QString KolabProxyResource::imapResourceForCollection( Akonadi::Collection::Id id )
+{
+ if (m_resourceIdentifier.contains(id)) {
+ return m_resourceIdentifier[id];
+ }
+ return QString();
+}
+
AKONADI_RESOURCE_MAIN( KolabProxyResource )
#include "kolabproxyresource.moc"
diff --git a/resources/kolabproxy/kolabproxyresource.h b/resources/kolabproxy/kolabproxyresource.h
index 7577b3143..861d1008c 100644
--- a/resources/kolabproxy/kolabproxyresource.h
+++ b/resources/kolabproxy/kolabproxyresource.h
@@ -1,145 +1,147 @@
/*
Copyright (c) 2009 Andras Mantia <amantia@kde.org>
Copyright (c) 2012 Christian Mollekopf <mollekopf@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 KOLABPROXY_KOLABPROXYRESOURCE_H
#define KOLABPROXY_KOLABPROXYRESOURCE_H
#include "kolabhandler.h"
#include <Akonadi/ResourceBase>
class FreeBusyUpdateHandler;
namespace Akonadi {
class Monitor;
}
class KolabProxyResource : public Akonadi::ResourceBase,
public Akonadi::AgentBase::ObserverV2
{
Q_OBJECT
public:
explicit KolabProxyResource( const QString &id );
~KolabProxyResource();
/**
* Creates a new KolabHandler for @p imapCollection given it actually is
* a Kolab folder.
*
* @return @c true if @p imapCollection is a Kolab folder, @c false otherwise.
*/
bool registerHandlerForCollection( const Akonadi::Collection &imapCollection );
+ QString imapResourceForCollection( Akonadi::Collection::Id id );
+
public Q_SLOTS:
virtual void configure( WId windowId );
protected Q_SLOTS:
void retrieveCollections();
void retrieveItems( const Akonadi::Collection &col );
bool retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts );
void imapItemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection );
void imapItemMoved( const Akonadi::Item &item,
const Akonadi::Collection &collectionSource,
const Akonadi::Collection &collectionDestination );
void imapItemRemoved( const Akonadi::Item &item );
void imapCollectionAdded( const Akonadi::Collection &collection,
const Akonadi::Collection &parent );
void imapCollectionRemoved( const Akonadi::Collection &collection );
void imapCollectionChanged( const Akonadi::Collection &collection );
void imapCollectionMoved( const Akonadi::Collection &collection,
const Akonadi::Collection &source,
const Akonadi::Collection &destination );
void itemCreatedDone( KJob *job );
void collectionFetchDone( KJob *job );
void retrieveItemFetchDone( KJob * );
void retrieveItemsFetchDone( KJob * );
void retrieveCollectionsTreeDone( KJob *job );
void addImapItem( const Akonadi::Item &item, Akonadi::Entity::Id collectionId );
void deleteImapItem( const Akonadi::Item &item );
protected:
virtual void aboutToQuit();
virtual void itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection );
virtual void itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts );
virtual void itemMoved( const Akonadi::Item &item,
const Akonadi::Collection &collectionSource,
const Akonadi::Collection &collectionDestination );
virtual void itemRemoved( const Akonadi::Item &item );
virtual void collectionAdded( const Akonadi::Collection &collection,
const Akonadi::Collection &parent );
virtual void collectionChanged( const Akonadi::Collection &collection );
// do not hide the other variant, use implementation from base class
// which just forwards to the one above
using Akonadi::AgentBase::ObserverV2::collectionChanged;
virtual void collectionMoved( const Akonadi::Collection &collection,
const Akonadi::Collection &source,
const Akonadi::Collection &destination );
virtual void collectionRemoved( const Akonadi::Collection &collection );
private:
Akonadi::Collection createCollection( const Akonadi::Collection &imapCollection );
void createItem( const Akonadi::Collection &imapCollection, const Akonadi::Item &kolabItem );
void applyAttributesToImap( Akonadi::Collection &imapCollection,
const Akonadi::Collection &kolabCollection );
void applyAttributesFromImap( Akonadi::Collection &kolabCollection,
const Akonadi::Collection &imapCollection );
void updateFreeBusyInformation( const Akonadi::Collection &imapCollection );
private slots:
void imapItemCreationResult( KJob *job );
void imapItemUpdateFetchResult( KJob *job );
void imapItemUpdateResult( KJob *job );
void imapItemUpdateCollectionFetchResult( KJob *job );
void imapFolderCreateResult( KJob *job );
void kolabFolderChangeResult( KJob *job );
void itemsReceived(const Akonadi::Item::List &);
private:
KolabHandler::Ptr getHandler(Akonadi::Collection::Id);
Akonadi::Monitor *m_monitor;
Akonadi::Monitor *m_collectionMonitor;
QMap<Akonadi::Collection::Id, KolabHandler::Ptr> m_monitoredCollections;
QMap<Akonadi::Collection::Id, QString> m_resourceIdentifier;
QList<Akonadi::Item::Id> m_excludeAppend;
FreeBusyUpdateHandler *m_freeBusyUpdateHandler;
};
#endif
diff --git a/resources/kolabproxy/org.freedesktop.Akonadi.kolabproxy.xml b/resources/kolabproxy/org.freedesktop.Akonadi.kolabproxy.xml
new file mode 100644
index 000000000..2d1f2b1a0
--- /dev/null
+++ b/resources/kolabproxy/org.freedesktop.Akonadi.kolabproxy.xml
@@ -0,0 +1,9 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.Akonadi.kolabproxy">
+ <method name="imapResourceForCollection" >
+ <arg name="collection" type="x" direction="in"/>
+ <arg direction="out" type="s" />
+ </method>
+ </interface>
+</node>

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 8:02 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10074687
Default Alt Text
(45 KB)

Event Timeline