Author: Michael J Rubinsky (mrubinsk@horde.org)
Inheritance: extends Horde_ActiveSync_Wbxml
Example #1
0
 /**
  * The heart of the server. Dispatch a request to the appropriate request
  * handler.
  *
  * @param string $cmd    The command we are requesting.
  * @param string $devId  The device id making the request. @deprecated
  *
  * @return string|boolean  false if failed, true if succeeded and response
  *                         content is wbxml, otherwise the
  *                         content-type string to send in the response.
  * @throws Horde_ActiveSync_Exception
  * @throws Horde_ActiveSync_Exception_InvalidRequest
  * @throws Horde_ActiveSync_PermissionDenied
  */
 public function handleRequest($cmd, $devId)
 {
     $get = $this->getGetVars();
     if (empty($cmd)) {
         $cmd = $get['Cmd'];
     }
     if (empty($devId)) {
         $devId = !empty($get['DeviceId']) ? Horde_String::upper($get['DeviceId']) : null;
     } else {
         $devId = Horde_String::upper($devId);
     }
     $this->_setLogger($get);
     // @TODO: Remove is_callable check for H6.
     // Callback to give the backend the option to limit EAS version based
     // on user/device/etc...
     if (is_callable(array($this->_driver, 'versionCallback'))) {
         $this->_driver->versionCallback($this);
     }
     // Autodiscovery handles authentication on it's own.
     if ($cmd == 'Autodiscover') {
         $request = new Horde_ActiveSync_Request_Autodiscover($this, new Horde_ActiveSync_Device($this->_state));
         if (!empty(self::$_logger)) {
             $request->setLogger(self::$_logger);
         }
         $result = $request->handle($this->_request);
         $this->_driver->clearAuthentication();
         return $result;
     }
     if (!$this->authenticate(new Horde_ActiveSync_Credentials($this))) {
         $this->activeSyncHeader();
         $this->versionHeader();
         $this->commandsHeader();
         throw new Horde_Exception_AuthenticationFailure();
     }
     self::$_logger->info(sprintf('[%s] %s request received for user %s', $this->_procid, Horde_String::upper($cmd), $this->_driver->getUser()));
     // These are all handled in the same class.
     if ($cmd == 'FolderDelete' || $cmd == 'FolderUpdate') {
         $cmd = 'FolderCreate';
     }
     // Device id is REQUIRED
     if (empty($devId)) {
         if ($cmd == 'Options') {
             $this->_doOptionsRequest();
             $this->_driver->clearAuthentication();
             return true;
         }
         $this->_driver->clearAuthentication();
         throw new Horde_ActiveSync_Exception_InvalidRequest('Device failed to send device id.');
     }
     // EAS Version
     $version = $this->getProtocolVersion();
     // Device. Even though versions of EAS > 12.1 are supposed to send
     // EAS status codes back to indicate various errors in allowing a client
     // to connect, we just throw an exception (thus causing a HTTP error
     // code to be sent as in versions 12.1 and below). Until we refactor for
     // Horde 6, we don't know the response type to wrap the status code in
     // until we load the request handler, which requires we start to parse
     // the WBXML stream and device information etc... This saves resources
     // as well as keeps things cleaner until we refactor.
     $device_result = $this->_handleDevice($devId);
     // Don't bother with everything else if all we want are Options
     if ($cmd == 'Options') {
         $this->_doOptionsRequest();
         $this->_driver->clearAuthentication();
         return true;
     }
     // Set provisioning support now that we are authenticated.
     $this->setProvisioning($this->_driver->getProvisioning(self::$_device));
     // Read the initial Wbxml header
     $this->_decoder->readWbxmlHeader();
     // Support Multipart response for ITEMOPERATIONS requests?
     $headers = $this->_request->getHeaders();
     if (!empty($headers['ms-asacceptmultipart']) && $headers['ms-asacceptmultipart'] == 'T' || !empty($get['AcceptMultiPart'])) {
         $this->_multipart = true;
         self::$_logger->info(sprintf('[%s] Requesting multipart data.', $this->_procid));
     }
     // Load the request handler to handle the request
     // We must send the EAS header here, since some requests may start
     // output and be large enough to flush the buffer (e.g., GetAttachment)
     // See Bug: 12486
     $this->activeSyncHeader();
     if ($cmd != 'GetAttachment') {
         $this->contentTypeHeader();
     }
     // Should we announce a new version is available to the client?
     if (!empty($this->_needMsRp)) {
         self::$_logger->info(sprintf('[%s] Announcing X-MS-RP to client.', $this->_procid));
         header("X-MS-RP: " . $this->getSupportedVersions());
     }
     // @TODO: Look at getting rid of having to set the version in the driver
     //        and get it from the device object for H6.
     $this->_driver->setDevice(self::$_device);
     $class = 'Horde_ActiveSync_Request_' . basename($cmd);
     if (class_exists($class)) {
         $request = new $class($this);
         $request->setLogger(self::$_logger);
         $result = $request->handle();
         self::$_logger->info(sprintf('[%s] Maximum memory usage for ActiveSync request: %d bytes.', $this->_procid, memory_get_peak_usage(true)));
         return $result;
     }
     $this->_driver->clearAuthentication();
     throw new Horde_ActiveSync_Exception_InvalidRequest(basename($cmd) . ' not supported.');
 }
