~ubuntu-branches/ubuntu/karmic/kdepim/karmic-backports

« back to all changes in this revision

Viewing changes to akonadi/opensync/datasink.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi, Alessandro Ghersi, Harald Sitter
  • Date: 2009-06-27 04:40:05 UTC
  • mfrom: (1.1.39 upstream)
  • Revision ID: james.westby@ubuntu.com-20090627044005-4y2vm9xz7rvmzi4p
Tags: 4:4.2.95svn20090701-0ubuntu1
[ Alessandro Ghersi ]
* New upstream release
  - Bump build-deps
* Remove akonadi-kde and libmaildir4 packages
  - remove akonadi-kde.install and libmaildir4.install
  - remove libmaildir4 from debian/rules
  - remove akonadi-kde and libmaildir4 from depends
  - remove akonadi-kde and libmaildir4 from installgen
* Update kdepim-dev.install
* Update kpilot.install
* Add akonadi-kde and libmaildir4 transitional packages

[ Harald Sitter ]
* KAddressbook replaces Kontact << 4.2.85 (LP: #378373)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (c) 2008 Volker Krause <vkrause@kde.org>
 
3
 
 
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.
 
8
 
 
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.
 
13
 
 
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
 
17
    02110-1301, USA.
 
18
*/
 
19
 
 
20
#include "datasink.h"
 
21
 
 
22
// calendar includes
 
23
#include <kcal/incidence.h>
 
24
#include <kcal/icalformat.h>
 
25
 
 
26
// contact includes
 
27
#include <kabc/vcardconverter.h>
 
28
#include <kabc/addressee.h>
 
29
 
 
30
// notes includes
 
31
// TODO
 
32
 
 
33
#include <KDebug>
 
34
#include <KLocale>
 
35
#include <KUrl>
 
36
 
 
37
using namespace Akonadi;
 
38
 
 
39
typedef boost::shared_ptr<KCal::Incidence> IncidencePtr;
 
40
 
 
41
 
 
42
DataSink::DataSink( int type ) :
 
43
    SinkBase( GetChanges | Commit | SyncDone )
 
44
{
 
45
  m_type = type;
 
46
}
 
47
 
 
48
DataSink::~DataSink() {
 
49
  if( m_hashtable )
 
50
    osync_hashtable_unref( m_hashtable );
 
51
}
 
52
 
 
53
bool DataSink::initialize(OSyncPlugin * plugin, OSyncPluginInfo * info, OSyncObjTypeSink *sink, OSyncError ** error)
 
54
{
 
55
  Q_UNUSED( plugin );
 
56
  Q_UNUSED( info );
 
57
  Q_UNUSED( error );
 
58
 
 
59
  bool enabled = osync_objtype_sink_is_enabled( sink );
 
60
  if( ! enabled ) {
 
61
    kDebug() << "sink is not enabled..";
 
62
    return false;
 
63
  }
 
64
 
 
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 ) );
 
67
 
 
68
  m_hashtable = osync_hashtable_new( hashfile.toUtf8(), osync_objtype_sink_get_name( sink ), error );
 
69
 
 
70
  if( ! osync_hashtable_load( m_hashtable, error ) ) {
 
71
    osync_trace(TRACE_EXIT_ERROR, "%s: %s", __PRETTY_FUNCTION__, osync_error_print( error ) );
 
72
    return false;
 
73
  }
 
74
 
 
75
  wrapSink( sink );
 
76
 
 
77
  return true;
 
78
}
 
79
 
 
80
Akonadi::Collection DataSink::collection() const
 
81
{
 
82
  OSyncPluginConfig *config = osync_plugin_info_get_config( pluginInfo() );
 
83
  Q_ASSERT( config );
 
84
 
 
85
  const char *objtype = osync_objtype_sink_get_name( sink() );
 
86
 
 
87
  OSyncPluginResource *res = osync_plugin_config_find_active_resource( config, objtype );
 
88
 
 
89
  if ( !res ) {
 
90
    error( OSYNC_ERROR_MISCONFIGURATION, i18n("No active resource for type \"%1\" found", objtype ) );
 
91
    return Collection();
 
92
  }
 
93
 
 
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 ) );
 
97
    return Collection();
 
98
  }
 
99
 
 
100
  return Collection::fromUrl( url );
 
101
}
 
102
 
 
103
void DataSink::getChanges()
 
104
{
 
105
  // ### broken in OpenSync, I don't get valid configuration here!
 
106
#if 1
 
107
  Collection col = collection();
 
108
  if ( !col.isValid() )
 
109
    return;
 
110
#else
 
111
  Collection col( 409 );
 
112
#endif
 
113
 
 
114
  OSyncError *oerror = 0;
 
115
 
 
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 ) ) {
 
120
      warning( oerror );
 
121
      osync_trace( TRACE_EXIT_ERROR, "%s: %s", __PRETTY_FUNCTION__, osync_error_print( &oerror ) );
 
122
      return;
 
123
    }
 
124
  }
 
125
 
 
126
  ItemFetchJob *job = new ItemFetchJob( col );
 
127
  job->fetchScope().fetchFullPayload();
 
