Author: Michael J Rubinsky (mrubinsk@horde.org)
Inheritance: extends Horde_ActiveSync_Request_Base
Esempio n. 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.');
 }
Esempio n. 2
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.');
 }