2
Copyright (c) 2008 Volker Krause <vkrause@kde.org>
4
This library is free software; you can redistribute it and/or modify it
5
under the terms of the GNU Library General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or (at your
7
option) any later version.
9
This library is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12
License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to the
16
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23
#include <kcal/incidence.h>
24
#include <kcal/icalformat.h>
27
#include <kabc/vcardconverter.h>
28
#include <kabc/addressee.h>
37
using namespace Akonadi;
39
typedef boost::shared_ptr<KCal::Incidence> IncidencePtr;
42
DataSink::DataSink( int type ) :
43
SinkBase( GetChanges | Commit | SyncDone )
48
DataSink::~DataSink() {
50
osync_hashtable_unref( m_hashtable );
53
bool DataSink::initialize(OSyncPlugin * plugin, OSyncPluginInfo * info, OSyncObjTypeSink *sink, OSyncError ** error)
59
bool enabled = osync_objtype_sink_is_enabled( sink );
61
kDebug() << "sink is not enabled..";
65
QString configdir( osync_plugin_info_get_configdir( info ) );
66
QString hashfile = QString("%1/%2-hash.db").arg( configdir, osync_objtype_sink_get_name( sink ) );
68
m_hashtable = osync_hashtable_new( hashfile.toUtf8(), osync_objtype_sink_get_name( sink ), error );
70
if( ! osync_hashtable_load( m_hashtable, error ) ) {
71
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __PRETTY_FUNCTION__, osync_error_print( error ) );
80
Akonadi::Collection DataSink::collection() const
82
OSyncPluginConfig *config = osync_plugin_info_get_config( pluginInfo() );
85
const char *objtype = osync_objtype_sink_get_name( sink() );
87
OSyncPluginResource *res = osync_plugin_config_find_active_resource( config, objtype );
90
error( OSYNC_ERROR_MISCONFIGURATION, i18n("No active resource for type \"%1\" found", objtype ) );
94
const KUrl url = KUrl( osync_plugin_resource_get_url( res ) );
95
if ( url.isEmpty() ) {
96
error( OSYNC_ERROR_MISCONFIGURATION, i18n("Url for object type \"%1\" is not configured.", objtype ) );
100
return Collection::fromUrl( url );
103
void DataSink::getChanges()
105
// ### broken in OpenSync, I don't get valid configuration here!
107
Collection col = collection();
108
if ( !col.isValid() )
111
Collection col( 409 );
114
OSyncError *oerror = 0;
116
if( osync_objtype_sink_get_slowsync( sink() ) ) {
117
kDebug() << "we're in the middle of slow-syncing...";
118
osync_trace( TRACE_INTERNAL, "Got slow-sync, resetting hashtable" );
119
if( ! osync_hashtable_slowsync( m_hashtable, &oerror ) ) {
121
osync_trace( TRACE_EXIT_ERROR, "%s: %s", __PRETTY_FUNCTION__, osync_error_print( &oerror ) );
126
ItemFetchJob *job = new ItemFetchJob( col );
127
job->fetchScope().fetchFullPayload();
129
QObject::connect( job, SIGNAL( itemsReceived( const Akonadi::Item::List & ) ), this, SLOT( slotItemsReceived( const Akonadi::Item::List & ) ) );
130
QObject::connect( job, SIGNAL( result( KJob * ) ), this, SLOT( slotGetChangesFinished( KJob * ) ) );
132
// FIXME give me a real eventloop please!
133
if ( !job->exec() ) {
134
error( OSYNC_ERROR_IO_ERROR, job->errorText() );
139
void DataSink::slotItemsReceived( const Item::List &items )
141
kDebug() << "retrieved" << items.count() << "items";
142
Q_FOREACH( const Item& item, items ) {
143
//kDebug() << item.payloadData();
144
reportChange( item );
148
void DataSink::reportChange( const Item& item )
150
OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env( pluginInfo() );
151
OSyncObjFormat *format = osync_format_env_find_objformat( formatenv, formatName().toLatin1() );
153
OSyncError *error = 0;
155
OSyncChange *change = osync_change_new( &error );
161
osync_change_set_uid( change, QString::number( item.id() ).toLatin1() );
165
OSyncData *odata = osync_data_new( item.payloadData().data(), item.payloadData().size(), format, &error );
167
osync_change_unref( change );
172
osync_data_set_objtype( odata, osync_objtype_sink_get_name( sink() ) );
174
osync_change_set_data( change, odata );
176
kDebug() << item.id() << "DATA:" << osync_data_get_printable( odata ) << "\n" << "ORIG:" << item.payloadData().data();
178
osync_data_unref( odata );
180
osync_change_set_hash( change, QString::number( item.revision() ).toLatin1() );
182
OSyncChangeType changeType = osync_hashtable_get_changetype( m_hashtable, change );
183
osync_change_set_changetype( change, changeType );
185
osync_hashtable_update_change( m_hashtable, change );
188
kDebug() << "changeid:" << osync_change_get_uid( change )
189
<< "itemid:" << item.id()
190
<< "revision:" << item.revision()
191
<< "changetype:" << changeType
192
<< "hash:" << osync_hashtable_get_hash( m_hashtable, osync_change_get_uid( change ) )
193
<< "objtype:" << osync_change_get_objtype( change )
194
<< "objform:" << osync_objformat_get_name( osync_change_get_objformat( change ) )
195
<< "sinkname:" << osync_objtype_sink_get_name( sink() );
197
if ( changeType != OSYNC_CHANGE_TYPE_UNMODIFIED )
198
osync_context_report_change( context(), change );
200
// perhaps this should be only called when an error has happened ie. never after _context_report_change()?
201
//osync_change_unref( change ); // if this gets called, we get broken pipes. any ideas?
204
void DataSink::slotGetChangesFinished( KJob * )
206
OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env( pluginInfo() );
207
OSyncObjFormat *format = osync_format_env_find_objformat( formatenv, formatName().toLatin1() );
209
// after the items have been processed, see what's been deleted and send them to opensync
210
OSyncError *error = 0;
211
OSyncList *u, *uids = osync_hashtable_get_deleted( m_hashtable );
213
for( u = uids; u; u = u->next) {
214
QString uid( (char *)u->data );
215
kDebug() << "going to delete with uid:" << uid;
217
OSyncChange *change = osync_change_new( &error );
223
osync_change_set_changetype( change, OSYNC_CHANGE_TYPE_DELETED );
224
osync_change_set_uid( change, uid.toLatin1() );
227
OSyncData *data = osync_data_new( NULL, 0, format, &error );
229
osync_change_unref( change );
234
osync_data_set_objtype( data, osync_objtype_sink_get_name( sink() ) );
235
osync_change_set_data( change, data );
237
osync_hashtable_update_change( m_hashtable, change );
239
osync_change_unref( change );
241
osync_list_free( uids );
243
kDebug() << "got all changes..";
247
void DataSink::commit(OSyncChange *change)
249
kDebug() << "change uid:" << osync_change_get_uid( change );
250
kDebug() << "objtype:" << osync_change_get_objtype( change );
251
kDebug() << "objform:" << osync_objformat_get_name (osync_change_get_objformat( change ) );
253
switch( osync_change_get_changetype( change ) ) {
254
case OSYNC_CHANGE_TYPE_ADDED: {
255
const Item item = createItem( change );
256
osync_change_set_uid( change, QString::number( item.id() ).toLatin1() );
257
osync_change_set_hash( change, QString::number( item.revision() ).toLatin1() );
258
kDebug() << "ADDED:" << osync_change_get_uid( change );
261
case OSYNC_CHANGE_TYPE_MODIFIED: {
262
const Item item = modifyItem( change );
263
osync_change_set_uid( change, QString::number( item.id() ).toLatin1() );
264
osync_change_set_hash( change, QString::number( item.revision() ).toLatin1() );
265
kDebug() << "MODIFIED:" << osync_change_get_uid( change );
268
case OSYNC_CHANGE_TYPE_DELETED: {
269
deleteItem( change );
270
kDebug() << "DELETED:" << osync_change_get_uid( change );
273
case OSYNC_CHANGE_TYPE_UNMODIFIED: {
274
kDebug() << "UNMODIFIED";
275
// should we do something here?
279
kDebug() << "got invalid changetype?";
282
osync_hashtable_update_change( m_hashtable, change );
286
const Item DataSink::createItem( OSyncChange *change )
288
Collection col = collection();
289
if ( !col.isValid() ) // error handling
291
kDebug() << "cuid:" << osync_change_get_uid( change );
293
ItemCreateJob *job = new Akonadi::ItemCreateJob( createAkonadiItem( change ), col );
296
kDebug() << "creating an item failed";
298
return job->item(); // handle !job->exec in return too..
301
const Item DataSink::modifyItem( OSyncChange *change )
304
osync_data_get_data( osync_change_get_data( change ), &plain, /*size*/0 );
305
QString str = QString::fromUtf8( plain );
307
QString id = QString( osync_change_get_uid( change ) );
308
Item item = fetchItem( id );
309
if( ! item.isValid() ) // TODO proper error handling
312
//event.setMimeType( "application/x-vnd.akonadi.calendar.event" );
313
//Item newItem = createAkonadiItem( change );
314
setPayload(&item, str);
315
ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob( item );
316
if( modifyJob->exec() ) {
317
kDebug() << "modification completed";
318
return modifyJob->item();
321
kDebug() << "unable to modify";
327
void DataSink::deleteItem( OSyncChange *change )
329
QString id = QString( osync_change_get_uid( change ) );
330
Item item = fetchItem( id );
331
if( ! item.isValid() ) // TODO proper error handling
334
kDebug() << "delete with id: " << item.id();
335
/*ItemDeleteJob *job = new ItemDeleteJob( item );
338
kDebug() << "item deleted";
341
kDebug() << "unable to delete item";*/
344
bool DataSink::setPayload( Item *item, const QString &str )
348
KCal::ICalFormat format;
349
KCal::Incidence *calEntry = format.fromString( str );
351
item->setMimeType( "application/x-vnd.akonadi.calendar.event" );
352
item->setPayload<IncidencePtr>( IncidencePtr( calEntry->clone() ) );
357
KABC::VCardConverter converter;
358
KABC::Addressee vcard = converter.parseVCard( str.toUtf8() );
359
kDebug() << vcard.uid() << vcard.name();
361
item->setMimeType( Addressee::mimeType() );
362
item->setPayload<KABC::Addressee>( vcard );
377
const Item DataSink::createAkonadiItem( OSyncChange *change )
380
osync_data_get_data( osync_change_get_data( change ), &plain, /*size*/0 );
381
QString str = QString::fromUtf8( plain );
383
setPayload(&item, str);
387
const QString DataSink::formatName()
392
formatName = "vevent20";
395
formatName = "vcard10";
398
formatName = "vnote10";
401
kDebug() << "invalid datasink type";
408
const Item DataSink::fetchItem( const QString& id )
410
ItemFetchJob *fetchJob = new ItemFetchJob( Item( id ) );
411
fetchJob->fetchScope().fetchFullPayload();
413
if( fetchJob->exec() ) {
414
foreach ( Item item, fetchJob->items() ) {
415
if( QString::number( item.id() ) == id ) {
416
kDebug() << "got item";
422
// no such item found?
426
void DataSink::syncDone()
429
OSyncError *error = 0;
430
osync_hashtable_save( m_hashtable, &error );
432
//TODO check for errors
436
#include "datasink.moc"