~ubuntu-branches/ubuntu/vivid/akonadi/vivid

« back to all changes in this revision

Viewing changes to libs/notificationmessagev2.cpp

  • Committer: Package Import Robot
  • Author(s): Rohan Garg, Rohan Garg, Philip Muškovac
  • Date: 2013-06-13 08:46:15 UTC
  • mfrom: (1.1.42)
  • Revision ID: package-import@ubuntu.com-20130613084615-e37v5pdoe2p2xu9d
Tags: 1.9.80-0ubuntu1
[ Rohan Garg ]
* New upstream release
  - Update symbols
  - Install asapcat with akonadi-server for now
  - Install notificationmessagev2_p.h with -dev package
  - Refresh disable_dbus_requiring_tests.diff

[ Philip Muškovac ]
* libkonadi-dev needs to depend on akonadi-server for the dbus service 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>
 
3
    Copyright (c) 2013 Daniel Vrátil <dvratil@redhat.com>
 
4
 
 
5
    This library is free software; you can redistribute it and/or modify it
 
6
    under the terms of the GNU Library General Public License as published by
 
7
    the Free Software Foundation; either version 2 of the License, or (at your
 
8
    option) any later version.
 
9
 
 
10
    This library is distributed in the hope that it will be useful, but WITHOUT
 
11
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
12
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
 
13
    License for more details.
 
14
 
 
15
    You should have received a copy of the GNU Library General Public License
 
16
    along with this library; see the file COPYING.LIB.  If not, write to the
 
17
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
18
    02110-1301, USA.
 
19
*/
 
20
 
 
21
 
 
22
#include "notificationmessagev2_p.h"
 
23
#include "notificationmessage_p.h"
 
24
#include "imapparser_p.h"
 
25
 
 
26
#include <QtCore/QDebug>
 
27
#include <QtCore/QHash>
 
28
#include <QtDBus/QDBusMetaType>
 
29
#include <qdbusconnection.h>
 
30
 
 
31
using namespace Akonadi;
 
32
 
 
33
class NotificationMessageV2::Private: public QSharedData
 
34
{
 
35
  public:
 
36
    Private()
 
37
      : QSharedData(),
 
38
        type( InvalidType ),
 
39
        operation( InvalidOp ),
 
40
        parentCollection( -1 ),
 
41
        parentDestCollection( -1 )
 
42
    {
 
43
    }
 
44
 
 
45
    Private( const Private &other )
 
46
      : QSharedData( other )
 
47
    {
 
48
      sessionId = other.sessionId;
 
49
      type = other.type;
 
50
      operation = other.operation;
 
51
      items = other.items;
 
52
      resource = other.resource;
 
53
      destResource = other.destResource;
 
54
      parentCollection = other.parentCollection;
 
55
      parentDestCollection = other.parentDestCollection;
 
56
      parts = other.parts;
 
57
      addedFlags = other.addedFlags;
 
58
      removedFlags = other.removedFlags;
 
59
    }
 
60
 
 
61
    bool compareWithoutOpAndParts( const Private &other ) const
 
62
    {
 
63
      return items == other.items
 
64
          && type == other.type
 
65
          && sessionId == other.sessionId
 
66
          && resource == other.resource
 
67
          && destResource == other.destResource
 
68
          && parentCollection == other.parentCollection
 
69
          && parentDestCollection == other.parentDestCollection;
 
70
    }
 
71
 
 
72
    bool operator==( const Private &other ) const
 
73
    {
 
74
      return operation == other.operation && parts == other.parts &&
 
75
             addedFlags == other.addedFlags && removedFlags == other.removedFlags &&
 
76
             compareWithoutOpAndParts( other );
 
77
    }
 
78
 
 
79
    template <typename T>
 
80
    static bool appendAndCompressImpl( T &list, const NotificationMessageV2 &msg );
 
81
 
 
82
    QByteArray sessionId;
 
83
    NotificationMessageV2::Type type;
 
84
    NotificationMessageV2::Operation operation;
 
85
    QMap<Id, NotificationMessageV2::Entity> items;
 
86
    QByteArray resource;
 
87
    QByteArray destResource;
 
88
    Id parentCollection;
 
89
    Id parentDestCollection;
 
90
    QSet<QByteArray> parts;
 
91
    QSet<QByteArray> addedFlags;
 
92
    QSet<QByteArray> removedFlags;
 
93
};
 
