Hello community,

here is the log from the commit of package kdepim4-runtime for openSUSE:Factory 
checked in at 2015-07-14 17:42:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kdepim4-runtime (Old)
 and      /work/SRC/openSUSE:Factory/.kdepim4-runtime.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kdepim4-runtime"

Changes:
--------
--- /work/SRC/openSUSE:Factory/kdepim4-runtime/kdepim4-runtime.changes  
2015-06-04 09:54:46.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.kdepim4-runtime.new/kdepim4-runtime.changes     
2015-07-14 17:44:08.000000000 +0200
@@ -1,0 +2,8 @@
+Mon Jul  6 06:34:08 UTC 2015 - [email protected]
+
+- Update to 4.14.10
+   * KDE Applications 15.04.3
+   * https://www.kde.org/announcements/announce-applications-15.04.3.php
+
+
+-------------------------------------------------------------------

Old:
----
  kdepim-runtime-4.14.9.tar.xz

New:
----
  kdepim-runtime-4.14.10.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kdepim4-runtime.spec ++++++
--- /var/tmp/diff_new_pack.fjqRXt/_old  2015-07-14 17:44:09.000000000 +0200
+++ /var/tmp/diff_new_pack.fjqRXt/_new  2015-07-14 17:44:09.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           kdepim4-runtime
-Version:        4.14.9
+Version:        4.14.10
 Release:        0
 Summary:        Base package of kdepim
 License:        LGPL-2.1+

++++++ kdepim-runtime-4.14.9.tar.xz -> kdepim-runtime-4.14.10.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kdepim-runtime-4.14.9/CMakeLists.txt 
new/kdepim-runtime-4.14.10/CMakeLists.txt
--- old/kdepim-runtime-4.14.9/CMakeLists.txt    2015-05-28 10:18:16.000000000 
+0200
+++ new/kdepim-runtime-4.14.10/CMakeLists.txt   2015-06-25 22:42:43.000000000 
+0200
@@ -36,7 +36,7 @@
     set(KDEPIM_RUNTIME_DEV_VERSION "")
 endif()
 
-set(KDEPIM_RUNTIME_VERSION "4.14.9${KDEPIM_RUNTIME_DEV_VERSION}")
+set(KDEPIM_RUNTIME_VERSION "4.14.10${KDEPIM_RUNTIME_DEV_VERSION}")
 
 configure_file(kdepim-runtime-version.h.cmake 
${CMAKE_CURRENT_BINARY_DIR}/kdepim-runtime-version.h @ONLY)
 
@@ -53,7 +53,7 @@
 include(KDE4Defaults)
 
 # KdepimLibs
-find_package(KdepimLibs 4.14.9)
+find_package(KdepimLibs 4.14.10)
 set_package_properties(KdepimLibs PROPERTIES DESCRIPTION "The KDEPIM 
libraries" URL "http://www.kde.org"; TYPE REQUIRED)
 
 #Boost
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davcollectionsfetchjob.cpp 
new/kdepim-runtime-4.14.10/resources/dav/common/davcollectionsfetchjob.cpp
--- old/kdepim-runtime-4.14.9/resources/dav/common/davcollectionsfetchjob.cpp   
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davcollectionsfetchjob.cpp  
2015-06-25 22:42:43.000000000 +0200
@@ -141,7 +141,14 @@
     _jobUrl.setUser( QString() );
     const QString jobUrl = _jobUrl.prettyUrl();
 
-    //kDebug() << davJob->response().toString();
+    // Validate that we got a valid PROPFIND response
+    QDomElement rootElement = davJob->response().documentElement();
+    if ( rootElement.tagName().compare( QLatin1String( "multistatus" ), 
Qt::CaseInsensitive ) != 0 ) {
+      setError( UserDefinedError );
+      setErrorText( i18n( "Invalid responses from backend" ) );
+      subjobFinished();
+      return;
+    }
 
     QByteArray resp( davJob->response().toByteArray() );
     QBuffer buffer( &resp );
@@ -151,12 +158,16 @@
     if ( !xquery.setFocus( &buffer ) ) {
       setError( UserDefinedError );
       setErrorText( i18n( "Error setting focus for XQuery" ) );
+      subjobFinished();
+      return;
     }
 
     xquery.setQuery( DavManager::self()->davProtocol( mUrl.protocol() 
)->collectionsXQuery() );
     if ( !xquery.isValid() ) {
       setError( UserDefinedError );
       setErrorText( i18n( "Invalid XQuery submitted by DAV implementation" ) );
+      subjobFinished();
+      return;
     }
 
     QString responsesStr;
@@ -168,6 +179,8 @@
     if ( !document.setContent( responsesStr, true ) ) {
       setError( UserDefinedError );
       setErrorText( i18n( "Invalid responses from backend" ) );
+      subjobFinished();
+      return;
     }
 
     if ( !error() ) {
@@ -301,6 +314,11 @@
     }
   }
 
