akonadi
itemfetchjob.cpp
00001 /* 00002 Copyright (c) 2006 - 2007 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 "itemfetchjob.h" 00021 00022 #include "attributefactory.h" 00023 #include "collection.h" 00024 #include "collectionselectjob_p.h" 00025 #include "imapparser_p.h" 00026 #include "itemfetchscope.h" 00027 #include "job_p.h" 00028 #include "protocol_p.h" 00029 #include "protocolhelper_p.h" 00030 00031 #include <kdebug.h> 00032 #include <KLocale> 00033 00034 #include <QtCore/QStringList> 00035 #include <QtCore/QTimer> 00036 00037 using namespace Akonadi; 00038 00039 class Akonadi::ItemFetchJobPrivate : public JobPrivate 00040 { 00041 public: 00042 ItemFetchJobPrivate( ItemFetchJob *parent ) 00043 : JobPrivate( parent ), 00044 mValuePool( 0 ) 00045 { 00046 mCollection = Collection::root(); 00047 } 00048 00049 ~ItemFetchJobPrivate() 00050 { 00051 delete mValuePool; 00052 } 00053 00054 void init() 00055 { 00056 Q_Q( ItemFetchJob ); 00057 mEmitTimer = new QTimer( q ); 00058 mEmitTimer->setSingleShot( true ); 00059 mEmitTimer->setInterval( 100 ); 00060 q->connect( mEmitTimer, SIGNAL( timeout() ), q, SLOT( timeout() ) ); 00061 q->connect( q, SIGNAL( result( KJob* ) ), q, SLOT( timeout() ) ); 00062 } 00063 00064 void timeout() 00065 { 00066 Q_Q( ItemFetchJob ); 00067 00068 mEmitTimer->stop(); // in case we are called by result() 00069 if ( !mPendingItems.isEmpty() ) { 00070 if ( !q->error() ) 00071 emit q->itemsReceived( mPendingItems ); 00072 mPendingItems.clear(); 00073 } 00074 } 00075 00076 void startFetchJob(); 00077 void selectDone( KJob * job ); 00078 00079 Q_DECLARE_PUBLIC( ItemFetchJob ) 00080 00081 Collection mCollection; 00082 Item::List mRequestedItems; 00083 Item::List mResultItems; 00084 ItemFetchScope mFetchScope; 00085 Item::List mPendingItems; // items pending for emitting itemsReceived() 00086 QTimer* mEmitTimer; 00087 ProtocolHelperValuePool *mValuePool; 00088 }; 00089 00090 void ItemFetchJobPrivate::startFetchJob() 00091 { 00092 Q_Q( ItemFetchJob ); 00093 QByteArray command = newTag(); 00094 if ( mRequestedItems.isEmpty() ) { 00095 command += " " AKONADI_CMD_ITEMFETCH " 1:*"; 00096 } else { 00097 try { 00098 command += ProtocolHelper::entitySetToByteArray( mRequestedItems, AKONADI_CMD_ITEMFETCH ); 00099 } catch ( const Exception &e ) { 00100 q->setError( Job::Unknown ); 00101 q->setErrorText( QString::fromUtf8( e.what() ) ); 00102 q->emitResult(); 00103 return; 00104 } 00105 } 00106 00107 command += ProtocolHelper::itemFetchScopeToByteArray( mFetchScope ); 00108 00109 writeData( command ); 00110 } 00111 00112 void ItemFetchJobPrivate::selectDone( KJob * job ) 00113 { 00114 if ( !job->error() ) 00115 // the collection is now selected, fetch the message(s) 00116 startFetchJob(); 00117 } 00118 00119 ItemFetchJob::ItemFetchJob( const Collection &collection, QObject * parent ) 00120 : Job( new ItemFetchJobPrivate( this ), parent ) 00121 { 00122 Q_D( ItemFetchJob ); 00123 00124 d->init(); 00125 d->mCollection = collection; 00126 d->mValuePool = new ProtocolHelperValuePool; // only worth it for lots of results 00127 } 00128 00129 ItemFetchJob::ItemFetchJob( const Item & item, QObject * parent) 00130 : Job( new ItemFetchJobPrivate( this ), parent ) 00131 { 00132 Q_D( ItemFetchJob ); 00133 00134 d->init(); 00135 d->mRequestedItems.append( item ); 00136 } 00137 00138 ItemFetchJob::ItemFetchJob(const Akonadi::Item::List& items, QObject* parent) 00139 : Job( new ItemFetchJobPrivate( this ), parent ) 00140 { 00141 Q_D( ItemFetchJob ); 00142 00143 d->init(); 00144 d->mRequestedItems = items; 00145 } 00146 00147 00148 ItemFetchJob::~ItemFetchJob() 00149 { 00150 } 00151 00152 void ItemFetchJob::doStart() 00153 { 00154 Q_D( ItemFetchJob ); 00155 00156 if ( d->mRequestedItems.isEmpty() ) { // collection content listing 00157 if ( d->mCollection == Collection::root() ) { 00158 setErrorText( i18n( "Cannot list root collection." ) ); 00159 setError( Unknown ); 00160 emitResult(); 00161 } 00162 CollectionSelectJob *job = new CollectionSelectJob( d->mCollection, this ); 00163 connect( job, SIGNAL( result( KJob* ) ), SLOT( selectDone( KJob* ) ) ); 00164 addSubjob( job ); 00165 } else 00166 d->startFetchJob(); 00167 } 00168 00169 void ItemFetchJob::doHandleResponse( const QByteArray & tag, const QByteArray & data ) 00170 { 00171 Q_D( ItemFetchJob ); 00172 00173 if ( tag == "*" ) { 00174 int begin = data.indexOf( "FETCH" ); 00175 if ( begin >= 0 ) { 00176 00177 // split fetch response into key/value pairs 00178 QList<QByteArray> fetchResponse; 00179 ImapParser::parseParenthesizedList( data, fetchResponse, begin + 6 ); 00180 00181 Item item; 00182 ProtocolHelper::parseItemFetchResult( fetchResponse, item, d->mValuePool ); 00183 if ( !item.isValid() ) 00184 return; 00185 00186 d->mResultItems.append( item ); 00187 d->mPendingItems.append( item ); 00188 if ( !d->mEmitTimer->isActive() ) 00189 d->mEmitTimer->start(); 00190 return; 00191 } 00192 } 00193 kDebug() << "Unhandled response: " << tag << data; 00194 } 00195 00196 Item::List ItemFetchJob::items() const 00197 { 00198 Q_D( const ItemFetchJob ); 00199 00200 return d->mResultItems; 00201 } 00202 00203 void ItemFetchJob::setFetchScope( ItemFetchScope &fetchScope ) 00204 { 00205 Q_D( ItemFetchJob ); 00206 00207 d->mFetchScope = fetchScope; 00208 } 00209 00210 void ItemFetchJob::setFetchScope( const ItemFetchScope &fetchScope ) 00211 { 00212 Q_D( ItemFetchJob ); 00213 00214 d->mFetchScope = fetchScope; 00215 } 00216 00217 ItemFetchScope &ItemFetchJob::fetchScope() 00218 { 00219 Q_D( ItemFetchJob ); 00220 00221 return d->mFetchScope; 00222 } 00223 00224 void ItemFetchJob::setCollection(const Akonadi::Collection& collection) 00225 { 00226 Q_D( ItemFetchJob ); 00227 00228 d->mCollection = collection; 00229 } 00230 00231 00232 #include "itemfetchjob.moc"