94
 
 
95
NotificationMessageV2::NotificationMessageV2():
 
96
  d( new Private )
 
97
{
 
98
}
 
99
 
 
100
NotificationMessageV2::NotificationMessageV2( const NotificationMessageV2 &other ):
 
101
  d( other.d )
 
102
{
 
103
}
 
104
 
 
105
NotificationMessageV2::~NotificationMessageV2()
 
106
{
 
107
}
 
108
 
 
109
NotificationMessageV2& NotificationMessageV2::operator=( const NotificationMessageV2 &other )
 
110
{
 
111
  if ( this != &other ) {
 
112
    d = other.d;
 
113
  }
 
114
 
 
115
  return *this;
 
116
}
 
117
 
 
118
bool NotificationMessageV2::operator==( const NotificationMessageV2 &other ) const
 
119
{
 
120
  return d == other.d;
 
121
}
 
122
 
 
123
void NotificationMessageV2::registerDBusTypes()
 
124
{
 
125
  qDBusRegisterMetaType<Akonadi::NotificationMessageV2>();
 
126
  qDBusRegisterMetaType<Akonadi::NotificationMessageV2::Entity>();
 
127
  qDBusRegisterMetaType<Akonadi::NotificationMessageV2::List>();
 
128
}
 
129
 
 
130
void NotificationMessageV2::addEntity( Id id, const QString &remoteId, const QString &remoteRevision, const QString &mimeType )
 
131
{
 
132
  NotificationMessageV2::Entity item;
 
133
  item.id = id;
 
134
  item.remoteId = remoteId;
 
135
  item.remoteRevision = remoteRevision;
 
136
  item.mimeType = mimeType;
 
137
 
 
138
  d->items.insert( id, item );
 
139
}
 
140
 
 
141
void NotificationMessageV2::setEntities( const QList<NotificationMessageV2::Entity> &items )
 
142
{
 
143
  d->items.clear();
 
144
  Q_FOREACH( const NotificationMessageV2::Entity &item, items ) {
 
145
    d->items.insert( item.id, item );
 
146
  }
 
147
}
 
148
 
 
149
QMap<NotificationMessageV2::Id, NotificationMessageV2::Entity> NotificationMessageV2::entities() const
 
150
{
 
151
  return d->items;
 
152
}
 
153
 
 
154
NotificationMessageV2::Entity NotificationMessageV2::entity( NotificationMessageV2::Id id ) const
 
155
{
 
156
  return d->items.value( id );
 
157
}
 
158
 
 
159
QList<NotificationMessageV2::Id> NotificationMessageV2::uids() const
 
160
{
 
161
  return d->items.keys();
 
162
}
 
163
 
 
164
QByteArray NotificationMessageV2::sessionId() const
 
165
{
 
166
  return d->sessionId;
 
167
}
 
168
 
 
169
void NotificationMessageV2::setSessionId( const QByteArray &sessionId )
 
170
{
 
171
  d->sessionId = sessionId;
 
172
}
 
173
 
 
174
NotificationMessageV2::Type NotificationMessageV2::type() const
 
175
{
 
176
  return d->type;
 
177
}
 
178
 
 
179
void NotificationMessageV2::setType( Type type )
 
180
{
 
181
  d->type = type;
 
182
}
 
183
 
 
184
NotificationMessageV2::Operation NotificationMessageV2::operation() const
 
