Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117823491
D4436.1775297487.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None
D4436.1775297487.diff
View Options
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -117,6 +117,48 @@
}
}
+ /**
+ * Encode a globalObjId according to https://interoperability.blob.core.windows.net/files/MS-ASEMAIL/%5bMS-ASEMAIL%5d-150526.pdf 2.2.2.3
+ *
+ * @param array $data An array with the data to encode
+ *
+ * @return string the encoded globalObjId
+ */
+ public static function encodeGlobalObjId(array $data): string
+ {
+ $classid = "040000008200e00074c5b7101a82e008";
+ $uid = $data['uid'];
+ $vcalid = "vCal-Uid\1\0\0\0{$uid}\0";
+
+ $packed = pack(
+ "H32nCCPx8Va*",
+ $classid,
+ $data['year'] ?? 0,
+ $data['month'] ?? 0,
+ $data['day'] ?? 0,
+ $data['now'] ?? 0,
+ strlen($vcalid),
+ $vcalid
+ );
+
+ return base64_encode($packed);
+ }
+
+ /**
+ * Decode a globalObjId according to https://interoperability.blob.core.windows.net/files/MS-ASEMAIL/%5bMS-ASEMAIL%5d-150526.pdf 2.2.2.3
+ *
+ * @param string the encoded globalObjId
+ *
+ * @return array An array with the decoded data
+ */
+ public static function decodeGlobalObjId(string $globalObjId): array
+ {
+ $unpackString = 'H32classid/nyear/Cmonth/Cday/Pnow/x8/Vbytecount/a*data';
+ $decoded = unpack($unpackString, base64_decode($globalObjId));
+ $decoded['uid'] = substr($decoded['data'], strlen("vCal-Uid\1\0\0\0"), -1);
+ return $decoded;
+ }
+
/**
* Creates model object
*
@@ -339,20 +381,54 @@
$result['nativeBodyType'] = $message->has_html_part() ? 2 : 1;
// Message class
+ $result['messageClass'] = 'IPM.Note';
+ $result['contentClass'] = 'urn:content-classes:message';
+
if ($headers->ctype == 'multipart/signed'
&& !empty($message->parts[1])
&& $message->parts[1]->mimetype == 'application/pkcs7-signature'
) {
$result['messageClass'] = 'IPM.Note.SMIME.MultipartSigned';
+ $result['contentClass'] = 'urn:content-classes:message';
}
else if ($headers->ctype == 'application/pkcs7-mime' || $headers->ctype == 'application/x-pkcs7-mime') {
$result['messageClass'] = 'IPM.Note.SMIME';
- }
- else {
- $result['messageClass'] = 'IPM.Note';
- }
+ $result['contentClass'] = 'urn:content-classes:message';
+ }
+ //TODO detect the correct type
+ else if ($headers->ctype == 'multipart/alternative' || $headers->ctype == 'text/calendar') {
+ if ($event = $this->get_invitation_event_from_message($message)) {
+ $result['messageClass'] = 'IPM.Schedule.Meeting.Request';
+ $result['contentClass'] = 'urn:content-classes:calendarmessage';
+
+ $meeting = array();
+
+ //TODO fill in the details
+ $meeting['allDayEvent'] = 0;
+ $meeting['startTime'] = $event['start'];
+ $meeting['dtStamp'] = $event['created'];
+ $meeting['endTime'] = $event['end'];
+ //TODO set recurring or not
+ $meeting['instanceType'] = Syncroton_Model_EmailMeetingRequest::TYPE_NORMAL;
+ // Timezone
+ // Kolab Format 3.0 and xCal does support timezone per-date, but ActiveSync allows
+ // only one timezone per-event. We'll use timezone of the start date
+ if ($event['start'] instanceof DateTime) {
+ $timezone = $event['start']->getTimezone();
+
+ if ($timezone && ($tz_name = $timezone->getName()) != 'UTC') {
+ $tzc = kolab_sync_timezone_converter::getInstance();
+ if ($tz_name = $tzc->encodeTimezone($tz_name, $event['start']->format('Y-m-d'))) {
+ $meeting['timeZone'] = $tz_name;
+ }
+ }
+ }
+ $meeting['globalObjId'] = self::encodeGlobalObjId(['uid' => $event['uid']]);
+ $meeting['meetingMessageType'] = Syncroton_Model_EmailMeetingRequest::MESSAGE_TYPE_NORMAL;
- $result['contentClass'] = 'urn:content-classes:message';
+ $result['meetingRequest'] = new Syncroton_Model_EmailMeetingRequest($meeting);
+ }
+ }
// Categories (Tags)
if (isset($this->tag_categories) && $this->tag_categories) {
@@ -1672,6 +1748,25 @@
return $out;
}
+ /**
+ * Returns calendar event data from the iTip invitation attached to a mail message
+ */
+ public function get_invitation_event_from_message($message)
+ {
+ // Parse the message and find iTip attachments
+ $libcal = libcalendaring::get_instance();
+ $libcal->mail_message_load(array('object' => $message));
+ $ical_objects = $libcal->get_mail_ical_objects();
+
+ // We support only one event in the iTip
+ foreach ($ical_objects as $mime_id => $event) {
+ if ($event['_type'] == 'event') {
+ return $event;
+ }
+ }
+ return null;
+ }
+
/**
* Returns calendar event data from the iTip invitation attached to a mail message
*/
@@ -1679,18 +1774,9 @@
{
// Get the mail message object
if ($message = $this->getObject($messageId)) {
- // Parse the message and find iTip attachments
- $libcal = libcalendaring::get_instance();
- $libcal->mail_message_load(array('object' => $message));
- $ical_objects = $libcal->get_mail_ical_objects();
-
- // We support only one event in the iTip
- foreach ($ical_objects as $mime_id => $event) {
- if ($event['_type'] == 'event') {
- return $event;
- }
- }
+ return $this->get_invitation_event_from_message($message);
}
+ return null;
}
diff --git a/tests/globalid_converter.php b/tests/globalid_converter.php
new file mode 100644
--- /dev/null
+++ b/tests/globalid_converter.php
@@ -0,0 +1,32 @@
+<?php
+
+require_once "../lib/kolab_sync_data.php";
+require_once "../lib/kolab_sync_data_email.php";
+
+class globalid_converter extends PHPUnit\Framework\TestCase
+{
+ function test_decode()
+ {
+ // https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-asemail/e7424ddc-dd10-431e-a0b7-5c794863370e
+ $input = 'BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAAMwAAAHZDYWwtVWlkAQAAAHs4MTQxMkQzQy0yQTI0LTRFOUQtQjIwRS0xMUY3QkJFOTI3OTl9AA==';
+ $output = kolab_sync_data_email::decodeGlobalObjId($input);
+
+ $this->assertSame(51, $output['bytecount']);
+ $this->assertSame('{81412D3C-2A24-4E9D-B20E-11F7BBE92799}', $output['uid']);
+
+ $encoded = kolab_sync_data_email::encodeGlobalObjId($output);
+ $this->assertSame($encoded, $input);
+
+
+ $input = 'BAAAAIIA4AB0xbcQGoLgCAfUCRDgQMnBJoXEAQAAAAAAAAAAEAAAAAvw7UtuTulOnjnjhns3jvM=';
+ $output = kolab_sync_data_email::decodeGlobalObjId($input);
+
+ $this->assertSame(16, $output['bytecount']);
+ $this->assertSame(2004, $output['year']);
+ $this->assertSame(9, $output['month']);
+ $this->assertSame(16, $output['day']);
+ //FIXME we don't currently implement non ical uids
+ // $encoded = kolab_sync_data_email::encodeGlobalObjId($output);
+ // $this->assertSame($encoded, $input);
+ }
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 4, 10:11 AM (8 h, 50 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18828946
Default Alt Text
D4436.1775297487.diff (7 KB)
Attached To
Mode
D4436: Initial support for meeting request
Attached
Detach File
Event Timeline