1<?php 2/*********************************************** 3* File : moveitems.php 4* Project : Z-Push 5* Descr : Provides the MOVEITEMS command 6* 7* Created : 16.02.2012 8* 9* Copyright 2007 - 2016 Zarafa Deutschland GmbH 10* 11* This program is free software: you can redistribute it and/or modify 12* it under the terms of the GNU Affero General Public License, version 3, 13* as published by the Free Software Foundation. 14* 15* This program is distributed in the hope that it will be useful, 16* but WITHOUT ANY WARRANTY; without even the implied warranty of 17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18* GNU Affero General Public License for more details. 19* 20* You should have received a copy of the GNU Affero General Public License 21* along with this program. If not, see <http://www.gnu.org/licenses/>. 22* 23* Consult LICENSE file for details 24************************************************/ 25 26class MoveItems extends RequestProcessor { 27 28 /** 29 * Handles the MoveItems command 30 * 31 * @param int $commandCode 32 * 33 * @access public 34 * @return boolean 35 */ 36 public function Handle($commandCode) { 37 if(!self::$decoder->getElementStartTag(SYNC_MOVE_MOVES)) 38 return false; 39 40 $moves = array(); 41 while(self::$decoder->getElementStartTag(SYNC_MOVE_MOVE)) { 42 $move = array(); 43 if(self::$decoder->getElementStartTag(SYNC_MOVE_SRCMSGID)) { 44 $move["srcmsgid"] = self::$decoder->getElementContent(); 45 if(!self::$decoder->getElementEndTag()) 46 break; 47 } 48 if(self::$decoder->getElementStartTag(SYNC_MOVE_SRCFLDID)) { 49 $move["srcfldid"] = self::$decoder->getElementContent(); 50 if(!self::$decoder->getElementEndTag()) 51 break; 52 } 53 if(self::$decoder->getElementStartTag(SYNC_MOVE_DSTFLDID)) { 54 $move["dstfldid"] = self::$decoder->getElementContent(); 55 if(!self::$decoder->getElementEndTag()) 56 break; 57 } 58 array_push($moves, $move); 59 60 if(!self::$decoder->getElementEndTag()) 61 return false; 62 } 63 64 if(!self::$decoder->getElementEndTag()) 65 return false; 66 67 self::$encoder->StartWBXML(); 68 69 self::$encoder->startTag(SYNC_MOVE_MOVES); 70 71 $operationResults = array(); 72 $operationCounter = 0; 73 $operationTotal = count($moves); 74 foreach($moves as $move) { 75 $operationCounter++; 76 self::$encoder->startTag(SYNC_MOVE_RESPONSE); 77 self::$encoder->startTag(SYNC_MOVE_SRCMSGID); 78 self::$encoder->content($move["srcmsgid"]); 79 self::$encoder->endTag(); 80 81 $status = SYNC_MOVEITEMSSTATUS_SUCCESS; 82 $result = false; 83 try { 84 $sourceBackendFolderId = self::$deviceManager->GetBackendIdForFolderId($move["srcfldid"]); 85 86 // if the source folder is an additional folder the backend has to be setup correctly 87 if (!self::$backend->Setup(ZPush::GetAdditionalSyncFolderStore($sourceBackendFolderId))) 88 throw new StatusException(sprintf("HandleMoveItems() could not Setup() the backend for folder id %s/%s", $move["srcfldid"], $sourceBackendFolderId), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); 89 90 $importer = self::$backend->GetImporter($sourceBackendFolderId); 91 if ($importer === false) 92 throw new StatusException(sprintf("HandleMoveItems() could not get an importer for folder id %s/%s", $move["srcfldid"], $sourceBackendFolderId), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); 93 94 // get saved SyncParameters of the source folder 95 $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState($move["srcfldid"]); 96 if (!$spa->HasSyncKey()) 97 throw new StatusException(sprintf("MoveItems(): Source folder id '%s' is not fully synchronized. Unable to perform operation.", $move["srcfldid"]), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); 98 99 // get saved SyncParameters of the destination folder 100 $destSpa = self::$deviceManager->GetStateManager()->GetSynchedFolderState($move["dstfldid"]); 101 if (!$destSpa->HasSyncKey()) { 102 $destSpa->SetFolderId($move["dstfldid"]); 103 $destSpa->SetSyncKey(self::$deviceManager->GetStateManager()->GetZeroSyncKey()); 104 } 105 106 $importer->SetMoveStates($spa->GetMoveState(), $destSpa->GetMoveState()); 107 $importer->ConfigContentParameters($spa->GetCPO()); 108 109 $result = $importer->ImportMessageMove($move["srcmsgid"], self::$deviceManager->GetBackendIdForFolderId($move["dstfldid"])); 110 // We discard the standard importer state for now. 111 112 // Get the move states and save them in the SyncParameters of the src and dst folder 113 list($srcMoveState, $dstMoveState) = $importer->GetMoveStates(); 114 if ($spa->GetMoveState() !== $srcMoveState) { 115 $spa->SetMoveState($srcMoveState); 116 self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa); 117 } 118 if ($destSpa->GetMoveState() !== $dstMoveState) { 119 $destSpa->SetMoveState($dstMoveState); 120 self::$deviceManager->GetStateManager()->SetSynchedFolderState($destSpa); 121 } 122 } 123 catch (StatusException $stex) { 124 if ($stex->getCode() == SYNC_STATUS_FOLDERHIERARCHYCHANGED) // same as SYNC_FSSTATUS_CODEUNKNOWN 125 $status = SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID; 126 else 127 $status = $stex->getCode(); 128 } 129 130 if ($operationCounter % 10 == 0) { 131 self::$topCollector->AnnounceInformation(sprintf("Moved %d objects out of %d", $operationCounter, $operationTotal)); 132 } 133 134 // save the operation result 135 if (!isset($operationResults[$status])) { 136 $operationResults[$status] = 0; 137 } 138 $operationResults[$status]++; 139 140 self::$encoder->startTag(SYNC_MOVE_STATUS); 141 self::$encoder->content($status); 142 self::$encoder->endTag(); 143 144 self::$encoder->startTag(SYNC_MOVE_DSTMSGID); 145 self::$encoder->content( (($result !== false ) ? $result : $move["srcmsgid"])); 146 self::$encoder->endTag(); 147 self::$encoder->endTag(); 148 } 149 150 self::$topCollector->AnnounceInformation(sprintf("Moved %d - Codes", $operationTotal), true); 151 foreach ($operationResults as $status => $occurences) { 152 self::$topCollector->AnnounceInformation(sprintf("%dx%d", $occurences, $status), true); 153 } 154 155 156 self::$encoder->endTag(); 157 return true; 158 } 159} 160