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