/** * delete folderstate (aka: forget that we have sent the folder to the client) * * @param string $_class the class from the xml * @param string $_contentId the Tine 2.0 id of the folder */ protected function _deleteFolderState($_class, $_folderId) { $folderStateFilter = new ActiveSync_Model_FolderStateFilter(array(array('field' => 'device_id', 'operator' => 'equals', 'value' => $this->_device->getId()), array('field' => 'class', 'operator' => 'equals', 'value' => $_class), array('field' => 'folderid', 'operator' => 'equals', 'value' => $_folderId))); $state = $this->_folderStateBackend->search($folderStateFilter, NULL, true); if (count($state) > 0) { $this->_folderStateBackend->delete($state[0]); } else { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " no folderstate found for " . print_r($folderStateFilter->toArray(), true)); } }
/** * generate MoveItems response */ public function getResponse() { $folderStateBackend = new ActiveSync_Backend_FolderState(); $moves = $this->_outputDom->documentElement; foreach ($this->_moves as $move) { $response = $moves->appendChild($this->_outputDom->createElementNS('uri:Move', 'Response')); $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'SrcMsgId', $move['srcMsgId'])); try { $folder = $folderStateBackend->getByProperty($move['srcFldId'], 'folderid'); $dataController = ActiveSync_Controller::dataFactory($folder->class, $this->_device, $this->_syncTimeStamp); $newId = $dataController->moveItem($move['srcFldId'], $move['srcMsgId'], $move['dstFldId']); $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', ActiveSync_Command_MoveItems::STATUS_SUCCESS)); $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'DstMsgId', $newId)); } catch (Tinebase_Exception_NotFound $e) { $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', ActiveSync_Command_MoveItems::STATUS_INVALID_SOURCE)); } catch (Exception $e) { $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', ActiveSync_Command_MoveItems::STATUS_INVALID_DESTINATION)); } } return $this->_outputDom; }
/** * return number of chnaged entries * * @param $_dataController * @param array $_collectionData * @param $_lastSyncTimeStamp * @return int number of changed entries */ private function _getItemEstimate($_dataController, $_collectionData, $_lastSyncTimeStamp) { // hack to have the same variable names all over the place $_collectionData['class'] = $_collectionData['folderType']; $_collectionData['collectionId'] = $_collectionData['serverEntryId']; $contentStateBackend = new ActiveSync_Backend_ContentState(); $folderStateBackend = new ActiveSync_Backend_FolderState(); // get current filterType $filter = new ActiveSync_Model_FolderStateFilter(array(array('field' => 'device_id', 'operator' => 'equals', 'value' => $this->_device->getId()), array('field' => 'class', 'operator' => 'equals', 'value' => $_collectionData['class']), array('field' => 'folderid', 'operator' => 'equals', 'value' => $_collectionData['collectionId']))); $folderState = $folderStateBackend->search($filter)->getFirstRecord(); if ($folderState instanceof ActiveSync_Model_FolderState) { $filterType = $folderState->lastfiltertype; } else { $filterType = 0; } $allClientEntries = $contentStateBackend->getClientState($this->_device, $_collectionData['class'], $_collectionData['collectionId']); $_dataController->updateCache($_collectionData['collectionId']); $allServerEntries = $_dataController->getServerEntries($_collectionData['collectionId'], $filterType); $addedEntries = array_diff($allServerEntries, $allClientEntries); $deletedEntries = array_diff($allClientEntries, $allServerEntries); $changedEntries = $_dataController->getChanged($_collectionData['collectionId'], $_lastSyncTimeStamp); return count($addedEntries) + count($deletedEntries) + count($changedEntries); }
/** * @param unknown_type $_deviceId * @param unknown_type $_class * @param unknown_type $_folderId * @return ActiveSync_Model_FolderState */ public function getFolderState($_deviceId, $_folderId) { $deviceId = $_deviceId instanceof ActiveSync_Model_Device ? $_deviceId->getId() : $_deviceId; // store current filter type $filter = new ActiveSync_Model_FolderStateFilter(array(array('field' => 'device_id', 'operator' => 'equals', 'value' => $deviceId), array('field' => 'folderid', 'operator' => 'equals', 'value' => $_folderId))); $folderStates = $this->_folderStateBackend->search($filter); if ($folderStates->count() == 0) { throw new Tinebase_Exception_NotFound('folderstate for device not found'); } return $folderStates->getFirstRecord(); }
/** * (non-PHPdoc) * @see ActiveSync_Command_Wbxml::getResponse() */ public function getResponse() { $controller = ActiveSync_Controller::getInstance(); $itemEstimate = $this->_outputDom->documentElement; foreach ($this->_collections as $collections) { foreach ($collections as $collectionData) { $response = $itemEstimate->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Response')); $dataController = ActiveSync_Controller::dataFactory($collectionData['class'], $this->_device, $this->_syncTimeStamp); try { // does the folder exist? $dataController->getFolder($collectionData['collectionId']); $folderExists = true; } catch (ActiveSync_Exception_FolderNotFound $asefnf) { $folderExists = false; } if ($folderExists !== true) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " folder does not exist"); $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_INVALID_COLLECTION)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Class', $collectionData['class'])); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData['collectionId'])); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', 0)); } elseif ($collectionData['syncKeyValid'] !== true) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " invalid synckey {$collectionData['syncKey']} provided"); /* * Android phones (and maybe others) don't take care about status 4(INVALID_SYNC_KEY) * To solve the problem we always return status 1(SUCCESS) even the sync key is invalid with Estimate set to 1. * This way the phone gets forced to sync. Handling invalid synckeys during sync command works without any problems. * $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_INVALID_SYNC_KEY)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Class', $collectionData['class'])); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData['collectionId'])); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', 0)); */ $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_SUCCESS)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Class', $collectionData['class'])); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData['collectionId'])); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', 1)); } else { $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_SUCCESS)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Class', $collectionData['class'])); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData['collectionId'])); if ($collectionData['syncKey'] <= 1) { // this is the first sync. in most cases there are data on the server. $count = count($dataController->getServerEntries($collectionData['collectionId'], $collectionData['filterType'])); } else { $count = $this->_getItemEstimate($dataController, $collectionData); } $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', $count)); } // store current filter type $filter = new ActiveSync_Model_FolderStateFilter(array(array('field' => 'device_id', 'operator' => 'equals', 'value' => $this->_device->getId()), array('field' => 'class', 'operator' => 'equals', 'value' => $collectionData['class']), array('field' => 'folderid', 'operator' => 'equals', 'value' => $collectionData['collectionId']))); $folderState = $this->_folderStateBackend->search($filter)->getFirstRecord(); // folderState can be NULL in case of not existing folder if ($folderState instanceof ActiveSync_Model_FolderState) { $folderState->lastfiltertype = $collectionData['filterType']; $this->_folderStateBackend->update($folderState); } } } return $this->_outputDom; }