akonadi
collectionfetchjob.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "collectionfetchjob.h"
00021
00022 #include "imapparser_p.h"
00023 #include "job_p.h"
00024 #include "protocol_p.h"
00025 #include "protocolhelper_p.h"
00026 #include "entity_p.h"
00027 #include "collectionfetchscope.h"
00028 #include "collectionutils_p.h"
00029
00030 #include <kdebug.h>
00031 #include <KLocale>
00032
00033 #include <QtCore/QHash>
00034 #include <QtCore/QStringList>
00035 #include <QtCore/QTimer>
00036
00037 using namespace Akonadi;
00038
00039 class Akonadi::CollectionFetchJobPrivate : public JobPrivate
00040 {
00041 public:
00042 CollectionFetchJobPrivate( CollectionFetchJob *parent )
00043 : JobPrivate( parent )
00044 {
00045 }
00046
00047 Q_DECLARE_PUBLIC( CollectionFetchJob )
00048
00049 CollectionFetchJob::Type mType;
00050 Collection mBase;
00051 Collection::List mBaseList;
00052 Collection::List mCollections;
00053 CollectionFetchScope mScope;
00054 Collection::List mPendingCollections;
00055 QTimer *mEmitTimer;
00056
00057 void timeout()
00058 {
00059 Q_Q( CollectionFetchJob );
00060
00061 mEmitTimer->stop();
00062 if ( !mPendingCollections.isEmpty() ) {
00063 emit q->collectionsReceived( mPendingCollections );
00064 mPendingCollections.clear();
00065 }
00066 }
00067 };
00068
00069 CollectionFetchJob::CollectionFetchJob( const Collection &collection, Type type, QObject *parent )
00070 : Job( new CollectionFetchJobPrivate( this ), parent )
00071 {
00072 Q_D( CollectionFetchJob );
00073
00074 d->mBase = collection;
00075 d->mType = type;
00076
00077 d->mEmitTimer = new QTimer( this );
00078 d->mEmitTimer->setSingleShot( true );
00079 d->mEmitTimer->setInterval( 100 );
00080 connect( d->mEmitTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
00081 connect( this, SIGNAL(result(KJob*)), this, SLOT(timeout()) );
00082 }
00083
00084 CollectionFetchJob::CollectionFetchJob( const Collection::List & cols, QObject * parent )
00085 : Job( new CollectionFetchJobPrivate( this ), parent )
00086 {
00087 Q_D( CollectionFetchJob );
00088
00089 Q_ASSERT( !cols.isEmpty() );
00090 if ( cols.size() == 1 ) {
00091 d->mBase = cols.first();
00092 d->mType = CollectionFetchJob::Base;
00093 } else {
00094 d->mBaseList = cols;
00095 }
00096
00097 d->mEmitTimer = new QTimer( this );
00098 d->mEmitTimer->setSingleShot( true );
00099 d->mEmitTimer->setInterval( 100 );
00100 connect( d->mEmitTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
00101 connect( this, SIGNAL(result(KJob*)), this, SLOT(timeout()) );
00102 }
00103
00104 CollectionFetchJob::~CollectionFetchJob()
00105 {
00106 }
00107
00108 Collection::List CollectionFetchJob::collections() const
00109 {
00110 Q_D( const CollectionFetchJob );
00111
00112 return d->mCollections;
00113 }
00114
00115 void CollectionFetchJob::doStart()
00116 {
00117 Q_D( CollectionFetchJob );
00118
00119 if ( !d->mBaseList.isEmpty() ) {
00120 foreach ( const Collection &col, d->mBaseList ) {
00121 CollectionFetchJob *subJob = new CollectionFetchJob( col, CollectionFetchJob::Base, this );
00122 subJob->setFetchScope( fetchScope() );
00123 }
00124 return;
00125 }
00126
00127 if ( !d->mBase.isValid() && d->mBase.remoteId().isEmpty() ) {
00128 setError( Unknown );
00129 setErrorText( i18n( "Invalid collection given." ) );
00130 emitResult();
00131 return;
00132 }
00133
00134 QByteArray command = d->newTag();
00135 if ( !d->mBase.isValid() ) {
00136 if ( CollectionUtils::hasValidHierarchicalRID( d->mBase ) )
00137 command += " HRID";
00138 else
00139 command += " " AKONADI_CMD_RID;
00140 }
00141 if ( d->mScope.includeUnubscribed() )
00142 command += " LIST ";
00143 else
00144 command += " LSUB ";
00145
00146 if ( d->mBase.isValid() )
00147 command += QByteArray::number( d->mBase.id() );
00148 else if ( CollectionUtils::hasValidHierarchicalRID( d->mBase ) )
00149 command += '(' + ProtocolHelper::hierarchicalRidToByteArray( d->mBase ) + ')';
00150 else
00151 command += ImapParser::quote( d->mBase.remoteId().toUtf8() );
00152
00153 command += ' ';
00154 switch ( d->mType ) {
00155 case Base:
00156 command += "0 (";
00157 break;
00158 case FirstLevel:
00159 command += "1 (";
00160 break;
00161 case Recursive:
00162 command += "INF (";
00163 break;
00164 default:
00165 Q_ASSERT( false );
00166 }
00167
00168 QList<QByteArray> filter;
00169 if ( !d->mScope.resource().isEmpty() ) {
00170 filter.append( "RESOURCE" );
00171 filter.append( d->mScope.resource().toUtf8() );
00172 }
00173
00174 if ( !d->mScope.contentMimeTypes().isEmpty() ) {
00175 filter.append( "MIMETYPE" );
00176 QList<QByteArray> mts;
00177 foreach ( const QString &mt, d->mScope.contentMimeTypes() )
00178 mts.append( mt.toUtf8() );
00179 filter.append( '(' + ImapParser::join( mts, " " ) + ')' );
00180 }
00181
00182 QList<QByteArray> options;
00183 if ( d->mScope.includeStatistics() ) {
00184 options.append( "STATISTICS" );
00185 options.append( "true" );
00186 }
00187 if ( d->mScope.ancestorRetrieval() != CollectionFetchScope::None ) {
00188 options.append( "ANCESTORS" );
00189 switch ( d->mScope.ancestorRetrieval() ) {
00190 case CollectionFetchScope::None:
00191 options.append( "0" );
00192 break;
00193 case CollectionFetchScope::Parent:
00194 options.append( "1" );
00195 break;
00196 case CollectionFetchScope::All:
00197 options.append( "INF" );
00198 break;
00199 default:
00200 Q_ASSERT( false );
00201 }
00202 }
00203
00204 command += ImapParser::join( filter, " " ) + ") (" + ImapParser::join( options, " " ) + ")\n";
00205 d->writeData( command );
00206 }
00207
00208 void CollectionFetchJob::doHandleResponse( const QByteArray & tag, const QByteArray & data )
00209 {
00210 Q_D( CollectionFetchJob );
00211
00212 if ( tag == "*" ) {
00213 Collection collection;
00214 ProtocolHelper::parseCollection( data, collection );
00215 if ( !collection.isValid() )
00216 return;
00217
00218 collection.d_ptr->resetChangeLog();
00219 d->mCollections.append( collection );
00220 d->mPendingCollections.append( collection );
00221 if ( !d->mEmitTimer->isActive() )
00222 d->mEmitTimer->start();
00223 return;
00224 }
00225 kDebug() << "Unhandled server response" << tag << data;
00226 }
00227
00228 void CollectionFetchJob::setResource(const QString & resource)
00229 {
00230 Q_D( CollectionFetchJob );
00231
00232 d->mScope.setResource( resource );
00233 }
00234
00235 void CollectionFetchJob::slotResult(KJob * job)
00236 {
00237 Q_D( CollectionFetchJob );
00238
00239 CollectionFetchJob *list = dynamic_cast<CollectionFetchJob*>( job );
00240 Q_ASSERT( job );
00241 d->mCollections += list->collections();
00242 Job::slotResult( job );
00243 if ( !job->error() && !hasSubjobs() )
00244 emitResult();
00245 }
00246
00247 void CollectionFetchJob::includeUnsubscribed(bool include)
00248 {
00249 Q_D( CollectionFetchJob );
00250
00251 d->mScope.setIncludeUnsubscribed( include );
00252 }
00253
00254 void CollectionFetchJob::includeStatistics(bool include)
00255 {
00256 Q_D( CollectionFetchJob );
00257
00258 d->mScope.setIncludeStatistics( include );
00259 }
00260
00261 void CollectionFetchJob::setFetchScope( const CollectionFetchScope &scope )
00262 {
00263 Q_D( CollectionFetchJob );
00264 d->mScope = scope;
00265 }
00266
00267 CollectionFetchScope& CollectionFetchJob::fetchScope()
00268 {
00269 Q_D( CollectionFetchJob );
00270 return d->mScope;
00271 }
00272
00273 #include "collectionfetchjob.moc"