akonadi
protocolhelper.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "protocolhelper_p.h"
00021
00022 #include "attributefactory.h"
00023 #include "collectionstatistics.h"
00024 #include "exception.h"
00025 #include <akonadi/private/imapparser_p.h>
00026 #include <akonadi/private/protocol_p.h>
00027
00028 #include <QtCore/QVarLengthArray>
00029
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032
00033 #include <boost/bind.hpp>
00034 #include <algorithm>
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 int ProtocolHelper::parseCollection(const QByteArray & data, Collection & collection, int start)
00083 {
00084 int pos = start;
00085
00086
00087 Collection::Id colId = -1;
00088 bool ok = false;
00089 pos = ImapParser::parseNumber( data, colId, &ok, pos );
00090 if ( !ok || colId <= 0 ) {
00091 kDebug( 5250 ) << "Could not parse collection id from response:" << data;
00092 return start;
00093 }
00094
00095 Collection::Id parentId = -1;
00096 pos = ImapParser::parseNumber( data, parentId, &ok, pos );
00097 if ( !ok || parentId < 0 ) {
00098 kDebug( 5250 ) << "Could not parse parent id from response:" << data;
00099 return start;
00100 }
00101
00102 collection = Collection( colId );
00103 collection.setParent( parentId );
00104
00105
00106 QVarLengthArray<QByteArray,16> attributes;
00107 pos = ImapParser::parseParenthesizedList( data, attributes, pos );
00108
00109 for ( int i = 0; i < attributes.count() - 1; i += 2 ) {
00110 const QByteArray key = attributes[i];
00111 const QByteArray value = attributes[i + 1];
00112
00113 if ( key == "NAME" ) {
00114 collection.setName( QString::fromUtf8( value ) );
00115 } else if ( key == "REMOTEID" ) {
00116 collection.setRemoteId( QString::fromUtf8( value ) );
00117 } else if ( key == "RESOURCE" ) {
00118 collection.setResource( QString::fromUtf8( value ) );
00119 } else if ( key == "MIMETYPE" ) {
00120 QVarLengthArray<QByteArray,16> ct;
00121 ImapParser::parseParenthesizedList( value, ct );
00122 QStringList ct2;
00123 for ( int j = 0; j < ct.size(); j++ )
00124 ct2 << QString::fromLatin1( ct[j] );
00125 collection.setContentMimeTypes( ct2 );
00126 } else if ( key == "MESSAGES" ) {
00127 CollectionStatistics s = collection.statistics();
00128 s.setCount( value.toLongLong() );
00129 collection.setStatistics( s );
00130 } else if ( key == "UNSEEN" ) {
00131 CollectionStatistics s = collection.statistics();
00132 s.setUnreadCount( value.toLongLong() );
00133 collection.setStatistics( s );
00134 } else if ( key == "SIZE" ) {
00135 CollectionStatistics s = collection.statistics();
00136 s.setSize( value.toLongLong() );
00137 collection.setStatistics( s );
00138 } else if ( key == "CACHEPOLICY" ) {
00139 CachePolicy policy;
00140 ProtocolHelper::parseCachePolicy( value, policy );
00141 collection.setCachePolicy( policy );
00142 } else {
00143 Attribute* attr = AttributeFactory::createAttribute( key );
00144 Q_ASSERT( attr );
00145 attr->deserialize( value );
00146 collection.addAttribute( attr );
00147 }
00148 }
00149
00150 return pos;
00151 }
00152
00153 QByteArray ProtocolHelper::attributesToByteArray(const Entity & entity, bool ns )
00154 {
00155 QList<QByteArray> l;
00156 foreach ( const Attribute *attr, entity.attributes() ) {
00157 l << encodePartIdentifier( ns ? PartAttribute : PartGlobal, attr->type() );
00158 l << ImapParser::quote( attr->serialized() );
00159 }
00160 return ImapParser::join( l, " " );
00161 }
00162
00163 QByteArray ProtocolHelper::encodePartIdentifier(PartNamespace ns, const QByteArray & label, int version )
00164 {
00165 const QByteArray versionString( version != 0 ? '[' + QByteArray::number( version ) + ']' : "" );
00166 switch ( ns ) {
00167 case PartGlobal:
00168 return label + versionString;
00169 case PartPayload:
00170 return "PLD:" + label + versionString;
00171 case PartAttribute:
00172 return "ATR:" + label + versionString;
00173 default:
00174 Q_ASSERT( false );
00175 }
00176 return QByteArray();
00177 }
00178
00179 QByteArray ProtocolHelper::decodePartIdentifier( const QByteArray &data, PartNamespace & ns )
00180 {
00181 if ( data.startsWith( "PLD:" ) ) {
00182 ns = PartPayload;
00183 return data.mid( 4 );
00184 } else if ( data.startsWith( "ATR:" ) ) {
00185 ns = PartAttribute;
00186 return data.mid( 4 );
00187 } else {
00188 ns = PartGlobal;
00189 return data;
00190 }
00191 }
00192
00193 QByteArray ProtocolHelper::itemSetToByteArray( const Item::List &_items, const QByteArray &command )
00194 {
00195 if ( _items.isEmpty() )
00196 throw Exception( "No items specified" );
00197
00198 Item::List items( _items );
00199
00200 QByteArray rv;
00201 std::sort( items.begin(), items.end(), boost::bind( &Item::id, _1 ) < boost::bind( &Item::id, _2 ) );
00202 if ( items.first().isValid() ) {
00203
00204 rv += " " AKONADI_CMD_UID " ";
00205 rv += command;
00206 rv += ' ';
00207 QList<Item::Id> uids;
00208 foreach ( const Item &item, items )
00209 uids << item.id();
00210 ImapSet set;
00211 set.add( uids );
00212 rv += set.toImapSequenceSet();
00213 } else {
00214
00215 QList<QByteArray> rids;
00216 foreach ( const Item &item, items ) {
00217 if ( item.remoteId().isEmpty() )
00218 throw Exception( i18n( "No remote identifier specified" ) );
00219 rids << ImapParser::quote( item.remoteId().toUtf8() );
00220 }
00221
00222 rv += " " AKONADI_CMD_RID " ";
00223 rv += command;
00224 rv += " (";
00225 rv += ImapParser::join( rids, " " );
00226 rv += ')';
00227 }
00228 return rv;
00229 }