/**
* 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;
}