Example #2
0
 /**
  * Recursively decodes the WBXML from input stream. This means that if this
  * message contains complex types (like Appointment.Recuurence for example)
  * the sub-objects are auto-instantiated and decoded as well. Places the
  * decoded objects in the local properties array.
  *
  * @param Horde_ActiveSync_Wbxml_Decoder  The stream decoder
  *
  * @throws Horde_ActiveSync_Exception
  */
 public function decodeStream(Horde_ActiveSync_Wbxml_Decoder &$decoder)
 {
     while (1) {
         $entity = $decoder->getElement();
         if ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
             if (!($entity[Horde_ActiveSync_Wbxml::EN_FLAGS] & Horde_ActiveSync_Wbxml::EN_FLAGS_CONTENT)) {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (!isset($map[self::KEY_TYPE])) {
                     $this->{$map}[self::KEY_ATTRIBUTE] = '';
                 } elseif ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                     $this->{$map}[self::KEY_ATTRIBUTE] = '';
                 }
                 continue;
             }
             // Found start tag
             if (!isset($this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]])) {
                 $this->_logger->err('Tag ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG] . ' unexpected in type XML type ' . get_class($this));
                 throw new Horde_ActiveSync_Exception('Unexpected tag');
             } else {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (isset($map[self::KEY_VALUES])) {
                     // Handle arrays of attribute values
                     while (1) {
                         if (!$decoder->getElementStartTag($map[self::KEY_VALUES])) {
                             break;
                         }
                         if (isset($map[self::KEY_TYPE])) {
                             $class = $map[self::KEY_TYPE];
                             $decoded = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $decoded->decodeStream($decoder);
                         } else {
                             $decoded = $decoder->getElementContent();
                         }
                         if (!isset($this->{$map}[self::KEY_ATTRIBUTE])) {
                             $this->{$map}[self::KEY_ATTRIBUTE] = array($decoded);
                         } else {
                             $this->{$map[self::KEY_ATTRIBUTE]}[] = $decoded;
                         }
                         if (!$decoder->getElementEndTag()) {
                             throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                         }
                     }
                     if (!$decoder->getElementEndTag()) {
                         return false;
                     }
                 } else {
                     // Handle a simple attribute value
                     if (isset($map[self::KEY_TYPE])) {
                         // Complex type, decode recursively
                         if ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                             $decoded = $this->_parseDate($decoder->getElementContent());
                             if (!$decoder->getElementEndTag()) {
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                         } elseif ($map[self::KEY_TYPE] == self::TYPE_HEX) {
                             $decoded = self::hex2bin($decoder->getElementContent());
                             if (!$decoder->getElementEndTag()) {
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                         } else {
                             $class = $map[self::KEY_TYPE];
                             $subdecoder = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             if ($subdecoder->decodeStream($decoder) === false) {
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                             $decoded = $subdecoder;
                             if (!$decoder->getElementEndTag()) {
                                 $this->_logger->err('No end tag for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                         }
                     } else {
                         // Simple type, just get content
                         $decoded = $decoder->getElementContent();
                         if ($decoded === false) {
                             $this->_logger->err('Unable to get content for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                         }
                         if (!$decoder->getElementEndTag()) {
                             $this->_logger->err('Unable to get end tag for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                             throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                         }
                     }
                     // $decoded now contains data object (or string)
                     $this->{$map}[self::KEY_ATTRIBUTE] = $decoded;
                 }
             }
         } elseif ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
             $decoder->_ungetElement($entity);
             break;
         } else {
             $this->_logger->err('Unexpected content in type');
             break;
         }
     }
 }
Example #3
0
 public function testRecurrenceDSTSwitch()
 {
     // Recurring event starts 10/1/2011 15:00:00 EDST
     $l = new Horde_Test_Log();
     $logger = $l->getLogger();
     // Test Decoding
     $stream = fopen(__DIR__ . '/fixtures/dst.wbxml', 'r+');
     $decoder = new Horde_ActiveSync_Wbxml_Decoder($stream);
     $element = $decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA);
     $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger));
     $appt->decodeStream($decoder);
     fclose($stream);
     $decoder->getElementEndTag();
     $rrule = $appt->getRecurrence();
     // Get the next recurrence, still during EDST
     $next = $rrule->nextActiveRecurrence(new Horde_Date('2011-10-15'));
     $this->assertEquals('2011-10-15 15:00:00', (string) $next->setTimezone('America/New_York'));
     // Now get an occurence after the transition to EST.
     $next = $rrule->nextActiveRecurrence(new Horde_Date('2011-12-01'));
     $this->assertEquals('2011-12-10 15:00:00', (string) $next->setTimezone('America/New_York'));
 }
Example #4
0
File: Base.php Project: horde/horde
 /**
  * Recursively decodes the WBXML from input stream. This means that if this
  * message contains complex types (like Appointment.Recuurence for example)
  * the sub-objects are auto-instantiated and decoded as well. Places the
  * decoded objects in the local properties array.
  *
  * @param Horde_ActiveSync_Wbxml_Decoder  The stream decoder
  *
  * @throws Horde_ActiveSync_Exception
  */
 public function decodeStream(Horde_ActiveSync_Wbxml_Decoder &$decoder)
 {
     while (1) {
         $entity = $decoder->getElement();
         if ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
             if (!($entity[Horde_ActiveSync_Wbxml::EN_FLAGS] & Horde_ActiveSync_Wbxml::EN_FLAGS_CONTENT)) {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (!isset($map[self::KEY_TYPE])) {
                     $this->{$map[self::KEY_ATTRIBUTE]} = '';
                 } elseif ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                     $this->{$map[self::KEY_ATTRIBUTE]} = '';
                 }
                 continue;
             }
             // Found start tag
             if (!isset($this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]])) {
                 $this->_logger->err(sprintf('Tag %s unexpected in type XML type %s.', $entity[Horde_ActiveSync_Wbxml::EN_TAG], get_class($this)));
                 throw new Horde_ActiveSync_Exception('Unexpected tag');
             } else {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (isset($map[self::KEY_VALUES])) {
                     // Handle arrays of attribute values
                     while (1) {
                         // If we can have multiple types of objects in this
                         // container, or we are parsing a NO_CONTAINER,
                         // check that we are not at the end tag of the
                         // or we have a valid start tag for the NO_CONTAINER
                         // object. If not, break out of loop.
                         if (is_array($map[self::KEY_VALUES])) {
                             $token = $decoder->peek();
                             if ($token[Horde_ActiveSync_Wbxml_Decoder::EN_TYPE] == Horde_ActiveSync_Wbxml_Decoder::EN_TYPE_ENDTAG) {
                                 break;
                             }
                         } elseif (!(isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER) && !$decoder->getElementStartTag($map[self::KEY_VALUES])) {
                             break;
                         }
                         // We know we have some valid value, parse out what
                         // it is. Either an array of (possibly varied)
                         // objects, a single object, or simple value.
                         if (is_array($map[self::KEY_VALUES])) {
                             $token = $decoder->getToken();
                             if (($idx = array_search($token[Horde_ActiveSync_Wbxml_Decoder::EN_TAG], $map[self::KEY_VALUES])) !== false) {
                                 $class = $map[self::KEY_TYPE][$idx];
                                 $decoded = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                                 $decoded->commandType = $this->commandType;
                                 $decoded->decodeStream($decoder);
                             } else {
                                 throw new Horde_ActiveSync_Exception('Error in message map configuration');
                             }
                         } elseif (isset($map[self::KEY_TYPE])) {
                             $class = $map[self::KEY_TYPE];
                             $decoded = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $decoded->commandType = $this->commandType;
                             $decoded->decodeStream($decoder);
                         } else {
                             $decoded = $decoder->getElementContent();
                         }
                         // Assign the parsed value to the mapped attribute.
                         if (!isset($this->{$map[self::KEY_ATTRIBUTE]})) {
                             $this->{$map[self::KEY_ATTRIBUTE]} = array($decoded);
                         } else {
                             $this->{$map[self::KEY_ATTRIBUTE]}[] = $decoded;
                         }
                         // Get the end tag of this attribute node.
                         if (!$decoder->getElementEndTag()) {
                             throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                         }
                         // For NO_CONTAINER attributes, need some magic to
                         // make sure we break out properly.
                         if (isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER) {
                             $e = $decoder->peek();
                             // Go back to the initial while if another block
                             // of a non-container element is found.
                             if ($e[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
                                 continue 2;
                             }
                             // Break on end tag because no other container
                             // elements block end is reached.
                             if ($e[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG || empty($e)) {
                                 break;
                             }
                         }
                     }
                     // Do not get container end tag for an array without a container
                     if (!(isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER) && !$decoder->getElementEndTag()) {
                         return false;
                     }
                 } else {
                     // Handle a simple attribute value
                     if (isset($map[self::KEY_TYPE])) {
                         if (in_array($map[self::KEY_TYPE], array(self::TYPE_DATE, self::TYPE_DATE_DASHES, self::TYPE_DATE_LOCAL))) {
                             $decoded = $this->_parseDate($decoder->getElementContent());
                         } elseif ($map[self::KEY_TYPE] == self::TYPE_HEX) {
                             $decoded = self::_hex2bin($decoder->getElementContent());
                         } else {
                             // Complex type, decode recursively
                             $class = $map[self::KEY_TYPE];
                             $subdecoder = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $subdecoder->commandType = $this->commandType;
                             $subdecoder->decodeStream($decoder);
                             $decoded = $subdecoder;
                         }
                     } else {
                         // Simple type, just get content
                         $decoded = $decoder->getElementContent();
                         if ($decoded === false) {
                             $decoded = '';
                             $this->_logger->notice(sprintf('Unable to get expected content for %s: Setting to an empty string.', $entity[Horde_ActiveSync_Wbxml::EN_TAG]));
                         }
                     }
                     if (!$decoder->getElementEndTag()) {
                         $this->_logger->err(sprintf('Unable to get end tag for %s.', $entity[Horde_ActiveSync_Wbxml::EN_TAG]));
                         throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                     }
                     $this->{$map[self::KEY_ATTRIBUTE]} = $decoded;
                 }
             }
         } elseif ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
             $decoder->_ungetElement($entity);
             break;
         } else {
             $this->_logger->err('Unexpected content in type');
             break;
         }
     }
     if (!$this->_validateDecodedValues()) {
         throw new Horde_ActiveSync_Exception(sprintf('Invalid values detected in %s.', get_class($this)));
     }
 }
