Overview

Packages

  • ActiveSync
  • None

Classes

  • Horde_ActiveSync
  • Horde_ActiveSync_Connector_Exporter
  • Horde_ActiveSync_Connector_Importer
  • Horde_ActiveSync_Driver_Base
  • Horde_ActiveSync_Exception
  • Horde_ActiveSync_Exception_InvalidRequest
  • Horde_ActiveSync_Exception_StateGone
  • Horde_ActiveSync_Message_Base
  • Horde_ActiveSync_Request_Base
  • Horde_ActiveSync_Request_FolderCreate
  • Horde_ActiveSync_Request_FolderSync
  • Horde_ActiveSync_Request_GetHierarchy
  • Horde_ActiveSync_Request_GetItemEstimate
  • Horde_ActiveSync_Request_MeetingResponse
  • Horde_ActiveSync_Request_MoveItems
  • Horde_ActiveSync_Request_Notify
  • Horde_ActiveSync_Request_Ping
  • Horde_ActiveSync_Request_Provision
  • Horde_ActiveSync_Request_Search
  • Horde_ActiveSync_Request_SendMail
  • Horde_ActiveSync_Request_SmartForward
  • Horde_ActiveSync_Request_SmartReply
  • Horde_ActiveSync_Request_Sync
  • Horde_ActiveSync_State_File
  • Horde_ActiveSync_Sync
  • Horde_ActiveSync_Wbxml
  • Horde_ActiveSync_Wbxml_Decoder
  • Horde_ActiveSync_Wbxml_Encoder
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * ActiveSync Handler for FOLDERSYNC requests
  4:  *
  5:  * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * @author Michael J. Rubinsky <mrubinsk@horde.org>
  8:  * @package ActiveSync
  9:  */
 10: /**
 11:  * Zarafa Deutschland GmbH, www.zarafaserver.de
 12:  * This file is distributed under GPL-2.0.
 13:  * Consult COPYING file for details
 14:  */
 15: class Horde_ActiveSync_Request_FolderSync extends Horde_ActiveSync_Request_Base
 16: {
 17:     /* SYNC Status response codes */
 18:     const STATUS_SUCCESS = 1;
 19:     const STATUS_SERVERERROR = 6;
 20:     const STATUS_TIMEOUT = 8;
 21:     const STATUS_KEYMISM = 9;
 22:     const STATUS_PROTOERR = 10;
 23: 
 24:     /**
 25:      * Handle the request.
 26:      *
 27:      * @return boolean
 28:      */
 29:     public function handle()
 30:     {
 31:         parent::handle();
 32: 
 33:         // Be optimistic
 34:         $this->_statusCode = self::STATUS_SUCCESS;
 35:         $this->_logger->info('[Horde_ActiveSync::handleFolderSync] Beginning FOLDERSYNC');
 36: 
 37:         // Check policy
 38:         if (!$this->checkPolicyKey($this->_activeSync->getPolicyKey())) {
 39:             return false;
 40:         }
 41: 
 42:         // Start parsing input
 43:         if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::FOLDERHIERARCHY_FOLDERSYNC)) {
 44:             $this->_logger->err('[Horde_ActiveSync::handleFolderSync] No input to parse');
 45:             $this->_statusCode = self::STATUS_PROTOERR;
 46:             $this->_handleError();
 47:             exit;
 48:         }
 49: 
 50:         // Get the current synckey from PIM
 51:         if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::FOLDERHIERARCHY_SYNCKEY)) {
 52:             $this->_logger->err('[Horde_ActiveSync::handleFolderSync] No input to parse');
 53:             $this->_statusCode = self::STATUS_PROTOERR;
 54:             $this->_handleError();
 55:             exit;
 56:         }
 57:         $synckey = $this->_decoder->getElementContent();
 58:         if (!$this->_decoder->getElementEndTag()) {
 59:             $this->_logger->err('[Horde_ActiveSync::handleFolderSync] No input to parse');
 60:             $this->_statusCode = self::STATUS_PROTOERR;
 61:             $this->_handleError();
 62:             exit;
 63:         }
 64:         $this->_logger->debug('[Horde_ActiveSync::handleFolderSync] syncKey: ' . $synckey);
 65: 
 66:         try {
 67:             $this->_state->loadState($synckey, 'foldersync');
 68:         } catch (Horde_ActiveSync_Exception $e) {
 69:             $this->_statusCode = self::STATUS_KEYMISM;
 70:             $this->_handleError();
 71:             exit;
 72:         }
 73: 
 74:         // Track if we have changes or not
 75:         $changes = false;
 76: 
 77:         // Deal with folder hierarchy changes
 78:         if ($this->_decoder->getElementStartTag(Horde_ActiveSync::FOLDERHIERARCHY_CHANGES)) {
 79:             // Ignore <Count> if present
 80:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::FOLDERHIERARCHY_COUNT)) {
 81:                 $this->_decoder->getElementContent();
 82:                 if (!$this->_decoder->getElementEndTag()) {
 83:                     $this->_statusCode = self::STATUS_PROTOERR;
 84:                     $this->_handleError();
 85:                     exit;
 86:                 }
 87:             }
 88: 
 89:             // Process the incoming changes to folders
 90:             $element = $this->_decoder->getElement();
 91:             if ($element[Horde_ActiveSync_Wbxml::EN_TYPE] != Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
 92:                 $this->_statusCode = self::STATUS_PROTOERR;
 93:                 $this->_handleError();
 94:                 exit;
 95:             }
 96: 
 97:             // Configure importer with last state
 98:             $importer = $this->_driver->getImporter();
 99:             $importer->init($this->_state, false);