185
{
 
186
  return d->operation;
 
187
}
 
188
 
 
189
void NotificationMessageV2::setOperation( Operation operation )
 
190
{
 
191
  d->operation = operation;
 
192
}
 
193
 
 
194
QByteArray NotificationMessageV2::resource() const
 
195
{
 
196
  return d->resource;
 
197
}
 
198
 
 
199
void NotificationMessageV2::setResource( const QByteArray &resource )
 
200
{
 
201
  d->resource = resource;
 
202
}
 
203
 
 
204
NotificationMessageV2::Id NotificationMessageV2::parentCollection() const
 
205
{
 
206
  return d->parentCollection;
 
207
}
 
208
 
 
209
NotificationMessageV2::Id NotificationMessageV2::parentDestCollection() const
 
210
{
 
211
  return d->parentDestCollection;
 
212
}
 
213
 
 
214
void NotificationMessageV2::setParentCollection( Id parent )
 
215
{
 
216
  d->parentCollection = parent;
 
217
}
 
218
 
 
219
void NotificationMessageV2::setParentDestCollection( Id parent )
 
220
{
 
221
  d->parentDestCollection = parent;
 
222
}
 
223
 
 
224
void NotificationMessageV2::setDestinationResource( const QByteArray &destResource )
 
225
{
 
226
  d->destResource = destResource;
 
227
}
 
228
 
 
229
QByteArray NotificationMessageV2::destinationResource() const
 
230
{
 
231
  return d->destResource;
 
232
}
 
233
 
 
234
QSet<QByteArray> NotificationMessageV2::itemParts() const
 
235
{
 
236
  return d->parts;
 
237
}
 
238
 
 
239
void NotificationMessageV2::setItemParts( const QSet<QByteArray> &parts )
 
240
{
 
241
  d->parts = parts;
 
242
}
 
243
 
 
244
QSet<QByteArray> NotificationMessageV2::addedFlags() const
 
245
{
 
246
  return d->addedFlags;
 
247
}
 
248
 
 
249
void NotificationMessageV2::setAddedFlags( const QSet<QByteArray> &addedFlags )
 
250
{
 
251
  d->addedFlags = addedFlags;
 
252
}
 
253
 
 
254
QSet<QByteArray> NotificationMessageV2::removedFlags() const
 
255
{
 
256
  return d->removedFlags;
 
257
}
 
258
 
 
259
void NotificationMessageV2::setRemovedFlags( const QSet<QByteArray> &removedFlags )
 
260
{
 
261
  d->removedFlags = removedFlags;
 
262
}
 
263
 
 
264
QString NotificationMessageV2::toString() const
 
