Author: Michael J Rubinsky (mrubinsk@horde.org)
Beispiel #1
0
 /**
  * Send a message change over the wbxml stream
  *
  * @param string $id                              The uid of the message
  * @param Horde_ActiveSync_Message_Base $message  The message object
  */
 public function messageChange($id, Horde_ActiveSync_Message_Base $message)
 {
     // Just ignore any messages that are not from this collection and
     // prevent sending the same object twice in one request.
     if ($message->getClass() != $this->_currentCollection['class'] || in_array($id, $this->_seenObjects)) {
         $this->_logger->notice(sprintf('[%s] IGNORING message %s since it looks like it was already sent or does not belong to this collection. Class: %s, CurrentClass: %s', $this->_procid, $id, $message->getClass(), $this->_currentCollection['class']));
         return;
     }
     // Ignore any empty objects.
     if ($message->isEmpty()) {
         $this->_logger->notice(sprintf('[%s] IGNORING message %s since it looks like it does not contain any data. Class: %s, CurrentClass: %s', $this->_procid, $id, $message->getClass(), $this->_currentCollection['class']));
         return;
     }
     // Remember this message
     $this->_seenObjects[] = $id;
     // Specify if this is an ADD or a MODIFY change?
     if ($message->flags === Horde_ActiveSync::FLAG_NEWMESSAGE) {
         $this->_encoder->startTag(Horde_ActiveSync::SYNC_ADD);
     } else {
         $this->_encoder->startTag(Horde_ActiveSync::SYNC_MODIFY);
     }
     // Send the message
     $this->_encoder->startTag(Horde_ActiveSync::SYNC_SERVERENTRYID);
     $this->_encoder->content($id);
     $this->_encoder->endTag();
     $this->_encoder->startTag(Horde_ActiveSync::SYNC_DATA);
     try {
         $message->encodeStream($this->_encoder);
     } catch (Horde_ActiveSync_Exception $e) {
         $this->_logger->err($e);
     }
     $this->_encoder->endTag();
     $this->_encoder->endTag();
 }
Beispiel #2
0
 /**
  * Const'r
  *
  * @see Horde_ActiveSync_Message_Base::__construct()
  */
 public function __construct(array $options = array())
 {
     parent::__construct($options);
     if ($this->_version >= Horde_ActiveSync::VERSION_FOURTEEN) {
         $this->_mapping += array(Horde_ActiveSync::AIRSYNCBASE_PREVIEW => array(self::KEY_ATTRIBUTE => 'preview'));
         $this->_properties += array('preview' => false);
     }
 }
Beispiel #3
0
 /**
  * Const'r
  *
  * @see Horde_ActiveSync_Message_Base::__construct()
  */
 public function __construct(array $options = array())
 {
     parent::__construct($options);
     if ($this->_version > Horde_ActiveSync::VERSION_FOURTEEN) {
         $this->_mapping += array(Horde_ActiveSync_Message_Mail::POOMMAIL2_MEETINGMESSAGETYPE => array(self::KEY_ATTRIBUTE => 'meetingmessagetype'));
         $this->_properties += array('meetingmessagetype' => false);
     }
 }
