Example #1
0
 /**
  * @param unknown_type $_class
  * @param Syncope_Model_IDevice $_device
  * @param DateTime $_timeStamp
  * @throws InvalidArgumentException
  * @return Syncope_Data_IData
  */
 public static function factory($_classFactory, Syncope_Model_IDevice $_device, DateTime $_timeStamp)
 {
     switch ($_classFactory) {
         case self::CLASS_CALENDAR:
             $className = Syncope_Registry::get(Syncope_Registry::CALENDAR_DATA_CLASS);
             break;
         case self::CLASS_CONTACTS:
             $className = Syncope_Registry::get(Syncope_Registry::CONTACTS_DATA_CLASS);
             break;
         case self::STORE_EMAIL:
         case self::CLASS_EMAIL:
             $className = Syncope_Registry::get(Syncope_Registry::EMAIL_DATA_CLASS);
             break;
         case self::CLASS_TASKS:
             $className = Syncope_Registry::get(Syncope_Registry::TASKS_DATA_CLASS);
             break;
         default:
             throw new InvalidArgumentException('invalid class type provided');
             breeak;
     }
     $class = new $className($_device, $_timeStamp);
     if (!$class instanceof Syncope_Data_IData) {
         throw new RuntimeException('class must be instanceof Syncope_Data_IData');
     }
     return $class;
 }
Example #2
0
 /**
  * Returns TRUE if the $index is a named value in the registry,
  * or FALSE if $index was not found in the registry.
  *
  * @param  string $index
  * @return boolean
  */
 public static function isRegistered($index)
 {
     if (self::$_registry === null) {
         return false;
     }
     return self::$_registry->offsetExists($index);
 }
 /**
  * (non-PHPdoc)
  * @see ActiveSync/ActiveSync_TestCase::setUp()
  */
 protected function setUp()
 {
     Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
     Syncope_Registry::setDatabase(Tinebase_Core::getDb());
     Syncope_Registry::setTransactionManager(Tinebase_TransactionManager::getInstance());
     $testDevice = ActiveSync_Backend_DeviceTests::getTestDevice();
     $this->objects['device'] = ActiveSync_Controller_Device::getInstance()->create($testDevice);
 }
Example #4
0
 public function __construct($userId, Zend_Controller_Request_Http $request = null, $body = null)
 {
     if (Syncope_Registry::isRegistered('loggerBackend')) {
         $this->_logger = Syncope_Registry::get('loggerBackend');
     }
     $this->_userId = $userId;
     $this->_request = $request !== null ? $request : new Zend_Controller_Request_Http();
     $this->_body = $body !== null ? $body : fopen('php://input', 'r');
     $this->_deviceBackend = Syncope_Registry::get('deviceBackend');
 }
 /**
  * (non-PHPdoc)
  * @see ActiveSync/ActiveSync_TestCase::setUp()
  */
 protected function setUp()
 {
     Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
     Syncope_Registry::setDatabase(Tinebase_Core::getDb());
     Syncope_Registry::setTransactionManager(Tinebase_TransactionManager::getInstance());
     $this->_deviceBackend = new Syncope_Backend_Device(Tinebase_Core::getDb(), SQL_TABLE_PREFIX . 'acsync_');
     $this->_folderBackend = new Syncope_Backend_Folder(Tinebase_Core::getDb(), SQL_TABLE_PREFIX . 'acsync_');
     $this->_syncStateBackend = new Syncope_Backend_SyncState(Tinebase_Core::getDb(), SQL_TABLE_PREFIX . 'acsync_');
     $this->_contentStateBackend = new Syncope_Backend_Content(Tinebase_Core::getDb(), SQL_TABLE_PREFIX . 'acsync_');
     $this->_device = $this->_deviceBackend->create(ActiveSync_Backend_DeviceTests::getTestDevice());
     Syncope_Registry::set('deviceBackend', $this->_deviceBackend);
     Syncope_Registry::set('folderStateBackend', $this->_folderBackend);
     Syncope_Registry::set('syncStateBackend', $this->_syncStateBackend);
     Syncope_Registry::set('contentStateBackend', $this->_contentStateBackend);
     Syncope_Registry::set('loggerBackend', Tinebase_Core::getLogger());
     Syncope_Registry::setContactsDataClass('ActiveSync_Controller_Contacts');
     Syncope_Registry::setCalendarDataClass('ActiveSync_Controller_Calendar');
     Syncope_Registry::setEmailDataClass('ActiveSync_Controller_Email');
     Syncope_Registry::setTasksDataClass('ActiveSync_Controller_Tasks');
 }
 /**
  * constructor
  */
 private function __construct()
 {
     if (Syncope_Registry::isRegistered('loggerBackend')) {
         $this->_logger = Syncope_Registry::get('loggerBackend');
     }
 }
Example #7
0
 /**
  * Tears down the fixture
  * This method is called after a test is executed.
  *
  * @access protected
  */
 protected function tearDown()
 {
     Syncope_Registry::getTransactionManager()->rollBack();
 }
Example #8
0
 /**
  * the constructor
  *
  * @param  mixed                    $_requestBody
  * @param  Syncope_Model_Device  $_device
  * @param  string                   $_policyKey
  */
 public function __construct($_requestBody, Syncope_Model_IDevice $_device, $_policyKey)
 {
     $this->_policyKey = $_policyKey;
     $this->_device = $_device;
     $this->_deviceBackend = Syncope_Registry::get('deviceBackend');
     $this->_folderBackend = Syncope_Registry::get('folderStateBackend');
     $this->_syncStateBackend = Syncope_Registry::get('syncStateBackend');
     $this->_contentStateBackend = Syncope_Registry::get('contentStateBackend');
     if (Syncope_Registry::isRegistered('loggerBackend')) {
         $this->_logger = Syncope_Registry::get('loggerBackend');
     }
     if ($this->_skipValidatePolicyKey !== true && $this->_policyKey === null) {
         #throw new Syncope_Exception_PolicyKeyMissing();
     }
     if ($this->_skipValidatePolicyKey !== true && ($this->_policyKey === 0 || $this->_device->policykey != $this->_policyKey)) {
         #throw new Syncope_Exception_ProvisioningNeeded();
     }
     // should we wipe the mobile phone?
     if ($this->_skipValidatePolicyKey !== true && !empty($this->_policyKey) && $this->_device->remotewipe >= Syncope_Command_Provision::REMOTEWIPE_REQUESTED) {
         throw new Syncope_Exception_ProvisioningNeeded();
     }
     $this->_inputDom = $_requestBody;
     $this->_syncTimeStamp = new DateTime(null, new DateTimeZone('UTC'));
     if ($this->_logger instanceof Zend_Log) {
         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " sync timestamp: " . $this->_syncTimeStamp->format('Y-m-d H:i:s'));
     }
     // Creates an instance of the DOMImplementation class
     $imp = new DOMImplementation();
     // Creates a DOMDocumentType instance
     $dtd = $imp->createDocumentType('AirSync', "-//AIRSYNC//DTD AirSync//EN", "http://www.microsoft.com/");
     // Creates a DOMDocument instance
     $this->_outputDom = $imp->createDocument($this->_defaultNameSpace, $this->_documentElement, $dtd);
     $this->_outputDom->formatOutput = false;
     $this->_outputDom->encoding = 'utf-8';
 }
