Page MenuHomePhorge

contactsresource.cpp
No OneTemporary

contactsresource.cpp

/*
Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>
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 "contactsresource.h"
#include "settings.h"
#include "contactsresourcesettingsadaptor.h"
#include "settingsdialog.h"
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QFile>
#include <akonadi/changerecorder.h>
#include <akonadi/collectionfetchscope.h>
#include <akonadi/entitydisplayattribute.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/dbusconnectionpool.h>
#include <akonadi/agentfactory.h>
using namespace Akonadi;
using namespace Akonadi_Contacts_Resource;
ContactsResource::ContactsResource( const QString &id )
: ResourceBase( id ),
mSettings( new ContactsResourceSettings( componentData().config() ) )
{
// setup the resource
new ContactsResourceSettingsAdaptor( mSettings );
DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/Settings" ),
mSettings, QDBusConnection::ExportAdaptors );
changeRecorder()->fetchCollection( true );
changeRecorder()->itemFetchScope().fetchFullPayload( true );
changeRecorder()->itemFetchScope().setAncestorRetrieval( ItemFetchScope::All );
changeRecorder()->collectionFetchScope().setAncestorRetrieval( CollectionFetchScope::All );
setHierarchicalRemoteIdentifiersEnabled( true );
mSupportedMimeTypes << KABC::Addressee::mimeType() << KABC::ContactGroup::mimeType() << Collection::mimeType();
if ( name().startsWith( QLatin1String( "akonadi_contacts_resource" ) ) )
setName( i18n( "Personal Contacts" ) );
// Make sure we have a valid directory (XDG dirs want this very much).
initializeDirectory(mSettings->path());
if ( mSettings->isConfigured() )
synchronize();
}
ContactsResource::~ContactsResource()
{
delete mSettings;
}
void ContactsResource::aboutToQuit()
{
}
void ContactsResource::configure( WId windowId )
{
QPointer<SettingsDialog> dlg = new SettingsDialog( mSettings, windowId );
if ( dlg->exec() ) {
mSettings->setIsConfigured( true );
mSettings->writeConfig();
clearCache();
initializeDirectory( baseDirectoryPath() );
synchronize();
emit configurationDialogAccepted();
} else {
emit configurationDialogRejected();
}
delete dlg;
}
Collection::List ContactsResource::createCollectionsForDirectory( const QDir &parentDirectory, const Collection &parentCollection ) const
{
Collection::List collections;
QDir dir( parentDirectory );
dir.setFilter( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable );
const QFileInfoList entries = dir.entryInfoList();
foreach ( const QFileInfo &entry, entries ) {
QDir subdir( entry.absoluteFilePath() );
Collection collection;
collection.setParentCollection( parentCollection );
collection.setRemoteId( entry.fileName() );
collection.setName( entry.fileName() );
collection.setContentMimeTypes( mSupportedMimeTypes );
collection.setRights( supportedRights( false ) );
collections << collection;
collections << createCollectionsForDirectory( subdir, collection );
}
return collections;
}
void ContactsResource::retrieveCollections()
{
// create the resource collection
Collection resourceCollection;
resourceCollection.setParentCollection( Collection::root() );
resourceCollection.setRemoteId( baseDirectoryPath() );
resourceCollection.setName( name() );
resourceCollection.setContentMimeTypes( mSupportedMimeTypes );
resourceCollection.setRights( supportedRights( true ) );
const QDir baseDir( baseDirectoryPath() );
Collection::List collections = createCollectionsForDirectory( baseDir, resourceCollection );
collections.append( resourceCollection );
collectionsRetrieved( collections );
}
void ContactsResource::retrieveItems( const Akonadi::Collection &collection )
{
QDir directory( directoryForCollection( collection ) );
if ( !directory.exists() ) {
cancelTask( i18n( "Directory '%1' does not exists", collection.remoteId() ) );
return;
}
directory.setFilter( QDir::Files | QDir::Readable );
Item::List items;
const QFileInfoList entries = directory.entryInfoList();
foreach ( const QFileInfo &entry, entries ) {
if ( entry.fileName() == "WARNING_README.txt" )
continue;
Item item;
item.setRemoteId( entry.fileName() );
if ( entry.fileName().endsWith( QLatin1String( ".vcf" ) ) )
item.setMimeType( KABC::Addressee::mimeType() );
else if ( entry.fileName().endsWith( QLatin1String( ".ctg" ) ) )
item.setMimeType( KABC::ContactGroup::mimeType() );
else {
cancelTask( i18n( "Found file of unknown format: '%1'", entry.absoluteFilePath() ) );
return;
}
items.append( item );
}
itemsRetrieved( items );
}
bool ContactsResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray>& )
{
const QString filePath = directoryForCollection( item.parentCollection() ) + QDir::separator() + item.remoteId();
Item newItem( item );
QFile file( filePath );
if ( !file.open( QIODevice::ReadOnly ) ) {
cancelTask( i18n( "Unable to open file '%1'", filePath ) );
return false;
}
if ( filePath.endsWith( QLatin1String( ".vcf" ) ) ) {
KABC::VCardConverter converter;
const QByteArray content = file.readAll();
const KABC::Addressee contact = converter.parseVCard( content );
if ( contact.isEmpty() ) {
cancelTask( i18n( "Found invalid contact in file '%1'", filePath ) );
return false;
}
newItem.setPayload<KABC::Addressee>( contact );
} else if ( filePath.endsWith( QLatin1String( ".ctg" ) ) ) {
KABC::ContactGroup group;
QString errorMessage;
if ( !KABC::ContactGroupTool::convertFromXml( &file, group, &errorMessage ) ) {
cancelTask( i18n( "Found invalid contact group in file '%1': %2", filePath, errorMessage ) );
return false;
}
newItem.setPayload<KABC::ContactGroup>( group );
} else {
cancelTask( i18n( "Found file of unknown format: '%1'", filePath ) );
return false;
}
file.close();
itemRetrieved( newItem );
return true;
}
void ContactsResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{
if ( mSettings->readOnly() ) {
cancelTask( i18n( "Trying to write to a read-only directory: '%1'", collection.remoteId() ) );
return;
}
const QString directoryPath = directoryForCollection( collection );
Item newItem( item );
if ( item.hasPayload<KABC::Addressee>() ) {
const KABC::Addressee contact = item.payload<KABC::Addressee>();
const QString fileName = directoryPath + QDir::separator() + contact.uid() + ".vcf";
KABC::VCardConverter converter;
const QByteArray content = converter.createVCard( contact );
QFile file( fileName );
if ( !file.open( QIODevice::WriteOnly ) ) {
cancelTask( i18n( "Unable to write to file '%1': %2", fileName, file.errorString() ) );
return;
}
file.write( content );
file.close();
newItem.setRemoteId( contact.uid() + ".vcf" );
} else if ( item.hasPayload<KABC::ContactGroup>() ) {
const KABC::ContactGroup group = item.payload<KABC::ContactGroup>();
const QString fileName = directoryPath + QDir::separator() + group.id() + ".ctg";
QFile file( fileName );
if ( !file.open( QIODevice::WriteOnly ) ) {
cancelTask( i18n( "Unable to write to file '%1': %2", fileName, file.errorString() ) );
return;
}
KABC::ContactGroupTool::convertToXml( group, &file );
file.close();
newItem.setRemoteId( group.id() + ".ctg" );
} else {
kWarning() << "got item without (usable) payload, ignoring it";
}
changeCommitted( newItem );
}
void ContactsResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
{
if ( mSettings->readOnly() ) {
cancelTask( i18n( "Trying to write to a read-only file: '%1'", item.remoteId() ) );
return;
}
Item newItem( item );
const QString fileName = directoryForCollection( item.parentCollection() ) + QDir::separator() + item.remoteId();
if ( item.hasPayload<KABC::Addressee>() ) {
const KABC::Addressee contact = item.payload<KABC::Addressee>();
KABC::VCardConverter converter;
const QByteArray content = converter.createVCard( contact );
QFile file( fileName );
if ( !file.open( QIODevice::WriteOnly ) ) {
cancelTask( i18n( "Unable to write to file '%1': %2", fileName, file.errorString() ) );
return;
}
file.write( content );
file.close();
newItem.setRemoteId( item.remoteId() );
} else if ( item.hasPayload<KABC::ContactGroup>() ) {
const KABC::ContactGroup group = item.payload<KABC::ContactGroup>();
QFile file( fileName );
if ( !file.open( QIODevice::WriteOnly ) ) {
cancelTask( i18n( "Unable to write to file '%1': %2", fileName, file.errorString() ) );
return;
}
KABC::ContactGroupTool::convertToXml( group, &file );
file.close();
newItem.setRemoteId( item.remoteId() );
} else {
cancelTask( i18n( "Received item with unknown payload %1", item.mimeType() ) );
return;
}
changeCommitted( newItem );
}
void ContactsResource::itemRemoved( const Akonadi::Item &item )
{
if ( mSettings->readOnly() ) {
cancelTask( i18n( "Trying to write to a read-only file: '%1'", item.remoteId() ) );
return;
}
// If the parent collection has no valid remote id, the parent
// collection will be removed in a second, so stop here and remove
// all items in collectionRemoved().
if ( item.parentCollection().remoteId().isEmpty() ) {
changeProcessed();
return;
}
const QString fileName = directoryForCollection( item.parentCollection() ) + QDir::separator() + item.remoteId();
if ( !QFile::remove( fileName ) ) {
cancelTask( i18n( "Unable to remove file '%1'", fileName ) );
return;
}
changeProcessed();
}
void ContactsResource::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent )
{
if ( mSettings->readOnly() ) {
cancelTask( i18n( "Trying to write to a read-only directory: '%1'", parent.remoteId() ) );
return;
}
const QString dirName = directoryForCollection( parent ) + QDir::separator() + collection.name();
if ( !QDir::root().mkpath( dirName ) ) {
cancelTask( i18n( "Unable to create folder '%1'.", dirName ) );
return;
}
initializeDirectory( dirName );
Collection newCollection( collection );
newCollection.setRemoteId( collection.name() );
changeCommitted( newCollection );
}
void ContactsResource::collectionChanged( const Akonadi::Collection &collection )
{
if ( mSettings->readOnly() ) {
cancelTask( i18n( "Trying to write to a read-only directory: '%1'", collection.remoteId() ) );
return;
}
if ( collection.parentCollection() == Collection::root() ) {
if ( collection.name() != name() )
setName( collection.name() );
changeProcessed();
return;
}
if ( collection.remoteId() == collection.name() ) {
changeProcessed();
return;
}
const QString dirName = directoryForCollection( collection );
QFileInfo oldDirectory( dirName );
if ( !QDir::root().rename( dirName, oldDirectory.absolutePath() + QDir::separator() + collection.name() ) ) {
cancelTask( i18n( "Unable to rename folder '%1'.", collection.name() ) );
return;
}
Collection newCollection( collection );
newCollection.setRemoteId( collection.name() );
changeCommitted( newCollection );
}
/**
* Removes a @p directory recursively.
*/
static bool removeDirectory( const QDir &directory )
{
const QFileInfoList infoList =
directory.entryInfoList( QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot );
foreach ( const QFileInfo &info, infoList ) {
if ( info.isDir() ) {
if ( !removeDirectory( QDir( info.absoluteFilePath() ) ) )
return false;
} else {
if ( !QFile::remove( info.filePath() ) )
return false;
}
}
if ( !QDir::root().rmdir( directory.absolutePath() ) )
return false;
return true;
}
void ContactsResource::collectionRemoved( const Akonadi::Collection &collection )
{
if ( mSettings->readOnly() ) {
cancelTask( i18n( "Trying to write to a read-only directory: '%1'", collection.remoteId() ) );
return;
}
if ( !removeDirectory( directoryForCollection( collection ) ) ) {
cancelTask( i18n( "Unable to delete folder '%1'.", collection.name() ) );
return;
}
changeProcessed();
}
void ContactsResource::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &collectionSource,
const Akonadi::Collection &collectionDestination )
{
const QString sourceFileName = directoryForCollection( collectionSource ) + QDir::separator() + item.remoteId();
const QString targetFileName = directoryForCollection( collectionDestination ) + QDir::separator() + item.remoteId();
if ( QFile::rename( sourceFileName, targetFileName ) )
changeProcessed();
else
cancelTask( i18n( "Unable to move file '%1' to '%2', '%2' already exists.", sourceFileName, targetFileName ) );
}
void ContactsResource::collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &collectionSource,
const Akonadi::Collection &collectionDestination )
{
const QString sourceDirectoryName = directoryForCollection( collectionSource ) + QDir::separator() + collection.remoteId();
const QString targetDirectoryName = directoryForCollection( collectionDestination ) + QDir::separator() + collection.remoteId();
if ( QFile::rename( sourceDirectoryName, targetDirectoryName ) )
changeProcessed();
else
cancelTask( i18n( "Unable to move directory '%1' to '%2', '%2' already exists.", sourceDirectoryName, targetDirectoryName ) );
}
QString ContactsResource::baseDirectoryPath() const
{
return mSettings->path();
}
void ContactsResource::initializeDirectory( const QString &path ) const
{
QDir dir( path );
// if folder does not exists, create it
if ( !dir.exists() )
QDir::root().mkpath( dir.absolutePath() );
// check whether warning file is in place...
QFile file( dir.absolutePath() + QDir::separator() + "WARNING_README.txt" );
if ( !file.exists() ) {
// ... if not, create it
file.open( QIODevice::WriteOnly );
file.write( "Important Warning!!!\n\n"
"Don't create or copy vCards inside this folder manually, they are managed by the Akonadi framework!\n" );
file.close();
}
}
Collection::Rights ContactsResource::supportedRights( bool isResourceCollection ) const
{
Collection::Rights rights = Collection::ReadOnly;
if ( !mSettings->readOnly() ) {
rights |= Collection::CanChangeItem;
rights |= Collection::CanCreateItem;
rights |= Collection::CanDeleteItem;
rights |= Collection::CanCreateCollection;
rights |= Collection::CanChangeCollection;
if ( !isResourceCollection )
rights |= Collection::CanDeleteCollection;
}
return rights;
}
QString ContactsResource::directoryForCollection( const Collection& collection ) const
{
if ( collection.remoteId().isEmpty() ) {
kWarning() << "Got incomplete ancestor chain:" << collection;
return QString();
}
if ( collection.parentCollection() == Collection::root() ) {
kWarning( collection.remoteId() != baseDirectoryPath() ) << "RID mismatch, is " << collection.remoteId()
<< " expected " << baseDirectoryPath();
return collection.remoteId();
}
const QString parentDirectory = directoryForCollection( collection.parentCollection() );
if ( parentDirectory.isNull() ) // invalid, != isEmpty() here!
return QString();
QString directory = parentDirectory;
if ( !directory.endsWith( '/' ) )
directory += QDir::separator() + collection.remoteId();
else
directory += collection.remoteId();
return directory;
}
AKONADI_AGENT_FACTORY( ContactsResource, akonadi_contacts_resource )
#include "contactsresource.moc"

File Metadata

Mime Type
text/x-c
Expires
Fri, Nov 1, 7:52 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10074540
Default Alt Text
contactsresource.cpp (16 KB)

Event Timeline