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