+  subjobFinished();
+}
+
+void DavCollectionsFetchJob::subjobFinished()
+{
   if ( --mSubJobCount == 0 )
     emitResult();
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davcollectionsfetchjob.h 
new/kdepim-runtime-4.14.10/resources/dav/common/davcollectionsfetchjob.h
--- old/kdepim-runtime-4.14.9/resources/dav/common/davcollectionsfetchjob.h     
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davcollectionsfetchjob.h    
2015-06-25 22:42:43.000000000 +0200
@@ -73,6 +73,7 @@
 
   private:
     void doCollectionsFetch( const KUrl &url );
+    void subjobFinished();
 
     DavUtils::DavUrl mUrl;
     DavCollection::List mCollections;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davitemdeletejob.cpp 
new/kdepim-runtime-4.14.10/resources/dav/common/davitemdeletejob.cpp
--- old/kdepim-runtime-4.14.9/resources/dav/common/davitemdeletejob.cpp 
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davitemdeletejob.cpp        
2015-06-25 22:42:43.000000000 +0200
@@ -18,6 +18,7 @@
 
 #include "davitemdeletejob.h"
 
+#include "davitemfetchjob.h"
 #include "davmanager.h"
 
 #include <kio/deletejob.h>
@@ -39,6 +40,16 @@
   connect( job, SIGNAL(result(KJob*)), this, SLOT(davJobFinished(KJob*)) );
 }
 
+DavItem DavItemDeleteJob::freshItem() const
+{
+  return mFreshItem;
+}
+
+int DavItemDeleteJob::freshResponseCode() const
+{
+  return mFreshResponseCode;
+}
+
 void DavItemDeleteJob::davJobFinished( KJob *job )
 {
   KIO::DeleteJob *deleteJob = qobject_cast<KIO::DeleteJob*>( job );
@@ -60,6 +71,25 @@
       setErrorText( i18n( "There was a problem with the request. The item has 
not been deleted from the server.\n"
                           "%1 (%2).", err, responseCode ) );
     }
