/** * Helper method for parsing incoming SYNC_FOLDERS nodes. * */ protected function _parseSyncFolders() { while ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDER)) { $collection = $this->_collections->getNewCollection(); while (($folder_tag = $this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERTYPE) ? Horde_ActiveSync::SYNC_FOLDERTYPE : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_SYNCKEY) ? Horde_ActiveSync::SYNC_SYNCKEY : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERID) ? Horde_ActiveSync::SYNC_FOLDERID : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_SUPPORTED) ? Horde_ActiveSync::SYNC_SUPPORTED : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_DELETESASMOVES) ? Horde_ActiveSync::SYNC_DELETESASMOVES : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_GETCHANGES) ? Horde_ActiveSync::SYNC_GETCHANGES : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_WINDOWSIZE) ? Horde_ActiveSync::SYNC_WINDOWSIZE : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_CONVERSATIONMODE) ? Horde_ActiveSync::SYNC_CONVERSATIONMODE : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_OPTIONS) ? Horde_ActiveSync::SYNC_OPTIONS : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_COMMANDS) ? Horde_ActiveSync::SYNC_COMMANDS : -1)))))))))) != -1) { switch ($folder_tag) { case Horde_ActiveSync::SYNC_FOLDERTYPE: // According to docs, in 12.1 this is sent here, in > 12.1 // it is NOT sent here, it is sent in the ADD command ONLY. // BUT, I haven't seen any 12.1 client actually send this. // Only < 12.1 - leave version sniffing out in this case. $collection['class'] = $this->_decoder->getElementContent(); if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol error'); } break; case Horde_ActiveSync::SYNC_SYNCKEY: $collection['synckey'] = $this->_decoder->getElementContent(); if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol error'); } break; case Horde_ActiveSync::SYNC_FOLDERID: $collection['id'] = $this->_decoder->getElementContent(); if ($collection['id'] === false) { // Log this case explicitly since we can't send back // a protocol error status (the response requires a // collection id and we obviously don't have one). $this->_logger->err(sprintf('[%s] PROTOCOL ERROR. Client sent an empty SYNC_FOLDERID value.', $this->_procid)); throw new Horde_ActiveSync_Exception('Protocol error'); } if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol error'); } break; case Horde_ActiveSync::SYNC_WINDOWSIZE: $collection['windowsize'] = $this->_decoder->getElementContent(); if (!$this->_decoder->getElementEndTag()) { $this->_statusCode = self::STATUS_PROTERROR; $this->_handleError($collection); return false; } if ($collection['windowsize'] < 1 || $collection['windowsize'] > self::MAX_WINDOW_SIZE) { $this->_logger->err(sprintf('[%s] Bad windowsize sent, defaulting to 512', $this->_procid)); $collection['windowsize'] = self::MAX_WINDOW_SIZE; } break; case Horde_ActiveSync::SYNC_CONVERSATIONMODE: // Optional element, but if it's present with an empty value // it defaults to true. $collection['conversationmode'] = $this->_decoder->getElementContent(); if ($collection['conversationmode'] !== false && !$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } elseif ($collection['conversationmode'] === false) { $collection['conversationmode'] = true; } break; case Horde_ActiveSync::SYNC_SUPPORTED: // Only allowed on initial sync request if ($collection['synckey'] != '0') { $this->_statusCode = self::STATUS_PROTERROR; $this->_handleError($collection); return false; } while (1) { $el = $this->_decoder->getElement(); if ($el[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) { break; } $collection['supported'][] = $el[2]; } if (!empty($collection['supported'])) { // Initial sync and we have SUPPORTED data - save it if (empty($this->_device->supported)) { $this->_device->supported = array(); } // Not all clients send the $collection['class'] in more // recent EAS versions. Grab it from the collection // handler if needed. if (empty($collection['class'])) { $collection['class'] = $this->_collections->getCollectionClass($collection['id']); } $this->_device->supported[$collection['class']] = $collection['supported']; $this->_device->save(); } break; case Horde_ActiveSync::SYNC_DELETESASMOVES: // Optional element, but if it's present with an empty value // it defaults to true. $collection['deletesasmoves'] = $this->_decoder->getElementContent(); if ($collection['deletesasmoves'] !== false && !$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } elseif ($collection['deletesasmoves'] === false) { $collection['deletesasmoves'] = true; } break; case Horde_ActiveSync::SYNC_GETCHANGES: // Optional element, but if it's present with an empty value // it defaults to true. Also, not sent by EAS 14 $collection['getchanges'] = $this->_decoder->getElementContent(); if ($collection['getchanges'] !== false && !$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } elseif ($collection['getchanges'] === false) { $collection['getchanges'] = true; } break; case Horde_ActiveSync::SYNC_OPTIONS: if (!$this->_decoder->isEmptyElement($this->_decoder->getLastStartElement())) { $this->_parseSyncOptions($collection); } break; case Horde_ActiveSync::SYNC_COMMANDS: if (!$this->_parseSyncCommands($collection)) { return false; } } } if (!$this->_decoder->getElementEndTag()) { $this->_statusCode = self::STATUS_PROTERROR; $this->_handleError($collection); return false; } if (isset($collection['filtertype']) && !$this->_collections->checkFilterType($collection['id'], $collection['filtertype'])) { $this->_logger->info(sprintf('[%s] Found updated filtertype, will force a SOFTDELETE.', $this->_procid)); $collection['forcerefresh'] = true; } try { $this->_collections->addCollection($collection); } catch (Horde_ActiveSync_Exception_StateGone $e) { $this->_statusCode = self::STATUS_FOLDERSYNC_REQUIRED; $this->_handleError($collection); return false; } catch (Horde_ActiveSync_Exception $e) { $this->_statusCode = self::STATUS_SERVERERROR; $this->_handleError($collection); return false; } if (!empty($collection['importedchanges'])) { $this->_collections->importedChanges = true; } if ($this->_collections->collectionExists($collection['id']) && !empty($collection['windowsize'])) { $this->_collections->updateWindowSize($collection['id'], $collection['windowsize']); } } if (!$this->_decoder->getElementEndTag()) { $this->_logger->err('Parsing Error'); return false; } return true; }