265
{
 
266
  QString rv;
 
267
 
 
268
  switch ( d->type ) {
 
269
    case Items:
 
270
      rv += QLatin1String( "Items " );
 
271
      break;
 
272
    case Collections:
 
273
      rv += QLatin1String( "Collections " );
 
274
      break;
 
275
    case InvalidType:
 
276
      return QLatin1String( "*INVALID TYPE* " );
 
277
  }
 
278
 
 
279
  QSet<QByteArray> items;
 
280
  Q_FOREACH ( const NotificationMessageV2::Entity &item, d->items ) {
 
281
    QString itemStr = QString::fromLatin1( "(%1,%2" ).arg( item.id ).arg( item.remoteId );
 
282
    if ( !item.remoteRevision.isEmpty() ) {
 
283
      itemStr += QString::fromLatin1( ",%1" ).arg( item.remoteRevision );
 
284
    }
 
285
    if ( !item.mimeType.isEmpty() ) {
 
286
      itemStr += QString::fromLatin1( ",%1" ).arg( item.mimeType );
 
287
    }
 
288
    itemStr += QLatin1String( ")" );
 
289
    items << itemStr.toLatin1();
 
290
  }
 
291
  rv += QLatin1String( "(" ) + QString::fromLatin1( ImapParser::join( items, ", " ) ) + QLatin1String( ")" );
 
292
 
 
293
  if ( d->parentDestCollection >= 0 ) {
 
294
    rv += QLatin1String( " from " );
 
295
  } else {
 
296
    rv += QLatin1String( " in " );
 
297
  }
 
298
 
 
299
  if ( d->parentCollection >= 0 ) {
 
300
    rv += QString::fromLatin1( "collection %1 " ).arg( d->parentCollection );
 
301
  } else {
 
302
    rv += QLatin1String( "unspecified parent collection " );
 
303
  }
 
304
 
 
305
  switch ( d->operation ) {
 
306
    case Add:
 
307
      rv += QLatin1String( "added" );
 
308
      break;
 
309
    case Modify:
 
310
      rv += QLatin1String( "modified parts (" );
 
311
      rv += QString::fromLatin1( ImapParser::join( d->parts.toList(), ", " ) );
 
312
      rv += QLatin1String( ")" );
 
313
      break;
 
314
    case ModifyFlags:
 
315
      rv += QLatin1String( "added flags (" );
 
316
      rv += QString::fromLatin1( ImapParser::join( d->addedFlags.toList(), ", " ) );
 
317
      rv += QLatin1String ( ") " );
 
318
 
 
319
      rv += QLatin1String( "removed flags (" );
 
320
      rv += QString::fromLatin1( ImapParser::join( d->removedFlags.toList(), ", " ) );
 
321
      rv += QLatin1String ( ") " );
 
322
      break;
 
323
    case Move:
 
324
      rv += QLatin1String( "moved" );
 
325
      break;
 
326
    case Remove:
 
327
      rv += QLatin1String( "removed" );
 
328
      break;
 
329
    case Link:
 
330
      rv += QLatin1String( "linked" );
 
331
      break;
 
332
    case Unlink:
 
333
      rv += QLatin1String( "unlinked" );
 
334
      break;
 
335
    case Subscribe:
 
336
      rv += QLatin1String( "subscribed" );
 
337
      break;
 
338
    case Unsubscribe:
 
339
      rv += QLatin1String( "unsubscribed" );
 
340
      break;
 
341
    case InvalidOp:
 
342
      return QLatin1String( "*INVALID OPERATION*" );
 
343
  }
 
344
 
 
345
  if ( d->parentDestCollection >= 0 )
 
346
    rv += QString::fromLatin1( " to collection %1" ).arg( d->parentDestCollection );
 
347
 
 
348
  return rv;
 
349
}
 
350
 
 
351
QDBusArgument& operator<<( QDBusArgument &arg, const Akonadi::NotificationMessageV2 &msg )
 
352
{
 
353
  arg.beginStructure();
 
354
  arg << msg.sessionId();
 
355
  arg << static_cast<int>( msg.type() );
 
356
  arg << static_cast<int>( msg.operation() );
 
357
  arg << msg.entities().values();
 
358
  arg << msg.resource();
 
359
  arg << msg.destinationResource();
 
360
  arg << msg.parentCollection();
 
361
  arg << msg.parentDestCollection();
 
362
 
 
363
  QStringList itemParts;
 
364
  Q_FOREACH ( const QByteArray &itemPart, msg.itemParts() ) {
 
365
    itemParts.append( QString::fromLatin1( itemPart ) );
 
366
  }
 
367
  arg << itemParts;
 
368
 
 
369
  arg << msg.addedFlags().toList();
 
370
  arg << msg.removedFlags().toList();
 
371
 
 
372
  arg.endStructure();
 
373
  return arg;
 
374
}
 
375
 
 
376
const QDBusArgument& operator>>( const QDBusArgument &arg, Akonadi::NotificationMessageV2 &msg )
 
