• Skip to content
  • Skip to link menu
KDE 4.5 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

akonadi

protocolhelper.cpp

00001 /*
00002     Copyright (c) 2008 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "protocolhelper_p.h"
00021 
00022 #include "attributefactory.h"
00023 #include "collectionstatistics.h"
00024 #include "entity_p.h"
00025 #include "exception.h"
00026 #include "itemserializer_p.h"
00027 #include "itemserializerplugin.h"
00028 
00029 #include <QtCore/QDateTime>
00030 #include <QtCore/QFile>
00031 #include <QtCore/QVarLengthArray>
00032 
00033 #include <kdebug.h>
00034 #include <klocale.h>
00035 
00036 using namespace Akonadi;
00037 
00038 int ProtocolHelper::parseCachePolicy(const QByteArray & data, CachePolicy & policy, int start)
00039 {
00040   QVarLengthArray<QByteArray,16> params;
00041   int end = Akonadi::ImapParser::parseParenthesizedList( data, params, start );
00042   for ( int i = 0; i < params.count() - 1; i += 2 ) {
00043     const QByteArray key = params[i];
00044     const QByteArray value = params[i + 1];
00045 
00046     if ( key == "INHERIT" )
00047       policy.setInheritFromParent( value == "true" );
00048     else if ( key == "INTERVAL" )
00049       policy.setIntervalCheckTime( value.toInt() );
00050     else if ( key == "CACHETIMEOUT" )
00051       policy.setCacheTimeout( value.toInt() );
00052     else if ( key == "SYNCONDEMAND" )
00053       policy.setSyncOnDemand( value == "true" );
00054     else if ( key == "LOCALPARTS" ) {
00055       QVarLengthArray<QByteArray,16> tmp;
00056       QStringList parts;
00057       Akonadi::ImapParser::parseParenthesizedList( value, tmp );
00058       for ( int j=0; j<tmp.size(); j++ )
00059         parts << QString::fromLatin1( tmp[j] );
00060       policy.setLocalParts( parts );
00061     }
00062   }
00063   return end;
00064 }
00065 
00066 QByteArray ProtocolHelper::cachePolicyToByteArray(const CachePolicy & policy)
00067 {
00068   QByteArray rv = "CACHEPOLICY (";
00069   if ( policy.inheritFromParent() ) {
00070     rv += "INHERIT true";
00071   } else {
00072     rv += "INHERIT false";
00073     rv += " INTERVAL " + QByteArray::number( policy.intervalCheckTime() );
00074     rv += " CACHETIMEOUT " + QByteArray::number( policy.cacheTimeout() );
00075     rv += " SYNCONDEMAND " + ( policy.syncOnDemand() ? QByteArray("true") : QByteArray("false") );
00076     rv += " LOCALPARTS (" + policy.localParts().join( QLatin1String(" ") ).toLatin1() + ')';
00077   }
00078   rv += ')';
00079   return rv;
00080 }
00081 
00082 void ProtocolHelper::parseAncestors( const QByteArray &data, Entity *entity, int start )
00083 {
00084   Q_UNUSED( start );
00085 
00086   QList<QByteArray> ancestors;
00087   ImapParser::parseParenthesizedList( data, ancestors );
00088   Entity* current = entity;
00089   foreach ( const QByteArray &uidRidPair, ancestors ) {
00090     QList<QByteArray> parentIds;
00091     ImapParser::parseParenthesizedList( uidRidPair, parentIds );
00092     if ( parentIds.size() != 2 )
00093       break;
00094     const Collection::Id uid = parentIds.at( 0 ).toLongLong();
00095     const QString rid = QString::fromUtf8( parentIds.at( 1 ) );
00096     if ( uid == Collection::root().id() ) {
00097       current->setParentCollection( Collection::root() );
00098       break;
00099     }
00100     current->parentCollection().setId( uid );
00101     current->parentCollection().setRemoteId( rid );
00102     current = &current->parentCollection();
00103   }
00104 }
00105 
00106 int ProtocolHelper::parseCollection(const QByteArray & data, Collection & collection, int start)
00107 {
00108   int pos = start;
00109 
00110   // collection and parent id
00111   Collection::Id colId = -1;
00112   bool ok = false;
00113   pos = ImapParser::parseNumber( data, colId, &ok, pos );
00114   if ( !ok || colId <= 0 ) {
00115     kDebug() << "Could not parse collection id from response:" << data;
00116     return start;
00117   }
00118 
00119   Collection::Id parentId = -1;
00120   pos = ImapParser::parseNumber( data, parentId, &ok, pos );
00121   if ( !ok || parentId < 0 ) {
00122     kDebug() << "Could not parse parent id from response:" << data;
00123     return start;
00124   }
00125 
00126   collection = Collection( colId );
00127   collection.setParentCollection( Collection( parentId ) );
00128 
00129   // attributes
00130   QVarLengthArray<QByteArray,16> attributes;
00131   pos = ImapParser::parseParenthesizedList( data, attributes, pos );
00132 
00133   for ( int i = 0; i < attributes.count() - 1; i += 2 ) {
00134     const QByteArray key = attributes[i];
00135     const QByteArray value = attributes[i + 1];
00136 
00137     if ( key == "NAME" ) {
00138       collection.setName( QString::fromUtf8( value ) );
00139     } else if ( key == "REMOTEID" ) {
00140       collection.setRemoteId( QString::fromUtf8( value ) );
00141     } else if ( key == "REMOTEREVISION" ) {
00142       collection.setRemoteRevision( QString::fromUtf8( value ) );
00143     } else if ( key == "RESOURCE" ) {
00144       collection.setResource( QString::fromUtf8( value ) );
00145     } else if ( key == "MIMETYPE" ) {
00146       QVarLengthArray<QByteArray,16> ct;
00147       ImapParser::parseParenthesizedList( value, ct );
00148       QStringList ct2;
00149       for ( int j = 0; j < ct.size(); j++ )
00150         ct2 << QString::fromLatin1( ct[j] );
00151       collection.setContentMimeTypes( ct2 );
00152     } else if ( key == "MESSAGES" ) {
00153       CollectionStatistics s = collection.statistics();
00154       s.setCount( value.toLongLong() );
00155       collection.setStatistics( s );
00156     } else if ( key == "UNSEEN" ) {
00157       CollectionStatistics s = collection.statistics();
00158       s.setUnreadCount( value.toLongLong() );
00159       collection.setStatistics( s );
00160     } else if ( key == "SIZE" ) {
00161       CollectionStatistics s = collection.statistics();
00162       s.setSize( value.toLongLong() );
00163       collection.setStatistics( s );
00164     } else if ( key == "CACHEPOLICY" ) {
00165       CachePolicy policy;
00166       ProtocolHelper::parseCachePolicy( value, policy );
00167       collection.setCachePolicy( policy );
00168     } else if ( key == "ANCESTORS" ) {
00169       parseAncestors( value, &collection );
00170     } else {
00171       Attribute* attr = AttributeFactory::createAttribute( key );
00172       Q_ASSERT( attr );
00173       attr->deserialize( value );
00174       collection.addAttribute( attr );
00175     }
00176   }
00177 
00178   return pos;
00179 }
00180 
00181 QByteArray ProtocolHelper::attributesToByteArray(const Entity & entity, bool ns )
00182 {
00183   QList<QByteArray> l;
00184   foreach ( const Attribute *attr, entity.attributes() ) {
00185     l << encodePartIdentifier( ns ? PartAttribute : PartGlobal, attr->type() );
00186     l << ImapParser::quote( attr->serialized() );
00187   }
00188   return ImapParser::join( l, " " );
00189 }
00190 
00191 QByteArray ProtocolHelper::encodePartIdentifier(PartNamespace ns, const QByteArray & label, int version )
00192 {
00193   const QByteArray versionString( version != 0 ? '[' + QByteArray::number( version ) + ']' : "" );
00194   switch ( ns ) {
00195     case PartGlobal:
00196       return label + versionString;
00197     case PartPayload:
00198       return "PLD:" + label + versionString;
00199     case PartAttribute:
00200       return "ATR:" + label + versionString;
00201     default:
00202       Q_ASSERT( false );
00203   }
00204   return QByteArray();
00205 }
00206 
00207 QByteArray ProtocolHelper::decodePartIdentifier( const QByteArray &data, PartNamespace & ns )
00208 {
00209   if ( data.startsWith( "PLD:" ) ) { //krazy:exclude=strings
00210     ns = PartPayload;
00211     return data.mid( 4 );
00212   } else if ( data.startsWith( "ATR:" ) ) { //krazy:exclude=strings
00213     ns = PartAttribute;
00214     return data.mid( 4 );
00215   } else {
00216     ns = PartGlobal;
00217     return data;
00218   }
00219 }
00220 
00221 QByteArray ProtocolHelper::hierarchicalRidToByteArray( const Collection &col )
00222 {
00223   if ( col == Collection::root() )
00224     return QByteArray("(0 \"\")");
00225   if ( col.remoteId().isEmpty() )
00226     return QByteArray();
00227   const QByteArray parentHrid = hierarchicalRidToByteArray( col.parentCollection() );
00228   return '(' + QByteArray::number( col.id() ) + ' ' + ImapParser::quote( col.remoteId().toUtf8() ) + ") " + parentHrid;
00229 }
00230 
00231 QByteArray ProtocolHelper::hierarchicalRidToByteArray( const Item &item )
00232 {
00233   const QByteArray parentHrid = hierarchicalRidToByteArray( item.parentCollection() );
00234   return '(' + QByteArray::number( item.id() ) + ' ' + ImapParser::quote( item.remoteId().toUtf8() ) + ") " + parentHrid;
00235 }  
00236 
00237 QByteArray ProtocolHelper::itemFetchScopeToByteArray( const ItemFetchScope &fetchScope )
00238 {
00239   QByteArray command;
00240 
00241   if ( fetchScope.fullPayload() )
00242     command += " " AKONADI_PARAM_FULLPAYLOAD;
00243   if ( fetchScope.allAttributes() )
00244     command += " " AKONADI_PARAM_ALLATTRIBUTES;
00245   if ( fetchScope.cacheOnly() )
00246     command += " " AKONADI_PARAM_CACHEONLY;
00247   if ( fetchScope.ancestorRetrieval() != ItemFetchScope::None ) {
00248     switch ( fetchScope.ancestorRetrieval() ) {
00249       case ItemFetchScope::Parent:
00250         command += " ANCESTORS 1";
00251         break;
00252       case ItemFetchScope::All:
00253         command += " ANCESTORS INF";
00254         break;
00255       default:
00256         Q_ASSERT( false );
00257     }
00258   }
00259 
00260   //TODO: detect somehow if server supports external payload attribute
00261   command += " " AKONADI_PARAM_EXTERNALPAYLOAD;
00262 
00263   command += " (UID REMOTEID REMOTEREVISION COLLECTIONID FLAGS SIZE DATETIME";
00264   foreach ( const QByteArray &part, fetchScope.payloadParts() )
00265     command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartPayload, part );
00266   foreach ( const QByteArray &part, fetchScope.attributes() )
00267     command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartAttribute, part );
00268   command += ")\n";
00269 
00270   return command;
00271 }
00272 
00273 void ProtocolHelper::parseItemFetchResult( const QList<QByteArray> &lineTokens, Item &item )
00274 {
00275   // create a new item object
00276   Item::Id uid = -1;
00277   int rev = -1;
00278   QString rid;
00279   QString remoteRevision;
00280   QString mimeType;
00281   Entity::Id cid = -1;
00282 
00283   for ( int i = 0; i < lineTokens.count() - 1; i += 2 ) {
00284     const QByteArray key = lineTokens.value( i );
00285     const QByteArray value = lineTokens.value( i + 1 );
00286 
00287     if ( key == "UID" )
00288       uid = value.toLongLong();
00289     else if ( key == "REV" )
00290       rev = value.toInt();
00291     else if ( key == "REMOTEID" ) {
00292       if ( !value.isEmpty() )
00293         rid = QString::fromUtf8( value );
00294       else
00295         rid.clear();
00296     } else if ( key == "REMOTEREVISION" ) {
00297       remoteRevision = QString::fromUtf8( value );
00298     } else if ( key == "COLLECTIONID" ) {
00299       cid = value.toInt();
00300     } else if ( key == "MIMETYPE" ) {
00301       mimeType = QString::fromLatin1( value );
00302     }
00303   }
00304 
00305   if ( uid < 0 || rev < 0 || mimeType.isEmpty() ) {
00306     kWarning() << "Broken fetch response: UID, RID, REV or MIMETYPE missing!";
00307     return;
00308   }
00309 
00310   item = Item( uid );
00311   item.setRemoteId( rid );
00312   item.setRevision( rev );
00313   item.setRemoteRevision( remoteRevision );
00314   item.setMimeType( mimeType );
00315   item.setStorageCollectionId( cid );
00316   if ( !item.isValid() )
00317     return;
00318 
00319   // parse fetch response fields
00320   for ( int i = 0; i < lineTokens.count() - 1; i += 2 ) {
00321     const QByteArray key = lineTokens.value( i );
00322     // skip stuff we dealt with already
00323     if ( key == "UID" || key == "REV" || key == "REMOTEID" ||
00324          key == "MIMETYPE"  || key == "COLLECTIONID" || key == "REMOTEREVISION" )
00325       continue;
00326     // flags
00327     if ( key == "FLAGS" ) {
00328       QList<QByteArray> flags;
00329       ImapParser::parseParenthesizedList( lineTokens[i + 1], flags );
00330       foreach ( const QByteArray &flag, flags ) {
00331         item.setFlag( flag );
00332       }
00333     } else if ( key == "SIZE" ) {
00334       const quint64 size = lineTokens[i + 1].toLongLong();
00335       item.setSize( size );
00336     } else if ( key == "DATETIME" ) {
00337       QDateTime datetime;
00338       ImapParser::parseDateTime( lineTokens[i + 1], datetime );
00339       item.setModificationTime( datetime );
00340     } else if ( key == "ANCESTORS" ) {
00341       ProtocolHelper::parseAncestors( lineTokens[i + 1], &item );
00342     } else {
00343       int version = 0;
00344       QByteArray plainKey( key );
00345       ProtocolHelper::PartNamespace ns;
00346 
00347       ImapParser::splitVersionedKey( key, plainKey, version );
00348       plainKey = ProtocolHelper::decodePartIdentifier( plainKey, ns );
00349 
00350       switch ( ns ) {
00351         case ProtocolHelper::PartPayload:
00352         {
00353           bool isExternal = false;
00354           const QByteArray fileKey = lineTokens.value( i + 1 );
00355           if ( fileKey == "[FILE]" ) {
00356             isExternal = true;
00357             i++;
00358             //kDebug() << "Payload is external: " << isExternal << " filename: " << lineTokens.value( i + 1 );
00359           }
00360           ItemSerializer::deserialize( item, plainKey, lineTokens.value( i + 1 ), version, isExternal );
00361           break;
00362         }
00363         case ProtocolHelper::PartAttribute:
00364         {
00365           Attribute* attr = AttributeFactory::createAttribute( plainKey );
00366           Q_ASSERT( attr );
00367           if ( lineTokens.value( i + 1 ) == "[FILE]" ) {
00368             ++i;
00369             QFile file( QString::fromUtf8( lineTokens.value( i + 1 ) ) );
00370             if ( file.open( QFile::ReadOnly ) )
00371               attr->deserialize( file.readAll() );
00372             else {
00373               kWarning() << "Failed to open attribute file: " << lineTokens.value( i + 1 );
00374               delete attr;
00375             }
00376           } else {
00377             attr->deserialize( lineTokens.value( i + 1 ) );
00378           }
00379           item.addAttribute( attr );
00380           break;
00381         }
00382         case ProtocolHelper::PartGlobal:
00383         default:
00384           kWarning() << "Unknown item part type:" << key;
00385       }
00386     }
00387   }
00388 
00389   item.d_ptr->resetChangeLog();
00390 }

akonadi

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal