PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/tine20/library/Syncroton/lib/Syncroton/Command/ItemOperations.php

https://gitlab.com/rsilveira1987/Expresso
PHP | 271 lines | 170 code | 57 blank | 44 comment | 19 complexity | a47ace27aaf868dcb0d4e377729a536f MD5 | raw file
  1. <?php
  2. /**
  3. * Syncroton
  4. *
  5. * @package Syncroton
  6. * @subpackage Command
  7. * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3
  8. * @copyright Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
  9. * @author Lars Kneschke <l.kneschke@metaways.de>
  10. */
  11. /**
  12. * class to handle ActiveSync ItemOperations command
  13. *
  14. * @package Syncroton
  15. * @subpackage Command
  16. */
  17. class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
  18. {
  19. const STATUS_SUCCESS = 1;
  20. const STATUS_PROTOCOL_ERROR = 2;
  21. const STATUS_SERVER_ERROR = 3;
  22. const STATUS_ITEM_FAILED_CONVERSION = 14;
  23. protected $_defaultNameSpace = 'uri:ItemOperations';
  24. protected $_documentElement = 'ItemOperations';
  25. /**
  26. * list of items to move
  27. *
  28. * @var array
  29. */
  30. protected $_fetches = array();
  31. /**
  32. * list of folder to empty
  33. *
  34. * @var array
  35. */
  36. protected $_emptyFolderContents = array();
  37. /**
  38. * parse MoveItems request
  39. *
  40. */
  41. public function handle()
  42. {
  43. $xml = simplexml_import_dom($this->_requestBody);
  44. if (isset($xml->Fetch)) {
  45. foreach ($xml->Fetch as $fetch) {
  46. $this->_fetches[] = $this->_handleFetch($fetch);
  47. }
  48. }
  49. if (isset($xml->EmptyFolderContents)) {
  50. foreach ($xml->EmptyFolderContents as $emptyFolderContents) {
  51. $this->_emptyFolderContents[] = $this->_handleEmptyFolderContents($emptyFolderContents);
  52. }
  53. }
  54. if ($this->_logger instanceof Zend_Log)
  55. $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " fetches: " . print_r($this->_fetches, true));
  56. }
  57. /**
  58. * generate ItemOperations response
  59. *
  60. * @todo add multipart support to all types of fetches
  61. */
  62. public function getResponse()
  63. {
  64. // add aditional namespaces
  65. $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSyncBase' , 'uri:AirSyncBase');
  66. $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSync' , 'uri:AirSync');
  67. $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Search' , 'uri:Search');
  68. $itemOperations = $this->_outputDom->documentElement;
  69. $itemOperations->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS));
  70. $response = $itemOperations->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Response'));
  71. foreach ($this->_fetches as $fetch) {
  72. $fetchTag = $response->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Fetch'));
  73. try {
  74. $dataController = Syncroton_Data_Factory::factory($fetch['store'], $this->_device, $this->_syncTimeStamp);
  75. if (isset($fetch['collectionId'])) {
  76. $fetchTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS));
  77. $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $fetch['collectionId']));
  78. $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $fetch['serverId']));
  79. $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties');
  80. $dataController
  81. ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['collectionId'], 'options' => $fetch['options'])), $fetch['serverId'])
  82. ->appendXML($properties, $this->_device);
  83. $fetchTag->appendChild($properties);
  84. } elseif (isset($fetch['longId'])) {
  85. $fetchTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS));
  86. $fetchTag->appendChild($this->_outputDom->createElementNS('uri:Search', 'LongId', $fetch['longId']));
  87. $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties');
  88. $dataController
  89. ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['longId'], 'options' => $fetch['options'])), $fetch['longId'])
  90. ->appendXML($properties, $this->_device);
  91. $fetchTag->appendChild($properties);
  92. } elseif (isset($fetch['fileReference'])) {
  93. $fetchTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS));
  94. $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSyncBase', 'FileReference', $fetch['fileReference']));
  95. $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties');
  96. $fileReference = $dataController->getFileReference($fetch['fileReference']);
  97. // unset data field and move content to stream
  98. if ($this->_requestParameters['acceptMultipart'] == true) {
  99. $this->_headers['Content-Type'] = 'application/vnd.ms-sync.multipart';
  100. $partStream = fopen("php://temp", 'r+');
  101. if (is_resource($fileReference->data)) {
  102. stream_copy_to_stream($fileReference->data, $partStream);
  103. } else {
  104. fwrite($partStream, $fileReference->data);
  105. }
  106. unset($fileReference->data);
  107. $this->_parts[] = $partStream;
  108. $fileReference->part = count($this->_parts);
  109. } else {
  110. $dataSize = $this->_getDataSize($fileReference->data);
  111. $total = $this->_outputDom->createElementNS('uri:ItemOperations', 'Total', $dataSize);
  112. $properties->appendChild($total);
  113. $range = $this->_outputDom->createElementNS('uri:ItemOperations', 'Range', '0-' . ($dataSize - 1));
  114. $properties->appendChild($range);
  115. }
  116. $fileReference->appendXML($properties, $this->_device);
  117. $fetchTag->appendChild($properties);
  118. }
  119. } catch (Syncroton_Exception_NotFound $e) {
  120. $response->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_ITEM_FAILED_CONVERSION));
  121. } catch (Exception $e) {
  122. //echo __LINE__; echo $e->getMessage(); echo $e->getTraceAsString();
  123. $response->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SERVER_ERROR));
  124. }
  125. }
  126. foreach ($this->_emptyFolderContents as $emptyFolderContents) {
  127. try {
  128. $folder = $this->_folderBackend->getFolder($this->_device, $emptyFolderContents['collectionId']);
  129. $dataController = Syncroton_Data_Factory::factory($folder->class, $this->_device, $this->_syncTimeStamp);
  130. $dataController->emptyFolderContents($emptyFolderContents['collectionId'], $emptyFolderContents['options']);
  131. $status = Syncroton_Command_ItemOperations::STATUS_SUCCESS;
  132. }
  133. catch (Syncroton_Exception_Status_ItemOperations $e) {
  134. $status = $e->getCode();
  135. }
  136. catch (Exception $e) {
  137. $status = Syncroton_Exception_Status_ItemOperations::ITEM_SERVER_ERROR;
  138. }
  139. $emptyFolderContentsTag = $this->_outputDom->createElementNS('uri:ItemOperations', 'EmptyFolderContents');
  140. $emptyFolderContentsTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', $status));
  141. $emptyFolderContentsTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $emptyFolderContents['collectionId']));
  142. $response->appendChild($emptyFolderContentsTag);
  143. }
  144. return $this->_outputDom;
  145. }
  146. protected function _handleFetch(SimpleXMLElement $fetch)
  147. {
  148. $fetchArray = array(
  149. 'store' => (string)$fetch->Store,
  150. 'options' => array()
  151. );
  152. // try to fetch element from namespace AirSync
  153. $airSync = $fetch->children('uri:AirSync');
  154. if (isset($airSync->CollectionId)) {
  155. $fetchArray['collectionId'] = (string)$airSync->CollectionId;
  156. $fetchArray['serverId'] = (string)$airSync->ServerId;
  157. }
  158. // try to fetch element from namespace Search
  159. $search = $fetch->children('uri:Search');
  160. if (isset($search->LongId)) {
  161. $fetchArray['longId'] = (string)$search->LongId;
  162. }
  163. // try to fetch element from namespace AirSyncBase
  164. $airSyncBase = $fetch->children('uri:AirSyncBase');
  165. if (isset($airSyncBase->FileReference)) {
  166. $fetchArray['fileReference'] = (string)$airSyncBase->FileReference;
  167. }
  168. if (isset($fetch->Options)) {
  169. // try to fetch element from namespace AirSyncBase
  170. $airSyncBase = $fetch->Options->children('uri:AirSyncBase');
  171. if (isset($airSyncBase->BodyPreference)) {
  172. foreach ($airSyncBase->BodyPreference as $bodyPreference) {
  173. $type = (int) $bodyPreference->Type;
  174. $fetchArray['options']['bodyPreferences'][$type] = array(
  175. 'type' => $type
  176. );
  177. // optional
  178. if (isset($bodyPreference->TruncationSize)) {
  179. $fetchArray['options']['bodyPreferences'][$type]['truncationSize'] = (int) $bodyPreference->TruncationSize;
  180. }
  181. // optional
  182. if (isset($bodyPreference->AllOrNone)) {
  183. $fetchArray['options']['bodyPreferences'][$type]['allOrNone'] = (int) $bodyPreference->AllOrNone;
  184. }
  185. }
  186. }
  187. }
  188. return $fetchArray;
  189. }
  190. protected function _handleEmptyFolderContents(SimpleXMLElement $emptyFolderContent)
  191. {
  192. $folderArray = array(
  193. 'collectiondId' => null,
  194. 'options' => array('deleteSubFolders' => FALSE)
  195. );
  196. // try to fetch element from namespace AirSync
  197. $airSync = $emptyFolderContent->children('uri:AirSync');
  198. $folderArray['collectionId'] = (string)$airSync->CollectionId;
  199. if (isset($emptyFolderContent->Options)) {
  200. $folderArray['options']['deleteSubFolders'] = isset($emptyFolderContent->Options->DeleteSubFolders);
  201. }
  202. return $folderArray;
  203. }
  204. protected function _getDataSize($data)
  205. {
  206. if (is_resource($data)) {
  207. rewind($data);
  208. fseek($data, 0, SEEK_END);
  209. return ftell($data);
  210. } else {
  211. return strlen($data);
  212. }
  213. }
  214. }