/**
* Handle device checks. Takes into account permissions and restrictions
* via various callback methods.
*
* @param string $devId The client provided device id.
*
* @return boolean If EAS version is > 12.1 returns false on any type of
* failure in allowing the device to connect. Sets
* appropriate internal variables to indicate the type of
* error to return to the client. Failure on EAS version
* < 12.1 results in throwing exceptions. Otherwise, return
* true.
* @throws Horde_ActiveSync_Exception, Horde_Exception_AuthenticationFailure
*/
protected function _handleDevice($devId)
{
$get = $this->getGetVars();
$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);
// Always throw exception in place of status code since we
// won't have a version number before the device is created.
throw new Horde_Exception_AuthenticationFailure($msg, $callback_ret);
} 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())) {
$this->_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);
}
}
// Save the device now that we know it is at least allowed to connect,
// or it has connected successfully at least once in the past.
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) {
// Use a status code here, since the device has already
// connected.
$this->_globalError = $callback_ret;
return false;
} else {
throw new Horde_Exception_AuthenticationFailure($msg, $callback_ret);
}
}
}
// 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;
return false;
} else {
throw new Horde_ActiveSync_Exception($msg);
}
}
return true;
}