Example #9
0
 /**
  * (non-PHPdoc)
  * @see Syncope_Command_Wbxml::getResponse()
  */
 public function getResponse()
 {
     $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSyncBase', 'uri:AirSyncBase');
     $sync = $this->_outputDom->documentElement;
     $collections = $sync->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collections'));
     foreach ($this->_collections as $collectionData) {
         // invalid collectionid provided
         if (!$collectionData['folder'] instanceof Syncope_Model_IFolder) {
             $collection = $collections->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collection'));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', 0));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData['collectionId']));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_FOLDER_HIERARCHY_HAS_CHANGED));
             // invalid synckey provided
         } elseif (!$collectionData['syncState'] instanceof Syncope_Model_ISyncState) {
             // set synckey to 0
             $collection = $collections->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collection'));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', 0));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData['collectionId']));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_INVALID_SYNC_KEY));
             // initial sync
         } elseif ($collectionData['syncState']->counter === 0) {
             $collectionData['syncState']->counter++;
             // initial sync
             // send back a new SyncKey only
             $collection = $collections->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collection'));
             if (!empty($collectionData['folder']->class)) {
                 $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Class', $collectionData['folder']->class));
             }
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', $collectionData['syncState']->counter));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData['collectionId']));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_SUCCESS));
         } else {
             $dataController = Syncope_Data_Factory::factory($collectionData['folder']->class, $this->_device, $this->_syncTimeStamp);
             $serverAdds = array();
             $serverChanges = array();
             $serverDeletes = array();
             $moreAvailable = false;
             if ($collectionData['getChanges'] === true) {
                 // continue sync session?
                 if (is_array($collectionData['syncState']->pendingdata)) {
                     if ($this->_logger instanceof Zend_Log) {
                         $this->_logger->info(__METHOD__ . '::' . __LINE__ . " restored from sync state ");
                     }
                     $serverAdds = $collectionData['syncState']->pendingdata['serverAdds'];
                     $serverChanges = $collectionData['syncState']->pendingdata['serverChanges'];
                     $serverDeletes = $collectionData['syncState']->pendingdata['serverDeletes'];
                 } else {
                     // fetch entries added since last sync
                     $allClientEntries = $this->_contentStateBackend->getFolderState($this->_device, $collectionData['folder']);
                     $allServerEntries = $dataController->getServerEntries($collectionData['collectionId'], $collectionData['filterType']);
                     // add entries
                     $serverDiff = array_diff($allServerEntries, $allClientEntries);
                     // add entries which produced problems during delete from client
                     $serverAdds = $collectionData['forceAdd'];
                     // add entries not yet sent to client
                     $serverAdds = array_unique(array_merge($serverAdds, $serverDiff));
                     # @todo still needed?
                     foreach ($serverAdds as $id => $serverId) {
                         // skip entries added by client during this sync session
                         if (isset($collectionData['added'][$serverId]) && !isset($collectionData['forceAdd'][$serverId])) {
                             if ($this->_logger instanceof Zend_Log) {
                                 $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped added entry: " . $serverId);
                             }
                             unset($serverAdds[$id]);
                         }
                     }
                     // entries to be deleted
                     $serverDeletes = array_diff($allClientEntries, $allServerEntries);
                     // fetch entries changed since last sync
                     $serverChanges = $dataController->getChangedEntries($collectionData['collectionId'], $collectionData['syncState']->lastsync, $this->_syncTimeStamp);
                     $serverChanges = array_merge($serverChanges, $collectionData['forceChange']);
                     foreach ($serverChanges as $id => $serverId) {
                         // skip entry, if it got changed by client during current sync
                         if (isset($collectionData['changed'][$serverId]) && !isset($collectionData['forceChange'][$serverId])) {
                             if ($this->_logger instanceof Zend_Log) {
                                 $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped changed entry: " . $serverId);
                             }
                             unset($serverChanges[$id]);
                         }
                     }
                     // entries comeing in scope are already in $serverAdds and do not need to
                     // be send with $serverCanges
                     $serverChanges = array_diff($serverChanges, $serverAdds);
                 }
                 if ($this->_logger instanceof Zend_Log) {
                     $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found (added/changed/deleted) " . count($serverAdds) . '/' . count($serverChanges) . '/' . count($serverDeletes) . ' entries for sync from server to client');
                 }
             }
             if (!empty($collectionData['added']) || !empty($collectionData['changed']) || !empty($collectionData['deleted']) || !empty($serverAdds) || !empty($serverChanges) || !empty($serverDeletes)) {
                 $collectionData['syncState']->counter++;
             }
             // collection header
             $collection = $collections->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collection'));
             if (!empty($collectionData['folder']->class)) {
                 $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Class', $collectionData['folder']->class));
             }
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', $collectionData['syncState']->counter));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData['collectionId']));
             $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_SUCCESS));
             $responses = $this->_outputDom->createElementNS('uri:AirSync', 'Responses');
             // send reponse for newly added entries
             if (!empty($collectionData['added'])) {
                 foreach ($collectionData['added'] as $entryData) {
                     $add = $responses->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Add'));
                     $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ClientId', $entryData['clientId']));
                     // we have no serverId is the add failed
                     if (isset($entryData['serverId'])) {
                         $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $entryData['serverId']));
                     }
                     $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', $entryData['status']));
                 }
             }
             // send reponse for changed entries
             if (!empty($collectionData['changed'])) {
                 foreach ($collectionData['changed'] as $serverId => $status) {
                     if ($status !== Syncope_Command_Sync::STATUS_SUCCESS) {
                         $change = $responses->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Change'));
                         $change->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId));
                         $change->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', $status));
                     }
                 }
             }
             // send response for to be fetched entries
             if (!empty($collectionData['toBeFetched'])) {
                 foreach ($collectionData['toBeFetched'] as $serverId) {
                     $fetch = $responses->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Fetch'));
                     $fetch->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId));
                     try {
                         $applicationData = $this->_outputDom->createElementNS('uri:AirSync', 'ApplicationData');
                         $dataController->appendXML($applicationData, $collectionData, $serverId);
                         $fetch->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_SUCCESS));
                         $fetch->appendChild($applicationData);
                     } catch (Exception $e) {
                         if ($this->_logger instanceof Zend_Log) {
                             $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage());
                         }
                         $fetch->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_OBJECT_NOT_FOUND));
                     }
                 }
             }
             if ($responses->hasChildNodes() === true) {
                 $collection->appendChild($responses);
             }
             if (count($serverAdds) + count($serverChanges) + count($serverDeletes) > $collectionData['windowSize']) {
                 $moreAvailable = true;
                 $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'MoreAvailable'));
             }
             $commands = $this->_outputDom->createElementNS('uri:AirSync', 'Commands');
             /**
              * process entries added on server side
              */
             $newContentStates = array();
             foreach ($serverAdds as $id => $serverId) {
                 if ($this->_totalCount === $collectionData['windowSize']) {
                     break;
                 }
                 #/**
                 # * somewhere is a problem in the logic for handling moreAvailable
                 # *
                 # * it can happen, that we have a contentstate (which means we sent the entry to the client
                 # * and that this entry is yet in $collectionData['syncState']->pendingdata['serverAdds']
                 # * I have no idea how this can happen, but the next lines of code work around this problem
                 # */
                 #try {
                 #    $this->_contentStateBackend->getContentState($this->_device, $collectionData['folder'], $serverId);
                 #
                 #    if ($this->_logger instanceof Zend_Log)
                 #        $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped an entry($serverId) which is already on the client");
                 #
                 #    unset($serverAdds[$id]);
                 #    continue;
                 #
                 #} catch (Syncope_Exception_NotFound $senf) {
                 #    // do nothing => content state should not exist yet
                 #}
                 try {
                     $add = $this->_outputDom->createElementNS('uri:AirSync', 'Add');
                     $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId));
                     $applicationData = $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ApplicationData'));
                     $dataController->appendXML($applicationData, $collectionData, $serverId);
                     $commands->appendChild($add);
                     $this->_totalCount++;
                 } catch (Exception $e) {
                     if ($this->_logger instanceof Zend_Log) {
                         $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage());
                     }
                 }
                 // mark as send to the client, even the conversion to xml might have failed
                 $newContentStates[] = new Syncope_Model_Content(array('device_id' => $this->_device, 'folder_id' => $collectionData['folder'], 'contentid' => $serverId, 'creation_time' => $this->_syncTimeStamp, 'creation_synckey' => $collectionData['syncState']->counter));
                 unset($serverAdds[$id]);
             }
             /**
              * process entries changed on server side
              */
             foreach ($serverChanges as $id => $serverId) {
                 if ($this->_totalCount === $collectionData['windowSize']) {
                     break;
                 }
                 try {
                     $change = $this->_outputDom->createElementNS('uri:AirSync', 'Change');
                     $change->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId));
                     $applicationData = $change->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ApplicationData'));
                     $dataController->appendXML($applicationData, $collectionData, $serverId);
                     $commands->appendChild($change);
                     $this->_totalCount++;
                 } catch (Exception $e) {
                     if ($this->_logger instanceof Zend_Log) {
                         $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage());
                     }
                 }
                 unset($serverChanges[$id]);
             }
             /**
              * process entries deleted on server side
              */
             $deletedContentStates = array();
             foreach ($serverDeletes as $id => $serverId) {
                 if ($this->_totalCount === $collectionData['windowSize']) {
                     break;
                 }
                 try {
                     // check if we have sent this entry to the phone
                     $state = $this->_contentStateBackend->getContentState($this->_device, $collectionData['folder'], $serverId);
                     $delete = $this->_outputDom->createElementNS('uri:AirSync', 'Delete');
                     $delete->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId));
                     $deletedContentStates[] = $state;
                     $commands->appendChild($delete);
                     $this->_totalCount++;
                 } catch (Exception $e) {
                     if ($this->_logger instanceof Zend_Log) {
                         $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage());
                     }
                 }
                 unset($serverDeletes[$id]);
             }
             if ($commands->hasChildNodes() === true) {
                 $collection->appendChild($commands);
             }
             if ($this->_logger instanceof Zend_Log) {
                 $this->_logger->info(__METHOD__ . '::' . __LINE__ . " new synckey is " . $collectionData['syncState']->counter);
             }
         }
         if (isset($collectionData['syncState']) && $collectionData['syncState'] instanceof Syncope_Model_ISyncState && $collectionData['syncState']->counter != $collectionData['syncKey']) {
             // increment sync timestamp by 1 second
             $this->_syncTimeStamp->modify('+1 sec');
             // store pending data in sync state when needed
             if (isset($moreAvailable) && $moreAvailable === true) {
                 $collectionData['syncState']->pendingdata = array('serverAdds' => (array) $serverAdds, 'serverChanges' => (array) $serverChanges, 'serverDeletes' => (array) $serverDeletes);
             } else {
                 $collectionData['syncState']->pendingdata = null;
             }
             if (!empty($collectionData['added'])) {
                 if ($this->_logger instanceof Zend_Log) {
                     $this->_logger->info(__METHOD__ . '::' . __LINE__ . " remove previous synckey as client added new entries");
                 }
                 $keepPreviousSyncKey = false;
             } else {
                 $keepPreviousSyncKey = true;
             }
             $collectionData['syncState']->lastsync = $this->_syncTimeStamp;
             try {
                 $transactionId = Syncope_Registry::getTransactionManager()->startTransaction(Syncope_Registry::getDatabase());
                 // store new synckey
                 $this->_syncStateBackend->create($collectionData['syncState'], $keepPreviousSyncKey);
                 // store contentstates for new entries added to client
                 if (isset($newContentStates)) {
                     foreach ($newContentStates as $state) {
                         $this->_contentStateBackend->create($state);
                     }
                 }
                 // remove contentstates for entries to be deleted on client
                 if (isset($deletedContentStates)) {
                     foreach ($deletedContentStates as $state) {
                         $this->_contentStateBackend->delete($state);
                     }
                 }
                 Syncope_Registry::getTransactionManager()->commitTransaction($transactionId);
             } catch (Zend_Db_Statement_Exception $zdse) {
                 // something went wrong
                 // maybe another parallel request added a new synckey
                 // we must remove data added from client
                 if (!empty($collectionData['added'])) {
                     foreach ($collectionData['added'] as $added) {
                         $this->_contentStateBackend->delete($added['contentState']);
                         $dataController->deleteEntry($collectionData['collectionId'], $added['serverId'], array());
                     }
                 }
                 Syncope_Registry::getTransactionManager()->rollBack();
                 throw $zdse;
             }
             // store current filter type
             try {
                 $folderState = $this->_folderBackend->getFolder($this->_device, $collectionData['collectionId']);
                 $folderState->lastfiltertype = $collectionData['filterType'];
                 $this->_folderBackend->update($folderState);
             } catch (Syncope_Exception_NotFound $senf) {
                 // failed to get folderstate => should not happen but is also no problem in this state
                 if ($this->_logger instanceof Zend_Log) {
                     $this->_logger->crit(__METHOD__ . '::' . __LINE__ . ' failed to get content state for: ' . $collectionData['collectionId']);
                 }
             }
         }
     }
     return $this->_outputDom;
 }