• Skip to content
  • Skip to link menu
KDE 4.8 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

akonadi

itemmodifyjob.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 "itemmodifyjob.h"
00021 #include "itemmodifyjob_p.h"
00022 
00023 #include "changemediator_p.h"
00024 #include "collection.h"
00025 #include "conflicthandling/conflicthandler_p.h"
00026 #include "entity_p.h"
00027 #include "imapparser_p.h"
00028 #include "item_p.h"
00029 #include "itemserializer_p.h"
00030 #include "job_p.h"
00031 #include "protocolhelper_p.h"
00032 
00033 #include <kdebug.h>
00034 
00035 using namespace Akonadi;
00036 
00037 ItemModifyJobPrivate::ItemModifyJobPrivate( ItemModifyJob *parent )
00038   : JobPrivate( parent ),
00039     mRevCheck( true ),
00040     mIgnorePayload( false ),
00041     mAutomaticConflictHandlingEnabled( true )
00042 {
00043 }
00044 
00045 void ItemModifyJobPrivate::setClean()
00046 {
00047   mOperations.insert( Dirty );
00048 }
00049 
00050 QByteArray ItemModifyJobPrivate::nextPartHeader()
00051 {
00052   QByteArray command;
00053   if ( !mParts.isEmpty() ) {
00054     QSetIterator<QByteArray> it( mParts );
00055     const QByteArray label = it.next();
00056     mParts.remove( label );
00057 
00058     mPendingData.clear();
00059     int version = 0;
00060     ItemSerializer::serialize( mItems.first(), label, mPendingData, version );
00061     command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartPayload, label, version );
00062     if ( mPendingData.size() > 0 ) {
00063       command += " {" + QByteArray::number( mPendingData.size() ) + "}\n";
00064     } else {
00065       if ( mPendingData.isNull() )
00066         command += " NIL";
00067       else
00068         command += " \"\"";
00069       command += nextPartHeader();
00070     }
00071   } else {
00072     command += ")\n";
00073   }
00074   return command;
00075 }
00076 
00077 void ItemModifyJobPrivate::conflictResolved()
00078 {
00079   Q_Q( ItemModifyJob );
00080 
00081   q->setError( KJob::NoError );
00082   q->setErrorText( QString() );
00083   q->emitResult();
00084 }
00085 
00086 void ItemModifyJobPrivate::conflictResolveError( const QString &message )
00087 {
00088   Q_Q( ItemModifyJob );
00089 
00090   q->setErrorText( q->errorText() + message );
00091   q->emitResult();
00092 }
00093 
00094 void ItemModifyJobPrivate::doUpdateItemRevision( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
00095 {
00096   Item::List::iterator it = std::find_if( mItems.begin(), mItems.end(), boost::bind( &Item::id, _1 ) == itemId );
00097   if ( it != mItems.end() && (*it).revision() == oldRevision )
00098     (*it).setRevision( newRevision );
00099 }
00100 
00101 
00102 ItemModifyJob::ItemModifyJob( const Item &item, QObject * parent )
00103   : Job( new ItemModifyJobPrivate( this ), parent )
00104 {
00105   Q_D( ItemModifyJob );
00106 
00107   d->mItems.append( item );
00108   d->mParts = item.loadedPayloadParts();
00109 
00110   d->mOperations.insert( ItemModifyJobPrivate::RemoteId );
00111   d->mOperations.insert( ItemModifyJobPrivate::RemoteRevision );
00112 }
00113 
00114 ItemModifyJob::ItemModifyJob( const Akonadi::Item::List &items, QObject *parent)
00115   : Job( new ItemModifyJobPrivate( this ), parent )
00116 {
00117   Q_ASSERT( !items.isEmpty() );
00118   Q_D( ItemModifyJob );
00119   d->mItems = items;
00120 
00121   // same as single item ctor
00122   if ( d->mItems.size() == 1 ) {
00123     d->mParts = items.first().loadedPayloadParts();
00124     d->mOperations.insert( ItemModifyJobPrivate::RemoteId );
00125     d->mOperations.insert( ItemModifyJobPrivate::RemoteRevision );
00126   } else {
00127     d->mIgnorePayload = true;
00128     d->mRevCheck = false;
00129   }
00130 }
00131 
00132 
00133 ItemModifyJob::~ItemModifyJob()
00134 {
00135 }
00136 
00137 void ItemModifyJob::doStart()
00138 {
00139   Q_D( ItemModifyJob );
00140 
00141   const Akonadi::Item item = d->mItems.first();
00142   QList<QByteArray> changes;
00143   foreach ( int op, d->mOperations ) {
00144     switch ( op ) {
00145       case ItemModifyJobPrivate::RemoteId:
00146         if ( !item.remoteId().isNull() ) {
00147           changes << "REMOTEID";
00148           changes << ImapParser::quote( item.remoteId().toUtf8() );
00149         }
00150         break;
00151       case ItemModifyJobPrivate::RemoteRevision:
00152         if ( !item.remoteRevision().isNull() ) {
00153           changes << "REMOTEREVISION";
00154           changes << ImapParser::quote( item.remoteRevision().toUtf8() );
00155         }
00156         break;
00157       case ItemModifyJobPrivate::Dirty:
00158         changes << "DIRTY";
00159         changes << "false";
00160         break;
00161     }
00162   }
00163 
00164   if ( item.d_func()->mClearPayload )
00165     changes << "INVALIDATECACHE";
00166 
00167   if ( item.d_func()->mFlagsOverwritten ) {
00168     changes << "FLAGS";
00169     changes << '(' + ImapParser::join( item.flags(), " " ) + ')';
00170   } else {
00171     if ( !item.d_func()->mAddedFlags.isEmpty() ) {
00172       changes << "+FLAGS";
00173       changes << '(' + ImapParser::join( item.d_func()->mAddedFlags, " " ) + ')';
00174     }
00175     if ( !item.d_func()->mDeletedFlags.isEmpty() ) {
00176       changes << "-FLAGS";
00177       changes << '(' + ImapParser::join( item.d_func()->mDeletedFlags, " " ) + ')';
00178     }
00179   }
00180 
00181   if ( !item.d_func()->mDeletedAttributes.isEmpty() ) {
00182     changes << "-PARTS";
00183     QList<QByteArray> attrs;
00184     foreach ( const QByteArray &attr, item.d_func()->mDeletedAttributes )
00185       attrs << ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartAttribute, attr );
00186     changes << '(' + ImapParser::join( attrs, " " ) + ')';
00187   }
00188 
00189   // nothing to do
00190   if ( changes.isEmpty() && d->mParts.isEmpty() && item.attributes().isEmpty() ) {
00191     emitResult();
00192     return;
00193   }
00194 
00195   d->mTag = d->newTag();
00196   QByteArray command = d->mTag;
00197   try {
00198     command += ProtocolHelper::entitySetToByteArray( d->mItems, "STORE" );
00199   } catch ( const Exception &e ) {
00200     setError( Job::Unknown );
00201     setErrorText( QString::fromUtf8( e.what() ) );
00202     emitResult();
00203     return;
00204   }
00205   command += ' ';
00206   if ( !d->mRevCheck || item.revision() < 0 ) {
00207     command += "NOREV ";
00208   } else {
00209     command += "REV " + QByteArray::number( item.revision() ) + ' ';
00210   }
00211 
00212   if ( item.d_func()->mSizeChanged )
00213     command += "SIZE " + QByteArray::number( item.size() );
00214 
00215   command += " (" + ImapParser::join( changes, " " );
00216   const QByteArray attrs = ProtocolHelper::attributesToByteArray( item, true );
00217   if ( !attrs.isEmpty() )
00218     command += ' ' + attrs;
00219   command += d->nextPartHeader();
00220   d->writeData( command );
00221   d->newTag(); // hack to circumvent automatic response handling
00222 }
00223 
00224 void ItemModifyJob::doHandleResponse(const QByteArray &_tag, const QByteArray & data)
00225 {
00226   Q_D( ItemModifyJob );
00227 
00228   if ( _tag == "+" ) { // ready for literal data
00229     d->writeData( d->mPendingData );
00230     d->writeData( d->nextPartHeader() );
00231     return;
00232   }
00233 
00234   if ( _tag == d->mTag ) {
00235     if ( data.startsWith( "OK" ) ) { //krazy:exclude=strings
00236       QDateTime modificationDateTime;
00237       int dateTimePos = data.indexOf( "DATETIME" );
00238       if ( dateTimePos != -1 ) {
00239         int resultPos = ImapParser::parseDateTime( data, modificationDateTime, dateTimePos + 8 );
00240         if ( resultPos == (dateTimePos + 8) ) {
00241           kDebug() << "Invalid DATETIME response to STORE command: " << _tag << data;
00242         }
00243       }
00244 
00245       Item &item = d->mItems.first();
00246       item.setModificationTime( modificationDateTime );
00247       item.d_ptr->resetChangeLog();
00248     } else {
00249       setError( Unknown );
00250       setErrorText( QString::fromUtf8( data ) );
00251 
00252       if ( data.contains( "[LLCONFLICT]" ) ) {
00253         if ( d->mAutomaticConflictHandlingEnabled ) {
00254           ConflictHandler *handler = new ConflictHandler( ConflictHandler::LocalLocalConflict, this );
00255           handler->setConflictingItems( d->mItems.first(), d->mItems.first() );
00256           connect( handler, SIGNAL(conflictResolved()), SLOT(conflictResolved()) );
00257           connect( handler, SIGNAL(error(QString)), SLOT(conflictResolveError(QString)) );
00258 
00259           QMetaObject::invokeMethod( handler, "start", Qt::QueuedConnection );
00260           return;
00261         }
00262       }
00263     }
00264 
00265     foreach ( const Item &item, d->mItems ) {
00266       ChangeMediator::invalidateItem(item);
00267     }
00268 
00269     emitResult();
00270     return;
00271   }
00272 
00273   if ( _tag == "*" ) {
00274     Akonadi::Item::Id id;
00275     ImapParser::parseNumber( data, id );
00276     int pos = data.indexOf( '(' );
00277     if ( pos <= 0 || id <= 0 ) {
00278       kDebug() << "Ignoring strange response: " << _tag << data;
00279       return;
00280     }
00281     Item::List::iterator it = std::find_if( d->mItems.begin(), d->mItems.end(), boost::bind( &Item::id, _1 ) == id );
00282     if ( it == d->mItems.end() ) {
00283       kDebug() << "Received STORE response for an item we did not modify: " << _tag << data;
00284       return;
00285     }
00286     QList<QByteArray> attrs;
00287     ImapParser::parseParenthesizedList( data, attrs, pos );
00288     for ( int i = 0; i < attrs.size() - 1; i += 2 ) {
00289       const QByteArray key = attrs.at( i );
00290       if ( key == "REV" ) {
00291         const int newRev = attrs.at( i + 1 ).toInt();
00292         const int oldRev = (*it).revision();
00293         if ( newRev < oldRev || newRev < 0 )
00294           continue;
00295         d->itemRevisionChanged( (*it).id(), oldRev, newRev );
00296         (*it).setRevision( newRev );
00297       }
00298     }
00299     return;
00300   }
00301 
00302   kDebug() << "Unhandled response: " << _tag << data;
00303 }
00304 
00305 void ItemModifyJob::setIgnorePayload( bool ignore )
00306 {
00307   Q_D( ItemModifyJob );
00308 
00309   if ( d->mIgnorePayload == ignore )
00310     return;
00311 
00312   d->mIgnorePayload = ignore;
00313   if ( d->mIgnorePayload )
00314     d->mParts = QSet<QByteArray>();
00315   else {
00316     Q_ASSERT( !d->mItems.first().mimeType().isEmpty() );
00317     d->mParts = d->mItems.first().loadedPayloadParts();
00318   }
00319 }
00320 
00321 bool ItemModifyJob::ignorePayload() const
00322 {
00323   Q_D( const ItemModifyJob );
00324 
00325   return d->mIgnorePayload;
00326 }
00327 
00328 void ItemModifyJob::disableRevisionCheck()
00329 {
00330   Q_D( ItemModifyJob );
00331 
00332   d->mRevCheck = false;
00333 }
00334 
00335 void ItemModifyJob::disableAutomaticConflictHandling()
00336 {
00337   Q_D( ItemModifyJob );
00338 
00339   d->mAutomaticConflictHandlingEnabled = false;
00340 }
00341 
00342 Item ItemModifyJob::item() const
00343 {
00344   Q_D( const ItemModifyJob );
00345   Q_ASSERT( d->mItems.size() == 1 );
00346 
00347   return d->mItems.first();
00348 }
00349 
00350 Item::List ItemModifyJob::items() const
00351 {
00352   Q_D( const ItemModifyJob );
00353   return d->mItems;
00354 }
00355 
00356 #include "itemmodifyjob.moc"

akonadi

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.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