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