+
+    if ( hasConflict() ) {
+      DavItemFetchJob *fetchJob = new DavItemFetchJob( mUrl, mItem );
+      connect( fetchJob, SIGNAL(result(KJob*)), this, 
SLOT(conflictingItemFetched(KJob*)) );
+      fetchJob->start();
+      return;
+    }
+  }
+
+  emitResult();
+}
+
+void DavItemDeleteJob::conflictingItemFetched( KJob *job )
+{
+  DavItemFetchJob *fetchJob = qobject_cast<DavItemFetchJob*>( job );
+  mFreshResponseCode = fetchJob->latestResponseCode();
+
+  if ( !job->error() ) {
+    mFreshItem = fetchJob->item();
   }
 
   emitResult();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davitemdeletejob.h 
new/kdepim-runtime-4.14.10/resources/dav/common/davitemdeletejob.h
--- old/kdepim-runtime-4.14.9/resources/dav/common/davitemdeletejob.h   
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davitemdeletejob.h  
2015-06-25 22:42:43.000000000 +0200
@@ -45,12 +45,25 @@
      */
     virtual void start();
 
+    /**
+     * Returns the item that triggered the conflict, if any.
+     */
+    DavItem freshItem() const;
+
+    /**
+     * Returns the response code we got when fetching the fresh item.
+     */
+    int freshResponseCode() const;
+
   private Q_SLOTS:
     void davJobFinished( KJob* );
+    void conflictingItemFetched( KJob* );
 
   private:
     DavUtils::DavUrl mUrl;
     DavItem mItem;
+    DavItem mFreshItem;
+    int mFreshResponseCode;
 };
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davitemfetchjob.cpp 
new/kdepim-runtime-4.14.10/resources/dav/common/davitemfetchjob.cpp
--- old/kdepim-runtime-4.14.9/resources/dav/common/davitemfetchjob.cpp  
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davitemfetchjob.cpp 
2015-06-25 22:42:43.000000000 +0200
@@ -41,7 +41,7 @@
 
 
 DavItemFetchJob::DavItemFetchJob( const DavUtils::DavUrl &url, const DavItem 
&item, QObject *parent )
-  : KJob( parent ), mUrl( url ), mItem( item )
+  : DavJobBase( parent ), mUrl( url ), mItem( item )
 {
 }
 
@@ -67,11 +67,12 @@
 void DavItemFetchJob::davJobFinished( KJob *job )
 {
   KIO::StoredTransferJob *storedJob = qobject_cast<KIO::StoredTransferJob*>( 
job );
+  const int responseCode = storedJob->queryMetaData( 
QLatin1String("responsecode") ).isEmpty() ?
+                            0 :
+                            storedJob->queryMetaData( 
QLatin1String("responsecode") ).toInt();
+  setLatestResponseCode( responseCode );
 
   if ( storedJob->error() ) {
-    const int responseCode = storedJob->queryMetaData( 
QLatin1String("responsecode") ).isEmpty() ?
-                              0 :
-                              storedJob->queryMetaData( 
QLatin1String("responsecode") ).toInt();
 
     QString err;
     if ( storedJob->error() != KIO::ERR_SLAVE_DEFINED )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davitemfetchjob.h 
new/kdepim-runtime-4.14.10/resources/dav/common/davitemfetchjob.h
--- old/kdepim-runtime-4.14.9/resources/dav/common/davitemfetchjob.h    
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davitemfetchjob.h   
2015-06-25 22:42:43.000000000 +0200
@@ -20,14 +20,13 @@
 #define DAVITEMFETCHJOB_H
 
 #include "davitem.h"
+#include "davjobbase.h"
 #include "davutils.h"
 
-#include <kjob.h>
-
 /**
  * @short A job that fetches a DAV item from the DAV server.
  */
-class DavItemFetchJob : public KJob
+class DavItemFetchJob : public DavJobBase
 {
   Q_OBJECT
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davitemmodifyjob.cpp 
new/kdepim-runtime-4.14.10/resources/dav/common/davitemmodifyjob.cpp
--- old/kdepim-runtime-4.14.9/resources/dav/common/davitemmodifyjob.cpp 
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davitemmodifyjob.cpp        
2015-06-25 22:42:43.000000000 +0200
@@ -25,7 +25,7 @@
 #include <klocale.h>
 
 DavItemModifyJob::DavItemModifyJob( const DavUtils::DavUrl &url, const DavItem 
&item, QObject *parent )
-  : DavJobBase( parent ), mUrl( url ), mItem( item )
+  : DavJobBase( parent ), mUrl( url ), mItem( item ), mFreshResponseCode( 0 )
 {
 }
 
@@ -50,6 +50,16 @@
   return mItem;
 }
 
+DavItem DavItemModifyJob::freshItem() const
+{
+  return mFreshItem;
+}
+
+int DavItemModifyJob::freshResponseCode() const
+{
+  return mFreshResponseCode;
+}
+
 void DavItemModifyJob::davJobFinished( KJob *job )
 {
   KIO::StoredTransferJob *storedJob = qobject_cast<KIO::StoredTransferJob*>( 
job );
@@ -70,7 +80,15 @@
     setErrorText( i18n( "There was a problem with the request. The item was 
not modified on the server.\n"
                         "%1 (%2).", err, responseCode ) );
 
-    emitResult();
+    if ( hasConflict() ) {
+      DavItemFetchJob *fetchJob = new DavItemFetchJob( mUrl, mItem );
+      connect( fetchJob, SIGNAL(result(KJob*)), this, 
SLOT(conflictingItemFetched(KJob*)) );
+      fetchJob->start();
+    }
+    else {
+      emitResult();
+    }
+
     return;
   }
 
@@ -111,3 +129,15 @@
   emitResult();
 }
 
+void DavItemModifyJob::conflictingItemFetched( KJob *job )
+{
+  DavItemFetchJob *fetchJob = qobject_cast<DavItemFetchJob*>( job );
+  mFreshResponseCode = fetchJob->latestResponseCode();
+
+  if ( !job->error() ) {
+    mFreshItem = fetchJob->item();
+  }
+
+  emitResult();
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davitemmodifyjob.h 
new/kdepim-runtime-4.14.10/resources/dav/common/davitemmodifyjob.h
--- old/kdepim-runtime-4.14.9/resources/dav/common/davitemmodifyjob.h   
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davitemmodifyjob.h  
2015-06-25 22:42:43.000000000 +0200
@@ -50,13 +50,26 @@
      */
     DavItem item() const;
 
+    /**
+     * Returns the item that triggered the conflict, if any.
+     */
+    DavItem freshItem() const;
+
+    /**
+     * Returns the response code we got when fetching the fresh item.
+     */
+    int freshResponseCode() const;
+
   private Q_SLOTS:
     void davJobFinished( KJob* );
     void itemRefreshed( KJob* );
+    void conflictingItemFetched( KJob* );
 
   private:
     DavUtils::DavUrl mUrl;
     DavItem mItem;
+    DavItem mFreshItem;
+    int mFreshResponseCode;
 };
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davjobbase.cpp 
new/kdepim-runtime-4.14.10/resources/dav/common/davjobbase.cpp
--- old/kdepim-runtime-4.14.9/resources/dav/common/davjobbase.cpp       
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davjobbase.cpp      
2015-06-25 22:42:43.000000000 +0200
@@ -78,6 +78,11 @@
   return ret;
 }
 