Beispiel #4
0
 /**
  * Const'r
  *
  * @see Horde_ActiveSync_Message_Base::__construct()
  */
 public function __construct(array $options = array())
 {
     parent::__construct($options);
     if ($this->_version < Horde_ActiveSync::VERSION_TWELVE) {
         $this->_mapping += array(self::POOMCAL_BODY => array(self::KEY_ATTRIBUTE => 'body'), self::POOMCAL_BODYTRUNCATED => array(self::KEY_ATTRIBUTE => 'bodytruncated'), self::POOMCAL_RTF => array(self::KEY_ATTRIBUTE => 'rtf'));
         $this->_properties += array('body' => false, 'bodytruncated' => 0, 'rtf' => false);
     } else {
         $this->_mapping += array(Horde_ActiveSync::AIRSYNCBASE_BODY => array(self::KEY_ATTRIBUTE => 'airsyncbasebody', self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseBody'));
         $this->_properties += array('airsyncbasebody' => false);
         if ($this->_version >= Horde_ActiveSync::VERSION_FOURTEEN) {
             $this->_mapping += array(self::POOMCAL_RESPONSEREQUESTED => array(self::KEY_ATTRIBUTE => 'responserequested'), self::POOMCAL_APPOINTMENTREPLYTIME => array(self::KEY_ATTRIBUTE => 'appointmentreplytime', self::KEY_TYPE => self::TYPE_DATE_DASHES), self::POOMCAL_RESPONSETYPE => array(self::KEY_ATTRIBUTE => 'responsetype'), self::POOMCAL_DISALLOWNEWTIMEPROPOSAL => array(self::KEY_ATTRIBUTE => 'disallownewtimeproposal'));
             $this->_properties += array('disallownewtimeproposal' => false, 'responserequested' => false, 'appointmentreplytime' => false, 'responsetype' => false);
         }
         if ($this->_version >= Horde_ActiveSync::VERSION_FOURTEENONE) {
             $this->_mapping += array(self::POOMCAL_ONLINECONFLINK => array(self::KEY_ATTRIBUTE => 'onlinemeetingconflink'), self::POOMCAL_ONLINEEXTLINK => array(self::KEY_ATTRIBUTE => 'onlinemeetingexternallink'));
             $this->_properties += array('onlinemeetingconflink' => false, 'onlinemeetingexternallink' => false);
         }
     }
 }
Beispiel #5
0
 /**
  * Const'r
  *
  * @see Horde_ActiveSync_Message_Base::__construct()
  */
 public function __construct(array $options = array())
 {
     parent::__construct($options);
     if ($this->_version < Horde_ActiveSync::VERSION_TWELVE) {
         $this->_mapping += array(self::POOMTASKS_BODY => array(self::KEY_ATTRIBUTE => 'body'), self::POOMTASKS_RTF => array(self::KEY_ATTRIBUTE => 'rtf'), self::POOMTASKS_BODYTRUNCATED => array(self::KEY_ATTRIBUTE => 'bodytruncated'));
         $this->_properties += array('body' => false, 'rtf' => false, 'bodytruncated' => 0);
     } else {
         $this->_mapping += array(Horde_ActiveSync::AIRSYNCBASE_BODY => array(self::KEY_ATTRIBUTE => 'airsyncbasebody', self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseBody'));
         $this->_properties += array('airsyncbasebody' => false);
     }
 }
Beispiel #6
0
 /**
  * Const'r
  *
  * @see Horde_ActiveSync_Message_Base::__construct()
  */
 public function __construct(array $options = array())
 {
     parent::__construct($options);
     if ($this->_version >= Horde_ActiveSync::VERSION_FOURTEEN) {
         $this->_mapping += array(Horde_ActiveSync_Message_Appointment::POOMCAL_CALENDARTYPE => array(self::KEY_ATTRIBUTE => 'calendartype'), Horde_ActiveSync_Message_Appointment::POOMCAL_ISLEAPMONTH => array(self::KEY_ATTRIBUTE => 'isleapmonth'));
         $this->_properties += array('calendartype' => false, 'isleapmonth' => false);
     }
     if ($this->_version == Horde_ActiveSync::VERSION_FOURTEENONE) {
         $this->_mapping += array(Horde_ActiveSync_Message_Appointment::POOMCAL_FIRSTDAYOFWEEK => array(self::KEY_ATTRIBUTE => 'firstdayofweek'));
         $this->_properties += array('firstdayofweek' => false);
     }
 }
Beispiel #7
0
 protected function _formatDate(Horde_Date $dt, $type)
 {
     if (empty($this->_device)) {
         $date = $dt;
     } else {
         $date = $this->_device->normalizePoomContactsDates($dt, true);
     }
     return parent::_formatDate($date, $type);
 }
Beispiel #8
0
 /**
  * Determines if the property specified has been ghosted by the client.
  * A ghosted property 1) IS listed in the supported list and 2) NOT
  * present in the current message. If it's IN the supported list and NOT
  * in the current message, then it IS ghosted and the server should keep
  * the field's current value when performing any change action due to this
  * message.
  *
  * @param string $property  The property to check
  *
  * @return boolean
  */
 public function isGhosted($property)
 {
     $isGhosted = parent::isGhosted($property);
     if (!$isGhosted && $property == self::PICTURE && $this->_device->hasQuirk(Horde_ActiveSYnc_Device::QUIRK_NEEDS_SUPPORTED_PICTURE_TAG)) {
         return true;
     }
     return $isGhosted;
 }
Beispiel #9
0
 /**
  * Determines if the property specified has been ghosted by the client.
  * A property is ghosted if it is NOT listed in the SUPPORTED list sent
  * by the client AND is NOT present in the request data.
  *
  * @param string $property  The property to check
  * @param array  $options   An array of options:
  *     - ignoreEmptyPictureTagCheck: boolean If true, will not check for the
  *       QUIRK_INCORRECTLY_SENDS_EMPTY_PICTURE_TAG quirk. @since  2.32.0
  *
  * @return boolean
  */
 public function isGhosted($property, $options = array())
 {
     // MS-ASCMD 2.2.3.168:
     // An empty SUPPORTED container indicates that ALL elements able to be
     // ghosted ARE ghosted. A *missing* SUPPORTED tag indicates that NO
     // fields are ghosted - any ghostable properties are always considered
     // NOT ghosted. Some clients like iOS 4.x screw this up by not sending
     // any SUPPORTED container and also not sending the picture field during
     // edits.
     if ($property == $this->_mapping[self::PICTURE][self::KEY_ATTRIBUTE]) {
         if (empty($options['ignoreEmptyPictureTagCheck']) && $this->_device->hasQuirk(Horde_ActiveSync_Device::QUIRK_INCORRECTLY_SENDS_EMPTY_PICTURE_TAG) && (!empty($this->_exists[$property]) && $this->{$property} == '' || empty($this->_exists[$property]))) {
             return true;
         }
         if (empty($this->_exists[$property]) && empty($this->_supported) && $this->_device->hasQuirk(Horde_ActiveSync_Device::QUIRK_NEEDS_SUPPORTED_PICTURE_TAG)) {
             return true;
         }
     }
     return parent::isGhosted($property);
 }
Beispiel #10
0
 /**
  * Const'r
  *
  * @see Horde_ActiveSync_Message_Base::__construct()
  */
 public function __construct(array $options = array())
 {
     parent::__construct($options);
     if ($this->_version == Horde_ActiveSync::VERSION_TWOFIVE) {
         $this->_mapping += array(self::POOMMAIL_ATTACHMENTS => array(self::KEY_ATTRIBUTE => 'attachments', self::KEY_TYPE => 'Horde_ActiveSync_Message_Attachment', self::KEY_VALUES => self::POOMMAIL_ATTACHMENT), self::POOMMAIL_BODYTRUNCATED => array(self::KEY_ATTRIBUTE => 'bodytruncated'), self::POOMMAIL_BODYSIZE => array(self::KEY_ATTRIBUTE => 'bodysize'), self::POOMMAIL_BODY => array(self::KEY_ATTRIBUTE => 'body'));
         $this->_properties += array('attachments' => false, 'bodytruncated' => false, 'bodysize' => false, 'body' => false);
     }
     if ($this->_version >= Horde_ActiveSync::VERSION_TWELVE) {
         $this->_mapping += array(Horde_ActiveSync::AIRSYNCBASE_NATIVEBODYTYPE => array(self::KEY_ATTRIBUTE => 'airsyncbasenativebodytype'), Horde_ActiveSync::AIRSYNCBASE_BODY => array(self::KEY_ATTRIBUTE => 'airsyncbasebody', self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseBody'), Horde_ActiveSync::AIRSYNCBASE_ATTACHMENTS => array(self::KEY_ATTRIBUTE => 'airsyncbaseattachments', self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseAttachment', self::KEY_VALUES => Horde_ActiveSync::AIRSYNCBASE_ATTACHMENT), self::POOMMAIL_FLAG => array(self::KEY_ATTRIBUTE => 'flag', self::KEY_TYPE => 'Horde_ActiveSync_Message_Flag'), self::POOMMAIL_CONTENTCLASS => array(self::KEY_ATTRIBUTE => 'contentclass'));
         $this->_properties += array('airsyncbasenativebodytype' => false, 'airsyncbasebody' => false, 'airsyncbaseattachments' => false, 'contentclass' => false, 'flag' => false);
         if ($this->_version >= Horde_ActiveSync::VERSION_FOURTEEN) {
             $this->_mapping += array(self::POOMMAIL_CATEGORIES => array(self::KEY_ATTRIBUTE => 'categories', self::KEY_VALUES => self::POOMMAIL_CATEGORY), self::POOMMAIL_CATEGORY => array(self::KEY_ATTRIBUTE => 'category'), self::POOMMAIL2_UMCALLERID => array(self::KEY_ATTRIBUTE => 'umcallerid'), self::POOMMAIL2_UMUSERNOTES => array(self::KEY_ATTRIBUTE => 'umusernotes'), self::POOMMAIL2_UMATTDURATION => array(self::KEY_ATTRIBUTE => 'umattduration'), self::POOMMAIL2_UMATTORDER => array(self::KEY_ATTRIBUTE => 'umattorder'), self::POOMMAIL2_CONVERSATIONID => array(self::KEY_ATTRIBUTE => 'conversationid'), self::POOMMAIL2_CONVERSATIONINDEX => array(self::KEY_ATTRIBUTE => 'conversationindex'), self::POOMMAIL2_LASTVERBEXECUTED => array(self::KEY_ATTRIBUTE => 'lastverbexecuted'), self::POOMMAIL2_LASTVERBEXECUTIONTIME => array(self::KEY_ATTRIBUTE => 'lastverbexecutiontime', self::KEY_TYPE => self::TYPE_DATE_DASHES), self::POOMMAIL2_RECEIVEDASBCC => array(self::KEY_ATTRIBUTE => 'receivedasbcc'), self::POOMMAIL2_SENDER => array(self::KEY_ATTRIBUTE => 'sender'), self::POOMMAIL2_CALENDARTYPE => array(self::KEY_ATTRIBUTE => 'calendartype'), self::POOMMAIL2_ISLEAPMONTH => array(self::KEY_ATTRIBUTE => 'isleapmonth'), self::POOMMAIL2_ACCOUNTID => array(self::KEY_ATTRIBUTE => 'accountid'), self::POOMMAIL2_FIRSTDAYOFWEEK => array(self::KEY_ATTRIBUTE => 'firstdayofweek'));
             $this->_properties += array('umcallerid' => false, 'umusernotes' => false, 'umattduration' => false, 'umattorder' => false, 'conversationid' => false, 'conversationindex' => false, 'lastverbexecuted' => false, 'lastverbexecutiontime' => false, 'receivedasbcc' => false, 'sender' => false, 'calendartype' => false, 'isleapmonth' => false, 'accountid' => false, 'firstdayofweek' => false, 'categories' => array(), 'messageid' => false, 'answered' => false, 'forwarded' => false);
         }
         if ($this->_version > Horde_ActiveSync::VERSION_FOURTEEN) {
             $this->_mapping += array(Horde_ActiveSync::AIRSYNCBASE_BODYPART => array(self::KEY_ATTRIBUTE => 'airsyncbasebodypart', self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseBodypart'));
             $this->_properties += array('airsyncbasebodypart' => false);
         }
     }
 }
Beispiel #11
0
 public function &__get($property)
 {
     // The saveinsent is an empty tag, and is considered true if it is
     // present.
     // Deal with the empty tags that are considered true if they are present
     switch ($property) {
         case 'saveinsent':
         case 'replacemime':
             $return = $this->_properties[$property] !== false;
             return $return;
     }
     return parent::__get($property);
 }
Beispiel #12
0
 /**
  * Override parent class' method. In EAS 16.0, top level appointment
  * properties are ALWAYS ghosted if they are not explicitly sent.
  *
  * @param string $property  The property to check
  *
  * @return boolean
  */
 public function isGhosted($property)
 {
     if ($this->_version >= Horde_ActiveSync::VERSION_SIXTEEN && empty($this->_exists[$property])) {
         return true;
     }
     return parent::isGhosted($property);
 }
Beispiel #13
0
 /**
  * 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;
 }
Beispiel #14
0
 /**
  * Set the list of non-ghosted fields for this message.
  *
  * @param array $fields  The array of fields.
  */
 public function setSupported(array $fields)
 {
     // See if we need to explicitly add the picture tag to the supported list.
     parent::setSupported($fields);
     if ($this->_device->hasQuirk(Horde_ActiveSync_Device::QUIRK_NEEDS_SUPPORTED_PICTURE_TAG) && !in_array($this->_mapping[self::PICTURE][self::KEY_ATTRIBUTE], $this->_supported)) {
         $this->_supported[] = $this->_mapping[self::PICTURE][self::KEY_ATTRIBUTE];
     }
 }