Commit 68fe5754 authored by Sebastian Kummer's avatar Sebastian Kummer

ZP-777 Verify potential hierarchy changes against a hierarchy hash

coming from all foldernames + parent ids.

Released under the Affero GNU General Public License (AGPL) version 3.
parent c1cc7929
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* Created : 01.10.2011 * Created : 01.10.2011
* *
* Copyright 2007 - 2015 Zarafa Deutschland GmbH * Copyright 2007 - 2016 Zarafa Deutschland GmbH
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3, * it under the terms of the GNU Affero General Public License, version 3,
...@@ -114,6 +114,7 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -114,6 +114,7 @@ class BackendZarafa implements IBackend, ISearchProvider {
$this->changesSink = false; $this->changesSink = false;
$this->changesSinkFolders = array(); $this->changesSinkFolders = array();
$this->changesSinkStores = array(); $this->changesSinkStores = array();
$this->changesSinkHierarchyHash = false;
$this->wastebasket = false; $this->wastebasket = false;
$this->session = false; $this->session = false;
$this->folderStatCache = array(); $this->folderStatCache = array();
...@@ -858,7 +859,8 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -858,7 +859,8 @@ class BackendZarafa implements IBackend, ISearchProvider {
return false; return false;
} }
ZLog::Write(LOGLEVEL_DEBUG, "ZarafaBackend->HasChangesSink(): created"); $this->changesSinkHierarchyHash = $this->getHierarchyHash();
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZarafaBackend->HasChangesSink(): created - HierarchyHash: %s", $this->changesSinkHierarchyHash));
// advise the main store and also to check if the connection supports it // advise the main store and also to check if the connection supports it
return $this->adviseStoreToSink($this->defaultstore); return $this->adviseStoreToSink($this->defaultstore);
...@@ -901,6 +903,7 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -901,6 +903,7 @@ class BackendZarafa implements IBackend, ISearchProvider {
*/ */
public function ChangesSink($timeout = 30) { public function ChangesSink($timeout = 30) {
$notifications = array(); $notifications = array();
$hierarchyNotifications = array();
$sinkresult = @mapi_sink_timedwait($this->changesSink, $timeout * 1000); $sinkresult = @mapi_sink_timedwait($this->changesSink, $timeout * 1000);
// reverse array so that the changes on folders are before changes on messages and // reverse array so that the changes on folders are before changes on messages and
// it's possible to filter such notifications // it's possible to filter such notifications
...@@ -908,14 +911,11 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -908,14 +911,11 @@ class BackendZarafa implements IBackend, ISearchProvider {
foreach ($sinkresult as $sinknotif) { foreach ($sinkresult as $sinknotif) {
// add a notification on a folder // add a notification on a folder
if ($sinknotif['objtype'] == MAPI_FOLDER) { if ($sinknotif['objtype'] == MAPI_FOLDER) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendZarafa->ChangesSink() Hierarchy notification for folder %s", bin2hex($sinknotif['entryid']))); $hierarchyNotifications[$sinknotif['entryid']] = IBackend::HIERARCHYNOTIFICATION;
$notifications[$sinknotif['entryid']] = IBackend::HIERARCHYNOTIFICATION;
} }
// change on a message, remove hierarchy notification // change on a message, remove hierarchy notification
if (isset($sinknotif['parentid']) && $sinknotif['objtype'] == MAPI_MESSAGE && isset($notifications[$sinknotif['parentid']])) { if (isset($sinknotif['parentid']) && $sinknotif['objtype'] == MAPI_MESSAGE && isset($notifications[$sinknotif['parentid']])) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendZarafa->ChangesSink() Remove hierarchy notification for %s because it is not relevant", unset($hierarchyNotifications[$sinknotif['parentid']]);
bin2hex($sinknotif['parentid'])));
unset($notifications[$sinknotif['parentid']]);
} }
// TODO check if adding $sinknotif['objtype'] = MAPI_MESSAGE wouldn't break anything // TODO check if adding $sinknotif['objtype'] = MAPI_MESSAGE wouldn't break anything
...@@ -928,6 +928,15 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -928,6 +928,15 @@ class BackendZarafa implements IBackend, ISearchProvider {
$notifications[] = $this->changesSinkFolders[$sinknotif['oldparentid']]; $notifications[] = $this->changesSinkFolders[$sinknotif['oldparentid']];
} }
} }
// validate hierarchy notifications by comparing the hierarchy hashes (too many false positives otherwise)
if (!empty($hierarchyNotifications)) {
$hash = $this->getHierarchyHash();
if ($hash !== $this->changesSinkHierarchyHash) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendZarafa->ChangesSink() Hierarchy notification, pending validation. HierarchyHash: %s", $hash));
$notifications[] = IBackend::HIERARCHYNOTIFICATION;
}
}
return $notifications; return $notifications;
} }
...@@ -1387,6 +1396,20 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -1387,6 +1396,20 @@ class BackendZarafa implements IBackend, ISearchProvider {
* Private methods * Private methods
*/ */
/**
* Returns a hash representing changes in the hierarchy of the main user.
* It changes if a folder is added, renamed or deleted.
*
* @access private
* @return string
*/
private function getHierarchyHash() {
$rootfolder = mapi_msgstore_openentry($this->defaultstore);
$hierarchy = mapi_folder_gethierarchytable($rootfolder, CONVENIENT_DEPTH);
return md5(serialize(mapi_table_queryallrows($hierarchy, array(PR_DISPLAY_NAME, PR_PARENT_ENTRYID))));
}
/** /**
* Advises a store to the changes sink * Advises a store to the changes sink
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment