• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

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 "itemserializer_p.h"
00028 #include "itemserializerplugin.h"
00029 #include "job_p.h"
00030 #include "entity_p.h"
00031 #include "protocol_p.h"
00032 #include "protocolhelper_p.h"
00033 
00034 #include <kdebug.h>
00035 
00036 #include <QtCore/QDateTime>
00037 #include <QtCore/QStringList>
00038 #include <QtCore/QTimer>
00039 #include <QtCore/QFile>
00040 
00041 using namespace Akonadi;
00042 
00043 class Akonadi::ItemFetchJobPrivate : public JobPrivate
00044 {
00045   public:
00046     ItemFetchJobPrivate( ItemFetchJob *parent )
00047       : JobPrivate( parent )
00048     {
00049     }
00050 
00051     void timeout()
00052     {
00053       Q_Q( ItemFetchJob );
00054 
00055       mEmitTimer->stop(); // in case we are called by result()
00056       if ( !mPendingItems.isEmpty() ) {
00057         emit q->itemsReceived( mPendingItems );
00058         mPendingItems.clear();
00059       }
00060     }
00061 
00062     void startFetchJob();
00063     void selectDone( KJob * job );
00064 
00065     Q_DECLARE_PUBLIC( ItemFetchJob )
00066 
00067     Collection mCollection;
00068     Item mItem;
00069     Item::List mItems;
00070     ItemFetchScope mFetchScope;
00071     Item::List mPendingItems; // items pending for emitting itemsReceived()
00072     QTimer* mEmitTimer;
00073 };
00074 
00075 void ItemFetchJobPrivate::startFetchJob()
00076 {
00077   QByteArray command = newTag();
00078   if ( mItem.isValid() )
00079     command += " " AKONADI_CMD_UID " " AKONADI_CMD_ITEMFETCH " " + QByteArray::number( mItem.id() );
00080   else if ( !mItem.remoteId().isEmpty() )
00081     command += " " AKONADI_CMD_RID " " AKONADI_CMD_ITEMFETCH " " + mItem.remoteId().toUtf8();
00082   else
00083     command += " " AKONADI_CMD_ITEMFETCH " 1:*";
00084 
00085   if ( mFetchScope.fullPayload() )
00086     command += " " AKONADI_PARAM_FULLPAYLOAD;
00087   if ( mFetchScope.allAttributes() )
00088     command += " " AKONADI_PARAM_ALLATTRIBUTES;
00089   if ( mFetchScope.cacheOnly() )
00090     command += " " AKONADI_PARAM_CACHEONLY;
00091 
00092   //TODO: detect somehow if server supports external payload attribute
00093   command += " " AKONADI_PARAM_EXTERNALPAYLOAD;
00094 
00095   command += " (UID REMOTEID COLLECTIONID FLAGS SIZE DATETIME";
00096   foreach ( const QByteArray &part, mFetchScope.payloadParts() )
00097     command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartPayload, part );
00098   foreach ( const QByteArray &part, mFetchScope.attributes() )
00099     command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartAttribute, part );
00100   command += ")\n";
00101 
00102   writeData( command );
00103 }
00104 
00105 void ItemFetchJobPrivate::selectDone( KJob * job )
00106 {
00107   if ( !job->error() )
00108     // the collection is now selected, fetch the message(s)
00109     startFetchJob();
00110 }
00111 
00112 ItemFetchJob::ItemFetchJob( const Collection &collection, QObject * parent )
00113   : Job( new ItemFetchJobPrivate( this ), parent )
00114 {
00115   Q_D( ItemFetchJob );
00116 
00117   d->mEmitTimer = new QTimer( this );
00118   d->mEmitTimer->setSingleShot( true );
00119   d->mEmitTimer->setInterval( 100 );
00120   connect( d->mEmitTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
00121   connect( this, SIGNAL(result(KJob*)), this, SLOT(timeout()) );
00122 
00123   d->mCollection = collection;
00124 }
00125 
00126 ItemFetchJob::ItemFetchJob( const Item & item, QObject * parent)
00127   : Job( new ItemFetchJobPrivate( this ), parent )
00128 {
00129   Q_D( ItemFetchJob );
00130 
00131   d->mEmitTimer = new QTimer( this );
00132   d->mEmitTimer->setSingleShot( true );
00133   d->mEmitTimer->setInterval( 100 );
00134   connect( d->mEmitTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
00135   connect( this, SIGNAL(result(KJob*)), this, SLOT(timeout()) );
00136 
00137   d->mCollection = Collection::root();
00138   d->mItem = item;
00139 }
00140 
00141 ItemFetchJob::~ItemFetchJob()
00142 {
00143 }
00144 
00145 void ItemFetchJob::doStart()
00146 {
00147   Q_D( ItemFetchJob );
00148 
00149   if ( !d->mItem.isValid() ) { // collection content listing
00150     if ( d->mCollection == Collection::root() ) {
00151       setErrorText( QLatin1String("Cannot list root collection.") );
00152       setError( Unknown );
00153       emitResult();
00154     }
00155     CollectionSelectJob *job = new CollectionSelectJob( d->mCollection, this );
00156     connect( job, SIGNAL(result(KJob*)), SLOT(selectDone(KJob*)) );
00157     addSubjob( job );
00158   } else
00159     d->startFetchJob();
00160 }
00161 
00162 void ItemFetchJob::doHandleResponse( const QByteArray & tag, const QByteArray & data )
00163 {
00164   Q_D( ItemFetchJob );
00165 
00166   if ( tag == "*" ) {
00167     int begin = data.indexOf( "FETCH" );
00168     if ( begin >= 0 ) {
00169 
00170       // split fetch response into key/value pairs
00171       QList<QByteArray> fetchResponse;
00172       ImapParser::parseParenthesizedList( data, fetchResponse, begin + 6 );
00173 
00174       // create a new item object
00175       Item::Id uid = -1;
00176       int rev = -1;
00177       QString rid;
00178       QString mimeType;
00179       Entity::Id cid = -1;
00180 
00181       for ( int i = 0; i < fetchResponse.count() - 1; i += 2 ) {
00182         const QByteArray key = fetchResponse.value( i );
00183         const QByteArray value = fetchResponse.value( i + 1 );
00184 
00185         if ( key == "UID" )
00186           uid = value.toLongLong();
00187         else if ( key == "REV" )
00188           rev = value.toInt();
00189         else if ( key == "REMOTEID" ) {
00190           if ( !value.isEmpty() )
00191             rid = QString::fromUtf8( value );
00192           else
00193             rid.clear();
00194         } else if ( key == "COLLECTIONID" ) {
00195           cid = value.toInt();
00196         } else if ( key == "MIMETYPE" )
00197           mimeType = QString::fromLatin1( value );
00198       }
00199 
00200       if ( uid < 0 || rev < 0 || mimeType.isEmpty() ) {
00201         kWarning( 5250 ) << "Broken fetch response: UID, RID, REV or MIMETYPE missing!";
00202         return;
00203       }
00204 
00205       Item item( uid );
00206       item.setRemoteId( rid );
00207       item.setRevision( rev );
00208       item.setMimeType( mimeType );
00209       item.setStorageCollectionId( cid );
00210       if ( !item.isValid() )
00211         return;
00212 
00213       // parse fetch response fields
00214       for ( int i = 0; i < fetchResponse.count() - 1; i += 2 ) {
00215         const QByteArray key = fetchResponse.value( i );
00216         // skip stuff we dealt with already
00217         if ( key == "UID" || key == "REV" || key == "REMOTEID" || key == "MIMETYPE"  || key == "COLLECTIONID")
00218           continue;
00219         // flags
00220         if ( key == "FLAGS" ) {
00221           QList<QByteArray> flags;
00222           ImapParser::parseParenthesizedList( fetchResponse[i + 1], flags );
00223           foreach ( const QByteArray &flag, flags ) {
00224             item.setFlag( flag );
00225           }
00226         } else if ( key == "SIZE" ) {
00227           const quint64 size = fetchResponse[i + 1].toLongLong();
00228           item.setSize( size );
00229         } else if ( key == "DATETIME" ) {
00230           QDateTime datetime;
00231           ImapParser::parseDateTime( fetchResponse[i + 1], datetime );
00232           item.setModificationTime( datetime );
00233         } else {
00234           int version = 0;
00235           QByteArray plainKey( key );
00236           ProtocolHelper::PartNamespace ns;
00237 
00238           ImapParser::splitVersionedKey( key, plainKey, version );
00239           plainKey = ProtocolHelper::decodePartIdentifier( plainKey, ns );
00240 
00241           switch ( ns ) {
00242             case ProtocolHelper::PartPayload:
00243             {
00244               bool isExternal = false;
00245               QByteArray fileKey = fetchResponse.value( i + 1 );
00246               if (fileKey == "[FILE]") {
00247                 isExternal = true;
00248                 i++;
00249                 kDebug( 5250 ) << "Payload is external: " << isExternal << " filename: " << fetchResponse.value( i + 1 );
00250               }
00251               ItemSerializer::deserialize( item, plainKey, fetchResponse.value( i + 1 ), version, isExternal );
00252               break;
00253             }
00254             case ProtocolHelper::PartAttribute:
00255             {
00256               Attribute* attr = AttributeFactory::createAttribute( plainKey );
00257               Q_ASSERT( attr );
00258               if ( fetchResponse.value( i + 1 ) == "[FILE]" ) {
00259                 ++i;
00260                 QFile f( QString::fromUtf8( fetchResponse.value( i + 1 ) ) );
00261                 if ( f.open( QFile::ReadOnly ) )
00262                   attr->deserialize( f.readAll() );
00263                 else {
00264                   kWarning() << "Failed to open attribute file: " << fetchResponse.value( i + 1 );
00265                   delete attr;
00266                 }
00267               } else {
00268                 attr->deserialize( fetchResponse.value( i + 1 ) );
00269               }
00270               item.addAttribute( attr );
00271               break;
00272             }
00273             case ProtocolHelper::PartGlobal:
00274             default:
00275               kWarning() << "Unknown item part type:" << key;
00276           }
00277         }
00278       }
00279 
00280       item.d_ptr->resetChangeLog();
00281       d->mItems.append( item );
00282       d->mPendingItems.append( item );
00283       if ( !d->mEmitTimer->isActive() )
00284         d->mEmitTimer->start();
00285       return;
00286     }
00287   }
00288   kDebug( 5250 ) << "Unhandled response: " << tag << data;
00289 }
00290 
00291 Item::List ItemFetchJob::items() const
00292 {
00293   Q_D( const ItemFetchJob );
00294 
00295   return d->mItems;
00296 }
00297 
00298 void ItemFetchJob::setFetchScope( ItemFetchScope &fetchScope )
00299 {
00300   Q_D( ItemFetchJob );
00301 
00302   d->mFetchScope = fetchScope;
00303 }
00304 
00305 ItemFetchScope &ItemFetchJob::fetchScope()
00306 {
00307   Q_D( ItemFetchJob );
00308 
00309   return d->mFetchScope;
00310 }
00311 
00312 void ItemFetchJob::setCollection(const Akonadi::Collection& collection)
00313 {
00314   Q_D( ItemFetchJob );
00315   d->mCollection = collection;
00316 }
00317 
00318 
00319 #include "itemfetchjob.moc"

akonadi

Skip menu "akonadi"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal