Skip to content

Commit

Permalink
Support synchronizing event attachments.
Browse files Browse the repository at this point in the history
  • Loading branch information
mrubinsk committed Aug 31, 2016
1 parent 38f16df commit ac5d8c3
Show file tree
Hide file tree
Showing 11 changed files with 374 additions and 22 deletions.
6 changes: 5 additions & 1 deletion framework/ActiveSync/doc/Horde/ActiveSync/TODO
Expand Up @@ -80,6 +80,9 @@ BC BREAKING (i.e., Horde 6).
living in the RPC layer (sending back certain headers, etc...) into this
class.

- Split out code for sending response in Sync.php to it's own class, or at the
very least, it's own method. ??

- Implement a Horde_ActiveSync_Change_Filter class/interface. Used to implement
workarounds for broken clients. E.g., filter out the ADD commands sent in
response to MOVEITEMS for Outlook clients. Use a similar pattern for other
Expand Down Expand Up @@ -112,7 +115,8 @@ BC BREAKING (i.e., Horde 6).
and transporting the various collection options/bodyprefs around.

- Likewise, implement a collection object instead of using an array to define
each collection.
each collection and have it be responsible for providing some of the return
objects/values (See comments in Sync.php).

- Implement Horde_ActiveSync_SyncKey.

Expand Down
15 changes: 9 additions & 6 deletions framework/ActiveSync/lib/Horde/ActiveSync/Connector/Importer.php
Expand Up @@ -142,8 +142,8 @@ public function setLogger($logger)
* @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
* @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,
Expand Down Expand Up @@ -178,7 +178,10 @@ public function importMessageChange(
'[%s] Conflict when updating %s, will overwrite client version on next sync.',
$this->_procid, $id)
);
return array($id, Horde_ActiveSync_Request_Sync::STATUS_CONFLICT);
return array(
$id,
'error' => array(Horde_ActiveSync_Request_Sync::STATUS_CONFLICT)
);
}
}
} elseif (!$id && $uid = $this->_state->isDuplicatePIMAddition($clientid)) {
Expand All @@ -202,8 +205,8 @@ public function importMessageChange(
$this->_procid, $id)
);
return $id
? array($id, Horde_ActiveSync_Request_Sync::STATUS_NOTFOUND)
: array(false, Horde_ActiveSync_Request_Sync::STATUS_SERVERERROR);
? array(0 => $id, 'error' => Horde_ActiveSync_Request_Sync::STATUS_NOTFOUND)
: array(0 => false, 'error' => Horde_ActiveSync_Request_Sync::STATUS_SERVERERROR);
}
$stat['serverid'] = $this->_folderId;

Expand All @@ -221,7 +224,7 @@ public function importMessageChange(
$this->_as->driver->getUser(),
$clientid);

return $stat['id'];
return $stat;
}

/**
Expand Down
@@ -0,0 +1,71 @@
<?php
/**
* Horde_ActiveSync_Message_AirSyncBaseAdd::
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2011-2016 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
*/
/**
* Horde_ActiveSync_Message_AirSyncBaseAdd::
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2011-2016 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
*/
class Horde_ActiveSync_Message_AirSyncBaseAdd extends Horde_ActiveSync_Message_Base
{

/**
* Property mappings
*
* @var array
*/
protected $_mapping = array(
Horde_ActiveSync::AIRSYNCBASE_CLIENTID => array(self::KEY_ATTRIBUTE => 'clientid'),
Horde_ActiveSync::AIRSYNCBASE_CONTENT => array(self::KEY_ATTRIBUTE => 'content'),
Horde_ActiveSync::AIRSYNCBASE_CONTENTID => array(self::KEY_ATTRIBUTE => 'contentid'),
Horde_ActiveSync::AIRSYNCBASE_CONTENTLOCATION => array(self::KEY_ATTRIBUTE => 'contentlocation'),
Horde_ActiveSync::AIRSYNCBASE_CONTENTTYPE => array(self::KEY_ATTRIBUTE => 'contenttype'),
Horde_ActiveSync::AIRSYNCBASE_DISPLAYNAME => array(self::KEY_ATTRIBUTE => 'displayname'),
Horde_ActiveSync::AIRSYNCBASE_ISINLINE => array(self::KEY_ATTRIBUTE => 'isinline'),
Horde_ActiveSync::AIRSYNCBASE_METHOD => array(self::KEY_ATTRIBUTE => 'method')
);

/**
* Property mapping.
*
* @var array
*/
protected $_properties = array(
'clientid' => false,
'content' => false,
'contentid' => false,
'contentlocation' => false,
'contenttype' => false,
'displayname' => false,
'isinline' => false,
'method' => false,
);

/**
* Return the type of message.
*
* @return string
*/
public function getClass()
{
return 'AirSyncBaseAdd';
}

}
Expand Up @@ -83,6 +83,27 @@ class Horde_ActiveSync_Message_AirSyncBaseAttachment extends Horde_ActiveSync_Me
'_data' => false
);

/**
* Const'r
*
* @see Horde_ActiveSync_Message_Base::__construct()
*/
public function __construct(array $options = array())
{
parent::__construct($options);
if ($this->_version >= Horde_ActiveSync::VERSION_SIXTEEN) {
$this->_mapping += array(
Horde_ActiveSync::AIRSYNCBASE_CLIENTID=> array(self::KEY_ATTRIBUTE => 'clientid')
);

$this->_properties += array(
'clientid' => false,
'filereference' => false,
);
}
}


/**
* Return the type of message.
*
Expand Down
@@ -0,0 +1,93 @@
<?php
/**
* Horde_ActiveSync_Message_AirSyncBaseAttachments::
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2011-2016 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
*/
/**
* Horde_ActiveSync_Message_AirSyncBaseAttachment::
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2011-2016 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
*/
class Horde_ActiveSync_Message_AirSyncBaseAttachments extends Horde_ActiveSync_Message_Base
{
/* Attachement types */
const ATT_TYPE_NORMAL = 1;
const ATT_TYPE_EMBEDDED = 5;

/**
* Property mappings
*
* @var array
*/
protected $_mapping = array(
Horde_ActiveSync::AIRSYNCBASE_ATTACHMENT => array(
self::KEY_ATTRIBUTE => 'attachment',
self::KEY_VALUES => Horde_ActiveSync::AIRSYNCBASE_ATTACHMENT,
self::KEY_PROPERTY => self::PROPERTY_NO_CONTAINER
)
);

/**
* Property mapping.
*
* @var array
*/
protected $_properties = array(
'attachment' => false,
);

/**
* Const'r
*
* @see Horde_ActiveSync_Message_Base::__construct()
*/
public function __construct(array $options = array())
{
parent::__construct($options);
if ($this->_version >= Horde_ActiveSync::VERSION_SIXTEEN) {
$this->_mapping += array(
Horde_ActiveSync::AIRSYNCBASE_ADD => array(
self::KEY_ATTRIBUTE => 'add',
self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseAdd',
self::KEY_PROPERTY => self::PROPERTY_MULTI_ARRAY
),
Horde_ActiveSync::AIRSYNCBASE_DELETE => array(
self::KEY_ATTRIBUTE => 'delete',
self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseDelete',
self::KEY_PROPERTY => self::PROPERTY_MULTI_ARRAY,
)
);

$this->_properties += array(
'add' => false,
'delete' => false,
);
}
}

/**
* Return the type of message.
*
* @return string
*/
public function getClass()
{
return 'AirSyncBaseAttachments';
}

}
@@ -0,0 +1,57 @@
<?php
/**
* Horde_ActiveSync_Message_AirSyncBaseDelete::
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2011-2016 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
*/
/**
* Horde_ActiveSync_Message_AirSyncBaseAdd::
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2011-2016 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
*/
class Horde_ActiveSync_Message_AirSyncBaseDelete extends Horde_ActiveSync_Message_Base
{

/**
* Property mappings
*
* @var array
*/
protected $_mapping = array(
Horde_ActiveSync::AIRSYNCBASE_FILEREFERENCE => array(self::KEY_ATTRIBUTE => 'filereference')
);

/**
* Property mapping.
*
* @var array
*/
protected $_properties = array(
'filereference' => false
);

/**
* Return the type of message.
*
* @return string
*/
public function getClass()
{
return 'AirSyncBaseDelete';
}

}
Expand Up @@ -179,7 +179,7 @@ class Horde_ActiveSync_Message_Appointment extends Horde_ActiveSync_Message_Base
'exceptions' => array(),
'organizeremail' => false,
'organizername' => false,
'meetingstatus' => self::MEETING_NOT_MEETING,
'meetingstatus' => false,
'recurrence' => false,
'reminder' => false,
'sensitivity' => false,
Expand Down Expand Up @@ -259,11 +259,13 @@ public function __construct(array $options = array())
Horde_ActiveSync::AIRSYNCBASE_LOCATION => array(self::KEY_ATTRIBUTE => 'location', self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseLocation'),
self::POOMCAL_CLIENTUID => array(self::KEY_ATTRIBUTE => 'clientuid'),
Horde_ActiveSync::AIRSYNCBASE_INSTANCEID => array(self::KEY_ATTRIBUTE => 'instanceid', self::KEY_TYPE => self::TYPE_DATE),
Horde_ActiveSync::AIRSYNCBASE_ATTACHMENTS => array(self::KEY_ATTRIBUTE => 'airsyncbaseattachments', self::KEY_TYPE => 'Horde_ActiveSync_Message_AirSyncBaseAttachments')
);
$this->_properties += array(
'location' => false,
'clientuid' => false,
'instanceid' => false,
'airsyncbaseattachments' => false
);
}
}
Expand Down Expand Up @@ -899,7 +901,7 @@ public function setMeetingStatus($status)
*/
public function getMeetingStatus()
{
return $this->_getAttribute('meetingstatus', self::MEETING_NOT_MEETING);
return $this->_getAttribute('meetingstatus');
}

/**
Expand Down
15 changes: 13 additions & 2 deletions framework/ActiveSync/lib/Horde/ActiveSync/Message/Base.php
Expand Up @@ -50,8 +50,8 @@ class Horde_ActiveSync_Message_Base
const TYPE_MAPI_STREAM = 4;
const TYPE_MAPI_GOID = 5;
const TYPE_DATE_LOCAL = 6;

const PROPERTY_NO_CONTAINER = 7;
const PROPERTY_MULTI_ARRAY = 8;

/**
* Holds the mapping for object properties
Expand Down Expand Up @@ -455,7 +455,18 @@ public function decodeStream(Horde_ActiveSync_Wbxml_Decoder &$decoder)
);
throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
}
$this->{$map[self::KEY_ATTRIBUTE]} = $decoded;
// If we have a container that can hold multiple
// properties that are also containers, but not all of
// the same type, we have to hanlde separately.
if (isset($map[self::KEY_PROPERTY]) &&
$map[self::KEY_PROPERTY] == self::PROPERTY_MULTI_ARRAY) {
if (!is_array($this->{$map[self::KEY_ATTRIBUTE]})) {
$this->{$map[self::KEY_ATTRIBUTE]} = array();
}
$this->{$map[self::KEY_ATTRIBUTE]}[] = $decoded;
} else {
$this->{$map[self::KEY_ATTRIBUTE]} = $decoded;
}
}
}
} elseif ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
Expand Down
Expand Up @@ -210,6 +210,11 @@ protected function _handle()
case 'fetch' :
switch(Horde_String::lower($value['store'])) {
case 'mailbox' :
// Yes, even though this is a "mailbox" store, this is
// how EAS identifies calendar attachments too since
// they are not documentLibrary items. The backend
// needs to be able to identify where to get the
// item from based solely on the filereference.
$this->_encoder->startTag(self::ITEMOPERATIONS_FETCH);
if (isset($value['airsyncbasefilereference'])) {
// filereference is already in the backend serverid format
Expand Down

0 comments on commit ac5d8c3

Please sign in to comment.