Skip to content

Commit

Permalink
AS16.1 - Implement Appointment Attachment save+remove
Browse files Browse the repository at this point in the history
AS16.1 changes based on grommunio-sync commit
grommunio/grommunio-sync@ca7e4be
  • Loading branch information
matidau committed Oct 29, 2024
1 parent 6135138 commit bfc96f3
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 15 deletions.
46 changes: 46 additions & 0 deletions src/backend/kopano/mapiprovider.php
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,52 @@ private function setAppointment($mapimessage, $appointment) {
mapi_message_modifyrecipients($mapimessage, 0, $recips);
}
mapi_setprops($mapimessage, $props);

// Since AS 16 we have to take care of MeetingRequest updates
if (Request::GetProtocolVersion() >= 16.0 && isset($appointment->meetingstatus) && $appointment->meetingstatus > 0) {
$mr = new Meetingrequest($this->store, $mapimessage, $this->session);
// initialize MR and/or update internal counters
$mr->updateMeetingRequest();
// when updating, check for significant changes and if needed will clear the existing recipient responses
if (!isset($appointment->clientuid)) {
$mr->checkSignificantChanges($oldProps, false, false);
}
$mr->sendMeetingRequest(false, false, false, false, array_values($old_receips));
}

if (!empty($appointment->asattachments)) {
foreach ($appointment->asattachments as $att) {
// new attachment to be saved
if ($att instanceof SyncBaseAttachmentAdd) {
SLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->setAppointment(): Saving attachment %s", $att->displayname));
// TODO: check: clientid (looks like an UUID), contentid, contentlocation
$props = [
PR_ATTACH_LONG_FILENAME => $att->displayname,
PR_DISPLAY_NAME => $att->displayname,
PR_ATTACH_METHOD => $att->method, // is this correct ??
PR_ATTACH_DATA_BIN => "",
PR_ATTACH_MIME_TAG => $att->contenttype,
PR_ATTACHMENT_HIDDEN => false,
PR_ATTACH_EXTENSION => pathinfo($att->displayname, PATHINFO_EXTENSION),
];
$attachment = mapi_message_createattach($mapimessage);
mapi_setprops($attachment, $props);
// Stream the file to the PR_ATTACH_DATA_BIN property
$stream = mapi_openproperty($attachment, PR_ATTACH_DATA_BIN, IID_IStream, 0, MAPI_CREATE | MAPI_MODIFY);
mapi_stream_write($stream, stream_get_contents($att->content));
// Commit the stream and save changes
mapi_stream_commit($stream);
mapi_savechanges($attachment);
}
// attachment to be removed
elseif ($att instanceof SyncBaseAttachmentDelete) {
list($id, $attachnum, $parentEntryid, $exceptionBasedate) = explode(":", $att->filereference);
SLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->setAppointment(): Deleting attachment with num: %s", $attachnum));
mapi_message_deleteattach($mapimessage, (int) $attachnum);
}
}
}
return true;
}

/**
Expand Down
48 changes: 35 additions & 13 deletions src/lib/core/streamer.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,30 @@ public function Decode(&$decoder) {
if(isset($map[self::STREAMER_ARRAY])) {
WBXMLDecoder::ResetInWhile("decodeArray");
while(WBXMLDecoder::InWhile("decodeArray")) {
$streamertype = false;
//do not get start tag for an array without a container
if (!(isset($map[self::STREAMER_PROP]) && $map[self::STREAMER_PROP] == self::STREAMER_TYPE_NO_CONTAINER)) {
if(!$decoder->getElementStartTag($map[self::STREAMER_ARRAY]))
// are there multiple possibilities for element encapsulation tags?
if (is_array($map[self::STREAMER_ARRAY])) {
$encapTagsTypes = $map[self::STREAMER_ARRAY];
}
else {
// set $streamertype to null if the element is a single string (e.g. category)
$encapTagsTypes = [$map[self::STREAMER_ARRAY] => $map[self::STREAMER_TYPE]] ?? null;
}
// Identify the used tag
$streamertype = false;
foreach ($encapTagsTypes as $tag => $type) {
if ($decoder->getElementStartTag($tag)) {
$streamertype = $type;
}
}
if ($streamertype === false) {
break;
}
}
if(isset($map[self::STREAMER_TYPE])) {
$decoded = new $map[self::STREAMER_TYPE];
if ($streamertype) {
$decoded = new $streamertype();

$decoded->Decode($decoder);
}
Expand Down Expand Up @@ -271,20 +288,25 @@ public function Encode(&$encoder) {

foreach ($this->{$map[self::STREAMER_VAR]} as $element) {
if(is_object($element)) {
$encoder->startTag($map[self::STREAMER_ARRAY]); // Outputs object container (eg Attachment)
// find corresponding encapsulation tag for element
if (!is_array($map[self::STREAMER_ARRAY])) {
$eltag = $map[self::STREAMER_ARRAY];
}
else {
$eltag = array_search(get_class($element), $map[self::STREAMER_ARRAY]);
}
$encoder->startTag($eltag); // Outputs object container (eg Attachment)
$element->Encode($encoder);
$encoder->endTag();
}
else {
if(strlen($element) == 0)
// Do not output empty items. Not sure if we should output an empty tag with $encoder->startTag($map[self::STREAMER_ARRAY], false, true);
;
else {
$encoder->startTag($map[self::STREAMER_ARRAY]);
$encoder->content($element);
$encoder->endTag();
$streamed = true;
}
// Do not output empty items. Not sure if we should output an empty tag with $encoder->startTag($map[self::STREAMER_ARRAY], false, true);
if (strlen($element) > 0) {
$encoder->startTag($map[self::STREAMER_ARRAY]);
$encoder->content($element);
$encoder->endTag();
$streamed = true;
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/lib/syncobjects/syncappointment.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,12 @@ function __construct() {
if (Request::GetProtocolVersion() >= 16.0) {
$mapping[SYNC_AIRSYNCBASE_ATTACHMENTS] = [
self::STREAMER_VAR => "asattachments",
self::STREAMER_TYPE => "SyncBaseAttachment",
self::STREAMER_ARRAY => SYNC_AIRSYNCBASE_ATTACHMENT,
// Different tags can be used to encapsulate the SyncBaseAttachmentSubtypes depending on its usecase
self::STREAMER_ARRAY => [
SYNC_AIRSYNCBASE_ATTACHMENT => "SyncBaseAttachment",
SYNC_AIRSYNCBASE_ADD => "SyncBaseAttachmentAdd",
SYNC_AIRSYNCBASE_DELETE => "SyncBaseAttachmentDelete",
],
];
$mapping[SYNC_AIRSYNCBASE_LOCATION] = [
self::STREAMER_VAR => "location",
Expand Down
24 changes: 24 additions & 0 deletions src/lib/syncobjects/syncbaseattachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,30 @@ function __construct() {
SYNC_AIRSYNCBASE_ISINLINE => array (self::STREAMER_VAR => "isinline"),
);

if (Request::GetProtocolVersion() >= 16.0) {
$mapping[SYNC_AIRSYNCBASE_CLIENTID] = [
self::STREAMER_VAR => "clientid",
self::STREAMER_RONOTIFY => true,
];
$mapping[SYNC_AIRSYNCBASE_CONTENTTYPE] = [
self::STREAMER_VAR => "contenttype",
self::STREAMER_RONOTIFY => true,
];
$mapping[SYNC_AIRSYNCBASE_CONTENT] = [
self::STREAMER_VAR => "content",
self::STREAMER_TYPE => self::STREAMER_TYPE_STREAM_ASPLAIN,
self::STREAMER_RONOTIFY => true,
];
}

parent::__construct($mapping);
}
}

// Subclasses
class SyncBaseAttachmentAdd extends SyncBaseAttachment {
// overload
}
class SyncBaseAttachmentDelete extends SyncBaseAttachment {
// overload
}
2 changes: 2 additions & 0 deletions src/vendor/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@
'SyncAttachment' => $baseDir . '/lib/syncobjects/syncattachment.php',
'SyncAttendee' => $baseDir . '/lib/syncobjects/syncattendee.php',
'SyncBaseAttachment' => $baseDir . '/lib/syncobjects/syncbaseattachment.php',
'SyncBaseAttachmentAdd' => $baseDir . '/lib/syncobjects/syncbaseattachment.php',
'SyncBaseAttachmentDelete' => $baseDir . '/lib/syncobjects/syncbaseattachment.php',
'SyncBaseBody' => $baseDir . '/lib/syncobjects/syncbasebody.php',
'SyncBaseBodyPart' => $baseDir . '/lib/syncobjects/syncbasebodypart.php',
'SyncCollections' => $baseDir . '/lib/core/synccollections.php',
Expand Down
2 changes: 2 additions & 0 deletions src/vendor/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ class ComposerStaticInit153a56a781a72686b71399955d98204f
'SyncAttachment' => __DIR__ . '/../..' . '/lib/syncobjects/syncattachment.php',
'SyncAttendee' => __DIR__ . '/../..' . '/lib/syncobjects/syncattendee.php',
'SyncBaseAttachment' => __DIR__ . '/../..' . '/lib/syncobjects/syncbaseattachment.php',
'SyncBaseAttachmentAdd' => __DIR__ . '/../..' . '/lib/syncobjects/syncbaseattachment.php',
'SyncBaseAttachmentDelete' => __DIR__ . '/../..' . '/lib/syncobjects/syncbaseattachment.php',
'SyncBaseBody' => __DIR__ . '/../..' . '/lib/syncobjects/syncbasebody.php',
'SyncBaseBodyPart' => __DIR__ . '/../..' . '/lib/syncobjects/syncbasebodypart.php',
'SyncCollections' => __DIR__ . '/../..' . '/lib/core/synccollections.php',
Expand Down

0 comments on commit bfc96f3

Please sign in to comment.