Author: Michael J Rubinsky (mrubinsk@horde.org)
Inheritance: implements IteratorAggregate
Beispiel #1
0
 /**
  * Receive, and parse, the incoming wbxml query.
  *
  * According to MS docs, OR is supported in the protocol, but will ALWAYS
  * return a searchToComplex status in Exchange 2007. Additionally, AND is
  * ONLY supported as the topmost element. No nested AND is allowed. All
  * such queries will return a searchToComplex status.
  *
  * @param boolean $subquery  Parsing a subquery.
  *
  * @return array
  */
 protected function _parseQuery($subquery = null)
 {
     $query = array();
     while (($type = $this->_decoder->getElementStartTag(self::SEARCH_AND) ? self::SEARCH_AND : ($this->_decoder->getElementStartTag(self::SEARCH_OR) ? self::SEARCH_OR : ($this->_decoder->getElementStartTag(self::SEARCH_EQUALTO) ? self::SEARCH_EQUALTO : ($this->_decoder->getElementStartTag(self::SEARCH_LESSTHAN) ? self::SEARCH_LESSTHAN : ($this->_decoder->getElementStartTag(self::SEARCH_GREATERTHAN) ? self::SEARCH_GREATERTHAN : ($this->_decoder->getElementStartTag(self::SEARCH_FREETEXT) ? self::SEARCH_FREETEXT : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERID) ? Horde_ActiveSync::SYNC_FOLDERID : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERTYPE) ? Horde_ActiveSync::SYNC_FOLDERTYPE : ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_DOCUMENTLIBRARY_LINKID) ? Horde_ActiveSync::SYNC_DOCUMENTLIBRARY_LINKID : ($this->_decoder->getElementStartTag(Horde_ActiveSync_Message_Mail::POOMMAIL_DATERECEIVED) ? Horde_ActiveSync_Message_Mail::POOMMAIL_DATERECEIVED : -1)))))))))) != -1) {
         switch ($type) {
             case self::SEARCH_AND:
             case self::SEARCH_OR:
             case self::SEARCH_EQUALTO:
             case self::SEARCH_LESSTHAN:
             case self::SEARCH_GREATERTHAN:
                 $q = array('op' => $type, 'value' => $this->_parseQuery(true));
                 if ($subquery) {
                     $query['subquery'][] = $q;
                 } else {
                     $query[] = $q;
                 }
                 $this->_decoder->getElementEndTag();
                 break;
             default:
                 if ($query[$type] = $this->_decoder->getElementContent()) {
                     if ($type == Horde_ActiveSync::SYNC_FOLDERID) {
                         $query['serverid'] = $this->_collections->getBackendIdForFolderUid($query[$type]);
                     }
                     $this->_decoder->getElementEndTag();
                 } else {
                     $this->_decoder->getElementStartTag(self::SEARCH_VALUE);
                     $query[$type] = $this->_decoder->getElementContent();
                     switch ($type) {
                         case Horde_ActiveSync_Message_Mail::POOMMAIL_DATERECEIVED:
                             $query[$type] = new Horde_Date($query[$type]);
                             break;
                     }
                     $this->_decoder->getElementEndTag();
                 }
                 break;
         }
     }
     return $query;
 }
