Back to index

d-push  2.0
changesmemorywrapper.php
Go to the documentation of this file.
00001 <?php
00002 /***********************************************
00003 * File      :   changesmemorywrapper.php
00004 * Project   :   Z-Push
00005 * Descr     :   Class that collect changes in memory
00006 *
00007 * Created   :   18.08.2011
00008 *
00009 * Copyright 2007 - 2011 Zarafa Deutschland GmbH
00010 *
00011 * This program is free software: you can redistribute it and/or modify
00012 * it under the terms of the GNU Affero General Public License, version 3,
00013 * as published by the Free Software Foundation with the following additional
00014 * term according to sec. 7:
00015 *
00016 * According to sec. 7 of the GNU Affero General Public License, version 3,
00017 * the terms of the AGPL are supplemented with the following terms:
00018 *
00019 * "Zarafa" is a registered trademark of Zarafa B.V.
00020 * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
00021 * The licensing of the Program under the AGPL does not imply a trademark license.
00022 * Therefore any rights, title and interest in our trademarks remain entirely with us.
00023 *
00024 * However, if you propagate an unmodified version of the Program you are
00025 * allowed to use the term "Z-Push" to indicate that you distribute the Program.
00026 * Furthermore you may use our trademarks where it is necessary to indicate
00027 * the intended purpose of a product or service provided you use it in accordance
00028 * with honest practices in industrial or commercial matters.
00029 * If you want to propagate modified versions of the Program under the name "Z-Push",
00030 * you may only do so if you have a written permission by Zarafa Deutschland GmbH
00031 * (to acquire a permission please contact Zarafa at trademark@zarafa.com).
00032 *
00033 * This program is distributed in the hope that it will be useful,
00034 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00036 * GNU Affero General Public License for more details.
00037 *
00038 * You should have received a copy of the GNU Affero General Public License
00039 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00040 *
00041 * Consult LICENSE file for details
00042 ************************************************/
00043 
00044 
00045 class ChangesMemoryWrapper extends HierarchyCache implements IImportChanges, IExportChanges {
00046     const CHANGE = 1;
00047     const DELETION = 2;
00048 
00049     private $changes;
00050     private $step;
00051     private $destinationImporter;
00052     private $exportImporter;
00053 
00060     public function ChangesMemoryWrapper() {
00061         $this->changes = array();
00062         $this->step = 0;
00063         parent::HierarchyCache();
00064     }
00065 
00074     public function Config($state, $flags = 0) {
00075         // we should never forward this changes to a backend
00076         if (!isset($this->destinationImporter)) {
00077             foreach($state as $addKey => $addFolder) {
00078                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("ChangesMemoryWrapper->Config(AdditionalFolders) : process folder '%s'", $addFolder->displayname));
00079                 if (isset($addFolder->NoBackendFolder) && $addFolder->NoBackendFolder == true) {
00080                     $hasRights = ZPush::GetBackend()->Setup($addFolder->Store, true, $addFolder->serverid);
00081                     // delete the folder on the device
00082                     if (! $hasRights) {
00083                         // delete the folder only if it was an additional folder before, else ignore it
00084                         $synchedfolder = $this->GetFolder($addFolder->serverid);
00085                         if (isset($synchedfolder->NoBackendFolder) && $synchedfolder->NoBackendFolder == true)
00086                             $this->ImportFolderDeletion($addFolder->serverid, $addFolder->parentid);
00087                         continue;
00088                     }
00089                 }
00090                 // add folder to the device - if folder is already on the device, nothing will happen
00091                 $this->ImportFolderChange($addFolder);
00092             }
00093 
00094             // look for folders which are currently on the device if there are now not to be synched anymore
00095             $alreadyDeleted = $this->GetDeletedFolders();
00096             foreach ($this->ExportFolders(true) as $sid => $folder) {
00097                 // we are only looking at additional folders
00098                 if (isset($folder->NoBackendFolder)) {
00099                     // look if this folder is still in the list of additional folders and was not already deleted (e.g. missing permissions)
00100                     if (!array_key_exists($sid, $state) && !array_key_exists($sid, $alreadyDeleted)) {
00101                         ZLog::Write(LOGLEVEL_INFO, sprintf("ChangesMemoryWrapper->Config(AdditionalFolders) : previously synchronized folder '%s' is not to be synched anymore. Sending delete to mobile.", $folder->displayname));
00102                         $this->ImportFolderDeletion($folder->serverid, $folder->parentid);
00103                     }
00104                 }
00105             }
00106         }
00107         return true;
00108     }
00109 
00110 
00114     public function GetState() { return false;}
00115     public function LoadConflicts($contentparameters, $state) { return true; }
00116     public function ConfigContentParameters($contentparameters) { return true; }
00117     public function ImportMessageReadFlag($id, $flags) { return true; }
00118     public function ImportMessageMove($id, $newfolder) { return true; }
00119 
00132     public function SetDestinationImporter(&$importer) {
00133         $this->destinationImporter = $importer;
00134     }
00135 
00145     public function ImportMessageChange($id, $message) {
00146         $this->changes[] = array(self::CHANGE, $id);
00147         return true;
00148     }
00149 
00158     public function ImportMessageDeletion($id) {
00159         $this->changes[] = array(self::DELETION, $id);
00160         return true;
00161     }
00162 
00171     public function IsChanged($id) {
00172         return (array_search(array(self::CHANGE, $id), $this->changes) === false) ? false:true;
00173     }
00174 
00183     public function IsDeleted($id) {
00184        return (array_search(array(self::DELETION, $id), $this->changes) === false) ? false:true;
00185     }
00186 
00195     public function ImportFolderChange($folder) {
00196         // if the destinationImporter is set, then this folder should be processed by another importer
00197         // instead of being loaded in memory.
00198         if (isset($this->destinationImporter)) {
00199             $ret = $this->destinationImporter->ImportFolderChange($folder);
00200 
00201             // if the operation was sucessfull, update the HierarchyCache
00202             if ($ret) {
00203                 // for folder creation, the serverid is not set and has to be updated before
00204                 if (!isset($folder->serverid) || $folder->serverid == "")
00205                     $folder->serverid = $ret;
00206 
00207                 $this->AddFolder($folder);
00208             }
00209             return $ret;
00210         }
00211         // load into memory
00212         else {
00213             if (isset($folder->serverid)) {
00214                 // The Zarafa HierarchyExporter exports all kinds of changes for folders (e.g. update no. of unread messages in a folder).
00215                 // These changes are not relevant for the mobiles, as something changes but the relevant displayname and parentid
00216                 // stay the same. These changes will be dropped and are not sent!
00217                 $cacheFolder = $this->GetFolder($folder->serverid);
00218                 if ($folder->equals($this->GetFolder($folder->serverid))) {
00219                     ZLog::Write(LOGLEVEL_DEBUG, sprintf("Change for folder '%s' will not be sent as modification is not relevant.", $folder->displayname));
00220                     return false;
00221                 }
00222 
00223                 // load this change into memory
00224                 $this->changes[] = array(self::CHANGE, $folder);
00225 
00226                 // HierarchyCache: already add/update the folder so changes are not sent twice (if exported twice)
00227                 $this->AddFolder($folder);
00228                 return true;
00229             }
00230             return false;
00231         }
00232     }
00233 
00243     public function ImportFolderDeletion($id, $parent = false) {
00244         // if the forwarder is set, then this folder should be processed by another importer
00245         // instead of being loaded in mem.
00246         if (isset($this->destinationImporter)) {
00247             $ret = $this->destinationImporter->ImportFolderDeletion($id, $parent);
00248 
00249             // if the operation was sucessfull, update the HierarchyCache
00250             if ($ret)
00251                 $this->DelFolder($id);
00252 
00253             return $ret;
00254         }
00255         else {
00256             // if this folder is not in the cache, the change does not need to be streamed to the mobile
00257             if ($this->GetFolder($id)) {
00258 
00259                 // load this change into memory
00260                 $this->changes[] = array(self::DELETION, $id, $parent);
00261 
00262                 // HierarchyCache: delete the folder so changes are not sent twice (if exported twice)
00263                 $this->DelFolder($id);
00264                 return true;
00265             }
00266         }
00267     }
00268 
00269 
00282     public function InitializeExporter(&$importer) {
00283         $this->exportImporter = $importer;
00284         $this->step = 0;
00285         return true;
00286     }
00287 
00294     public function GetChangeCount() {
00295         return count($this->changes);
00296     }
00297 
00304     public function Synchronize() {
00305         if($this->step < count($this->changes) && isset($this->exportImporter)) {
00306 
00307             $change = $this->changes[$this->step];
00308 
00309             if ($change[0] == self::CHANGE) {
00310                 if (! $this->GetFolder($change[1]->serverid, true))
00311                     $change[1]->flags = SYNC_NEWMESSAGE;
00312 
00313                 $this->exportImporter->ImportFolderChange($change[1]);
00314             }
00315             // deletion
00316             else {
00317                 $this->exportImporter->ImportFolderDeletion($change[1], $change[2]);
00318             }
00319             $this->step++;
00320 
00321             // return progress array
00322             return array("steps" => count($this->changes), "progress" => $this->step);
00323         }
00324         else
00325             return false;
00326     }
00327 
00335     public function __wakeup() {
00336         $this->changes = array();
00337         $this->step = 0;
00338     }
00339 }
00340 
00341 ?>