diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php index 155ea781d..fa50e4d4b 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php @@ -160,6 +160,31 @@ class PdoAddressBook $bReadWrite = $this->isDAVReadWrite(); + /** + * An empty list on either side is far more often a fault than a real + * "delete everything": a fresh or rebuilt local store, a DAV listing + * that failed to parse, a stale server-side index. Acting on it + * destroys data the other side still holds, so skip the deletions in + * that direction and let the following import/export reconcile. + */ + $iLocalLive = 0; + foreach ($aLocalSyncData as $aGuardData) { + if (empty($aGuardData['deleted'])) { + ++$iLocalLive; + } + } + $iRemoteCount = \count($aRemoteSyncData); + $bProtectRemote = (0 === $iLocalLive && 0 < $iRemoteCount); + $bProtectLocal = (0 === $iRemoteCount && 0 < $iLocalLive); + if ($bProtectRemote) { + \SnappyMail\Log::warning('PdoAddressBook', "Sync() local store is empty while remote holds" + . " {$iRemoteCount} contacts: importing only, no remote deletions"); + } + if ($bProtectLocal) { + \SnappyMail\Log::warning('PdoAddressBook', "Sync() remote listing is empty while local holds" + . " {$iLocalLive} contacts: keeping local, no local deletions"); + } + // Delete remote when Mode = read + write if ($bReadWrite) { \SnappyMail\Log::info('PdoAddressBook', 'Sync() is import and export'); @@ -168,7 +193,7 @@ class PdoAddressBook if ($aData['deleted']) { ++$iCount; unset($aLocalSyncData[$sKey]); - if (isset($aRemoteSyncData[$sKey], $aRemoteSyncData[$sKey]['vcf'])) { + if (!$bProtectRemote && isset($aRemoteSyncData[$sKey], $aRemoteSyncData[$sKey]['vcf'])) { \SnappyMail\HTTP\Stream::JSON(['messsage'=>"Delete remote {$sKey}"]); $this->davClientRequest($oClient, 'DELETE', $sPath.$aRemoteSyncData[$sKey]['vcf']); } @@ -183,9 +208,11 @@ class PdoAddressBook // Delete local $aIdsForDeletion = array(); - foreach ($aLocalSyncData as $sKey => $aData) { - if (!empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) { - $aIdsForDeletion[] = $aData['id_contact']; + if (!$bProtectLocal) { + foreach ($aLocalSyncData as $sKey => $aData) { + if (!empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) { + $aIdsForDeletion[] = $aData['id_contact']; + } } } if (\count($aIdsForDeletion)) {