Example #5
0
 /**
  * Recursively decodes the WBXML from input stream. This means that if this
  * message contains complex types (like Appointment.Recuurence for example)
  * the sub-objects are auto-instantiated and decoded as well. Places the
  * decoded objects in the local properties array.
  *
  * @param Horde_ActiveSync_Wbxml_Decoder  The stream decoder
  *
  * @throws Horde_ActiveSync_Exception
  */
 public function decodeStream(Horde_ActiveSync_Wbxml_Decoder &$decoder)
 {
     while (1) {
         $entity = $decoder->getElement();
         if ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
             if (!($entity[Horde_ActiveSync_Wbxml::EN_FLAGS] & Horde_ActiveSync_Wbxml::EN_FLAGS_CONTENT)) {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (!isset($map[self::KEY_TYPE])) {
                     $this->{$map[self::KEY_ATTRIBUTE]} = '';
                 } elseif ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                     $this->{$map[self::KEY_ATTRIBUTE]} = '';
                 }
                 continue;
             }
             // Found start tag
             if (!isset($this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]])) {
                 $this->_logger->err('Tag ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG] . ' unexpected in type XML type ' . get_class($this));
                 throw new Horde_ActiveSync_Exception('Unexpected tag');
             } else {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (isset($map[self::KEY_VALUES])) {
                     // Handle arrays of attribute values
                     while (1) {
                         //do not get start tag for an array without a container
                         if (!(isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER)) {
                             if (!$decoder->getElementStartTag($map[self::KEY_VALUES])) {
                                 break;
                             }
                         }
                         if (isset($map[self::KEY_TYPE])) {
                             $class = $map[self::KEY_TYPE];
                             $decoded = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $decoded->decodeStream($decoder);
                         } else {
                             $decoded = $decoder->getElementContent();
                         }
                         if (!isset($this->{$map[self::KEY_ATTRIBUTE]})) {
                             $this->{$map[self::KEY_ATTRIBUTE]} = array($decoded);
                         } else {
                             $this->{$map[self::KEY_ATTRIBUTE]}[] = $decoded;
                         }
                         if (!$decoder->getElementEndTag()) {
                             throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                         }
                         if (isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER) {
                             $e = $decoder->peek();
                             //go back to the initial while if another block of no container elements is found
                             if ($e[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
                                 continue 2;
                             }
                             //break on end tag because no container elements block end is reached
                             if ($e[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
                                 break;
                             }
                             if (empty($e)) {
                                 break;
                             }
                         }
                     }
                     //do not get container end tag for an array without a container
                     if (!(isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER)) {
                         if (!$decoder->getElementEndTag()) {
                             return false;
                         }
                     }
                 } else {
                     // Handle a simple attribute value
                     if (isset($map[self::KEY_TYPE])) {
                         // Complex type, decode recursively
                         if ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                             $decoded = $this->_parseDate($decoder->getElementContent());
                         } elseif ($map[self::KEY_TYPE] == self::TYPE_HEX) {
                             $decoded = self::hex2bin($decoder->getElementContent());
                         } else {
                             $class = $map[self::KEY_TYPE];
                             $subdecoder = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $subdecoder->decodeStream($decoder);
                             $decoded = $subdecoder;
                         }
                     } else {
                         // Simple type, just get content
                         $decoded = $decoder->getElementContent();
                         if ($decoded === false) {
                             $decoded = '';
                             $this->_logger->notice('Unable to get expected content for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG] . ': Setting to an empty string.');
                         }
                     }
                     if (!$decoder->getElementEndTag()) {
                         $this->_logger->err('Unable to get end tag for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                         throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                     }
                     $this->{$map[self::KEY_ATTRIBUTE]} = $decoded;
                 }
             }
         } elseif ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
             $decoder->_ungetElement($entity);
             break;
         } else {
             $this->_logger->err('Unexpected content in type');
             break;
         }
     }
 }
Example #6
0
 /**
  * The heart of the server. Dispatch a request to the appropriate request
  * handler.
  *
  * @param string $cmd    The command we are requesting.
  * @param string $devId  The device id making the request. @deprecated
  *
  * @return string|boolean  false if failed, true if succeeded and response
  *                         content is wbxml, otherwise the
  *                         content-type string to send in the response.
  * @throws Horde_ActiveSync_Exception
  * @throws Horde_ActiveSync_Exception_InvalidRequest
  * @throws Horde_ActiveSync_PermissionDenied
  */
 public function handleRequest($cmd, $devId)
 {
     $get = $this->getGetVars();
     if (empty($cmd)) {
         $cmd = $get['Cmd'];
     }
     if (empty($devId)) {
         $devId = !empty($get['DeviceId']) ? Horde_String::upper($get['DeviceId']) : null;
     } else {
         $devId = Horde_String::upper($devId);
     }
     $this->_setLogger($get);
     // @TODO: Remove is_callable check for H6.
     // Callback to give the backend the option to limit EAS version based
     // on user/device/etc...
     if (is_callable(array($this->_driver, 'versionCallback'))) {
         $this->_driver->versionCallback($this);
     }
     // Autodiscovery handles authentication on it's own.
     if ($cmd == 'Autodiscover') {
         $request = new Horde_ActiveSync_Request_Autodiscover($this, new Horde_ActiveSync_Device($this->_state));
         if (!empty(self::$_logger)) {
             $request->setLogger(self::$_logger);
         }
         $result = $request->handle($this->_request);
         $this->_driver->clearAuthentication();
         return $result;
     }
     if (!$this->authenticate(new Horde_ActiveSync_Credentials($this))) {
         $this->activeSyncHeader();
         $this->versionHeader();
         $this->commandsHeader();
         throw new Horde_Exception_AuthenticationFailure();
     }
     self::$_logger->info(sprintf('[%s] %s request received for user %s', $this->_procid, Horde_String::upper($cmd), $this->_driver->getUser()));
     // These are all handled in the same class.
     if ($cmd == 'FolderDelete' || $cmd == 'FolderUpdate') {
         $cmd = 'FolderCreate';
     }
     // Device id is REQUIRED
     if (empty($devId)) {
         if ($cmd == 'Options') {
             $this->_doOptionsRequest();
             $this->_driver->clearAuthentication();
             return true;
         }
         $this->_driver->clearAuthentication();
         throw new Horde_ActiveSync_Exception_InvalidRequest('Device failed to send device id.');
     }
     // EAS Version
     $version = $this->getProtocolVersion();
     // Does device exist AND does the user have an account on the device?
     if (!$this->_state->deviceExists($devId, $this->_driver->getUser())) {
         // Device might exist, but with a new (additional) user account
         if ($this->_state->deviceExists($devId)) {
             self::$_device = $this->_state->loadDeviceInfo($devId);
         } else {
             self::$_device = new Horde_ActiveSync_Device($this->_state);
         }
         self::$_device->policykey = 0;
         self::$_device->userAgent = $this->_request->getHeader('User-Agent');
         self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
         self::$_device->rwstatus = self::RWSTATUS_NA;
         self::$_device->user = $this->_driver->getUser();
         self::$_device->id = $devId;
         self::$_device->needsVersionUpdate($this->getSupportedVersions());
         self::$_device->version = $version;
         // @TODO: Remove is_callable check for H6.
         //        Combine this with the modifyDevice callback? Allow $device
         //        to be modified here?
         if (is_callable(array($this->_driver, 'createDeviceCallback'))) {
             $callback_ret = $this->_driver->createDeviceCallback(self::$_device);
             if ($callback_ret !== true) {
                 $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
                 self::$_logger->err($msg);
                 if ($version > self::VERSION_TWELVEONE) {
                     $this->_globalError = $callback_ret;
                 } else {
                     throw new Horde_ActiveSync_Exception($msg);
                 }
             } else {
                 // Give the driver a chance to modify device properties.
                 if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
                     self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
                 }
             }
         }
     } else {
         self::$_device = $this->_state->loadDeviceInfo($devId, $this->_driver->getUser());
         // If the device state was removed from storage, we may lose the
         // device properties, so try to repopulate what we can. userAgent
         // is ALWAYS available, so if it's missing, the state is gone.
         if (empty(self::$_device->userAgent)) {
             self::$_device->userAgent = $this->_request->getHeader('User-Agent');
             self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
             self::$_device->user = $this->_driver->getUser();
         }
         if (empty(self::$_device->version)) {
             self::$_device->version = $version;
         }
         if (self::$_device->version < $this->_maxVersion && self::$_device->needsVersionUpdate($this->getSupportedVersions())) {
             $needMsRp = true;
         }
         // Give the driver a chance to modify device properties.
         if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
             self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
         }
     }
     self::$_device->save();
     if (is_callable(array($this->_driver, 'deviceCallback'))) {
         $callback_ret = $this->_driver->deviceCallback(self::$_device);
         if ($callback_ret !== true) {
             $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
             self::$_logger->err($msg);
             if ($version > self::VERSION_TWELVEONE) {
                 $this->_globalError = $callback_ret;
             } else {
                 throw new Horde_ActiveSync_Exception($msg);
             }
         }
     }
     // Lastly, check if the device has been set to blocked.
     if (self::$_device->blocked) {
         $msg = sprintf('The device %s was blocked.', self::$_device->id);
         self::$_logger->err($msg);
         if ($version > self::VERSION_TWELVEONE) {
             $this->_globalError = Horde_ActiveSync_Status::DEVICE_BLOCKED_FOR_USER;
         } else {
             throw new Horde_ActiveSync_Exception($msg);
         }
     }
     // Don't bother with everything else if all we want are Options
     if ($cmd == 'Options') {
         $this->_doOptionsRequest();
         $this->_driver->clearAuthentication();
         return true;
     }
     // Set provisioning support now that we are authenticated.
     $this->setProvisioning($this->_driver->getProvisioning(self::$_device));
     // Read the initial Wbxml header
     $this->_decoder->readWbxmlHeader();
     // Support Multipart response for ITEMOPERATIONS requests?
     $headers = $this->_request->getHeaders();
     if (!empty($headers['ms-asacceptmultipart']) && $headers['ms-asacceptmultipart'] == 'T' || !empty($get['AcceptMultiPart'])) {
         $this->_multipart = true;
         self::$_logger->info(sprintf('[%s] Requesting multipart data.', $this->_procid));
     }
     // Load the request handler to handle the request
     // We must send the eas header here, since some requests may start
     // output and be large enough to flush the buffer (e.g., GetAttachment)
     // See Bug: 12486
     $this->activeSyncHeader();
     if ($cmd != 'GetAttachment') {
         $this->contentTypeHeader();
     }
     // Should we announce a new version is available to the client?
     if (!empty($needMsRp)) {
         self::$_logger->info(sprintf('[%s] Announcing X-MS-RP to client.', $this->_procid));
         header("X-MS-RP: " . $this->getSupportedVersions());
     }
     // @TODO: Look at getting rid of having to set the version in the driver
     //        and get it from the device object for H6.
     $this->_driver->setDevice(self::$_device);
     $class = 'Horde_ActiveSync_Request_' . basename($cmd);
     if (class_exists($class)) {
         $request = new $class($this);
         $request->setLogger(self::$_logger);
         $result = $request->handle();
         self::$_logger->info(sprintf('[%s] Maximum memory usage for ActiveSync request: %d bytes.', $this->_procid, memory_get_peak_usage(true)));
         return $result;
     }
     $this->_driver->clearAuthentication();
     throw new Horde_ActiveSync_Exception_InvalidRequest(basename($cmd) . ' not supported.');
 }