+bool DavJobBase::hasConflict() const
+{
+  return latestResponseCode() == 412;
+}
+
 void DavJobBase::setLatestResponseCode( unsigned int code )
 {
   mLatestResponseCode = code;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/common/davjobbase.h 
new/kdepim-runtime-4.14.10/resources/dav/common/davjobbase.h
--- old/kdepim-runtime-4.14.9/resources/dav/common/davjobbase.h 2015-05-28 
10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/common/davjobbase.h        
2015-06-25 22:42:43.000000000 +0200
@@ -60,6 +60,11 @@
      */
     bool canRetryLater() const;
 
+    /**
+     * Check if the job failed because of a conflict
+     */
+    bool hasConflict() const;
+
   protected:
     /**
      * Sets the latest response code received.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/resource/davgroupwareresource.cpp 
new/kdepim-runtime-4.14.10/resources/dav/resource/davgroupwareresource.cpp
--- old/kdepim-runtime-4.14.9/resources/dav/resource/davgroupwareresource.cpp   
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/resource/davgroupwareresource.cpp  
2015-06-25 22:42:43.000000000 +0200
@@ -423,7 +423,7 @@
         extraItems << extraItem;
       }
     }
-  
+
     if ( extraItems.isEmpty() ) {
       // Urrrr?
       // Well, just delete the item.
@@ -892,12 +892,17 @@
 
   if ( modifyJob->error() ) {
     kError() << "Error when uploading item:" << modifyJob->error() << 
modifyJob->errorString();
-    if ( modifyJob->canRetryLater() ) {
+
+    if ( modifyJob->hasConflict() ) {
+      handleConflict( item, dependentItems, modifyJob->freshItem(), isRemoval, 
modifyJob->freshResponseCode() );
+    }
+    else if ( modifyJob->canRetryLater() ) {
       retryAfterFailure(modifyJob->errorString());
     }
     else {
       cancelTask( i18n( "Unable to change item: %1", modifyJob->errorString() 
) );
     }
+
     return;
   }
 
@@ -928,7 +933,38 @@
         dependentItems[i].setRemoteRevision( davItem.etag() );
         mEtagCache.setEtag( dependentItems.at( i ).remoteId(), davItem.etag() 
);
       }
-      
+
+      Akonadi::ItemModifyJob *j = new Akonadi::ItemModifyJob( dependentItems );
+      j->setIgnorePayload( true );
+    }
+  }
+}
+
+void DavGroupwareResource::onDeletedItemRecreated(KJob* job)
+{
+  const DavItemCreateJob *createJob = qobject_cast<DavItemCreateJob*>( job );
+  const DavItem davItem = createJob->item();
+  Akonadi::Item item = createJob->property( "item" ).value<Akonadi::Item>();
+  Akonadi::Item::List dependentItems = createJob->property( "dependentItems" 
).value<Akonadi::Item::List>();
+
+  if ( davItem.etag().isEmpty() ) {
+    const DavUtils::DavUrl davUrl = Settings::self()->davUrlFromCollectionUrl( 
item.parentCollection().remoteId(), item.remoteId() );
+    DavItemFetchJob *fetchJob = new DavItemFetchJob( davUrl, davItem );
+    fetchJob->setProperty( "item", QVariant::fromValue( item ) );
+    fetchJob->setProperty( "dependentItems", QVariant::fromValue( 
dependentItems ) );
+    connect( fetchJob, SIGNAL(result(KJob*)), SLOT(onItemRefreshed(KJob*)) );
+    fetchJob->start();
+  } else {
+    item.setRemoteRevision( davItem.etag() );
+    mEtagCache.setEtag( davItem.url(), davItem.etag() );
+    changeCommitted( item );
+
+    if ( !dependentItems.isEmpty() ) {
+      for ( int i = 0; i < dependentItems.size(); ++i ) {
+        dependentItems[i].setRemoteRevision( davItem.etag() );
+        mEtagCache.setEtag( dependentItems.at( i ).remoteId(), davItem.etag() 
);
+      }
+
       Akonadi::ItemModifyJob *j = new Akonadi::ItemModifyJob( dependentItems );
       j->setIgnorePayload( true );
     }
@@ -940,14 +976,15 @@
   if ( job->error() ) {
     const DavItemDeleteJob *deleteJob = qobject_cast<DavItemDeleteJob*>( job );
 
-    if ( deleteJob->canRetryLater() ) {
+    if ( deleteJob->hasConflict() ) {
+      // Use a shortcut here as we don't show a conflict dialog to the user.
+      handleConflict( Akonadi::Item(), Akonadi::Item::List(), 
deleteJob->freshItem(), true, 0 );
+    } else if ( deleteJob->canRetryLater() ) {
       retryAfterFailure(job->errorString());
-    }
-    else {
+    } else {
       cancelTask( i18n( "Unable to remove item: %1", job->errorString() ) );
     }
-  }
-  else {
+  } else {
     Akonadi::Item item = job->property( "item" ).value<Akonadi::Item>();
     Akonadi::Collection collection = job->property( "collection" 
).value<Akonadi::Collection>();
     mItemsRidCache[collection.remoteId()].remove( item.remoteId() );
@@ -966,6 +1003,129 @@
   mEtagCache.setEtag( itemUrl, etag );
 }
 
+void DavGroupwareResource::handleConflict( const Item& lI, const Item::List& 
localDependentItems, const DavItem& rI, bool isLocalRemoval, int responseCode )
+{
+  Akonadi::Item localItem( lI );
+  Akonadi::Item remoteItem, tmpRemoteItem;                           // The 
tmp* vars are here to store the result of the parseDavData() call
+  Akonadi::Item::List remoteDependentItems, tmpRemoteDependentItems; // as we 
have no idea which item triggered the conflict.
+  kDebug() << "Fresh response code is" << responseCode;
+  bool isRemoteRemoval = ( responseCode == 404 || responseCode == 410 );
+
+  if ( !isRemoteRemoval ) {
+    if ( !DavUtils::parseDavData( rI, tmpRemoteItem, tmpRemoteDependentItems ) 
) {
+      // TODO: set a more correct error message here
+      cancelTask( i18n( "Unable to change item: %1", QLatin1String( "conflict 
resolution failed" ) ) );
+      return;
+      // TODO: we can end up here if the remote item was deleted
+    }
+
+    // Now try to find the item that really triggered the conflict
+    Akonadi::Item::List allRemoteItems; allRemoteItems << tmpRemoteItem << 
tmpRemoteDependentItems;
+    foreach ( const Akonadi::Item &tmpItem, allRemoteItems ) {
+      if ( tmpItem.payloadData() != localItem.payloadData() ) {
+        if ( remoteItem.isValid() ) {
+          // Oops, we can only manage one changed item at this stage, sorry...
+          // TODO: make this translatable
+          cancelTask( i18n( "Unable to change item: %1", QLatin1String( "more 
than one item was changed in the backend" ) ) );
+          return;
+        }
+        remoteItem = tmpItem;
+      } else {
+        remoteDependentItems << tmpItem;
+      }
+    }
+  }
+
+  if ( isLocalRemoval ) {
+    // TODO: implement with the configurable strategy
+    /*
+     * Here by default we don't delete an event that was modified in the 
backend, and
+     * instead we just abort the current task.
+     * Also, trigger an immediate sync to refresh the item.
+     */
+    kDebug() << "Local removal conflict";
+    // TODO: make this translatable
+    cancelTask( i18n( "Unable to remove item: %1", QLatin1String( "it was 
changed in the backend in the meantime" ) ) );
+    synchronize();
+  } else if ( isRemoteRemoval ) {
+    // TODO: implement with the configurable strategy
+    /*
+     * Here also it is a bit tricky to clear the item in the local cache as 
the resource
+     * will not get notified if the user chooses to delete the item and 
abandon the local
+     * modification. For the time being let's just re-upload the changed item.
+     */
+    kDebug() << "Remote removal conflict";
+    Akonadi::Collection collection = localItem.parentCollection();
+    DavItem davItem = DavUtils::createDavItem( localItem, collection, 
localDependentItems );
+
+    QString urlStr = localItem.remoteId();
+    if ( urlStr.contains( QChar( '#' ) ) )
+      urlStr.truncate( urlStr.indexOf( QChar( '#' ) ) );
+    davItem.setUrl( urlStr );
+    const DavUtils::DavUrl davUrl = Settings::self()->davUrlFromCollectionUrl( 
collection.remoteId(), urlStr );
+
+    DavItemCreateJob *job = new DavItemCreateJob( davUrl, davItem );
+    job->setProperty( "item", QVariant::fromValue( localItem ) );
+    job->setProperty( "dependentItems", QVariant::fromValue( 
localDependentItems ) );
+    connect( job, SIGNAL(result(KJob*)), SLOT(onDeletedItemRecreated(KJob*)) );
+    job->start();
+  } else {
+    const QString remoteEtag = rI.etag();
+
+    localItem.setRemoteRevision( remoteEtag );
+    changeCommitted( localItem );
+
+    // Update the ETag cache in all cases as the new ETag will have to be used
+    // later for any update or deletion
+    mEtagCache.setEtag( rI.url(), remoteEtag );
+
+    // The first step is to fire a first modify job that will replace the item 
currently
+    // in the local cache with the one that was found in the backend.
+    Akonadi::Item updatedItem( localItem );
+    updatedItem.setPayloadFromData( remoteItem.payloadData() );
+    updatedItem.setRemoteRevision( remoteEtag );
+    Akonadi::ItemModifyJob *j = new Akonadi::ItemModifyJob( updatedItem );
+    j->setIgnorePayload( false );
+    j->start();
+
+    // So now we have in the cache what's in the backend but the user is not 
aware
+    // that behind the scenes something terrible is happening. Well, nearly...
+    // To notify him of this, and due to the way the conflict handler works, 
we have
+    // to re-attempt a modification to revert the modify job that was just 
fired.
+    // So yes, we are effectively re-submitting the client-provided content, 
but
+    // with a revision that will trigger the conflict dialog.
+    // The only problem is that the user will see that we update the item 
before
+    // the conflict dialog has time to display (if it's not behind the 
application
+    // window).
+    localItem.setRevision( 0 );
+    j = new Akonadi::ItemModifyJob( localItem );
+    j->setIgnorePayload( false );
+    connect( j, SIGNAL(result(KJob*)), this, 
SLOT(onConflictModifyJobFinished(KJob*)) );
+    j->start();
+
+    // Hopefully for the dependent items everything will be fine. Right?
+    // Not so sure in fact.
+    if ( !remoteDependentItems.isEmpty() ) {
+      for ( int i = 0; i < remoteDependentItems.size(); ++i ) {
+        remoteDependentItems[i].setRemoteRevision( remoteEtag );
+        mEtagCache.setEtag( remoteDependentItems.at( i ).remoteId(), 
remoteEtag );
+      }
+
+      Akonadi::ItemModifyJob *j = new Akonadi::ItemModifyJob( 
remoteDependentItems );
+      j->setIgnorePayload( true );
+    }
+  }
+}
+
+void DavGroupwareResource::onConflictModifyJobFinished( KJob *job )
+{
+  Akonadi::ItemModifyJob *j = qobject_cast<Akonadi::ItemModifyJob*>( job );
+  if ( j->error() ) {
+    kError() << "Conflict update failed: " << job->errorText();
+    // TODO: what do we do now? We just committed an item that's in a weird 
state...
+  }
+}
+
 bool DavGroupwareResource::configurationIsValid()
 {
   if ( Settings::self()->configuredDavUrls().empty() ) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kdepim-runtime-4.14.9/resources/dav/resource/davgroupwareresource.h 
new/kdepim-runtime-4.14.10/resources/dav/resource/davgroupwareresource.h
--- old/kdepim-runtime-4.14.9/resources/dav/resource/davgroupwareresource.h     
2015-05-28 10:18:16.000000000 +0200
+++ new/kdepim-runtime-4.14.10/resources/dav/resource/davgroupwareresource.h    
2015-06-25 22:42:43.000000000 +0200
@@ -101,10 +101,18 @@
 
     void onCollectionDiscovered( int protocol, const QString &collectionUrl, 
const QString &configuredUrl );
     void onEtagChanged( const QString &itemUrl, const QString &etag );
+    void onConflictModifyJobFinished( KJob *job );
+    void onDeletedItemRecreated( KJob *job );
 
   private:
     void doItemChange( const Akonadi::Item &item, const Akonadi::Item::List 
&dependentItems = Akonadi::Item::List() );
     void doItemRemoval( const Akonadi::Item &item );
+    void handleConflict( const Akonadi::Item &localItem,
+                         const Akonadi::Item::List &localDependentItems,
+                         const DavItem &remoteItem,
+                         bool isLocalRemoval,
+                         int responseCode
+                       );
 
     bool configurationIsValid();
     void retryAfterFailure(const QString &errorMessage);


Reply via email to