Beispiel #2
0
 /**
  * Handle incoming SYNC nodes
  *
  * @param array $collection  The current collection array.
  *
  * @return boolean
  */
 protected function _parseSyncCommands(&$collection)
 {
     // Some broken clients send SYNC_COMMANDS with a synckey of 0.
     // This is a violation of the spec, and could lead to all kinds
     // of data integrity issues.
     if (empty($collection['synckey'])) {
         $this->_logger->warn(sprintf('[%s] Attempting a SYNC_COMMANDS, but device failed to send synckey. Ignoring.', $this->_procid));
     }
     if (empty($collection['class'])) {
         $collection['class'] = $this->_collections->getCollectionClass($collection['id']);
     }
     if (empty($collection['serverid'])) {
         try {
             $collection['serverid'] = $this->_collections->getBackendIdForFolderUid($collection['id']);
         } catch (Horde_ActiveSync_Exception $e) {
             $this->_statusCode = self::STATUS_FOLDERSYNC_REQUIRED;
             $this->_handleError($colleciton);
             return false;
         }
     }
     try {
         $this->_collections->initCollectionState($collection);
     } catch (Horde_ActiveSync_Exception_StateGone $e) {
         $this->_logger->warn(sprintf('[%s] State not found sending STATUS_KEYMISM', $this->_procid));
         $this->_statusCode = self::STATUS_KEYMISM;
         $this->_handleError($collection);
         return false;
     } catch (Horde_ActiveSync_Exception_StaleState $e) {
         $this->_logger->notice($e->getMessage());
         $this->_statusCode = self::STATUS_SERVERERROR;
         $this->_handleGlobalSyncError();
         return false;
     } catch (Horde_ActiveSync_Exception $e) {
         $this->_logger->err($e->getMessage());
         $this->_statusCode = self::STATUS_SERVERERROR;
         $this->_handleGlobalSyncError();
         return false;
     }
     // Configure importer with last state
     if (!empty($collection['synckey'])) {
         $importer = $this->_activeSync->getImporter();
         $importer->init($this->_state, $collection['id'], $collection['conflict']);
     }
     $nchanges = 0;
     while (1) {
         // SYNC_MODIFY, SYNC_REMOVE, SYNC_ADD or SYNC_FETCH
         $element = $this->_decoder->getElement();
         if ($element[Horde_ActiveSync_Wbxml::EN_TYPE] != Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
             $this->_decoder->_ungetElement($element);
             break;
         }
         $nchanges++;
         // Only sent during SYNC_MODIFY/SYNC_REMOVE/SYNC_FETCH
         if (($element[Horde_ActiveSync_Wbxml::EN_TAG] == Horde_ActiveSync::SYNC_MODIFY || $element[Horde_ActiveSync_Wbxml::EN_TAG] == Horde_ActiveSync::SYNC_REMOVE || $element[Horde_ActiveSync_Wbxml::EN_TAG] == Horde_ActiveSync::SYNC_FETCH) && $this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_SERVERENTRYID)) {
             $serverid = $this->_decoder->getElementContent();
             // Work around broken clients (Blackberry) that can send empty
             // $serverid values as a single empty <SYNC_SERVERENTRYID /> tag.
             if ($serverid !== false && !$this->_decoder->getElementEndTag()) {
                 $this->_statusCode = self::STATUS_PROTERROR;
                 $this->_handleGlobalSyncError();
                 $this->_logger->err('Parsing Error - expecting </SYNC_SERVERENTRYID>');
                 return false;
             }
         } else {
             $serverid = false;
         }
         // This tag is only sent here during > 12.1 and SYNC_ADD requests...
         // and it's not even sent by all clients. Parse it if it's there,
         // ignore it if not.
         if ($this->_activeSync->device->version > Horde_ActiveSync::VERSION_TWELVEONE && $element[Horde_ActiveSync_Wbxml::EN_TAG] == Horde_ActiveSync::SYNC_ADD && $this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERTYPE)) {
             $collection['class'] = $this->_decoder->getElementContent();
             if (!$this->_decoder->getElementEndTag()) {
                 $this->_statusCode = self::STATUS_PROTERROR;
                 $this->_handleGlobalSyncError();
                 $this->_logger->err('Parsing Error - expecting </SYNC_FOLDERTYPE>');
                 return false;
             }
         }
         // Only sent during SYNC_ADD
         if ($element[Horde_ActiveSync_Wbxml::EN_TAG] == Horde_ActiveSync::SYNC_ADD && $this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_CLIENTENTRYID)) {
             $clientid = $this->_decoder->getElementContent();
             if (!$this->_decoder->getElementEndTag()) {
                 $this->_statusCode = self::STATUS_PROTERROR;
                 $this->_handleGlobalSyncError();
                 $this->_logger->err('Parsing Error - expecting </SYNC_CLIENTENTRYID>');
                 return false;
             }
         } else {
             $clientid = false;
         }
         // Create Message object from messages passed from client.
         // Only passed during SYNC_ADD or SYNC_MODIFY
         if (($element[Horde_ActiveSync_Wbxml::EN_TAG] == Horde_ActiveSync::SYNC_ADD || $element[Horde_ActiveSync_Wbxml::EN_TAG] == Horde_ActiveSync::SYNC_MODIFY) && $this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA)) {
             switch ($collection['class']) {
                 case Horde_ActiveSync::CLASS_EMAIL:
                     $appdata = Horde_ActiveSync::messageFactory('Mail');
                     $appdata->decodeStream($this->_decoder);
                     break;
                 case Horde_ActiveSync::CLASS_CONTACTS:
                     $appdata = Horde_ActiveSync::messageFactory('Contact');
                     $appdata->decodeStream($this->_decoder);
                     break;
                 case Horde_ActiveSync::CLASS_CALENDAR:
                     $appdata = Horde_ActiveSync::messageFactory('Appointment');
                     $appdata->decodeStream($this->_decoder);
                     break;
                 case Horde_ActiveSync::CLASS_TASKS:
                     $appdata = Horde_ActiveSync::messageFactory('Task');
                     $appdata->decodeStream($this->_decoder);
                     break;
                 case Horde_ActiveSync::CLASS_NOTES:
                     $appdata = Horde_ActiveSync::messageFactory('Note');
                     $appdata->decodeStream($this->_decoder);
                     break;
                 case Horde_ActiveSync::CLASS_SMS:
                     $appdata = Horde_ActiveSync::messageFactory('Mail');
                     $appdata->decodeStream($this->_decoder);
                     break;
             }
             if (!$this->_decoder->getElementEndTag()) {
                 // End application data
                 $this->_statusCode = self::STATUS_PROTERROR;
                 $this->_handleGlobalSyncError();
                 return false;
             }
         }
         if (!empty($collection['synckey'])) {
             switch ($element[Horde_ActiveSync_Wbxml::EN_TAG]) {
                 case Horde_ActiveSync::SYNC_MODIFY:
                     if (isset($appdata)) {
                         $id = $importer->importMessageChange($serverid, $appdata, $this->_device, false);
                         if ($id && !is_array($id)) {
                             $collection['importedchanges'] = true;
                         } elseif (is_array($id)) {
                             $collection['importfailures'][$id[0]] = $id[1];
                         }
                     }
                     break;
                 case Horde_ActiveSync::SYNC_ADD:
                     if (isset($appdata)) {
                         $id = $importer->importMessageChange(false, $appdata, $this->_device, $clientid, $collection['class']);
                         if ($clientid && $id && !is_array($id)) {
                             $collection['clientids'][$clientid] = $id;
                             $collection['importedchanges'] = true;
                         } elseif (!$id || is_array($id)) {
                             $collection['clientids'][$clientid] = false;
                         }
                     }
                     break;
                 case Horde_ActiveSync::SYNC_REMOVE:
                     // Work around broken clients that send empty $serverid.
                     if ($serverid) {
                         $collection['removes'][] = $serverid;
                     }
                     break;
                 case Horde_ActiveSync::SYNC_FETCH:
                     $collection['fetchids'][] = $serverid;
                     break;
             }
         }
         if (!$this->_decoder->getElementEndTag()) {
             $this->_statusCode = self::STATUS_PROTERROR;
             $this->_handleGlobalSyncError();
             $this->_logger->err('Parsing error');
             return false;
         }
     }
     // Do all the SYNC_REMOVE requests at once
     if (!empty($collection['removes']) && !empty($collection['synckey'])) {
         if (!empty($collection['deletesasmoves']) && ($folderid = $this->_driver->getWasteBasket($collection['class']))) {
             $results = $importer->importMessageMove($collection['removes'], $folderid);
         } else {
             $results = $importer->importMessageDeletion($collection['removes'], $collection['class']);
             if (is_array($results)) {
                 $results['results'] = $results;
                 $results['missing'] = array_diff($collection['removes'], $results['results']);
             }
         }
         if (!empty($results['missing'])) {
             $collection['missing'] = $results['missing'];
         }
         unset($collection['removes']);
         $collection['importedchanges'] = true;
     }
     $this->_logger->info(sprintf('[%s] Processed %d incoming changes', $this->_procid, $nchanges));
     if (!$this->_decoder->getElementEndTag()) {
         // end commands
         $this->_statusCode = self::STATUS_PROTERROR;
         $this->_handleGlobalSyncError();
         $this->_logger->err('PARSING ERROR');
         return false;
     }
     return true;
 }