akonadi
itemfetchjob.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "itemfetchjob.h"
00021
00022 #include "attributefactory.h"
00023 #include "collection.h"
00024 #include "collectionselectjob.h"
00025 #include "imapparser_p.h"
00026 #include "itemfetchscope.h"
00027 #include "itemserializer.h"
00028 #include "itemserializerplugin.h"
00029 #include "job_p.h"
00030 #include "entity_p.h"
00031 #include "protocol_p.h"
00032 #include "protocolhelper.h"
00033
00034 #include <kdebug.h>
00035
00036 #include <QtCore/QDateTime>
00037 #include <QtCore/QStringList>
00038 #include <QtCore/QTimer>
00039
00040 using namespace Akonadi;
00041
00042 class Akonadi::ItemFetchJobPrivate : public JobPrivate
00043 {
00044 public:
00045 ItemFetchJobPrivate( ItemFetchJob *parent )
00046 : JobPrivate( parent )
00047 {
00048 }
00049
00050 void timeout()
00051 {
00052 Q_Q( ItemFetchJob );
00053
00054 mEmitTimer->stop();
00055 if ( !mPendingItems.isEmpty() ) {
00056 emit q->itemsReceived( mPendingItems );
00057 mPendingItems.clear();
00058 }
00059 }
00060
00061 void startFetchJob();
00062 void selectDone( KJob * job );
00063
00064 Q_DECLARE_PUBLIC( ItemFetchJob )
00065
00066 Collection mCollection;
00067 Item mItem;
00068 Item::List mItems;
00069 ItemFetchScope mFetchScope;
00070 Item::List mPendingItems;
00071 QTimer* mEmitTimer;
00072 };
00073
00074 void ItemFetchJobPrivate::startFetchJob()
00075 {
00076 QByteArray command = newTag();
00077 if ( !mItem.isValid() )
00078 command += " " AKONADI_CMD_ITEMFETCH " 1:*";
00079 else
00080 command += " " AKONADI_CMD_UID " " AKONADI_CMD_ITEMFETCH " " + QByteArray::number( mItem.id() );
00081
00082 if ( mFetchScope.fullPayload() )
00083 command += " " AKONADI_PARAM_FULLPAYLOAD;
00084 if ( mFetchScope.allAttributes() )
00085 command += " " AKONADI_PARAM_ALLATTRIBUTES;
00086 if ( mFetchScope.cacheOnly() )
00087 command += " " AKONADI_PARAM_CACHEONLY;
00088
00089 command += " (UID REMOTEID FLAGS SIZE DATETIME";
00090 foreach ( const QByteArray &part, mFetchScope.payloadParts() )
00091 command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartPayload, part );
00092 foreach ( const QByteArray &part, mFetchScope.attributes() )
00093 command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartAttribute, part );
00094 command += ")\n";
00095
00096 writeData( command );
00097 }
00098
00099 void ItemFetchJobPrivate::selectDone( KJob * job )
00100 {
00101 if ( !job->error() )
00102
00103 startFetchJob();
00104 }
00105
00106 ItemFetchJob::ItemFetchJob( const Collection &collection, QObject * parent )
00107 : Job( new ItemFetchJobPrivate( this ), parent )
00108 {
00109 Q_D( ItemFetchJob );
00110
00111 d->mEmitTimer = new QTimer( this );
00112 d->mEmitTimer->setSingleShot( true );
00113 d->mEmitTimer->setInterval( 100 );
00114 connect( d->mEmitTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
00115 connect( this, SIGNAL(result(KJob*)), this, SLOT(timeout()) );
00116
00117 d->mCollection = collection;
00118 }
00119
00120 ItemFetchJob::ItemFetchJob( const Item & item, QObject * parent)
00121 : Job( new ItemFetchJobPrivate( this ), parent )
00122 {
00123 Q_D( ItemFetchJob );
00124
00125 d->mEmitTimer = new QTimer( this );
00126 d->mEmitTimer->setSingleShot( true );
00127 d->mEmitTimer->setInterval( 100 );
00128 connect( d->mEmitTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
00129 connect( this, SIGNAL(result(KJob*)), this, SLOT(timeout()) );
00130
00131 d->mCollection = Collection::root();
00132 d->mItem = item;
00133 }
00134
00135 ItemFetchJob::~ItemFetchJob()
00136 {
00137 }
00138
00139 void ItemFetchJob::doStart()
00140 {
00141 Q_D( ItemFetchJob );
00142
00143 if ( !d->mItem.isValid() ) {
00144 if ( d->mCollection == Collection::root() ) {
00145 setErrorText( QLatin1String("Cannot list root collection.") );
00146 setError( Unknown );
00147 emitResult();
00148 }
00149 CollectionSelectJob *job = new CollectionSelectJob( d->mCollection, this );
00150 connect( job, SIGNAL(result(KJob*)), SLOT(selectDone(KJob*)) );
00151 addSubjob( job );
00152 } else
00153 d->startFetchJob();
00154 }
00155
00156 void ItemFetchJob::doHandleResponse( const QByteArray & tag, const QByteArray & data )
00157 {
00158 Q_D( ItemFetchJob );
00159
00160 if ( tag == "*" ) {
00161 int begin = data.indexOf( "FETCH" );
00162 if ( begin >= 0 ) {
00163
00164
00165 QList<QByteArray> fetchResponse;
00166 ImapParser::parseParenthesizedList( data, fetchResponse, begin + 6 );
00167
00168
00169 Item::Id uid = -1;
00170 int rev = -1;
00171 QString rid;
00172 QString mimeType;
00173
00174 for ( int i = 0; i < fetchResponse.count() - 1; i += 2 ) {
00175 const QByteArray key = fetchResponse.value( i );
00176 const QByteArray value = fetchResponse.value( i + 1 );
00177
00178 if ( key == "UID" )
00179 uid = value.toLongLong();
00180 else if ( key == "REV" )
00181 rev = value.toInt();
00182 else if ( key == "REMOTEID" )
00183 rid = QString::fromUtf8( value );
00184 else if ( key == "MIMETYPE" )
00185 mimeType = QString::fromLatin1( value );
00186 }
00187
00188 if ( uid < 0 || rev < 0 || mimeType.isEmpty() ) {
00189 kWarning( 5250 ) << "Broken fetch response: UID, RID, REV or MIMETYPE missing!";
00190 return;
00191 }
00192
00193 Item item( uid );
00194 item.setRemoteId( rid );
00195 item.setRevision( rev );
00196 item.setMimeType( mimeType );
00197 if ( !item.isValid() )
00198 return;
00199
00200
00201 for ( int i = 0; i < fetchResponse.count() - 1; i += 2 ) {
00202 const QByteArray key = fetchResponse.value( i );
00203
00204 if ( key == "UID" || key == "REV" || key == "REMOTEID" || key == "MIMETYPE" )
00205 continue;
00206
00207 if ( key == "FLAGS" ) {
00208 QList<QByteArray> flags;
00209 ImapParser::parseParenthesizedList( fetchResponse[i + 1], flags );
00210 foreach ( const QByteArray &flag, flags ) {
00211 item.setFlag( flag );
00212 }
00213 } else if ( key == "SIZE" ) {
00214 const quint64 size = fetchResponse[i + 1].toLongLong();
00215 item.setSize( size );
00216 } else if ( key == "DATETIME" ) {
00217 QDateTime datetime;
00218 ImapParser::parseDateTime( fetchResponse[i + 1], datetime );
00219 item.setModificationTime( datetime );
00220 } else {
00221 int version = 0;
00222 QByteArray plainKey( key );
00223 ProtocolHelper::PartNamespace ns;
00224
00225 ImapParser::splitVersionedKey( key, plainKey, version );
00226 plainKey = ProtocolHelper::decodePartIdentifier( plainKey, ns );
00227
00228 switch ( ns ) {
00229 case ProtocolHelper::PartPayload:
00230 ItemSerializer::deserialize( item, plainKey, fetchResponse.value( i + 1 ), version );
00231 break;
00232 case ProtocolHelper::PartAttribute:
00233 {
00234 Attribute* attr = AttributeFactory::createAttribute( plainKey );
00235 Q_ASSERT( attr );
00236 attr->deserialize( fetchResponse.value( i + 1 ) );
00237 item.addAttribute( attr );
00238 break;
00239 }
00240 case ProtocolHelper::PartGlobal:
00241 default:
00242 kWarning() << "Unknown item part type:" << key;
00243 }
00244 }
00245 }
00246
00247 item.d_ptr->resetChangeLog();
00248 d->mItems.append( item );
00249 d->mPendingItems.append( item );
00250 if ( !d->mEmitTimer->isActive() )
00251 d->mEmitTimer->start();
00252 return;
00253 }
00254 }
00255 kDebug( 5250 ) << "Unhandled response: " << tag << data;
00256 }
00257
00258 Item::List ItemFetchJob::items() const
00259 {
00260 Q_D( const ItemFetchJob );
00261
00262 return d->mItems;
00263 }
00264
00265 void ItemFetchJob::setFetchScope( ItemFetchScope &fetchScope )
00266 {
00267 Q_D( ItemFetchJob );
00268
00269 d->mFetchScope = fetchScope;
00270 }
00271
00272 ItemFetchScope &ItemFetchJob::fetchScope()
00273 {
00274 Q_D( ItemFetchJob );
00275
00276 return d->mFetchScope;
00277 }
00278
00279 #include "itemfetchjob.moc"