20 #include "protocolhelper_p.h"
22 #include "attributefactory.h"
23 #include "collectionstatistics.h"
25 #include "exception.h"
26 #include "itemserializer_p.h"
27 #include "itemserializerplugin.h"
29 #include <QtCore/QDateTime>
30 #include <QtCore/QFile>
31 #include <QtCore/QVarLengthArray>
36 using namespace Akonadi;
38 int ProtocolHelper::parseCachePolicy(
const QByteArray & data,
CachePolicy & policy,
int start)
40 QVarLengthArray<QByteArray,16> params;
41 int end = Akonadi::ImapParser::parseParenthesizedList( data, params, start );
42 for (
int i = 0; i < params.count() - 1; i += 2 ) {
43 const QByteArray key = params[i];
44 const QByteArray value = params[i + 1];
46 if ( key ==
"INHERIT" )
48 else if ( key ==
"INTERVAL" )
50 else if ( key ==
"CACHETIMEOUT" )
52 else if ( key ==
"SYNCONDEMAND" )
54 else if ( key ==
"LOCALPARTS" ) {
55 QVarLengthArray<QByteArray,16> tmp;
57 Akonadi::ImapParser::parseParenthesizedList( value, tmp );
58 for (
int j=0; j<tmp.size(); j++ )
59 parts << QString::fromLatin1( tmp[j] );
66 QByteArray ProtocolHelper::cachePolicyToByteArray(
const CachePolicy & policy)
68 QByteArray rv =
"CACHEPOLICY (";
72 rv +=
"INHERIT false";
74 rv +=
" CACHETIMEOUT " + QByteArray::number( policy.
cacheTimeout() );
75 rv +=
" SYNCONDEMAND " + ( policy.
syncOnDemand() ? QByteArray(
"true") : QByteArray(
"false") );
76 rv +=
" LOCALPARTS (" + policy.
localParts().join( QLatin1String(
" ") ).toLatin1() +
')';
82 void ProtocolHelper::parseAncestorsCached(
const QByteArray &data,
Entity *entity,
Collection::Id parentCollection,
83 ProtocolHelperValuePool *pool,
int start )
85 if ( !pool || parentCollection == -1 ) {
87 parseAncestors( data, entity, start );
91 if ( pool->ancestorCollections.contains( parentCollection ) ) {
96 parseAncestors( data, entity, start );
97 pool->ancestorCollections.insert( parentCollection, entity->
parentCollection() );
101 void ProtocolHelper::parseAncestors(
const QByteArray &data,
Entity *entity,
int start )
105 static const Collection::Id rootCollectionId = Collection::root().id();
106 QVarLengthArray<QByteArray, 16> ancestors;
107 QVarLengthArray<QByteArray, 16> parentIds;
109 ImapParser::parseParenthesizedList( data, ancestors );
111 for (
int i = 0; i < ancestors.count(); ++i ) {
113 ImapParser::parseParenthesizedList( ancestors[ i ], parentIds );
114 if ( parentIds.size() != 2 )
118 if ( uid == rootCollectionId ) {
129 int ProtocolHelper::parseCollection(
const QByteArray & data,
Collection & collection,
int start)
136 pos = ImapParser::parseNumber( data, colId, &ok, pos );
137 if ( !ok || colId <= 0 ) {
138 kDebug() <<
"Could not parse collection id from response:" << data;
143 pos = ImapParser::parseNumber( data, parentId, &ok, pos );
144 if ( !ok || parentId < 0 ) {
145 kDebug() <<
"Could not parse parent id from response:" << data;
153 QVarLengthArray<QByteArray,16> attributes;
154 pos = ImapParser::parseParenthesizedList( data, attributes, pos );
156 for (
int i = 0; i < attributes.count() - 1; i += 2 ) {
157 const QByteArray key = attributes[i];
158 const QByteArray value = attributes[i + 1];
160 if ( key ==
"NAME" ) {
161 collection.
setName( QString::fromUtf8( value ) );
162 }
else if ( key ==
"REMOTEID" ) {
163 collection.
setRemoteId( QString::fromUtf8( value ) );
164 }
else if ( key ==
"REMOTEREVISION" ) {
166 }
else if ( key ==
"RESOURCE" ) {
167 collection.
setResource( QString::fromUtf8( value ) );
168 }
else if ( key ==
"MIMETYPE" ) {
169 QVarLengthArray<QByteArray,16> ct;
170 ImapParser::parseParenthesizedList( value, ct );
172 for (
int j = 0; j < ct.size(); j++ )
173 ct2 << QString::fromLatin1( ct[j] );
175 }
else if ( key ==
"MESSAGES" ) {
179 }
else if ( key ==
"UNSEEN" ) {
183 }
else if ( key ==
"SIZE" ) {
185 s.
setSize( value.toLongLong() );
187 }
else if ( key ==
"CACHEPOLICY" ) {
189 ProtocolHelper::parseCachePolicy( value, policy );
191 }
else if ( key ==
"ANCESTORS" ) {
192 parseAncestors( value, &collection );
204 QByteArray ProtocolHelper::attributesToByteArray(
const Entity & entity,
bool ns )
208 l << encodePartIdentifier( ns ? PartAttribute : PartGlobal, attr->
type() );
211 return ImapParser::join( l,
" " );
214 QByteArray ProtocolHelper::encodePartIdentifier(
PartNamespace ns,
const QByteArray & label,
int version )
216 const QByteArray versionString( version != 0 ?
'[' + QByteArray::number( version ) +
']' :
"" );
219 return label + versionString;
221 return "PLD:" + label + versionString;
223 return "ATR:" + label + versionString;
230 QByteArray ProtocolHelper::decodePartIdentifier(
const QByteArray &data,
PartNamespace & ns )
232 if ( data.startsWith(
"PLD:" ) ) {
234 return data.mid( 4 );
235 }
else if ( data.startsWith(
"ATR:" ) ) {
237 return data.mid( 4 );
244 QByteArray ProtocolHelper::hierarchicalRidToByteArray(
const Collection &col )
246 if ( col == Collection::root() )
247 return QByteArray(
"(0 \"\")");
250 const QByteArray parentHrid = hierarchicalRidToByteArray( col.
parentCollection() );
251 return '(' + QByteArray::number( col.
id() ) +
' ' + ImapParser::quote( col.
remoteId().toUtf8() ) +
") " + parentHrid;
254 QByteArray ProtocolHelper::hierarchicalRidToByteArray(
const Item &item )
256 const QByteArray parentHrid = hierarchicalRidToByteArray( item.
parentCollection() );
257 return '(' + QByteArray::number( item.
id() ) +
' ' + ImapParser::quote( item.
remoteId().toUtf8() ) +
") " + parentHrid;
260 QByteArray ProtocolHelper::itemFetchScopeToByteArray(
const ItemFetchScope &fetchScope )
265 command +=
" " AKONADI_PARAM_FULLPAYLOAD;
267 command +=
" " AKONADI_PARAM_ALLATTRIBUTES;
269 command +=
" " AKONADI_PARAM_CACHEONLY;
272 case ItemFetchScope::Parent:
273 command +=
" ANCESTORS 1";
275 case ItemFetchScope::All:
276 command +=
" ANCESTORS INF";
284 command +=
" " AKONADI_PARAM_EXTERNALPAYLOAD;
286 command +=
" (UID REMOTEID REMOTEREVISION COLLECTIONID FLAGS SIZE";
288 command +=
" DATETIME";
289 foreach (
const QByteArray &part, fetchScope.
payloadParts() )
290 command +=
' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartPayload, part );
291 foreach (
const QByteArray &part, fetchScope.
attributes() )
292 command +=
' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartAttribute, part );
298 void ProtocolHelper::parseItemFetchResult(
const QList<QByteArray> &lineTokens,
Item &item, ProtocolHelperValuePool *valuePool )
304 QString remoteRevision;
308 for (
int i = 0; i < lineTokens.count() - 1; i += 2 ) {
309 const QByteArray key = lineTokens.value( i );
310 const QByteArray value = lineTokens.value( i + 1 );
313 uid = value.toLongLong();
314 else if ( key ==
"REV" )
316 else if ( key ==
"REMOTEID" ) {
317 if ( !value.isEmpty() )
318 rid = QString::fromUtf8( value );
321 }
else if ( key ==
"REMOTEREVISION" ) {
322 remoteRevision = QString::fromUtf8( value );
323 }
else if ( key ==
"COLLECTIONID" ) {
325 }
else if ( key ==
"MIMETYPE" ) {
327 mimeType = valuePool->mimeTypePool.sharedValue( QString::fromLatin1( value ) );
329 mimeType = QString::fromLatin1( value );
333 if ( uid < 0 || rev < 0 || mimeType.isEmpty() ) {
334 kWarning() <<
"Broken fetch response: UID, RID, REV or MIMETYPE missing!";
343 item.setStorageCollectionId( cid );
348 for (
int i = 0; i < lineTokens.count() - 1; i += 2 ) {
349 const QByteArray key = lineTokens.value( i );
351 if ( key ==
"UID" || key ==
"REV" || key ==
"REMOTEID" ||
352 key ==
"MIMETYPE" || key ==
"COLLECTIONID" || key ==
"REMOTEREVISION" )
355 if ( key ==
"FLAGS" ) {
356 QList<QByteArray> flags;
357 ImapParser::parseParenthesizedList( lineTokens[i + 1], flags );
358 if ( !flags.isEmpty() ) {
360 convertedFlags.reserve( flags.size() );
361 foreach (
const QByteArray &flag, flags ) {
363 convertedFlags.insert( valuePool->flagPool.sharedValue( flag ) );
365 convertedFlags.insert( flag );
369 }
else if ( key ==
"SIZE" ) {
370 const quint64 size = lineTokens[i + 1].toLongLong();
372 }
else if ( key ==
"DATETIME" ) {
374 ImapParser::parseDateTime( lineTokens[i + 1], datetime );
376 }
else if ( key ==
"ANCESTORS" ) {
377 ProtocolHelper::parseAncestorsCached( lineTokens[i + 1], &item, cid, valuePool );
380 QByteArray plainKey( key );
383 ImapParser::splitVersionedKey( key, plainKey, version );
384 plainKey = ProtocolHelper::decodePartIdentifier( plainKey, ns );
387 case ProtocolHelper::PartPayload:
389 bool isExternal =
false;
390 const QByteArray fileKey = lineTokens.value( i + 1 );
391 if ( fileKey ==
"[FILE]" ) {
396 ItemSerializer::deserialize( item, plainKey, lineTokens.value( i + 1 ), version, isExternal );
399 case ProtocolHelper::PartAttribute:
403 if ( lineTokens.value( i + 1 ) ==
"[FILE]" ) {
405 QFile file( QString::fromUtf8( lineTokens.value( i + 1 ) ) );
406 if ( file.open( QFile::ReadOnly ) )
409 kWarning() <<
"Failed to open attribute file: " << lineTokens.value( i + 1 );
420 case ProtocolHelper::PartGlobal:
422 kWarning() <<
"Unknown item part type:" << key;
427 item.d_ptr->resetChangeLog();