128
 
 
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 * ) ) );
 
131
 
 
132
  // FIXME give me a real eventloop please!
 
133
  if ( !job->exec() ) {
 
134
    error( OSYNC_ERROR_IO_ERROR, job->errorText() );
 
135
    return;
 
136
  }
 
137
}
 
138
 
 
139
void DataSink::slotItemsReceived( const Item::List &items )
 
140
{
 
141
  kDebug() << "retrieved" << items.count() << "items";
 
142
  Q_FOREACH( const Item& item, items ) {
 
143
    //kDebug() << item.payloadData();
 
144
    reportChange( item );
 
145
  }
 
146
}
 
147
 
 
148
void DataSink::reportChange( const Item& item )
 
149
{
 
150
  OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env( pluginInfo() );
 
151
  OSyncObjFormat *format = osync_format_env_find_objformat( formatenv, formatName().toLatin1() );
 
152
 
 
153
  OSyncError *error = 0;
 
154
 
 
155
  OSyncChange *change = osync_change_new( &error );
 
156
  if ( !change ) {
 
157
    warning( error );
 
158
    return;
 
159
  }
 
160
 
 
161
  osync_change_set_uid( change, QString::number( item.id() ).toLatin1() );
 
162
 
 
163
  error = 0;
 
164
 
 
165
  OSyncData *odata = osync_data_new( item.payloadData().data(), item.payloadData().size(), format, &error );
 
166
  if ( !odata ) {
 
167
    osync_change_unref( change );
 
168
    warning( error );
 
169
    return;
 
170
  }
 
171
 
 
172
  osync_data_set_objtype( odata, osync_objtype_sink_get_name( sink() ) );
 
173
 
 
174
  osync_change_set_data( change, odata );
 
175
 
 
176
  kDebug() << item.id() << "DATA:" << osync_data_get_printable( odata ) << "\n" << "ORIG:" << item.payloadData().data();
 
177
 
 
178
  osync_data_unref( odata );
 
179
 
 
180
  osync_change_set_hash( change, QString::number( item.revision() ).toLatin1() );
 
181
 
 
182
  OSyncChangeType changeType = osync_hashtable_get_changetype( m_hashtable, change );
 
183
  osync_change_set_changetype( change, changeType );
 
184
 
 
185
  osync_hashtable_update_change( m_hashtable, change );
 
186
 
 
187
/*
 
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() );
 
196
*/
 
197
  if ( changeType != OSYNC_CHANGE_TYPE_UNMODIFIED )
 
198
    osync_context_report_change( context(), change );
 
199
 
 
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?
 
202
}
 
203
 
 
204
void DataSink::slotGetChangesFinished( KJob * )
 
205
{
 
206
  OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env( pluginInfo() );
 
207
  OSyncObjFormat *format = osync_format_env_find_objformat( formatenv, formatName().toLatin1() );
 
208
 
 
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 );
 
212
 
 
213
  for( u = uids; u; u = u->next) {
 
214
    QString uid( (char *)u->data );
 
215
    kDebug() << "going to delete with uid:" << uid;
 
216
 
 
217
    OSyncChange *change = osync_change_new( &error );
 
218
    if( !change ) {
 
219
      warning( error );
 
220
      continue;
 
221
    }
 
222
 
 
223
    osync_change_set_changetype( change, OSYNC_CHANGE_TYPE_DELETED );
 
224
    osync_change_set_uid( change, uid.toLatin1() );
 
225
 
 
226
    error = 0;
 
227
    OSyncData *data = osync_data_new( NULL, 0, format, &error );
 
228
    if( !data ) {
 
229
      osync_change_unref( change );
 
230
      warning( error );
 
231
      continue;
 
232
    }
 
233
 
 
234
    osync_data_set_objtype( data, osync_objtype_sink_get_name( sink() ) );
 
235
    osync_change_set_data( change, data );
 
236
 
 
237
    osync_hashtable_update_change( m_hashtable, change );
 
238
 
 
239
    osync_change_unref( change );
 
240
  }
 
241
  osync_list_free( uids );
 
242
 
 
243
  kDebug() << "got all changes..";
 
244
  success();
 
245
}
 
246
 
 
247
void DataSink::commit(OSyncChange *change)
 
248
{
 
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 ) );
 
252
 
 
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 );
 
259
      break; }
 
260
 
 
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 );
 
266
      break; }
 
267
 
 
268
    case OSYNC_CHANGE_TYPE_DELETED: {
 
269
      deleteItem( change );
 
270
      kDebug() << "DELETED:" << osync_change_get_uid( change );
 
271
      break; }
 
272
 
 
273
    case OSYNC_CHANGE_TYPE_UNMODIFIED: {
 
274
      kDebug() << "UNMODIFIED";
 
275
      // should we do something here?
 
276
      break; }
 
277
 
 
278
    default:
 
279
      kDebug() << "got invalid changetype?";
 
280
  }
 
281
 
 
282
  osync_hashtable_update_change( m_hashtable, change );
 
283
  success();
 
284
}
 
285
 
 
286
const Item DataSink::createItem( OSyncChange *change )
 