377
{
 
378
  QByteArray ba;
 
379
  int i;
 
380
  QList<NotificationMessageV2::Entity> items;
 
381
  NotificationMessageV2::Id id;
 
382
  QString str;
 
383
  QStringList strl;
 
384
  QList<QByteArray> bal;
 
385
 
 
386
  arg.beginStructure();
 
387
  arg >> ba;
 
388
  msg.setSessionId( ba );
 
389
  arg >> i;
 
390
  msg.setType( static_cast<NotificationMessageV2::Type>( i ) );
 
391
  arg >> i;
 
392
  msg.setOperation( static_cast<NotificationMessageV2::Operation>( i ) );
 
393
  arg >> items;
 
394
  msg.setEntities( items );
 
395
  arg >> ba;
 
396
  msg.setResource( ba );
 
397
  arg >> ba;
 
398
  msg.setDestinationResource( ba );
 
399
  arg >> id;
 
400
  msg.setParentCollection( id );
 
401
  arg >> id;
 
402
  msg.setParentDestCollection( id );
 
403
 
 
404
  arg >> strl;
 
405
 
 
406
  QSet<QByteArray> itemParts;
 
407
  Q_FOREACH ( const QString &itemPart, strl ) {
 
408
    itemParts.insert( itemPart.toLatin1() );
 
409
  }
 
410
  msg.setItemParts( itemParts );
 
411
 
 
412
  arg >> bal;
 
413
  msg.setAddedFlags( bal.toSet() );
 
414
  arg >> bal;
 
415
  msg.setRemovedFlags( bal.toSet() );
 
416
 
 
417
  arg.endStructure();
 
418
  return arg;
 
419
}
 
420
 
 
421
QDBusArgument& operator<<( QDBusArgument &arg, const Akonadi::NotificationMessageV2::Entity &item )
 
422
{
 
423
  arg.beginStructure();
 
424
  arg << item.id;
 
425
  arg << item.remoteId;
 
426
  arg << item.remoteRevision;
 
427
  arg << item.mimeType;
 
428
  arg.endStructure();
 
429
 
 
430
  return arg;
 
431
}
 
432
 
 
433
const QDBusArgument& operator>>( const QDBusArgument &arg, Akonadi::NotificationMessageV2::Entity &item )
 
434
{
 
435
  arg.beginStructure();
 
436
  arg >> item.id;
 
437
  arg >> item.remoteId;
 
438
  arg >> item.remoteRevision;
 
439
  arg >> item.mimeType;
 
440
  arg.endStructure();
 
441
 
 
442
  return arg;
 
443
}
 
444
 
 
445
uint qHash( const Akonadi::NotificationMessageV2 &msg )
 
446
{
 
447
  uint i = 0;
 
448
  Q_FOREACH( const NotificationMessageV2::Entity &item, msg.entities() ) {
 
449
    i += item.id;
 
450
  }
 
451
 
 
452
  return qHash( i + (msg.type() << 31) + (msg.operation() << 28) );
 
453
}
 
454
 
 
455
QVector<NotificationMessage> NotificationMessageV2::toNotificationV1() const
 
456
{
 
457
  QVector<NotificationMessage> v1;
 
458
 
 
459
  Q_FOREACH( const Entity &item, d->items ) {
 
460
    NotificationMessage msgv1;
 
461
    msgv1.setSessionId( d->sessionId );
 
462
    msgv1.setUid( item.id );
 
463
    msgv1.setRemoteId( item.remoteId );
 
464
    msgv1.setMimeType( item.mimeType );
 
465
    msgv1.setType( static_cast<NotificationMessage::Type>( d->type ) );
 
466
    if ( d->operation == ModifyFlags ) {
 
467
      msgv1.setOperation( NotificationMessage::Modify );
 
468
    } else {
 
469
      msgv1.setOperation( static_cast<NotificationMessage::Operation>( d->operation ) );
 
470
    }
 
471
 
 
472
    msgv1.setResource( d->resource );
 
473
    msgv1.setDestinationResource( d->destResource );
 
474
    msgv1.setParentCollection( d->parentCollection );
 
475
    msgv1.setParentDestCollection( d->parentDestCollection );
 
476
 
 
477
    // Backward compatibility hack
 
478
    QSet<QByteArray> parts;
 
479
    if ( d->operation == Remove ) {
 
480
      QByteArray rr = item.remoteRevision.toLatin1();
 
481
      parts << (rr.isEmpty() ? "1" : rr);
 
482
    } else if ( d->operation == ModifyFlags ) {
 
483
      parts << "FLAGS";
 
484
    } else {
 
485
      parts = d->parts;
 
486
    }
 
487
    msgv1.setItemParts( parts );
 
488
 
 
489
    v1 << msgv1;
 
490
  }
 
491
 
 
492
  return v1;
 
493
}
 
