SQL update script must be run. It's necessary to force the device to refresh - sorry, Jan ;).
You might be able to get away with only refreshing one collection (like calendars), or even just
pretend to edit the account settings and re-save them (which usually produces a foldersync request).
Alternatively, you can manually add the username/device mapping if it's known to the users table,
and add the username to the other new username fields in the map table and state table.
to the database tables if they are known.
throw new Horde_ActiveSync_Exception('Device failed to send device id.');
}
$state = $this->_driver->getStateObject();
- if (!empty($devId) && !$state->deviceExists($devId)) {
+ if (!empty($devId) && !$state->deviceExists($devId, $this->_driver->getUser())) {
$get = $this->_request->getGetParams();
$device = new StdClass();
$device->userAgent = $this->_request->getHeader('User-Agent');
$device->user = $this->_driver->getUser();
$device->id = $devId;
$state->setDeviceInfo($device);
+ } elseif (!empty($devId)) {
+ // @TODO: Check if the empty check is necessary
+ $device = $state->getDeviceInfo($devId, $this->_driver->getUser());
}
/* Load the request handler to handle the request */
$this->_encoder,
$this->_request,
$this,
- $devId,
+ $device,
$this->_provisioning);
$request->setLogger($this->_logger);
* @param string $id The server's uid for the message if this is a
* change to an existing message.
* @param Horde_ActiveSync_Message_Base $message The activesync message
- * @param stdClass $device The device information
+ * @param object $device The device information
*
* @see framework/ActiveSync/lib/Horde/ActiveSync/Driver/Horde_ActiveSync_Driver_Base#changeMessage($folderid, $id, $message)
*/
Horde_ActiveSync_Wbxml_Encoder $encoder,
Horde_Controller_Request_Http $request,
Horde_ActiveSync $as,
- $devId,
+ $device,
$provisioning)
{
/* Backend driver */
$this->_state = &$driver->getStateObject();
/* Device info */
- $this->_device = $this->_state->getDeviceInfo($devId);
+ $this->_device = $device;
}
/**
* header - which is against the specification. Check the user agent
* for Android (maybe need version sniffing in the future) and set the
* policykey to null for those devices. */
- $this->_device = $this->_state->getDeviceInfo($this->_device->id);
+ $this->_device = $this->_state->getDeviceInfo($this->_device->id, $this->_driver->getUser());
if (strpos($this->_device->userAgent, 'Android') !== false) {
$sentKey = null;
}
/* Initialize the state machine */
$this->_state = &$this->_driver->getStateObject();
- $this->_state->getDeviceInfo($this->_device->id);
+ $this->_state->getDeviceInfo($this->_device->id, $this->_driver->getUser());
/* See if we have an existing PING state. Need to do this here, before
* we read in the PING request since the PING request is allowed to omit
* sections if they have been sent previously */
- $collections = array_values($this->_state->initPingState($this->_device->id));
+ $collections = array_values($this->_state->initPingState($this->_device));
$lifetime = $this->_checkHeartbeat($this->_state->getHeartbeatInterval());
/* Build the $collections array if we receive request from PIM */
/**
* Device info cache
*
- * @var array
+ * @var object
*/
protected $_deviceInfo;
public function __construct($params = array())
{
$this->_params = $params;
+ if (empty($params['logger'])) {
+ $this->_logger = new Horde_Support_Stub();
+ }
}
/**
*/
public function getPolicyKey($devId)
{
- $info = $this->getDeviceInfo($devId);
- return $info->policykey;
+ //@TODO - combine _devId and _deviceInfo
+ /* See if we have it already */
+ if (empty($this->_deviceInfo) || $this->_devId != $devId) {
+ throw new Horde_ActiveSync_Exception('Device not loaded.');
+ }
+
+ return $this->_deviceInfo->policykey;
}
/**
*/
public function getDeviceRWStatus($devId)
{
- $info = $this->getDeviceInfo($devId);
- return $info->rwstatus;
+ //@TODO - combine _devId and _deviceInfo
+ /* See if we have it already */
+ if (empty($this->_deviceInfo) || $this->_devId != $devId) {
+ throw new Horde_ActiveSync_Exception('Device not loaded.');
+ }
+
+ return $this->_deviceInfo->rwstatus;
}
/**
/**
* Load/initialize the ping state for the specified device.
*
- * @param string $devId
+ * @param object $device
*/
- abstract public function initPingState($devId);
+ abstract public function initPingState($device);
/**
* Load the ping state for the given device id
abstract public function updateState($type, $change, $origin = Horde_ActiveSync::CHANGE_ORIGIN_NA);
/**
+ * Save folder data for a specific device. This is needed for BC with older
+ * activesync versions that use GETHIERARCHY requests to get the folder info
+ * instead of maintaining the folder state with FOLDERSYNC requests.
+ *
+ * @param object $device The device object
+ * @param array $folders The folder data
+ *
+ * @return boolean
+ * @throws Horde_ActiveSync_Exception
+ */
+ abstract public function setFolderData($device, $folders);
+
+ /**
+ * Get the folder data for a specific device
+ *
+ * @param object $device The device object
+ * @param string $class The folder class to fetch (Calendar, Contacts etc.)
+ *
+ * @return mixed Either an array of folder data || false
+ */
+ abstract public function getFolderData($device, $class);
+
+ /**
* Get all items that have changed since the last sync time
*
* @param integer $flags
/**
* Obtain the device object.
*
- * @param string $devId
+ * @param object $device
+ * @param string $user
*
* @return StdClass
*/
- abstract public function getDeviceInfo($devId);
+ abstract public function getDeviceInfo($device, $user);
/**
* Check that a given device id is known to the server. This is regardless
* of Provisioning status.
*
- * @param string $devId
+ * @param string $devId The device id to check
+ * @param string $user The device should be owned by this user.
*
* @return boolean
*/
- abstract public function deviceExists($devId);
+ abstract public function deviceExists($devId, $user);
/**
* Set new device info
*
- * @param string $devId The device id.
- * @param StdClass $data The device information
+ * @param object $device The device information
*
* @return boolean
*/
abstract public function listDevices();
/**
- * Get the last time a particular device issued a SYNC request.
- *
- * @param string $devId The device id
+ * Get the last time the currently loaded device issued a SYNC request.
*
* @return integer The timestamp of the last sync, regardless of collection
* @throws Horde_ActiveSync_Exception
*/
- abstract public function getLastSyncTimestamp($devId);
+ abstract public function getLastSyncTimestamp();
}
\ No newline at end of file
/**
* Obtain the device object.
*
- * @param string $devId
+ * @param string $devId The device id to obtain
+ * @param string $user The user account to use
*
- * @return StdClass
+ * @return object The device info object
+ * @throws Horde_ActiveSync_Exception
*/
- public function getDeviceInfo($devId)
+ public function getDeviceInfo($devId, $user)
{
$this->_devId = $devId;
- $file = $this->_stateDir . '/' . $this->_backend->getUser() . '/info-' . $devId;
+ $file = $this->_stateDir . '/' . $user . '/info-' . $devId;
if (file_exists($file)) {
return unserialize(file_get_contents($file));
+ } else {
+ throw new Horde_ActiveSync_Exception('Device not found.');
}
-
- /* Default structure */
- $device = new StdClass();
- $device->policykey = 0;
- $device->rwstatus = Horde_ActiveSync::RWSTATUS_NA;
- $device->deviceType = '';
- $device->userAgent = '';
- $device->id = $devId;
-
- return $device;
}
/**
* of Provisioning status.
*
* @param string $devId
+ * @param string $user
*
* @return boolean
*/
- public function deviceExists($devId)
+ public function deviceExists($devId, $user)
{
- return file_exists($this->_stateDir . '/' . $this->_backend->getUser() . '/info-' . $devId);
+ return file_exists($this->_stateDir . '/' . $user . '/info-' . $devId);
}
/**
* @return integer The timestamp of the last sync, regardless of collection
* @throws Horde_ActiveSync_Exception
*/
- public function getLastSyncTimestamp($devId)
+ public function getLastSyncTimestamp()
{
throw new Horde_ActiveSync_Exception('Not Implemented');
}
* contains the current folder state on the PIM.
* sync_devid: The device id.
* sync_folderid: The folder id for this sync.
+ * sync_user: The user for this synckey
*
* syncMapTable (horde_activesync_map):
* message_uid - The server uid for the object
* sync_key - The syncKey that was current at the time the change
* was received.
* sync_devid - The device id this change was done on.
+ * sync_user - The user that initiated the change.
*
* syncDeviceTable (horde_activesync_device:
* device_id - The unique id for this device
* device_type - The device type the PIM identifies itself with
* device_agent - The user agent string sent by the device
- * device_ping - The device's current PING state information.
* device_policykey - The current policykey for this device
* device_rwstatus - The current remote wipe status for this device
- * device_user - The user this device belongs to.
+ *
+ * syncUsersTable (horde_activesync_device_users:
+ * device_user
+ * device_id
+ * device_ping
+ * device_folders
* </pre>
*
* Copyright 2010 The Horde Project (http://www.horde.org)
protected $_syncStateTable;
protected $_syncMapTable;
protected $_syncDeviceTable;
+ protected $_syncUsersTable;
/**
* Const'r
* 'syncMapTable' - Name of table for remembering what changes
* are due to PIM import so we don't mirror the
* changes back to the PIM on next Sync
+ * 'syncUsersTable' - Name of table for mapping users to devices.
*
* @return Horde_ActiveSync_StateMachine_File
*/
$this->_syncStateTable = $params['statetable'];
$this->_syncMapTable = $params['maptable'];
$this->_syncDeviceTable = $params['devicetable'];
+ $this->_syncUsersTable = $params['userstable'];
$this->_db = $params['db'];
}
/* Update state table to remember this last synctime and key */
$sql = 'INSERT INTO ' . $this->_syncStateTable
- . ' (sync_key, sync_data, sync_devid, sync_time, sync_folderid) VALUES (?, ?, ?, ?, ?)';
+ . ' (sync_key, sync_data, sync_devid, sync_time, sync_folderid, sync_user) VALUES (?, ?, ?, ?, ?, ?)';
/* Remember any left over changes */
if ($this->_type == 'foldersync') {
$data,
$this->_devId,
$this->_thisSyncTS,
- !empty($this->_collection['id']) ? $this->_collection['id'] : 'foldersync');
+ !empty($this->_collection['id']) ? $this->_collection['id'] : 'foldersync',
+ $this->_deviceInfo->user);
try {
$this->_db->insert($sql, $params);
} catch (Horde_Db_Exception $e) {
* activesync versions that use GETHIERARCHY requests to get the folder info
* instead of maintaining the folder state with FOLDERSYNC requests.
*
- * @param string $devId The device Id
- * @param array $folders The folder data
+ * @param object $device The device object
+ * @param array $folders The folder data
*
* @return boolean
* @throws Horde_ActiveSync_Exception
*/
- public function setFolderData($devId, $folders)
+ public function setFolderData($device, $folders)
{
if (!is_array($folders) || empty ($folders)) {
return false;
$unique_folders[Horde_ActiveSync::FOLDER_TYPE_CONTACT] = Horde_ActiveSync::FOLDER_TYPE_DUMMY;
}
- /* Storage to SQL? */
- $sql = 'UPDATE ' . $this->_syncDeviceTable . ' SET device_folders = ? WHERE device_id = ?';
+ /* Store it*/
+ $sql = 'UPDATE ' . $this->_syncUsersTable . ' SET device_folders = ? WHERE device_id = ? AND device_user = ?';
try {
- return $this->_db->update($sql, array(serialize($folders), $devId));
+ return $this->_db->update($sql, array(serialize($folders), $device->id, $device->user));
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
/**
* Get the folder data for a specific device
*
- * @param string $devId The device id
- * @param string $class The folder class to fetch (Calendar, Contacts etc.)
+ * @param object $device The device object
+ * @param string $class The folder class to fetch (Calendar, Contacts etc.)
*
* @return mixed Either an array of folder data || false
*/
- public function getFolderData($devId, $class)
+ public function getFolderData($device, $class)
{
- $sql = 'SELECT device_folders FROM ' . $this->_syncDeviceTable . ' WHERE device_id = ?';
+ $sql = 'SELECT device_folders FROM ' . $this->_syncUsersTable . ' WHERE device_id = ? AND device_user = ?';
try {
- $folders = $this->_db->selectValue($sql, array($devId));
+ $folders = $this->_db->selectValue($sql, array($device->id, $device->user));
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
*
* @return The $collection array
*/
- public function initPingState($devId)
+ public function initPingState($device)
{
/* This would normally already be loaded by getDeviceInfo() but we
* should verify we have the correct device loaded etc... */
- if (!isset($this->_pingState) || $this->_devId !== $devId) {
- $this->getDeviceInfo($devId);
+ if (!isset($this->_pingState) || $this->_devId !== $device->id) {
+ throw new Horde_ActiveSync_Exception('Device not loaded');
}
/* Need to get the last sync time for this collection */
* Obtain the device object. For this driver, we also store the PING data
* in the device table.
*
- * @param string $devId
+ * @param string $devId The device id to obtain
+ * @param string $user The user to retrieve user-specific device info for
*
- * @return StdClass
+ * @return object The device obejct
+ * @throws Horde_ActiveSync_Exception
*/
- public function getDeviceInfo($devId)
+ public function getDeviceInfo($devId, $user)
{
+ //@TODO - combine _devId and _deviceInfo
/* See if we have it already */
if ($this->_devId == $devId && !empty($this->_deviceInfo)) {
return $this->_deviceInfo;
}
$this->_devId = $devId;
- $query = 'SELECT device_type, device_agent, device_ping, device_policykey, device_rwstatus, device_user, device_supported FROM '
- . $this->_syncDeviceTable . ' WHERE device_id = ?';
+ $query = 'SELECT device_type, device_agent, device_ping, device_policykey, device_rwstatus, device_supported FROM '
+ . $this->_syncDeviceTable . ' d INNER JOIN ' . $this->_syncUsersTable . ' u ON d.device_id = u.device_id WHERE u.device_id = ? AND u.device_user = ?';
try {
- $result = $this->_db->selectOne($query, array($devId));
+ $this->_logger->debug('SQL QUERY: ' . $query . ' VALUES: ' . $devId . ' ' . $user);
+ $result = $this->_db->selectOne($query, array($devId, $user));
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
$this->_deviceInfo->deviceType = $result['device_type'];
$this->_deviceInfo->userAgent = $result['device_agent'];
$this->_deviceInfo->id = $devId;
- $this->_deviceInfo->user = $result['device_user'];
+ $this->_deviceInfo->user = $user;
$this->_deviceInfo->supported = unserialize($result['device_supported']);
if ($result['device_ping']) {
$this->_pingState = empty($result['device_ping']) ? array() : unserialize($result['device_ping']);
$this->resetPingState();
}
} else {
- /* Default structure */
- $this->_deviceInfo->policykey = 0;
- $this->_deviceInfo->rwstatus = Horde_ActiveSync::RWSTATUS_NA;
- $this->_deviceInfo->deviceType = '';
- $this->_deviceInfo->userAgent = '';
- $this->_deviceInfo->id = $devId;
- $this->_deviceInfo->user = $this->_backend->getUser();
- $this->setDeviceInfo($this->_deviceInfo);
- $this->resetPingState();
+ throw new Horde_ActiveSync_Exception('Device not found.');
}
return $this->_deviceInfo;
/**
* Set new device info
*
- * @param StdClass $data The device information
+ * @param object $data The device information
*
* @return boolean
*/
public function setDeviceInfo($data)
{
- /* Delete the old entry, just in case */
- $this->_deviceInfo = $data;
+ /* Make sure we have the device entry */
try {
- $query = 'DELETE FROM ' . $this->_syncDeviceTable . ' WHERE device_id = ?';
- $this->_db->execute($query, array($data->id));
-
- $query = 'INSERT INTO ' . $this->_syncDeviceTable
- . '(device_type, device_agent, device_ping, device_policykey, device_rwstatus, device_id, device_user, device_supported)'
- . ' VALUES(?, ?, ?, ?, ?, ?, ?, ?)';
-
- $values = array($data->deviceType,
- $data->userAgent,
- '',
- $data->policykey,
- $data->rwstatus,
- $data->id,
- $data->user,
- (!empty($data->supported) ? serialize($data->supported) : ''));
+ if (!$this->deviceExists($data->id)) {
+ $this->_logger->debug('[' . $data->id . '] Device entry does not exist, creating it.');
+ $query = 'INSERT INTO ' . $this->_syncDeviceTable
+ . ' (device_type, device_agent, device_policykey, device_rwstatus, device_id, device_supported)'
+ . ' VALUES(?, ?, ?, ?, ?, ?)';
+ $values = array(
+ $data->deviceType,
+ $data->userAgent,
+ $data->policykey,
+ $data->rwstatus,
+ $data->id,
+ (!empty($data->supported) ? serialize($data->supported) : '')
+ );
+ $this->_db->execute($query, $values);
+ }
+ } catch(Horde_Db_Exception $e) {
+ throw new Horde_ActiveSync_Exception($e);
+ }
- $this->_devId = $data->id;
+ $this->_deviceInfo = $data;
- return $this->_db->insert($query, $values);
+ /* See if we have the user already also */
+ try {
+ $query = 'SELECT COUNT(*) FROM ' . $this->_syncUsersTable . ' WHERE device_id = ? AND device_user = ?';
+ $cnt = $this->_db->selectValue($query, array($data->id, $data->user));
+ if (!$cnt) {
+ $this->_logger->debug('[' . $data->id . '] Device entry does not exist for user ' . $data->user . ', creating it.');
+ $query = 'INSERT INTO ' . $this->_syncUsersTable
+ . ' (device_ping, device_id, device_user)'
+ . ' VALUES(?, ?, ?)';
+
+ $values = array(
+ '',
+ $data->id,
+ $data->user
+ );
+ $this->_devId = $data->id;
+ return $this->_db->insert($query, $values);
+ } else {
+ return true;
+ }
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
/**
* Check that a given device id is known to the server. This is regardless
- * of Provisioning status.
+ * of Provisioning status. If $user is provided, checks that the device
+ * is attached to the provided username.
*
- * @param string $devId
+ * @param string $devId The device id to check.
+ * @param string $user The device should be owned by this user.
*
* @return boolean
*/
- public function deviceExists($devId)
+ public function deviceExists($devId, $user = null)
{
- $query = 'SELECT COUNT(*) FROM ' . $this->_syncDeviceTable . ' WHERE device_id = ?';
+ if (!empty($user)) {
+ $query = 'SELECT COUNT(*) FROM ' . $this->_syncDeviceTable . ' d INNER JOIN '
+ . $this->_syncUsersTable . ' u ON d.device_id = u.device_id WHERE '
+ . ' d.device_id = ? AND u.device_user = ?';
+ $values = array($devId, $user);
+ } else {
+ $query = 'SELECT COUNT(*) FROM ' . $this->_syncDeviceTable . ' WHERE device_id = ?';
+ $values = array($devId);
+ }
try {
- return $this->_db->selectValue($query, array($devId));
+ return $this->_db->selectValue($query, $values);
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
*/
public function listDevices($user = null)
{
- $sql = 'SELECT * from ' . $this->_syncDeviceTable;
- $values = array();
- if ($user) {
- $sql .= ' WHERE device_user = ?';
- $values[] = $user;
+ if (!empty($user)) {
+ $query = 'SELECT d.device_id device_id, device_type, device_agent,'
+ . ' device_policykey, device_rwstatus, device_user FROM '
+ . $this->_syncDeviceTable . ' d INNER JOIN ' . $this->_syncUsersTable
+ . ' u ON d.device_id = u.device_id WHERE u.device_user = ?';
+ $values = array($user);
+ } else {
+ $query = 'SELECT * from ' . $this->_syncDeviceTable;
+ $values = array();
}
try {
- return $this->_db->selectAll($sql, $values);
+ return $this->_db->selectAll($query, $values);
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
}
/**
- * Get the last time a particular device issued a SYNC request.
- *
- * @param string $devId The device id
+ * Get the last time the loaded device issued a SYNC request.
*
* @return integer The timestamp of the last sync, regardless of collection
* @throws Horde_ActiveSync_Exception
*/
- public function getLastSyncTimestamp($devId)
+ public function getLastSyncTimestamp()
{
- $sql = 'SELECT sync_time FROM ' . $this->_syncStateTable . ' WHERE sync_devid = ?';
+ if (empty($this->_deviceInfo)) {
+ throw new Horde_ActiveSync_Exception('Device not loaded.');
+ }
+
+ $sql = 'SELECT MAX(sync_time) FROM ' . $this->_syncStateTable . ' WHERE sync_devid = ? AND sync_user = ?';
try {
- return $this->_db->selectValue($sql, array($devId));
+ return $this->_db->selectValue($sql, array($this->_devId, $this->_deviceInfo->user));
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
}
$state = serialize(array('lifetime' => $this->_pingState['lifetime'], 'collections' => $this->_pingState['collections']));
- $query = 'UPDATE ' . $this->_syncDeviceTable . ' SET device_ping = ? WHERE device_id = ?';
+ $query = 'UPDATE ' . $this->_syncUsersTable . ' SET device_ping = ? WHERE device_id = ? AND device_user = ?';
try {
- return $this->_db->update($query, array($state, $this->_devId));
+ return $this->_db->update($query, array($state, $this->_devId, $this->_deviceInfo->user));
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
*/
public function setPolicyKey($devId, $key)
{
- if (empty($this->_deviceInfo)) {
- $this->getDeviceInfo($devId);
+ if (empty($this->_deviceInfo) || $devId != $this->_deviceInfo->id) {
+ throw new Horde_ActiveSync_Exception('Device not loaded');
}
$query = 'UPDATE ' . $this->_syncDeviceTable . ' SET device_policykey = ? WHERE device_id = ?';
*/
public function setDeviceRWStatus($devId, $status)
{
- if (empty($this->_deviceInfo)) {
- $this->getDeviceInfo($devId);
+ if (empty($this->_deviceInfo) || $devId != $this->_deviceInfo->id) {
+ throw new Horde_ActiveSync_Exception('Device not loaded');
}
$query = 'UPDATE ' . $this->_syncDeviceTable . ' SET device_rwstatus = ?';
$values = array($status);
if ($status == Horde_ActiveSync::RWSTATUS_PENDING) {
- /* Need to clear the policykey to force a provision */
+ /* Need to clear the policykey to force a PROVISION */
$query .= ',device_policykey = ?';
$values[] = 0;
}
* Explicitly remove a state from storage.
*
* @param string $synckey The specific state to remove
- * @param string $devId Remove all information for this device (ignores synckey)
+ * @param string $devId Remove all information for this device.
+ * @param string $user When removing device info, restrict to removing
+ * data for this user only.
*
* @throws Horde_ActiveSyncException
*/
- public function removeState($synckey = null, $devId = null)
+ public function removeState($synckey = null, $devId = null, $user = null)
{
$state_query = 'DELETE FROM ' . $this->_syncStateTable . ' WHERE';
$map_query = 'DELETE FROM ' . $this->_syncMapTable . ' WHERE';
- if ($devId) {
+ if ($devId && $user) {
+ $state_query .= ' sync_devid = ? AND sync_user = ?';
+ $map_query .= ' sync_devid = ? AND sync_user = ?';
+ $user_query = 'DELETE FROM ' . $this->_syncUsersTable . ' WHERE device_id = ? AND device_user = ?';
+ $values = array($devId, $user);
+ $this->_logger->debug('[' . $devId . '] Removing device state for user ' . $user . '.');
+ } elseif ($devId){
$state_query .= ' sync_devid = ?';
$map_query .= ' sync_devid = ?';
+ $user_query = 'DELETE FROM ' . $this->_syncUsersTable . ' WHERE device_id = ?';
$device_query = 'DELETE FROM ' . $this->_syncDeviceTable . ' WHERE device_id = ?';
$values = array($devId);
- $this->_logger->debug('[' . $devId . '] Removing device state.');
+ $this->_logger->debug('[' . $devId . '] Removing device state for user ' . $user . '.');
+
} else {
$state_query .= ' sync_key = ?';
$map_query .= ' sync_key = ?';
try {
$this->_db->delete($state_query, $values);
$this->_db->delete($map_query, $values);
+ if (!empty($user_query)) {
+ $this->_db->delete($user_query, $values);
+ }
if (!empty($device_query)) {
$this->_db->delete($device_query, $values);
+ } elseif (!empty($user_query)) {
+ /* If there was a user_deletion, check if we should remove the
+ * device entry as well */
+ $sql = 'SELECT COUNT(*) FROM ' . $this->_syncUsersTable . ' WHERE device_id = ?';
+ if (!$this->_db->selectValue($sql, array($devId))) {
+ $query = 'DELETE FROM ' . $this->_syncDeviceTable . ' WHERE device_id = ?';
+ $this->_db->delete($query, array($devId));
+ }
}
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
*/
protected function _getPIMChangeTS($uid)
{
- $sql = 'SELECT sync_modtime FROM ' . $this->_syncMapTable . ' WHERE message_uid = ? AND sync_devid = ?';
+ $sql = 'SELECT sync_modtime FROM ' . $this->_syncMapTable . ' WHERE message_uid = ? AND sync_devid = ? AND sync_user = ?';
try {
- return $this->_db->selectValue($sql, array($uid, $this->_devId));
+ return $this->_db->selectValue($sql, array($uid, $this->_devId, $this->_deviceInfo->user));
} catch (Horde_Db_Exception $e) {
throw new Horde_ActiveSync_Exception($e);
}
/**
* Check for the existence of ANY entries in the map table for this device.
* An extra database query for each sync, but the payoff is that we avoid
- * having to state every message change we send to the PIM if there are no
+ * having to stat every message change we send to the PIM if there are no
* PIM generated changes for this sync period.
*
* @return boolean
/* Fixtures - don't really need data, since the change is not actually done */
$message = new Horde_ActiveSync_Message_Contact();
+ /* Mock device object */
+ $device = new stdClass();
+ $device->supported = array();
+
/* Try adding a new contact */
try {
- $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER, 0, $message);
+ $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER, 0, $message, $device);
} catch (Horde_ActiveSync_Exception $e) {
$this->fail($e->getMessage());
}
/* Try editing a contact */
try {
- $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER, 'localhost@123.123', $message);
+ $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER, 'localhost@123.123', $message, $device);
} catch (Horde_ActiveSync_Exception $e) {
$this->fail($e->getMessage());
}
/* Try adding a new appointment */
$message = new Horde_ActiveSync_Message_Appointment();
try {
- $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::APPOINTMENTS_FOLDER, 0, $message);
+ $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::APPOINTMENTS_FOLDER, 0, $message, $device);
} catch (Horde_ActiveSync_Exception $e) {
$this->fail($e->getMessage());
}
/* Try editing an appointment */
try {
- $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::APPOINTMENTS_FOLDER, 'localhost@123.123', $message);
+ $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::APPOINTMENTS_FOLDER, 'localhost@123.123', $message, $device);
} catch (Horde_ActiveSync_Exception $e) {
$this->fail($e->getMessage());
}
/* Try adding a new task */
$message = new Horde_ActiveSync_Message_Task();
try {
- $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::TASKS_FOLDER, 0, $message);
+ $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::TASKS_FOLDER, 0, $message, $device);
} catch (Horde_ActiveSync_Exception $e) {
$this->fail($e->getMessage());
}
/* Try editing an appointment */
try {
- $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::TASKS_FOLDER, 'localhost@123.123', $message);
+ $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::TASKS_FOLDER, 'localhost@123.123', $message, $device);
} catch (Horde_ActiveSync_Exception $e) {
$this->fail($e->getMessage());
}
data:">horde_activesync_state</configstring>
<configstring name="maptable" desc="Name of table to hold mapping data
for device-sent changes.">horde_activesync_map</configstring>
+ <configstring name="userstable" desc="Name of table to hold user-device
+ data:">horde_activesync_device_users</configstring>
</configsection>
</case>
<case name="file" desc="Generic file based driver">
$t->setOption('gettext', true);
$selfurl = $ui->selfUrl();
$t->set('reset', $selfurl->copy()->add('reset', 1));
+ $t->set('username', Horde_Auth::getAuth());
$devices = $stateMachine->listDevices(Horde_Auth::getAuth());
$devs = array();
$i = 1;
foreach ($devices as $device) {
$device['class'] = fmod($i++, 2) ? 'rowOdd' : 'rowEven';
- $ts = $stateMachine->getLastSyncTimestamp($device['device_id']);
+ $stateMachine->getDeviceInfo($device['device_id'], Horde_Auth::getAuth());
+ $ts = $stateMachine->getLastSyncTimestamp();
$device['ts'] = empty($ts) ? _("None") : strftime($GLOBALS['prefs']->getValue('date_format') . ' %H:%M', $ts);
switch ($device['device_rwstatus']) {
case Horde_ActiveSync::RWSTATUS_PENDING:
} elseif ($ui->vars->reset) {
$devices = $stateMachine->listDevices(Horde_Auth::getAuth());
foreach ($devices as $device) {
- $stateMachine->removeState(null, $device['device_id']);
+ $stateMachine->removeState(null, $device['device_id'], $ui->vars->removeuser);
}
$GLOBALS['notification']->push(_("All state removed for your devices. They will resynchronize next time they connect to the server."));
} elseif ($ui->vars->removedevice) {
- $stateMachine->removeState(null, $ui->vars->removedevice);
+ $stateMachine->removeState(null, $ui->vars->removedevice, $ui->vars->removeuser);
}
}
sync_data TEXT,
sync_devid VARCHAR(255),
sync_folderid VARCHAR(255),
+ sync_user VARCHAR(255) NOT NULL,
--
PRIMARY KEY (sync_key)
);
sync_modtime INT,
sync_key VARCHAR(255) NOT NULL,
sync_devid VARCHAR(255) NOT NULL,
- sync_folderid VARCHAR(255) NOT NULL
+ sync_folderid VARCHAR(255) NOT NULL,
+ sync_user VARCHAR(255) NOT NULL
);
GO
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
CREATE INDEX activesync_map_devid_idx ON horde_activesync_map (sync_devid);
CREATE INDEX activesync_map_message_idx ON horde_activesync_map (message_uid);
GO
device_id VARCHAR(255) NOT NULL,
device_type VARCHAR(255) NOT NULL,
device_agent VARCHAR(255) NOT NULL,
- device_ping TEXT,
device_supported TEXT,
device_policykey BIGINT DEFAULT 0,
device_rwstatus INT,
- device_folders TEXT,
- device_user VARCHAR(255),
-
--
PRIMARY KEY (device_id)
);
GO
-CREATE INDEX activesync_device_user_idx ON horde_activesync_device (device_user);
+CREATE TABLE horde_activesync_device_users (
+ device_id VARCHAR(255) NOT NULL,
+ device_user VARCHAR(255) NOT NULL,
+ device_ping TEXT,
+ device_folders TEXT,
+--
+ PRIMARY KEY (device_id, device_user)
+);
GO
+
+CREATE INDEX activesync_device_users_idx ON horde_activesync_device_users (device_user);
+GO
\ No newline at end of file
sync_data TEXT,
sync_devid VARCHAR(255),
sync_folderid VARCHAR(255),
+ sync_user VARCHAR(255) NOT NULL,
--
PRIMARY KEY (sync_key)
);
sync_modtime INTEGER,
sync_key VARCHAR(255) NOT NULL,
sync_devid VARCHAR(255) NOT NULL,
- sync_folderid VARCHAR(255) NOT NULL
+ sync_folderid VARCHAR(255) NOT NULL,
+ sync_user VARCHAR(255) NOT NULL
);
CREATE INDEX activesync_map_devid_idx ON horde_activesync_map (sync_devid);
CREATE INDEX activesync_map_message_idx ON horde_activesync_map (message_uid);
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
+
CREATE TABLE horde_activesync_device (
device_id VARCHAR(255) NOT NULL,
device_type VARCHAR(255) NOT NULL,
device_agent VARCHAR(255) NOT NULL,
- device_ping TEXT,
device_supported TEXT,
device_policykey BIGINT DEFAULT 0,
device_rwstatus INTEGER,
- device_folders TEXT,
- device_user VARCHAR(255),
-
--
PRIMARY KEY (device_id)
);
-CREATE INDEX activesync_device_user_idx ON horde_activesync_device (device_user);
+CREATE TABLE horde_activesync_device_users (
+ device_id VARCHAR(255) NOT NULL,
+ device_user VARCHAR(255) NOT NULL,
+ device_ping TEXT,
+ device_folders TEXT,
+--
+ PRIMARY KEY (device_id, device_user)
+);
+
+CREATE INDEX activesync_device_users_idx ON horde_activesync_device_users (device_user);
-- Done.
sync_data CLOB,
sync_devid VARCHAR2(255),
sync_folderid VARCHAR2(255),
+ sync_user VARCHAR2(255) NOT NULL,
--
PRIMARY KEY (sync_key)
);
sync_modtime NUMBER(16),
sync_key VARCHAR2(255) NOT NULL,
sync_devid VARCHAR2(255) NOT NULL,
- sync_folderid VARCHAR2(255) NOT NULL
+ sync_folderid VARCHAR2(255) NOT NULL,
+ sync_user VARCHAR2(255) NOT NULL
);
CREATE INDEX activesync_map_devid_idx ON horde_activesync_map (sync_devid);
CREATE INDEX activesync_map_message_idx ON horde_activesync_map (message_uid);
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
+
CREATE TABLE horde_activesync_device (
device_id VARCHAR2(255) NOT NULL,
device_type VARCHAR2(255) NOT NULL,
device_agent VARCHAR2(255) NOT NULL,
- device_ping CLOB,
device_supported CLOB,
device_policykey NUMBER(16) DEFAULT 0,
device_rwstatus NUMBER(8),
- device_folders CLOB,
- device_user VARCHAR2(255),
--
PRIMARY KEY (device_id)
);
-CREATE INDEX activesync_device_user_idx ON horde_activesync_device (device_user);
+CREATE TABLE horde_activesync_device_users (
+ device_id VARCHAR2(255) NOT NULL,
+ device_user VARCHAR2(255) NOT NULL,
+ device_ping CLOB,
+ device_folders CLOB,
+--
+ PRIMARY KEY (device_id, device_user)
+);
+CREATE INDEX activesync_device_users_idx ON horde_activesync_device_users (device_user);
exit
sync_data TEXT,
sync_devid VARCHAR(255),
sync_folderid VARCHAR(255),
+ sync_user VARCHAR(255) NOT NULL,
--
PRIMARY KEY (sync_key)
);
sync_modtime INT,
sync_key VARCHAR(255) NOT NULL,
sync_devid VARCHAR(255) NOT NULL,
- sync_folderid VARCHAR(255) NOT NULL
+ sync_folderid VARCHAR(255) NOT NULL,
+ sync_user VARCHAR(255) NOT NULL
);
CREATE INDEX activesync_map_devid_idx ON horde_activesync_map (sync_devid);
CREATE INDEX activesync_map_message_idx ON horde_activesync_map (message_uid);
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
CREATE TABLE horde_activesync_device (
device_id VARCHAR(255) NOT NULL,
device_type VARCHAR(255) NOT NULL,
device_agent VARCHAR(255) NOT NULL,
- device_ping TEXT,
device_supported TEXT,
device_policykey BIGINT DEFAULT 0,
device_rwstatus INT,
- device_folders TEXT,
- device_user VARCHAR(255),
-
--
PRIMARY KEY (device_id)
);
-CREATE INDEX activesync_device_user_idx ON horde_activesync_device (device_user);
+CREATE TABLE horde_activesync_device_users (
+ device_id VARCHAR(255) NOT NULL,
+ device_user VARCHAR(255) NOT NULL,
+ device_ping TEXT,
+ device_folders TEXT,
+--
+ PRIMARY KEY (device_id, device_user)
+);
+CREATE INDEX activesync_device_users_idx ON horde_activesync_device_users (device_user);
COMMIT;
sync_data TEXT,
sync_devid VARCHAR(255),
sync_folderid VARCHAR(255),
+ sync_user VARCHAR(255) NOT NULL,
--
PRIMARY KEY (sync_key)
);
sync_modtime INTEGER,
sync_key VARCHAR(255) NOT NULL,
sync_devid VARCHAR(255) NOT NULL,
- sync_folderid VARCHAR(255) NOT NULL
+ sync_folderid VARCHAR(255) NOT NULL,
+ sync_user VARCHAR(255) NOT NULL
);
CREATE INDEX activesync_map_devid_idx ON horde_activesync_map (sync_devid);
CREATE INDEX activesync_map_message_idx ON horde_activesync_map (message_uid);
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
CREATE TABLE horde_activesync_device (
device_id VARCHAR(255) NOT NULL,
device_type VARCHAR(255) NOT NULL,
device_agent VARCHAR(255) NOT NULL,
- device_ping TEXT,
device_supported TEXT,
device_policykey BIGINT DEFAULT 0,
device_rwstatus INTEGER,
- device_folders TEXT,
- device_user VARCHAR(255),
-
--
PRIMARY KEY (device_id)
);
-CREATE INDEX activesync_device_user_idx ON horde_activesync_device (device_user);
\ No newline at end of file
+CREATE TABLE horde_activesync_device_users (
+ device_id VARCHAR(255) NOT NULL,
+ device_user VARCHAR(255) NOT NULL,
+ device_ping TEXT,
+ device_folders TEXT,
+--
+ PRIMARY KEY (device_id, device_user)
+);
+CREATE INDEX activesync_device_users_idx ON horde_activesync_device_users (device_user);
sync_data text,
sync_devid varchar(255),
sync_folderid varchar(255),
+ sync_user varchar(255),
--
PRIMARY KEY (sync_key)
);
sync_modtime numeric(10, 0),
sync_key varchar(255) NOT NULL,
sync_devid varchar(255) NOT NULL,
- sync_folderid varchar(255) NOT NULL
+ sync_folderid varchar(255) NOT NULL,
+ sync_user varchar(255)
);
go
device_id varchar(255) NOT NULL,
device_type varchar(255) NOT NULL,
device_agent varchar(255) NOT NULL,
- device_ping text,
device_supported text,
device_policykey number(11, 0) DEFAULT 0,
device_rwstatus number(10, 0),
- device_folders text,
- device_user varchar(255),
-
--
PRIMARY KEY (device_id)
);
go
+CREATE TABLE horde_activesync_device_users (
+ device_id varchar(255) NOT NULL,
+ device_user varchar(255) NOT NULL,
+ device_ping text,
+ device_folders text,
+--
+ PRIMARY KEY (device_id, device_user)
+);
+go
+
-- CREATE TABLE horde_datatree_seq (
-- id numeric(10,0) IDENTITY NOT NULL,
-- PRIMARY KEY (id)
CREATE INDEX activesync_device_user_idx ON horde_activesync_device (device_user);
go
+CREATE INDEX activesync_device_users_idx ON horde_activesync_device_users (device_user);
+go
+
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
+go
+
-- CREATE INDEX vfs_path_idx ON horde_vfs (vfs_path)
-- go
<notnull>false</notnull>
</field>
+ <field>
+ <name>sync_user</name>
+ <type>text</type>
+ <length>255</length>
+ <notnull>false</notnull>
+ </field>
+
<index>
<name>activesync_state_primary</name>
<primary>true</primary>
<notnull>false</notnull>
</field>
+ <field>
+ <name>sync_user</name>
+ <type>text</type>
+ <length>255</length>
+ <notnull>false</notnull>
+ </field>
+
<index>
<name>activesync_map_message_idx</name>
<field>
</field>
</index>
+ <index>
+ <name>activesync_map_user_idx</name>
+ <field>
+ <name>sync_user</name>
+ </field>
+ </index>
+
</declaration>
</table>
</field>
<field>
- <name>device_ping</name>
- <type>clob</type>
- <notnull>false</notnull>
- </field>
-
- <field>
<name>device_supported</name>
<type>clob</type>
<notnull>false</notnull>
<notnull>false</notnull>
</field>
+ <index>
+ <name>activesync_device_primary</name>
+ <primary>true</primary>
+ <field>
+ <name>device_id</name>
+ </field>
+ </index>
+
+ </declaration>
+
+ </table>
+
+ <table>
+
+ <name>horde_activesync_device_users</name>
+
+ <declaration>
+ <field>
+ <name>device_ping</name>
+ <type>clob</type>
+ <notnull>false</notnull>
+ </field>
+
<field>
<name>device_folders</name>
<type>clob</type>
</field>
<index>
- <name>activesync_device_primary</name>
- <primary>true</primary>
- <field>
- <name>device_id</name>
- </field>
- </index>
-
- <index>
- <name>activesync_device_user_message_idx</name>
+ <name>activesync_device_user_idx</name>
<field>
<name>device_user</name>
</field>
</declaration>
</table>
-
</database>
sync_data TEXT,
sync_devid VARCHAR(255),
sync_folderid VARCHAR(255),
+ sync_user VARCHAR(255) NOT NULL,
--
PRIMARY KEY (sync_key)
);
sync_modtime INTEGER,
sync_key VARCHAR(255) NOT NULL,
sync_devid VARCHAR(255) NOT NULL,
- sync_folderid VARCHAR(255) NOT NULL
+ sync_folderid VARCHAR(255) NOT NULL,
+ sync_user VARCHAR(255) NOT NULL
);
CREATE INDEX activesync_map_devid_idx ON horde_activesync_map (sync_devid);
CREATE INDEX activesync_map_message_idx ON horde_activesync_map (message_uid);
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
+
CREATE TABLE horde_activesync_device (
device_id VARCHAR(255) NOT NULL,
device_type VARCHAR(255) NOT NULL,
device_agent VARCHAR(255) NOT NULL,
- device_ping TEXT,
device_supported TEXT,
device_policykey BIGINT DEFAULT 0,
device_rwstatus INTEGER,
- device_folders TEXT,
- device_user VARCHAR(255),
-
--
PRIMARY KEY (device_id)
);
-CREATE INDEX activesync_device_user_idx ON horde_activesync_device (device_user);
+CREATE TABLE horde_activesync_device_users (
+ device_id VARCHAR(255) NOT NULL,
+ device_user VARCHAR(255) NOT NULL,
+ device_ping TEXT,
+ device_folders TEXT,
+--
+ PRIMARY KEY (device_id, device_user)
+);
+
+CREATE INDEX activesync_device_user_idx ON horde_activesync_users (device_user);
--- /dev/null
+ALTER TABLE horde_activesync_state ADD COLUMN sync_user VARCHAR(255);
+
+ALTER TABLE horde_activesync_device DROP COLUMN device_user;
+ALTER TABLE horde_activesync_device DROP COLUMN device_ping;
+ALTER TABLE horde_activesync_device DROP COLUMN device_folders;
+
+DROP INDEX activesync_device_user_idx;
+
+CREATE TABLE horde_activesync_device_users (
+ device_id VARCHAR(255) NOT NULL,
+ device_user VARCHAR(255) NOT NULL,
+ device_ping TEXT,
+ device_folders TEXT,
+--
+ PRIMARY KEY (device_id, device_user)
+);
+CREATE INDEX activesync_device_users_idx ON horde_activesync_device_users (device_user);
+
+ALTER TABLE horde_activesync_map ADD COLUMN sync_user VARCHAR(255);
+CREATE INDEX activesync_map_user_idx ON horde_activesync_map (sync_user);
+
<input type="hidden" id="removedevice" name="removedevice" />
<input type="hidden" name="wipeid" id="wipeid" />
<input type="hidden" name="cancelwipe" id="cancelwipe" />
+<input type="hidden" name="removeuser" id="removeuser" value="<tag:username />" />
<table class="horde-table striped">
<tr>
<th></th>
<if:devices.ispending>
<input class="button" type="button" value="<gettext>Cancel Wipe</gettext>" onclick="HordeActiveSyncPrefs.cancelRemoteWipe('<tag:devices.device_id />');" />
</if:devices.ispending>
- <input class="button" type="button" value="<gettext>Remove</gettext>" onclick="HordeActiveSyncPrefs.removeDevice('<tag:devices.device_id />');" />
+ <input class="button" type="button" value="<gettext>Remove</gettext>" onclick="HordeActiveSyncPrefs.removeDevice('<tag:devices.device_id />', '<tag:devices.device_user />');" />
</td>
<td><tag:devices.device_type /></td>
<td><tag:devices.ts /></td>