100: 
101:             while (1) {
102:                 $folder = new Horde_ActiveSync_Message_Folder(array('logger' => $this->_logger));
103:                 if (!$folder->decodeStream($this->_decoder)) {
104:                     break;
105:                 }
106: 
107:                 switch ($element[Horde_ActiveSync_Wbxml::EN_TAG]) {
108:                 case SYNC_ADD:
109:                 case SYNC_MODIFY:
110:                     $serverid = $importer->importFolderChange($folder);
111:                     $changes = true;
112:                     break;
113:                 case SYNC_REMOVE:
114:                     $serverid = $importer->importFolderDeletion($folder);
115:                     $changes = true;
116:                     break;
117:                 }
118:             }
119: 
120:             if (!$this->_decoder->getElementEndTag()) {
121:                 $this->_statusCode = self::STATUS_PROTOERR;
122:                 $this->_handleError();
123:                 exit;
124:             }
125:         }
126: 
127:         if (!$this->_decoder->getElementEndTag()) {
128:             $this->_statusCode = self::STATUS_PROTOERR;
129:             $this->_handleError();
130:             exit;
131:         }
132: 
133:         // Start sending server -> PIM changes
134:         $this->_logger->debug('[Horde_ActiveSync::handleFolderSync] Preparing to send changes to PIM');
135:         $newsynckey = $this->_state->getNewSyncKey($synckey);
136:         $seenfolders = $this->_state->getKnownFolders();
137:         $this->_logger->debug('[Horde_ActiveSync::handleFolderSync] newSyncKey: ' . $newsynckey);
138: 
139:         // The $exporter just caches all folder changes in-memory, so we can
140:         // count before sending the actual data.
141:         $exporter = new Horde_ActiveSync_Connector_Exporter();
142:         $sync = $this->_driver->getSyncObject();
143:         $sync->init($this->_state, $exporter, array('synckey' => $synckey));
144: 
145:         // Perform the actual sync operation
146:         while(is_array($sync->syncronize()));
147: 
148:         // Output our WBXML reply now
149:         $this->_encoder->StartWBXML();
150: 
151:         $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_FOLDERSYNC);
152: 
153:         $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_STATUS);
154:         $this->_encoder->content($this->_statusCode);
155:         $this->_encoder->endTag();
156: 
157:         $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_SYNCKEY);
158:         $this->_encoder->content((($changes || $exporter->count > 0) ? $newsynckey : $synckey));
159:         $this->_encoder->endTag();
160: 
161:         $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_CHANGES);
162: 
163:         $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_COUNT);
164:         $this->_encoder->content($exporter->count);
165:         $this->_encoder->endTag();
166: 
167:         if (count($exporter->changed) > 0) {
168:             foreach ($exporter->changed as $folder) {
169:                 if (isset($folder->serverid) && in_array($folder->serverid, $seenfolders)) {
170:                     $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_UPDATE);
171:                 } else {
172:                     $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_ADD);
173:                 }
174:                 $folder->encodeStream($this->_encoder);
175:                 $this->_encoder->endTag();
176:             }
177:         }
178: 
179:         if (count($exporter->deleted) > 0) {
180:             foreach ($exporter->deleted as $folder) {
181:                 $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_REMOVE);
182:                 $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_SERVERENTRYID);
183:                 $this->_encoder->content($folder);
184:                 $this->_encoder->endTag();
185:                 $this->_encoder->endTag();
186:             }
187:         }
188: 
189:         $this->_encoder->endTag();
190:         $this->_encoder->endTag();
191: 
192:         // Save the state as well as the known folder cache if we had any
193:         // changes.
194:         if ($exporter->count || $changed) {
195:             $this->_state->setNewSyncKey($newsynckey);
196:             $this->_state->save();
197:         }
198:         $this->_cleanUpAfterPairing();
199: 
200:         return true;
201:     }
202: 
203:     /**
204:      * Helper function for sending error responses
205:      *
206:      */
207:     private function _handleError()
208:     {
209:         $this->_encoder->startWBXML();
210:         $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_FOLDERSYNC);
211:         $this->_encoder->startTag(Horde_ActiveSync::FOLDERHIERARCHY_STATUS);
212:         $this->_encoder->content($this->_statusCode);
213:         $this->_encoder->endTag();
214:         $this->_encoder->endTag();
215:     }
216: 
217: }
API documentation generated by ApiGen