494
 
 
495
template <typename T>
 
496
bool NotificationMessageV2::Private::appendAndCompressImpl( T &list, const NotificationMessageV2 &msg )
 
497
{
 
498
  // fast-path for stuff that is not considered during O(n) compression below
 
499
  if ( msg.operation() != Add && msg.operation() != Link && msg.operation() != Unlink && msg.operation() != Subscribe && msg.operation() != Unsubscribe && msg.operation() != Move ) {
 
500
 
 
501
    typename T::Iterator end = list.end();
 
502
    for ( typename T::Iterator it = list.begin(); it != end; ) {
 
503
      if ( msg.d.constData()->compareWithoutOpAndParts( *((*it).d.constData()) ) ) {
 
504
 
 
505
        // both are modifications, merge them together and drop the new one
 
506
        if ( msg.operation() == Modify && it->operation() == Modify ) {
 
507
          (*it).setItemParts( (*it).itemParts() + msg.itemParts() );
 
508
          return false;
 
509
        }
 
510
 
 
511
        else if ( msg.operation() == ModifyFlags && it->operation() == ModifyFlags ) {
 
512
          (*it).setAddedFlags( (*it).addedFlags() + msg.addedFlags() );
 
513
          (*it).setRemovedFlags( (*it).removedFlags() + msg.removedFlags() );
 
514
 
 
515
           // If merged notifications result in no-change notification, drop both.
 
516
          if ( (*it).addedFlags() == (*it).removedFlags() ) {
 
517
            it = list.erase( it );
 
518
            end = list.end();
 
519
          }
 
520
 
 
521
          return false;
 
522
        }
 
523
        // new one is a modification, the existing one not, so drop the new one
 
524
        else if ( ( ( msg.operation() == Modify ) || ( msg.operation() == ModifyFlags ) ) && ( (*it).operation() != Modify) && (*it).operation() != ModifyFlags ) {
 
525
          return false;
 
526
        }
 
527
        // new on is a deletion, erase the existing modification ones (and keep going, in case there are more)
 
528
        else if ( msg.operation() == Remove && ((*it).operation() == Modify || (*it).operation() == ModifyFlags) ) {
 
529
          it = list.erase( it );
 
530
          end = list.end();
 
531
        }
 
532
        // keep looking
 
533
        else {
 
534
          ++it;
 
535
        }
 
536
      } else {
 
537
        ++it;
 
538
      }
 
539
    }
 
540
  }
 
541
 
 
542
  list.append( msg );
 
543
  return true;
 
544
}
 
545
 
 
546
bool NotificationMessageV2::appendAndCompress( NotificationMessageV2::List &list, const NotificationMessageV2 &msg )
 
547
{
 
548
  return Private::appendAndCompressImpl<NotificationMessageV2::List>( list, msg );
 
549
}
 
550
 
 
551
bool NotificationMessageV2::appendAndCompress( QList<NotificationMessageV2> &list, const NotificationMessageV2 &msg )
 
552
{
 
553
  return Private::appendAndCompressImpl< QList<NotificationMessageV2> >( list, msg );
 
554
}