/** * Returns entries that have been modified in the server database. * * @param string $databaseURI URI of Database to sync. Like calendar, * tasks, contacts or notes. May include * optional parameters: * tasks?options=ignorecompleted. * @param integer $from_ts Start timestamp. * @param integer $to_ts Exclusive end timestamp. Not yet * implemented. * @param array &$adds Output array: hash of adds suid => 0 * @param array &$mods Output array: hash of modifications * suid => cuid * @param array &$dels Output array: hash of deletions suid => cuid * * @return mixed True on success or a PEAR_Error object. */ public function getServerChanges($databaseURI, $from_ts, $to_ts, &$adds, &$mods, &$dels) { $database = $this->normalize($databaseURI); $adds = $mods = $dels = array(); // Handle additions: $data = $this->_db->queryAll('SELECT syncml_id, syncml_created_ts from syncml_data ' . 'WHERE syncml_db = ' . $this->_db->quote($database, 'text') . ' AND syncml_uid = ' . $this->_db->quote($this->_user, 'text') . ' AND syncml_created_ts >= ' . $this->_db->quote($from_ts, 'integer') . ' AND syncml_created_ts < ' . $this->_db->quote($to_ts, 'integer')); if ($this->_checkForError($data)) { return $data; } foreach ($data as $d) { $suid = $d[0]; $suid_ts = $d[1]; $sync_ts = $this->_getChangeTS($databaseURI, $suid); if ($sync_ts && $sync_ts >= $suid_ts) { // Change was done by us upon request of client, don't mirror // that back to the client. $this->logMessage("Added to server from client: {$suid} ignored", 'DEBUG'); continue; } $adds[$suid] = 0; } // Only compile changes on delta sync: if ($from_ts > 0) { // Handle replaces. We might get IDs that are already in the adds // array but that's ok: The calling code takes care to ignore // these. $data = $this->_db->queryAll('SELECT syncml_id, syncml_modified_ts from syncml_data ' . 'WHERE syncml_db = ' . $this->_db->quote($database, 'text') . ' AND syncml_uid = ' . $this->_db->quote($this->_user, 'text') . ' AND syncml_modified_ts >= ' . $this->_db->quote($from_ts, 'integer') . ' AND syncml_modified_ts < ' . $this->_db->quote($to_ts, 'integer')); if ($this->_checkForError($data)) { return $data; } foreach ($data as $d) { // Only the server needs to check the change timestamp do // identify client-sent changes. if ($this->_backendMode == Horde_SyncMl_Backend::MODE_SERVER) { $suid = $d[0]; $suid_ts = $d[1]; $sync_ts = $this->_getChangeTS($databaseURI, $suid); if ($sync_ts && $sync_ts >= $suid_ts) { // Change was done by us upon request of client, don't // mirror that back to the client. $this->logMessage("Changed on server after sent from client: {$suid} ignored", 'DEBUG'); continue; } $mods[$suid] = $this->_getCuid($databaseURI, $suid); } else { $mods[$d[0]] = $d[0]; } } } // Handle deletions: // We assume stupid a backend datastore (syncml_data) where deleted // items are simply "gone" from the datastore. So we need to do our // own bookkeeping to identify entries that have been deleted since // the last sync run. // This is done by the _trackDeless() helper function: we feed it with // a current list of all suids and get the ones missing (and thus // deleted) in return. $data = $this->_db->queryCol('SELECT syncml_id from syncml_data WHERE syncml_db = ' . $this->_db->quote($database, 'text') . ' AND syncml_uid = ' . $this->_db->quote($this->_user, 'text')); if ($this->_checkForError($data)) { return $data; } // Get deleted items and store current items: // Only use the deleted information on delta sync. On initial slowsync // we just need to call _trackDeletes() once to init the list. $data = $this->_trackDeletes($databaseURI, $data); if ($this->_checkForError($data)) { return $data; } if ($from_ts > 0) { foreach ($data as $suid) { // Only the server needs to handle the cuid suid map: if ($this->_backendMode == Horde_SyncMl_Backend::MODE_SERVER) { $dels[$suid] = $this->_getCuid($databaseURI, $suid); } else { $dels[$suid] = $suid; } } } }