• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
protocolhelper.cpp
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 "protocolhelper_p.h"
21
22#include "attributefactory.h"
23#include "collectionstatistics.h"
24#include "entity_p.h"
25#include "exception.h"
26#include "itemserializer_p.h"
27#include "itemserializerplugin.h"
28#include "servermanager.h"
29#include "tagfetchscope.h"
30#include <akonadi/private/xdgbasedirs_p.h>
31
32#include <QtCore/QDateTime>
33#include <QtCore/QFile>
34#include <QtCore/QVarLengthArray>
35#include <QtCore/QFileInfo>
36#include <QtCore/QDir>
37
38#include <kdebug.h>
39#include <klocalizedstring.h>
40
41using namespace Akonadi;
42
43int ProtocolHelper::parseCachePolicy(const QByteArray & data, CachePolicy & policy, int start)
44{
45 QVarLengthArray<QByteArray,16> params;
46 int end = Akonadi::ImapParser::parseParenthesizedList( data, params, start );
47 for ( int i = 0; i < params.count() - 1; i += 2 ) {
48 const QByteArray key = params[i];
49 const QByteArray value = params[i + 1];
50
51 if ( key == "INHERIT" )
52 policy.setInheritFromParent( value == "true" );
53 else if ( key == "INTERVAL" )
54 policy.setIntervalCheckTime( value.toInt() );
55 else if ( key == "CACHETIMEOUT" )
56 policy.setCacheTimeout( value.toInt() );
57 else if ( key == "SYNCONDEMAND" )
58 policy.setSyncOnDemand( value == "true" );
59 else if ( key == "LOCALPARTS" ) {
60 QVarLengthArray<QByteArray,16> tmp;
61 QStringList parts;
62 Akonadi::ImapParser::parseParenthesizedList( value, tmp );
63 for ( int j=0; j<tmp.size(); j++ )
64 parts << QString::fromLatin1( tmp[j] );
65 policy.setLocalParts( parts );
66 }
67 }
68 return end;
69}
70
71QByteArray ProtocolHelper::cachePolicyToByteArray(const CachePolicy & policy)
72{
73 QByteArray rv = "CACHEPOLICY (";
74 if ( policy.inheritFromParent() ) {
75 rv += "INHERIT true";
76 } else {
77 rv += "INHERIT false";
78 rv += " INTERVAL " + QByteArray::number( policy.intervalCheckTime() );
79 rv += " CACHETIMEOUT " + QByteArray::number( policy.cacheTimeout() );
80 rv += " SYNCONDEMAND " + ( policy.syncOnDemand() ? QByteArray("true") : QByteArray("false") );
81 rv += " LOCALPARTS (" + policy.localParts().join( QLatin1String(" ") ).toLatin1() + ')';
82 }
83 rv += ')';
84 return rv;
85}
86
87void ProtocolHelper::parseAncestorsCached( const QByteArray &data, Entity *entity, Collection::Id parentCollection,
88 ProtocolHelperValuePool *pool, int start )
89{
90 if ( !pool || parentCollection == -1 ) {
91 // if no pool or parent collection id is provided we can't cache anything, so continue as usual
92 parseAncestors( data, entity, start );
93 return;
94 }
95
96 if ( pool->ancestorCollections.contains( parentCollection ) ) {
97 // ancestor chain is cached already, so use the cached value
98 entity->setParentCollection( pool->ancestorCollections.value( parentCollection ) );
99 } else {
100 // not cached yet, parse the chain
101 parseAncestors( data, entity, start );
102 pool->ancestorCollections.insert( parentCollection, entity->parentCollection() );
103 }
104}
105
106void ProtocolHelper::parseAncestors( const QByteArray &data, Entity *entity, int start )
107{
108 Q_UNUSED( start );
109
110 static const Collection::Id rootCollectionId = Collection::root().id();
111 QVarLengthArray<QByteArray, 16> ancestors;
112 QVarLengthArray<QByteArray, 16> parentIds;
113
114 ImapParser::parseParenthesizedList( data, ancestors );
115 Entity* current = entity;
116 for ( int i = 0; i < ancestors.count(); ++i ) {
117 parentIds.clear();
118 ImapParser::parseParenthesizedList( ancestors[ i ], parentIds );
119 if ( parentIds.size() != 2 )
120 break;
121
122 const Collection::Id uid = parentIds[ 0 ].toLongLong();
123 if ( uid == rootCollectionId ) {
124 current->setParentCollection( Collection::root() );
125 break;
126 }
127
128 current->parentCollection().setId( uid );
129 current->parentCollection().setRemoteId( QString::fromUtf8( parentIds[ 1 ] ) );
130 current = &current->parentCollection();
131 }
132}
133
134static Collection::ListPreference parsePreference( const QByteArray &value )
135{
136 if ( value == "TRUE" ) {
137 return Collection::ListEnabled;
138 }
139 if ( value == "FALSE" ) {
140 return Collection::ListDisabled;
141 }
142 return Collection::ListDefault;
143}
144
145int ProtocolHelper::parseCollection(const QByteArray & data, Collection & collection, int start)
146{
147 int pos = start;
148
149 // collection and parent id
150 Collection::Id colId = -1;
151 bool ok = false;
152 pos = ImapParser::parseNumber( data, colId, &ok, pos );
153 if ( !ok || colId <= 0 ) {
154 kDebug() << "Could not parse collection id from response:" << data;
155 return start;
156 }
157
158 Collection::Id parentId = -1;
159 pos = ImapParser::parseNumber( data, parentId, &ok, pos );
160 if ( !ok || parentId < 0 ) {
161 kDebug() << "Could not parse parent id from response:" << data;
162 return start;
163 }
164
165 collection = Collection( colId );
166 collection.setParentCollection( Collection( parentId ) );
167
168 // attributes
169 QVarLengthArray<QByteArray,16> attributes;
170 pos = ImapParser::parseParenthesizedList( data, attributes, pos );
171
172 for ( int i = 0; i < attributes.count() - 1; i += 2 ) {
173 const QByteArray key = attributes[i];
174 const QByteArray value = attributes[i + 1];
175
176 if ( key == "NAME" ) {
177 collection.setName( QString::fromUtf8( value ) );
178 } else if ( key == "REMOTEID" ) {
179 collection.setRemoteId( QString::fromUtf8( value ) );
180 } else if ( key == "REMOTEREVISION" ) {
181 collection.setRemoteRevision( QString::fromUtf8( value ) );
182 } else if ( key == "RESOURCE" ) {
183 collection.setResource( QString::fromUtf8( value ) );
184 } else if ( key == "MIMETYPE" ) {
185 QVarLengthArray<QByteArray,16> ct;
186 ImapParser::parseParenthesizedList( value, ct );
187 QStringList ct2;
188 for ( int j = 0; j < ct.size(); j++ )
189 ct2 << QString::fromLatin1( ct[j] );
190 collection.setContentMimeTypes( ct2 );
191 } else if ( key == "VIRTUAL" ) {
192 collection.setVirtual( value.toUInt() != 0 );
193 } else if ( key == "MESSAGES" ) {
194 CollectionStatistics s = collection.statistics();
195 s.setCount( value.toLongLong() );
196 collection.setStatistics( s );
197 } else if ( key == "UNSEEN" ) {
198 CollectionStatistics s = collection.statistics();
199 s.setUnreadCount( value.toLongLong() );
200 collection.setStatistics( s );
201 } else if ( key == "SIZE" ) {
202 CollectionStatistics s = collection.statistics();
203 s.setSize( value.toLongLong() );
204 collection.setStatistics( s );
205 } else if ( key == "CACHEPOLICY" ) {
206 CachePolicy policy;
207 ProtocolHelper::parseCachePolicy( value, policy );
208 collection.setCachePolicy( policy );
209 } else if ( key == "ANCESTORS" ) {
210 parseAncestors( value, &collection );
211 } else if ( key == "ENABLED" ) {
212 collection.setEnabled( value == "TRUE" );
213 } else if ( key == "DISPLAY" ) {
214 collection.setLocalListPreference( Collection::ListDisplay, parsePreference( value ) );
215 } else if ( key == "SYNC" ) {
216 collection.setLocalListPreference( Collection::ListSync, parsePreference( value ) );
217 } else if ( key == "INDEX" ) {
218 collection.setLocalListPreference( Collection::ListIndex, parsePreference( value ) );
219 } else if ( key == "REFERENCED" ) {
220 collection.setReferenced( value == "TRUE" );
221 } else {
222 Attribute* attr = AttributeFactory::createAttribute( key );
223 Q_ASSERT( attr );
224 attr->deserialize( value );
225 collection.addAttribute( attr );
226 }
227 }
228
229 return pos;
230}
231
232QByteArray ProtocolHelper::attributesToByteArray(const Entity & entity, bool ns )
233{
234 QList<QByteArray> l;
235 foreach ( const Attribute *attr, entity.attributes() ) {
236 l << encodePartIdentifier( ns ? PartAttribute : PartGlobal, attr->type() );
237 l << ImapParser::quote( attr->serialized() );
238 }
239 return ImapParser::join( l, " " );
240}
241
242QByteArray ProtocolHelper::attributesToByteArray(const AttributeEntity & entity, bool ns )
243{
244 QList<QByteArray> l;
245 foreach ( const Attribute *attr, entity.attributes() ) {
246 l << encodePartIdentifier( ns ? PartAttribute : PartGlobal, attr->type() );
247 l << ImapParser::quote( attr->serialized() );
248 }
249 return ImapParser::join( l, " " );
250}
251
252QByteArray ProtocolHelper::encodePartIdentifier(PartNamespace ns, const QByteArray & label, int version )
253{
254 const QByteArray versionString( version != 0 ? QByteArray(QByteArray("[") + QByteArray::number( version ) + QByteArray("]")) : "" );
255 switch ( ns ) {
256 case PartGlobal:
257 return label + versionString;
258 case PartPayload:
259 return "PLD:" + label + versionString;
260 case PartAttribute:
261 return "ATR:" + label + versionString;
262 default:
263 Q_ASSERT( false );
264 }
265 return QByteArray();
266}
267
268QByteArray ProtocolHelper::decodePartIdentifier( const QByteArray &data, PartNamespace & ns )
269{
270 if ( data.startsWith( "PLD:" ) ) { //krazy:exclude=strings
271 ns = PartPayload;
272 return data.mid( 4 );
273 } else if ( data.startsWith( "ATR:" ) ) { //krazy:exclude=strings
274 ns = PartAttribute;
275 return data.mid( 4 );
276 } else {
277 ns = PartGlobal;
278 return data;
279 }
280}
281
282QByteArray ProtocolHelper::entitySetToByteArray( const QList<Item> &_objects, const QByteArray &command )
283{
284 if ( _objects.isEmpty() )
285 throw Exception( "No objects specified" );
286
287 Item::List objects( _objects );
288 std::sort( objects.begin(), objects.end(), boost::bind( &Item::id, _1 ) < boost::bind( &Item::id, _2 ) );
289 if ( objects.first().isValid() ) {
290 // all items have a uid set
291 return entitySetToByteArray<Item>(objects, command);
292 }
293 // check if all items have a gid
294 if ( std::find_if( objects.constBegin(), objects.constEnd(),
295 boost::bind( &QString::isEmpty, boost::bind( &Item::gid, _1 ) ) )
296 == objects.constEnd() )
297 {
298 QList<QByteArray> gids;
299 foreach ( const Item &object, objects ) {
300 gids << ImapParser::quote( object.gid().toUtf8() );
301 }
302
303 QByteArray rv;
304 //rv += " " AKONADI_CMD_GID " ";
305 rv += " " "GID" " ";
306 if ( !command.isEmpty() ) {
307 rv += command;
308 rv += ' ';
309 }
310 rv += '(';
311 rv += ImapParser::join( gids, " " );
312 rv += ')';
313 return rv;
314 }
315 return entitySetToByteArray<Item>(objects, command);
316}
317
318QByteArray ProtocolHelper::tagSetToImapSequenceSet( const Akonadi::Tag::List &_objects )
319{
320 if ( _objects.isEmpty() )
321 throw Exception( "No objects specified" );
322
323 Tag::List objects( _objects );
324
325 std::sort( objects.begin(), objects.end(), boost::bind( &Tag::id, _1 ) < boost::bind( &Tag::id, _2 ) );
326 if ( !objects.first().isValid() ) {
327 throw Exception( "Not all tags have a uid" );
328 }
329 // all items have a uid set
330 QVector<Tag::Id> uids;
331 foreach ( const Tag &object, objects )
332 uids << object.id();
333 ImapSet set;
334 set.add( uids );
335 return set.toImapSequenceSet();
336}
337
338QByteArray ProtocolHelper::tagSetToByteArray( const Tag::List &_objects, const QByteArray &command )
339{
340 if ( _objects.isEmpty() )
341 throw Exception( "No objects specified" );
342
343 Tag::List objects( _objects );
344
345 QByteArray rv;
346 std::sort( objects.begin(), objects.end(), boost::bind( &Tag::id, _1 ) < boost::bind( &Tag::id, _2 ) );
347 if ( objects.first().isValid() ) {
348 // all items have a uid set
349 rv += " " AKONADI_CMD_UID " ";
350 if ( !command.isEmpty() ) {
351 rv += command;
352 rv += ' ';
353 }
354 QVector<Tag::Id> uids;
355 foreach ( const Tag &object, objects )
356 uids << object.id();
357 ImapSet set;
358 set.add( uids );
359 rv += set.toImapSequenceSet();
360 return rv;
361 }
362 throw Exception( "Not all tags have a uid" );
363}
364
365QByteArray ProtocolHelper::commandContextToByteArray(const Akonadi::Collection &collection, const Akonadi::Tag &tag,
366 const Item::List &requestedItems, const QByteArray &command)
367{
368 QByteArray r = " ";
369 if (requestedItems.isEmpty()) {
370 r += command + " 1:*";
371 } else {
372 r += ProtocolHelper::entitySetToByteArray(requestedItems, command);
373 }
374
375 if (tag.isValid()) {
376 r += " " AKONADI_PARAM_TAGID " " + QByteArray::number(tag.id()) + " ";
377 }
378
379 if (collection == Collection::root()) {
380 if (requestedItems.isEmpty() && !tag.isValid()) { // collection content listing
381 throw Exception("Cannot perform item operations on root collection.");
382 }
383 } else {
384 if (collection.isValid()) {
385 r += " " AKONADI_PARAM_COLLECTIONID " " + QByteArray::number(collection.id()) + ' ';
386 } else if (!collection.remoteId().isEmpty()) {
387 r += " " AKONADI_PARAM_COLLECTION " " + ImapParser::quote(collection.remoteId().toUtf8()) + ' ';
388 }
389 }
390
391 return r;
392}
393
394
395QByteArray ProtocolHelper::hierarchicalRidToByteArray( const Collection &col )
396{
397 if ( col == Collection::root() )
398 return QByteArray("(0 \"\")");
399 if ( col.remoteId().isEmpty() )
400 return QByteArray();
401 const QByteArray parentHrid = hierarchicalRidToByteArray( col.parentCollection() );
402 return '(' + QByteArray::number( col.id() ) + ' ' + ImapParser::quote( col.remoteId().toUtf8() ) + ") " + parentHrid;
403}
404
405QByteArray ProtocolHelper::hierarchicalRidToByteArray( const Item &item )
406{
407 const QByteArray parentHrid = hierarchicalRidToByteArray( item.parentCollection() );
408 return '(' + QByteArray::number( item.id() ) + ' ' + ImapParser::quote( item.remoteId().toUtf8() ) + ") " + parentHrid;
409}
410
411QByteArray ProtocolHelper::itemFetchScopeToByteArray( const ItemFetchScope &fetchScope )
412{
413 QByteArray command;
414
415 if ( fetchScope.fullPayload() )
416 command += " " AKONADI_PARAM_FULLPAYLOAD;
417 if ( fetchScope.allAttributes() )
418 command += " " AKONADI_PARAM_ALLATTRIBUTES;
419 if ( fetchScope.cacheOnly() )
420 command += " " AKONADI_PARAM_CACHEONLY;
421 if ( fetchScope.checkForCachedPayloadPartsOnly() )
422 command += " " AKONADI_PARAM_CHECKCACHEDPARTSONLY;
423 if ( fetchScope.ignoreRetrievalErrors() )
424 command += " " "IGNOREERRORS";
425 if ( fetchScope.ancestorRetrieval() != ItemFetchScope::None ) {
426 switch ( fetchScope.ancestorRetrieval() ) {
427 case ItemFetchScope::Parent:
428 command += " ANCESTORS 1";
429 break;
430 case ItemFetchScope::All:
431 command += " ANCESTORS INF";
432 break;
433 default:
434 Q_ASSERT( false );
435 }
436 }
437 if ( fetchScope.fetchChangedSince().isValid() ) {
438 command += " " AKONADI_PARAM_CHANGEDSINCE " " + QByteArray::number( fetchScope.fetchChangedSince().toTime_t() );
439 }
440
441 //TODO: detect somehow if server supports external payload attribute
442 command += " " AKONADI_PARAM_EXTERNALPAYLOAD;
443
444 command += " (UID COLLECTIONID FLAGS SIZE";
445 if ( fetchScope.fetchRemoteIdentification() )
446 command += " " AKONADI_PARAM_REMOTEID " " AKONADI_PARAM_REMOTEREVISION;
447 if ( fetchScope.fetchGid() )
448 command += " GID";
449 if ( fetchScope.fetchTags() ) {
450 command += " TAGS";
451 if ( !fetchScope.tagFetchScope().fetchIdOnly() ) {
452 command += " " + ProtocolHelper::tagFetchScopeToByteArray( fetchScope.tagFetchScope() );
453 }
454 }
455 if ( fetchScope.fetchVirtualReferences() )
456 command += " VIRTREF";
457 if ( fetchScope.fetchModificationTime() )
458 command += " DATETIME";
459 foreach ( const QByteArray &part, fetchScope.payloadParts() )
460 command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartPayload, part );
461 foreach ( const QByteArray &part, fetchScope.attributes() )
462 command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartAttribute, part );
463 command += ")\n";
464
465 return command;
466}
467
468QByteArray ProtocolHelper::tagFetchScopeToByteArray( const TagFetchScope &fetchScope )
469{
470 QByteArray command;
471
472 command += "(UID";
473 Q_FOREACH (const QByteArray &part, fetchScope.attributes()) {
474 command += ' ' + ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartAttribute, part);
475 }
476 command += ")";
477 return command;
478}
479
480static Item::Flags convertFlags( const QList<QByteArray>& flags, ProtocolHelperValuePool *valuePool )
481{
482#if __cplusplus >= 201103L || defined(__GNUC__) || defined(__clang__)
483 // When the compiler supports thread-safe static initialization (mandated by the C++11 memory model)
484 // then use it to share the common case of a single-item set only containing the \SEEN flag.
485 // NOTE: GCC and clang has threadsafe static initialization for some time now, even without C++11.
486 if (flags.size() == 1 && flags.first() == "\\SEEN") {
487 static const Item::Flags sharedSeen = Item::Flags() << QByteArray( "\\SEEN" );
488 return sharedSeen;
489 }
490#endif
491
492 Item::Flags convertedFlags;
493 convertedFlags.reserve( flags.size() );
494 foreach ( const QByteArray &flag, flags ) {
495 if ( valuePool )
496 convertedFlags.insert( valuePool->flagPool.sharedValue( flag ) );
497 else
498 convertedFlags.insert( flag );
499 }
500 return convertedFlags;
501}
502
503void ProtocolHelper::parseItemFetchResult( const QList<QByteArray> &lineTokens, Item &item, ProtocolHelperValuePool *valuePool )
504{
505 // create a new item object
506 Item::Id uid = -1;
507 int rev = -1;
508 QString rid;
509 QString remoteRevision;
510 QString gid;
511 QString mimeType;
512 Entity::Id cid = -1;
513
514 for ( int i = 0; i < lineTokens.count() - 1; i += 2 ) {
515 const QByteArray key = lineTokens.value( i );
516 const QByteArray value = lineTokens.value( i + 1 );
517
518 if ( key == "UID" )
519 uid = value.toLongLong();
520 else if ( key == "REV" )
521 rev = value.toInt();
522 else if ( key == "REMOTEID" ) {
523 if ( !value.isEmpty() )
524 rid = QString::fromUtf8( value );
525 else
526 rid.clear();
527 } else if ( key == "REMOTEREVISION" ) {
528 remoteRevision = QString::fromUtf8( value );
529 } else if ( key == "GID" ) {
530 gid = QString::fromUtf8( value );
531 } else if ( key == "COLLECTIONID" ) {
532 cid = value.toInt();
533 } else if ( key == "MIMETYPE" ) {
534 if ( valuePool )
535 mimeType = valuePool->mimeTypePool.sharedValue( QString::fromLatin1( value ) );
536 else
537 mimeType = QString::fromLatin1( value );
538 }
539 }
540
541 if ( uid < 0 || rev < 0 || mimeType.isEmpty() ) {
542 kWarning() << "Broken fetch response: UID, REV or MIMETYPE missing!";
543 return;
544 }
545
546 item = Item( uid );
547 item.setRemoteId( rid );
548 item.setRevision( rev );
549 item.setRemoteRevision( remoteRevision );
550 item.setGid( gid );
551 item.setMimeType( mimeType );
552 item.setStorageCollectionId( cid );
553 if ( !item.isValid() )
554 return;
555
556 // parse fetch response fields
557 for ( int i = 0; i < lineTokens.count() - 1; i += 2 ) {
558 const QByteArray key = lineTokens.value( i );
559 // skip stuff we dealt with already
560 if ( key == "UID" || key == "REV" || key == "REMOTEID" ||
561 key == "MIMETYPE" || key == "COLLECTIONID" || key == "REMOTEREVISION" || key == "GID" )
562 continue;
563 // flags
564 if ( key == "FLAGS" ) {
565 QList<QByteArray> flags;
566 ImapParser::parseParenthesizedList( lineTokens[i + 1], flags );
567 if ( !flags.isEmpty() ) {
568 item.setFlags( convertFlags( flags, valuePool ) );
569 }
570 } else if ( key == "TAGS" ) {
571 Tag::List tags;
572 if ( lineTokens[i + 1].startsWith("(") ) {
573 QList<QByteArray> tagsData;
574 ImapParser::parseParenthesizedList( lineTokens[i + 1], tagsData );
575 Q_FOREACH (const QByteArray &t, tagsData) {
576 QList<QByteArray> tagParts;
577 ImapParser::parseParenthesizedList( t, tagParts );
578 Tag tag;
579 parseTagFetchResult(tagParts, tag);
580 tags << tag;
581 }
582 } else {
583 ImapSet set;
584 ImapParser::parseSequenceSet( lineTokens[i + 1], set );
585 Q_FOREACH ( const ImapInterval &interval, set.intervals() ) {
586 Q_ASSERT( interval.hasDefinedBegin() );
587 Q_ASSERT( interval.hasDefinedEnd() );
588 for ( qint64 i = interval.begin(); i <= interval.end(); i++ ) {
589 //TODO use value pool when tag is shared data
590 tags << Tag( i );
591 }
592 }
593 }
594 item.setTags( tags );
595 } else if ( key == "VIRTREF" ) {
596 ImapSet set;
597 ImapParser::parseSequenceSet( lineTokens[i + 1], set );
598 Collection::List collections;
599 Q_FOREACH ( const ImapInterval &interval, set.intervals() ) {
600 Q_ASSERT( interval.hasDefinedBegin() );
601 Q_ASSERT( interval.hasDefinedEnd() );
602 for ( qint64 i = interval.begin(); i <= interval.end(); i++ ) {
603 collections << Collection(i);
604 }
605 }
606 item.setVirtualReferences(collections);
607 } else if ( key == "CACHEDPARTS" ) {
608 QSet<QByteArray> partsSet;
609 QList<QByteArray> parts;
610 ImapParser::parseParenthesizedList( lineTokens[i + 1], parts );
611 foreach ( const QByteArray &part, parts ) {
612 partsSet.insert(part.mid(4));
613 }
614 item.setCachedPayloadParts( partsSet );
615 } else if ( key == "SIZE" ) {
616 const quint64 size = lineTokens[i + 1].toLongLong();
617 item.setSize( size );
618 } else if ( key == "DATETIME" ) {
619 QDateTime datetime;
620 ImapParser::parseDateTime( lineTokens[i + 1], datetime );
621 item.setModificationTime( datetime );
622 } else if ( key == "ANCESTORS" ) {
623 ProtocolHelper::parseAncestorsCached( lineTokens[i + 1], &item, cid, valuePool );
624 } else {
625 int version = 0;
626 QByteArray plainKey( key );
627 ProtocolHelper::PartNamespace ns;
628
629 ImapParser::splitVersionedKey( key, plainKey, version );
630 plainKey = ProtocolHelper::decodePartIdentifier( plainKey, ns );
631
632 switch ( ns ) {
633 case ProtocolHelper::PartPayload:
634 {
635 bool isExternal = false;
636 const QByteArray fileKey = lineTokens.value( i + 1 );
637 if ( fileKey == "[FILE]" ) {
638 isExternal = true;
639 i++;
640 //kDebug() << "Payload is external: " << isExternal << " filename: " << lineTokens.value( i + 1 );
641 }
642 ItemSerializer::deserialize( item, plainKey, lineTokens.value( i + 1 ), version, isExternal );
643 break;
644 }
645 case ProtocolHelper::PartAttribute:
646 {
647 Attribute* attr = AttributeFactory::createAttribute( plainKey );
648 Q_ASSERT( attr );
649 if ( lineTokens.value( i + 1 ) == "[FILE]" ) {
650 ++i;
651 QFile file( QString::fromUtf8( lineTokens.value( i + 1 ) ) );
652 if ( file.open( QFile::ReadOnly ) )
653 attr->deserialize( file.readAll() );
654 else {
655 kWarning() << "Failed to open attribute file: " << lineTokens.value( i + 1 );
656 delete attr;
657 attr = 0;
658 }
659 } else {
660 attr->deserialize( lineTokens.value( i + 1 ) );
661 }
662 if ( attr )
663 item.addAttribute( attr );
664 break;
665 }
666 case ProtocolHelper::PartGlobal:
667 default:
668 kWarning() << "Unknown item part type:" << key;
669 }
670 }
671 }
672
673 item.d_ptr->resetChangeLog();
674}
675
676void ProtocolHelper::parseTagFetchResult( const QList<QByteArray> &lineTokens, Tag &tag )
677{
678 for (int i = 0; i < lineTokens.count() - 1; i += 2) {
679 const QByteArray key = lineTokens.value(i);
680 const QByteArray value = lineTokens.value(i + 1);
681
682 if (key == "UID") {
683 tag.setId(value.toLongLong());
684 } else if (key == "GID") {
685 tag.setGid(value);
686 } else if (key == "REMOTEID") {
687 tag.setRemoteId(value);
688 } else if (key == "PARENT") {
689 tag.setParent(Tag(value.toLongLong()));
690 } else if ( key == "MIMETYPE" ) {
691 tag.setType(value);
692 } else {
693 Attribute *attr = AttributeFactory::createAttribute(key);
694 if (!attr) {
695 kWarning() << "Unknown tag attribute" << key;
696 continue;
697 }
698 attr->deserialize(value);
699 tag.addAttribute(attr);
700 }
701 }
702}
703
704QString ProtocolHelper::akonadiStoragePath()
705{
706 QString fullRelPath = QLatin1String("akonadi");
707 if (Akonadi::ServerManager::hasInstanceIdentifier()) {
708 fullRelPath += QDir::separator() + QLatin1String("instance") + QDir::separator() + Akonadi::ServerManager::instanceIdentifier();
709 }
710 return XdgBaseDirs::saveDir("data", fullRelPath);
711}
712
713QString ProtocolHelper::absolutePayloadFilePath(const QString &fileName)
714{
715 QFileInfo fi(fileName);
716 if (!fi.isAbsolute()) {
717 return akonadiStoragePath() + QDir::separator() + QLatin1String("file_db_data") + QDir::separator() + fileName;
718 }
719
720 return fileName;
721}
722
723bool ProtocolHelper::streamPayloadToFile(const QByteArray &command, const QByteArray &data, QByteArray &error)
724{
725 const int fnStart = command.indexOf("[FILE ") + 6;
726 if (fnStart == -1) {
727 kDebug() << "Unexpected response";
728 return false;
729 }
730 const int fnEnd = command.indexOf("]", fnStart);
731 const QByteArray fn = command.mid(fnStart, fnEnd - fnStart);
732 const QString fileName = ProtocolHelper::absolutePayloadFilePath(QString::fromLatin1(fn));
733 if (!fileName.startsWith(akonadiStoragePath())) {
734 kWarning() << "Invalid file path" << fileName;
735 error = "Invalid file path";
736 return false;
737 }
738 QFile file(fileName);
739 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
740 kWarning() << "Failed to open destination payload file" << file.errorString();
741 error = "Failed to store payload into file";
742 return false;
743 }
744 if (file.write(data) != data.size()) {
745 kWarning() << "Failed to write all payload data to file";
746 error = "Failed to store payload into file";
747 return false;
748 }
749 kDebug() << "Wrote" << data.size() << "bytes to " << file.fileName();
750
751 // Make sure stuff is written to disk
752 file.close();
753 return true;
754}
755
756
757QByteArray ProtocolHelper::listPreference(Collection::ListPurpose purpose, Collection::ListPreference preference)
758{
759 QByteArray command;
760 switch(purpose) {
761 case Collection::ListDisplay:
762 command += "DISPLAY ";
763 break;
764 case Collection::ListSync:
765 command += "SYNC ";
766 break;
767 case Collection::ListIndex:
768 command += "INDEX ";
769 break;
770 }
771 switch(preference) {
772 case Collection::ListEnabled:
773 command += "TRUE";
774 break;
775 case Collection::ListDisabled:
776 command += "FALSE";
777 break;
778 case Collection::ListDefault:
779 command += "DEFAULT";
780 break;
781 }
782 return command;
783}
784
785QByteArray ProtocolHelper::enabled(bool state)
786{
787 if (state) {
788 return "ENABLED TRUE";
789 }
790 return "ENABLED FALSE";
791}
792
793QByteArray ProtocolHelper::referenced(bool state)
794{
795 if (state) {
796 return "REFERENCED TRUE";
797 }
798 return "REFERENCED FALSE";
799}
Akonadi::AttributeEntity
Parent class for entities that can have attributes.
Definition attributeentity.h:40
Akonadi::AttributeEntity::attributes
Attribute::List attributes() const
Returns a list of all attributes of the entity.
Definition attributeentity.cpp:99
Akonadi::AttributeFactory::createAttribute
static Attribute * createAttribute(const QByteArray &type)
Creates an entity attribute object of the given type.
Definition attributefactory.cpp:147
Akonadi::Attribute
Provides interface for custom attributes for Entity.
Definition attribute.h:139
Akonadi::Attribute::deserialize
virtual void deserialize(const QByteArray &data)=0
Sets the data of this attribute, using the same encoding as returned by toByteArray().
Akonadi::Attribute::serialized
virtual QByteArray serialized() const =0
Returns a QByteArray representation of the attribute which will be storaged.
Akonadi::Attribute::type
virtual QByteArray type() const =0
Returns the type of the attribute.
Akonadi::CachePolicy
Represents the caching policy for a collection.
Definition cachepolicy.h:72
Akonadi::CachePolicy::cacheTimeout
int cacheTimeout() const
Returns the cache timeout for non-permanently cached parts in minutes; -1 means indefinitely.
Definition cachepolicy.cpp:108
Akonadi::CachePolicy::inheritFromParent
bool inheritFromParent() const
Returns whether it inherits cache policy from the parent collection.
Definition cachepolicy.cpp:88
Akonadi::CachePolicy::intervalCheckTime
int intervalCheckTime() const
Returns the interval check time in minutes, -1 for never.
Definition cachepolicy.cpp:118
Akonadi::CachePolicy::setLocalParts
void setLocalParts(const QStringList &parts)
Specifies the parts to permanently cache locally.
Definition cachepolicy.cpp:103
Akonadi::CachePolicy::localParts
QStringList localParts() const
Returns the parts to permanently cache locally.
Definition cachepolicy.cpp:98
Akonadi::CachePolicy::syncOnDemand
bool syncOnDemand() const
Returns whether the collection will be synced automatically when necessary, i.e.
Definition cachepolicy.cpp:128
Akonadi::CachePolicy::setIntervalCheckTime
void setIntervalCheckTime(int time)
Sets interval check time.
Definition cachepolicy.cpp:123
Akonadi::CachePolicy::setCacheTimeout
void setCacheTimeout(int timeout)
Sets cache timeout for non-permanently cached parts.
Definition cachepolicy.cpp:113
Akonadi::CachePolicy::setInheritFromParent
void setInheritFromParent(bool inherit)
Sets whether the cache policy should be inherited from the parent collection.
Definition cachepolicy.cpp:93
Akonadi::CachePolicy::setSyncOnDemand
void setSyncOnDemand(bool enable)
Sets whether the collection shall be synced automatically when necessary, i.e.
Definition cachepolicy.cpp:133
Akonadi::CollectionStatistics
Provides statistics information of a Collection.
Definition collectionstatistics.h:70
Akonadi::CollectionStatistics::setUnreadCount
void setUnreadCount(qint64 count)
Sets the number of unread items in this collection.
Definition collectionstatistics.cpp:82
Akonadi::CollectionStatistics::setSize
void setSize(qint64 size)
Sets the total size of the items in this collection.
Definition collectionstatistics.cpp:92
Akonadi::CollectionStatistics::setCount
void setCount(qint64 count)
Sets the number of items in this collection.
Definition collectionstatistics.cpp:72
Akonadi::Collection
Represents a collection of PIM items.
Definition collection.h:76
Akonadi::Collection::ListPurpose
ListPurpose
Describes the purpose of the listing.
Definition collection.h:335
Akonadi::Collection::ListSync
@ ListSync
Listing for synchronization.
Definition collection.h:336
Akonadi::Collection::ListIndex
@ ListIndex
Listing for indexing the content.
Definition collection.h:338
Akonadi::Collection::ListDisplay
@ ListDisplay
Listing for display to the user.
Definition collection.h:337
Akonadi::Collection::root
static Collection root()
Returns the root collection.
Definition collection.cpp:192
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition collection.h:81
Akonadi::Collection::ListPreference
ListPreference
Describes the list preference value.
Definition collection.h:324
Akonadi::Collection::ListDefault
@ ListDefault
Fallback to enabled state.
Definition collection.h:327
Akonadi::Collection::ListDisabled
@ ListDisabled
Disable collectoin for specified purpose.
Definition collection.h:326
Akonadi::Collection::ListEnabled
@ ListEnabled
Enable collection for specified purpose.
Definition collection.h:325
Akonadi::Entity
The base class for Item and Collection.
Definition entity.h:60
Akonadi::Entity::remoteId
QString remoteId() const
Returns the remote id of the entity.
Definition entity.cpp:82
Akonadi::Entity::parentCollection
Collection parentCollection() const
Returns the parent collection of this object.
Definition entity.cpp:185
Akonadi::Entity::attributes
Attribute::List attributes() const
Returns a list of all attributes of the entity.
Definition entity.cpp:153
Akonadi::Entity::setId
void setId(Id identifier)
Sets the unique identifier of the entity.
Definition entity.cpp:67
Akonadi::Entity::setParentCollection
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition entity.cpp:194
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition entity.cpp:72
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition entity.h:65
Akonadi::Entity::setRemoteId
void setRemoteId(const QString &id)
Sets the remote id of the entity.
Definition entity.cpp:77
Akonadi::Exception
Base class for exceptions used by the Akonadi library.
Definition exception.h:36
Akonadi::Internal::SharedValuePool::sharedValue
T sharedValue(const T &value)
Returns the shared value equal to value .
Definition sharedvaluepool_p.h:66
Akonadi::ItemFetchScope
Specifies which parts of an item should be fetched from the Akonadi storage.
Definition itemfetchscope.h:70
Akonadi::ItemFetchScope::fetchVirtualReferences
bool fetchVirtualReferences() const
Returns whether virtual references should be retrieved.
Definition itemfetchscope.cpp:217
Akonadi::ItemFetchScope::allAttributes
bool allAttributes() const
Returns whether all available attributes should be fetched.
Definition itemfetchscope.cpp:89
Akonadi::ItemFetchScope::fetchRemoteIdentification
bool fetchRemoteIdentification() const
Returns whether item remote identification should be retrieved.
Definition itemfetchscope.cpp:182
Akonadi::ItemFetchScope::fullPayload
bool fullPayload() const
Returns whether the full payload should be fetched.
Definition itemfetchscope.cpp:65
Akonadi::ItemFetchScope::fetchTags
bool fetchTags() const
Returns whether tags should be retrieved.
Definition itemfetchscope.cpp:192
Akonadi::ItemFetchScope::cacheOnly
bool cacheOnly() const
Returns whether payload data should be requested from remote sources or just from the local cache.
Definition itemfetchscope.cpp:104
Akonadi::ItemFetchScope::fetchModificationTime
bool fetchModificationTime() const
Returns whether item modification time should be retrieved.
Definition itemfetchscope.cpp:142
Akonadi::ItemFetchScope::checkForCachedPayloadPartsOnly
bool checkForCachedPayloadPartsOnly() const
Returns whether payload data should be fetched or only checked for presence in the cache.
Definition itemfetchscope.cpp:122
Akonadi::ItemFetchScope::attributes
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
Definition itemfetchscope.cpp:75
Akonadi::ItemFetchScope::ignoreRetrievalErrors
bool ignoreRetrievalErrors() const
Returns whether retrieval errors should be ignored.
Definition itemfetchscope.cpp:162
Akonadi::ItemFetchScope::payloadParts
QSet< QByteArray > payloadParts() const
Returns the payload parts that should be fetched.
Definition itemfetchscope.cpp:51
Akonadi::ItemFetchScope::fetchGid
bool fetchGid() const
Returns whether item GID should be retrieved.
Definition itemfetchscope.cpp:152
Akonadi::ItemFetchScope::ancestorRetrieval
AncestorRetrieval ancestorRetrieval() const
Returns the ancestor retrieval depth.
Definition itemfetchscope.cpp:127
Akonadi::ItemFetchScope::tagFetchScope
TagFetchScope & tagFetchScope()
Returns the tag fetch scope.
Definition itemfetchscope.cpp:202
Akonadi::ItemFetchScope::fetchChangedSince
KDateTime fetchChangedSince() const
Returns timestamp of the oldest item to fetch.
Definition itemfetchscope.cpp:172
Akonadi::ItemFetchScope::All
@ All
Retrieve all ancestors, up to Collection::root()
Definition itemfetchscope.h:79
Akonadi::ItemFetchScope::Parent
@ Parent
Only retrieve the immediate parent collection.
Definition itemfetchscope.h:78
Akonadi::ItemFetchScope::None
@ None
No ancestor retrieval at all (the default)
Definition itemfetchscope.h:77
Akonadi::ItemSerializer::deserialize
static void deserialize(Item &item, const QByteArray &label, const QByteArray &data, int version, bool external)
throws ItemSerializerException on failure
Definition itemserializer.cpp:84
Akonadi::ProtocolHelper::itemFetchScopeToByteArray
static QByteArray itemFetchScopeToByteArray(const ItemFetchScope &fetchScope)
Converts a given ItemFetchScope object into a protocol representation.
Definition protocolhelper.cpp:411
Akonadi::ProtocolHelper::parseCachePolicy
static int parseCachePolicy(const QByteArray &data, CachePolicy &policy, int start=0)
Parse a cache policy definition.
Definition protocolhelper.cpp:43
Akonadi::ProtocolHelper::hierarchicalRidToByteArray
static QByteArray hierarchicalRidToByteArray(const Collection &col)
Converts the given collection's hierarchical RID into a protocol representation.
Definition protocolhelper.cpp:395
Akonadi::ProtocolHelper::parseAncestors
static void parseAncestors(const QByteArray &data, Entity *entity, int start=0)
Convert a ancestor chain from its protocol representation into an Entity object.
Definition protocolhelper.cpp:106
Akonadi::ProtocolHelper::tagFetchScopeToByteArray
static QByteArray tagFetchScopeToByteArray(const TagFetchScope &fetchScope)
Converts a given TagFetchScope object into a protocol representation.
Definition protocolhelper.cpp:468
Akonadi::ProtocolHelper::attributesToByteArray
static QByteArray attributesToByteArray(const Entity &entity, bool ns=false)
Convert attributes to their protocol representation.
Definition protocolhelper.cpp:232
Akonadi::ProtocolHelper::PartNamespace
PartNamespace
Part namespaces.
Definition protocolhelper_p.h:62
Akonadi::ProtocolHelper::parseCollection
static int parseCollection(const QByteArray &data, Collection &collection, int start=0)
Parse a collection description.
Definition protocolhelper.cpp:145
Akonadi::ProtocolHelper::decodePartIdentifier
static QByteArray decodePartIdentifier(const QByteArray &data, PartNamespace &ns)
Decode part label and namespace.
Definition protocolhelper.cpp:268
Akonadi::ProtocolHelper::parseItemFetchResult
static void parseItemFetchResult(const QList< QByteArray > &lineTokens, Item &item, ProtocolHelperValuePool *valuePool=0)
Parses a single line from an item fetch job result into an Item object.
Definition protocolhelper.cpp:503
Akonadi::ProtocolHelper::cachePolicyToByteArray
static QByteArray cachePolicyToByteArray(const CachePolicy &policy)
Convert a cache policy object into its protocol representation.
Definition protocolhelper.cpp:71
Akonadi::ProtocolHelper::parseAncestorsCached
static void parseAncestorsCached(const QByteArray &data, Entity *entity, Collection::Id parentCollection, ProtocolHelperValuePool *valuePool=0, int start=0)
Convert a ancestor chain from its protocol representation into an Entity object.
Definition protocolhelper.cpp:87
Akonadi::ProtocolHelper::encodePartIdentifier
static QByteArray encodePartIdentifier(PartNamespace ns, const QByteArray &label, int version=0)
Encodes part label and namespace.
Definition protocolhelper.cpp:252
Akonadi::ProtocolHelper::entitySetToByteArray
static QByteArray entitySetToByteArray(const QList< T > &_objects, const QByteArray &command)
Converts the given set of items into a protocol representation.
Definition protocolhelper_p.h:125
Akonadi::ServerManager::hasInstanceIdentifier
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
Definition servermanager.cpp:289
Akonadi::ServerManager::instanceIdentifier
static QString instanceIdentifier()
Returns the identifier of the Akonadi instance we are connected to.
Definition servermanager.cpp:284
Akonadi::TagFetchScope
Specifies which parts of a tag should be fetched from the Akonadi storage.
Definition tagfetchscope.h:34
Akonadi::TagFetchScope::fetchIdOnly
bool fetchIdOnly() const
Sets wether only the id of the tags should be retieved or the complete tag.
Definition tagfetchscope.cpp:79
Akonadi::TagFetchScope::attributes
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
Definition tagfetchscope.cpp:59
Akonadi::Tag
An Akonadi Tag.
Definition tag.h:44
Akonadi::Tag::id
Id id() const
Returns the unique identifier of the tag.
Definition tag.cpp:131
Akonadi
FreeBusyManager::Singleton.
Definition actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal