This would happen e.g., if the client failed to receive the server response
after successfully importing new messages.
abstract public isDuplicatePIMAddition ( string $id ) : string | ||
$id | string | The client id sent during message addition. |
return | string | The UID for the given clientid, null if none found. |
/** * Import a message change from the wbxml stream * * @param string|boolean $id A server message id or * false if a new message. * @param Horde_ActiveSync_Message_Base $message A message object * @param Horde_ActiveSync_Device $device A device descriptor * @param integer $clientid Client id sent from PIM * on message addition. * @param string $class The collection class (only needed for SMS). * @since 2.6.0 * * @todo Revisit passing $class for SMS. Probably pass class in the * const'r. * * @return string|array|boolean The server message id, an array containing * the serverid and failure code, or false */ public function importMessageChange($id, Horde_ActiveSync_Message_Base $message, Horde_ActiveSync_Device $device, $clientid, $class = null) { // Don't support SMS, but can't tell client that. Send back a phoney // UID for any imported SMS objects. if ($class == Horde_ActiveSync::CLASS_SMS || strpos($id, 'IGNORESMS_') === 0) { return 'IGNORESMS_' . $clientid; } // Changing an existing object if ($id && $this->_flags == Horde_ActiveSync::CONFLICT_OVERWRITE_PIM) { $conflict = $this->_isConflict(Horde_ActiveSync::CHANGE_TYPE_CHANGE, $this->_folderId, $id); if ($conflict) { $this->_logger->notice(sprintf('[%s] Conflict when updating %s, will overwrite client version on next sync.', $this->_procid, $id)); return array($id, Horde_ActiveSync_Request_Sync::STATUS_CONFLICT); } } elseif (!$id && ($uid = $this->_state->isDuplicatePIMAddition($clientid))) { // Already saw this addition, but PIM never received UID $this->_logger->notice(sprintf('[%s] Duplicate addition for %s', $this->_procid, $uid)); return $uid; } // Tell the backend about the change if (!($stat = $this->_as->driver->changeMessage($this->_folderId, $id, $message, $device))) { $this->_logger->err(sprintf('[%s] Change message failed when updating %s', $this->_procid, $id)); return $id ? array($id, Horde_ActiveSync_Request_Sync::STATUS_NOTFOUND) : array(false, Horde_ActiveSync_Request_Sync::STATUS_SERVERERROR); } $stat['serverid'] = $this->_folderId; // Record the state of the message, but only if we aren't updating // categories. @todo This should be fixed, but for now we can't // differentiate between different flag changes. Note that categories // only exists for email changes so for non email this will still // work as before. if (!array_key_exists('categories', $stat) || $stat['categories'] === false) { $this->_state->updateState($message instanceof Horde_ActiveSync_Message_Mail ? Horde_ActiveSync::CHANGE_TYPE_FLAGS : Horde_ActiveSync::CHANGE_TYPE_CHANGE, $stat, Horde_ActiveSync::CHANGE_ORIGIN_PIM, $this->_as->driver->getUser(), $clientid); } return $stat['id']; }
/** * Import a message change from the wbxml stream * * @param string|boolean $id A server message id or * false if a new message. * @param Horde_ActiveSync_Message_Base $message A message object * @param Horde_ActiveSync_Device $device A device descriptor * @param integer $clientid Client id sent from client. * on message addition. * @param string $class The collection class - needed for SMS since the * actual serverid will be for an email folder. * @since 2.6.0 * @param string $synckey The synckey currently being processed when * processing a SYNC_MODIFY command. * @since 2.31.0 * * @todo Revisit passing $class for SMS. Probably pass class in the * const'r. * * @return array|boolean A stat array, or an array containing the 'error' * key on error, or false on duplicate addition. */ public function importMessageChange($id, Horde_ActiveSync_Message_Base $message, Horde_ActiveSync_Device $device, $clientid, $class = false, $synckey = false) { // Don't support SMS, but can't tell client that. Send back a phoney // UID for any imported SMS objects. if ($class == Horde_ActiveSync::CLASS_SMS || strpos($id, 'IGNORESMS_') === 0) { return 'IGNORESMS_' . $clientid; } // Changing an existing object if ($id && $this->_flags == Horde_ActiveSync::CONFLICT_OVERWRITE_PIM) { // This is complicated by the fact that in EAS 16.0, clients // will send a CHANGE for adding/editing an exception along with // a seperate change with the entire appointment - even if nothing // else has changed. This leads to conficts (since the appointment // is marked as changed after the first edit). Sniff that out here // and prevent the conflict check for those messages. if (!$message instanceof Horde_ActiveSync_Message_Appointment && $this->_state->isDuplicatePIMChange($id, $synckey)) { $conflict = $this->_isConflict(Horde_ActiveSync::CHANGE_TYPE_CHANGE, $this->_folderId, $id); if ($conflict) { $this->_logger->notice(sprintf('[%s] Conflict when updating %s, will overwrite client version on next sync.', $this->_procid, $id)); return array($id, 'error' => array(Horde_ActiveSync_Request_Sync::STATUS_CONFLICT)); } } } elseif (!$id && ($uid = $this->_state->isDuplicatePIMAddition($clientid))) { // Already saw this addition, but client never received UID $this->_logger->notice(sprintf('[%s] Duplicate addition for %s', $this->_procid, $uid)); return $uid; } // Set the supported/ghosted data if this is a SYNC_MODIFY. if ($id && !empty($device->supported[$class])) { $message->setSupported($device->supported[$class]); } // Tell the backend about the change if (!($stat = $this->_as->driver->changeMessage($this->_folderId, $id, $message, $device))) { $this->_logger->err(sprintf('[%s] Change message failed when updating %s', $this->_procid, $id)); return $id ? array(0 => $id, 'error' => Horde_ActiveSync_Request_Sync::STATUS_NOTFOUND) : array(0 => false, 'error' => Horde_ActiveSync_Request_Sync::STATUS_SERVERERROR); } $stat['serverid'] = $this->_folderId; // Record the state of the message. // Email messages are only changed if they are Drafts or if we are // updating flags. // When CHANGING a draft message, we are actually deleting the old one // and replacing it with a message (since we can't edit an existing // IMAP message while keeping the UID the same). So, do not call // updateState() for these messages since we don't want to ignore // this as a PIM sourced change - the change will be caught during // normal ping/sync cycle. if ($message instanceof Horde_ActiveSync_Message_Mail) { if (!empty($message->airsyncbasebody) && !empty($id)) { // Changing an existing Draft mail. return $stat; } // Either a flag change, or adding a new Draft mail. $changeType = !empty($message->airsyncbasebody) ? Horde_ActiveSync::CHANGE_TYPE_DRAFT : Horde_ActiveSync::CHANGE_TYPE_FLAGS; } else { $changeType = Horde_ActiveSync::CHANGE_TYPE_CHANGE; } $this->_state->updateState($changeType, $stat, Horde_ActiveSync::CHANGE_ORIGIN_PIM, $this->_as->driver->getUser(), $clientid); return $stat; }