287
{
 
288
  Collection col = collection();
 
289
  if ( !col.isValid() ) // error handling
 
290
    return Item();
 
291
  kDebug() << "cuid:" << osync_change_get_uid( change );
 
292
 
 
293
  ItemCreateJob *job = new Akonadi::ItemCreateJob( createAkonadiItem( change ), col );
 
294
 
 
295
  if( ! job->exec() )
 
296
    kDebug() << "creating an item failed";
 
297
 
 
298
  return job->item(); // handle !job->exec in return too..
 
299
}
 
300
 
 
301
const Item DataSink::modifyItem( OSyncChange *change )
 
302
{
 
303
  char *plain = 0;
 
304
  osync_data_get_data( osync_change_get_data( change ), &plain, /*size*/0 );
 
305
  QString str = QString::fromUtf8( plain );
 
306
 
 
307
  QString id = QString( osync_change_get_uid( change ) );
 
308
  Item item = fetchItem( id );
 
309
  if( ! item.isValid() ) // TODO proper error handling
 
310
    return Item();
 
311
 
 
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();
 
319
  }
 
320
  else
 
321
    kDebug() << "unable to modify";
 
322
 
 
323
 
 
324
  return Item();
 
325
}
 
326
 
 
327
void DataSink::deleteItem( OSyncChange *change )
 
328
{
 
329
  QString id = QString( osync_change_get_uid( change ) );
 
330
  Item item = fetchItem( id );
 
331
  if( ! item.isValid() ) // TODO proper error handling
 
332
    return;
 
333
 
 
334
  kDebug() << "delete with id: " << item.id();
 
335
  /*ItemDeleteJob *job = new ItemDeleteJob( item );
 
336
 
 
337
 if( job->exec() ) {
 
338
   kDebug() << "item deleted";
 
339
 }
 
340
 else
 
341
   kDebug() << "unable to delete item";*/
 
342
}
 
343
 
 
344
bool DataSink::setPayload( Item *item, const QString &str )
 
345
{
 
346
  switch( m_type ) {
 
347
    case Calendar: {
 
348
      KCal::ICalFormat format;
 
349
      KCal::Incidence *calEntry = format.fromString( str );
 
350
 
 
351
      item->setMimeType( "application/x-vnd.akonadi.calendar.event" );
 
352
      item->setPayload<IncidencePtr>( IncidencePtr( calEntry->clone() ) );
 
353
 
 
354
      break;
 
355
    }
 
356
    case Contacts: {
 
357
      KABC::VCardConverter converter;
 
358
      KABC::Addressee vcard = converter.parseVCard( str.toUtf8() );
 
359
      kDebug() << vcard.uid() << vcard.name();
 
360
 
 
361
      item->setMimeType( Addressee::mimeType() );
 
362
      item->setPayload<KABC::Addressee>( vcard );
 
363
      break;
 
364
    }
 
365
    case Notes: {
 
366
      kDebug() << "notes";
 
367
      break;
 
368
    }
 
369
    default:
 
370
      // should not happen
 
371
     return false;
 
372
  }
 
373
 
 
374
  return true;
 
375
}
 
376
 
 
377
const Item DataSink::createAkonadiItem( OSyncChange *change )
 
378
{
 
379
  char *plain = 0;
 
380
  osync_data_get_data( osync_change_get_data( change ), &plain, /*size*/0 );
 
381
  QString str = QString::fromUtf8( plain );
 
382
  Akonadi::Item item;
 
383
  setPayload(&item, str);
 
384
  return item;
 
385
}
 
386
 
 
387
const QString DataSink::formatName()
 
388
{
 
389
  QString formatName;
 
390
  switch( m_type ) {
 
391
    case Calendar:
 
392
      formatName = "vevent20";
 
393
      break;
 
394
    case Contacts:
 
395
      formatName = "vcard10";
 
396
      break;
 
397
    case Notes:
 
398
      formatName = "vnote10";
 
399
      break;
 
400
    default:
 
401
      kDebug() << "invalid datasink type";
 
402
      return QString();
 
403
  }
 
404
 
 
405
  return formatName;
 
406
}
 
407
 
 
408
const Item DataSink::fetchItem( const QString& id )
 
409
{
 
410
  ItemFetchJob *fetchJob = new ItemFetchJob( Item( id ) );
 
411
  fetchJob->fetchScope().fetchFullPayload();
 
412
 
 
413
  if( fetchJob->exec() ) {
 
414
    foreach ( Item item, fetchJob->items() ) {
 
415
      if( QString::number( item.id() ) == id ) {
 
416
        kDebug() << "got item";
 
417
        return item;
 
418
      }
 
419
    }
 
420
  }
 
421
 
 
422
  // no such item found?
 
423
  return Item();
 
424
}
 
425
 
 
426
void DataSink::syncDone()
 
427
{
 
428
  kDebug();
 
429
  OSyncError *error = 0;
 
430
  osync_hashtable_save( m_hashtable, &error );
 
431
 
 
432
  //TODO check for errors
 
433
  success();
 
434
}
 
435
 
 
436
#include "datasink.moc"