Projects
Kolab:16
kolab-syncroton
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 13
View file
kolab-syncroton.spec
Changed
@@ -36,7 +36,7 @@ %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name} Name: kolab-syncroton -Version: 2.3.5 +Version: 2.3.6 Release: 1%{?dist} Summary: ActiveSync for Kolab Groupware @@ -47,11 +47,6 @@ Source0: https://mirror.kolabenterprise.com/pub/releases/%{name}-%{version}.tar.gz Source1: kolab-syncroton.logrotate -Patch0001: 0001-T2477-GAL-for-Outlook.patch -Patch0002: 0002-Fix-MeetingStatus-value-Bifrost-T34257.patch -Patch0003: 0003-Add-important-note-about-uid-and-changed-fields-in-G.patch -Patch0004: 0004-T2519-Fix-Recurrence-element-structure.patch - BuildArch: noarch # Use this build requirement to make sure we are using @@ -97,11 +92,6 @@ %prep %setup -q -n %{name}-%{version} -%patch0001 -p1 -%patch0002 -p1 -%patch0003 -p1 -%patch0004 -p1 - %build %install @@ -232,6 +222,9 @@ %attr(0770,%{httpd_user},%{httpd_group}) %{_var}/log/%{name} %changelog +* Wed Jul 19 2017 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 2.3.6-1 +- Release 2.3.6 + * Sun Jun 18 2017 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 2.3.5-2 - Implement a GAL virtual folder with LDAP backend for Outlook over Activesync - Fix organizer / ownership for events
View file
0001-T2477-GAL-for-Outlook.patch
Deleted
@@ -1,626 +0,0 @@ -From 3695940a9949322c6ea9b6b71d8319ada8d84d9e Mon Sep 17 00:00:00 2001 -From: Aleksander Machniak <machniak@kolabsys.com> -Date: Fri, 16 Jun 2017 08:42:27 +0000 -Subject: [PATCH 1/4] T2477: GAL for Outlook - ---- - config/config.inc.php.dist | 24 +++ - lib/kolab_sync_data.php | 44 +++-- - lib/kolab_sync_data_contacts.php | 360 ++++++++++++++++++++++++++++++++++++++- - lib/kolab_sync_data_gal.php | 35 ++-- - 4 files changed, 421 insertions(+), 42 deletions(-) - -diff --git a/config/config.inc.php.dist b/config/config.inc.php.dist -index 6864820..2433475 100644 ---- a/config/config.inc.php.dist -+++ b/config/config.inc.php.dist -@@ -52,6 +52,20 @@ $config['activesync_addressbooks'] = array(); - */ - $config['activesync_gal_fieldmap'] = null; - -+// List of device types that will sync the LDAP addressbook(s) as a normal folder. -+// For devices that do not support GAL searching, e.g. Outlook. -+// Examples: -+// array('windowsoutlook') # enable for Oultook only -+// true # enable for all -+$config['activesync_gal_sync'] = false; -+ -+// GAL cache. As reading all contacts from LDAP may be slow, caching is recommended. -+$config['activesync_gal_cache'] = 'db'; -+ -+// TTL of GAL cache entries. Technically this causes that synchronized -+// contacts will not be updated (queried) often than the specified interval. -+$config['activesync_gal_cache_ttl'] = '1d'; -+ - // List of Roundcube plugins - // WARNING: Not all plugins used in Roundcube can be listed here - $config['activesync_plugins'] = array(); -@@ -89,6 +103,16 @@ $config['activesync_init_subscriptions'] = 0; - // action and enable folder hierarchies only on device types known to support it. - $config['activesync_multifolder_blacklist'] = null; - -+// Blacklist overwrites for specified object type. If set to an array -+// it will have a precedence over 'activesync_multifolder_blacklist' list only for that type. -+// Note: Outlook does not support multiple folders for contacts, -+// in that case use $config['activesync_multifolder_blacklist_contact'] = array('windowsoutlook'); -+$config['activesync_multifolder_blacklist_mail'] = null; -+$config['activesync_multifolder_blacklist_event'] = null; -+$config['activesync_multifolder_blacklist_contact'] = null; -+$config['activesync_multifolder_blacklist_note'] = null; -+$config['activesync_multifolder_blacklist_task'] = null; -+ - // Enables adding sender name in the From: header of send email - // when a device uses email address only (e.g. iOS devices) - $config['activesync_fix_from'] = false; -diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php -index a32e738..b03d04b 100644 ---- a/lib/kolab_sync_data.php -+++ b/lib/kolab_sync_data.php -@@ -247,16 +247,18 @@ abstract class kolab_sync_data implements Syncroton_Data_IData - */ - protected function isMultiFolder() - { -- $blacklist = rcube::get_instance()->config->get('activesync_multifolder_blacklist'); -+ $config = rcube::get_instance()->config; -+ $blacklist = $config->get('activesync_multifolder_blacklist_' . $this->modelName); - -- if (is_array($blacklist)) { -- $is_multifolder = !in_array_nocase($this->device->devicetype, $blacklist); -+ if (!is_array($blacklist)) { -+ $blacklist = $config->get('activesync_multifolder_blacklist'); - } -- else { -- $is_multifolder = in_array_nocase($this->device->devicetype, $this->ext_devices); -+ -+ if (is_array($blacklist)) { -+ return !$this->deviceTypeFilter($blacklist); - } - -- return $is_multifolder; -+ return in_array_nocase($this->device->devicetype, $this->ext_devices); - } - - /** -@@ -908,17 +910,6 @@ abstract class kolab_sync_data implements Syncroton_Data_IData - */ - public function hasChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState) - { -- // Try to detect change in multi-folder mode and throw exception -- // so device will re-sync folders hierarchy -- // @TODO: this is a temp solution until we have real hierarchy -- // changes detection fort Ping/Hartbeat -- $is_multifolder = $this->isMultiFolder(); -- if (($is_multifolder && $folder->serverId == $this->defaultRootFolder) -- || (!$is_multifolder && $folder->type >= 12) -- ) { -- throw new Syncroton_Exception_NotFound('Folder not found'); -- } -- - try { - if ($this->getChangedEntriesCount($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype)) { - return true; -@@ -1819,4 +1810,23 @@ abstract class kolab_sync_data implements Syncroton_Data_IData - - return $result; - } -+ -+ /** -+ * Check if current device type string matches any of options -+ */ -+ protected function deviceTypeFilter($options) -+ { -+ foreach ($options as $option) { -+ if ($option[0] == '/') { -+ if (preg_match($option, $this->device->devicetype)) { -+ return true; -+ } -+ } -+ else if (stripos($this->device->devicetype, $option) !== false) { -+ return true; -+ } -+ } -+ -+ return false; -+ } - } -diff --git a/lib/kolab_sync_data_contacts.php b/lib/kolab_sync_data_contacts.php -index e348474..0562377 100644 ---- a/lib/kolab_sync_data_contacts.php -+++ b/lib/kolab_sync_data_contacts.php -@@ -4,7 +4,7 @@ - +--------------------------------------------------------------------------+ - | Kolab Sync (ActiveSync for Kolab) | - | | -- | Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> | -+ | Copyright (C) 2011-2017, Kolab Systems AG <contact@kolabsys.com> | - | | - | This program is free software: you can redistribute it and/or modify | - | it under the terms of the GNU Affero General Public License as published | -@@ -124,6 +124,25 @@ class kolab_sync_data_contacts extends kolab_sync_data - */ - protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED; - -+ /** -+ * Identifier of special Global Address List folder -+ * -+ * @var string -+ */ -+ protected $galFolder = 'GAL'; -+ -+ /** -+ * Name of special Global Address List folder -+ * -+ * @var string -+ */ -+ protected $galFolderName = 'Global Address Book'; -+ -+ protected $galPrefix = 'GAL:'; -+ protected $galSources; -+ protected $galResult; -+ protected $galCache; -+ - - /** - * Creates model object -@@ -136,6 +155,10 @@ class kolab_sync_data_contacts extends kolab_sync_data - $data = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId); - $result = array(); - -+ if (empty($data)) { -+ throw new Syncroton_Exception_NotFound("Contact $serverId not found"); -+ } -+ - // Contacts namespace fields - foreach ($this->mapping as $key => $name) { - $value = $this->getKolabDataItem($data, $name); -@@ -169,8 +192,13 @@ class kolab_sync_data_contacts extends kolab_sync_data - - // email address(es): email1Address, email2Address, email3Address - for ($x=0; $x<3; $x++) { -- if (!empty($data['email'][$x]) && !empty($data['email'][$x]['address'])) { -- $result['email' . ($x+1) . 'Address'] = $data['email'][$x]['address']; -+ if ($email = $data['email'][$x]) { -+ if (is_array($email)) { -+ $email = $email['address']; -+ } -+ if ($email) { -+ $result['email' . ($x+1) . 'Address'] = $email; -+ } - } - } - -@@ -267,6 +295,148 @@ class kolab_sync_data_contacts extends kolab_sync_data - } - - /** -+ * Return list of supported folders for this backend -+ * -+ * @return array -+ */
View file
0002-Fix-MeetingStatus-value-Bifrost-T34257.patch
Deleted
@@ -1,71 +0,0 @@ -From 07a86bbd51c6444135eb8ed7ded465aad64167eb Mon Sep 17 00:00:00 2001 -From: Aleksander Machniak <machniak@kolabsys.com> -Date: Fri, 16 Jun 2017 15:07:10 +0000 -Subject: [PATCH 2/4] Fix MeetingStatus value (Bifrost#T34257) - -Wrong value caused Outlook to think every event with attendees is organized -by the current user even if he was an attendee not organizer. ---- - lib/kolab_sync_data_calendar.php | 39 ++++++++++++++++++++++++++++++++++++++- - 1 file changed, 38 insertions(+), 1 deletion(-) - -diff --git a/lib/kolab_sync_data_calendar.php b/lib/kolab_sync_data_calendar.php -index 14d929f..fcfd51f 100644 ---- a/lib/kolab_sync_data_calendar.php -+++ b/lib/kolab_sync_data_calendar.php -@@ -308,7 +308,7 @@ class kolab_sync_data_calendar extends kolab_sync_data implements Syncroton_Data - } - - // Event meeting status -- $result['meetingStatus'] = intval(!empty($result['attendees'])); -+ $this->meeting_status_from_kolab($collection, $event, $result); - - // Recurrence (and exceptions) - $this->recurrence_from_kolab($collection, $event, $result); -@@ -543,6 +543,43 @@ class kolab_sync_data_calendar extends kolab_sync_data implements Syncroton_Data - } - - /** -+ * Set MeetingStatus according to event data -+ */ -+ protected function meeting_status_from_kolab($collection, $event, &$result) -+ { -+ // 0 - The event is an appointment, which has no attendees. -+ // 1 - The event is a meeting and the user is the meeting organizer. -+ // 3 - This event is a meeting, and the user is not the meeting organizer. -+ // 5 - The meeting has been canceled and the user was the meeting organizer. -+ // 7 - The meeting has been canceled. The user was not the meeting organizer. -+ $status = 0; -+ -+ if (!empty($event['attendees'])) { -+ // Find out if the user is an organizer -+ // TODO: Delegation/aliases support -+ $user_emails = kolab_sync::get_instance()->user->list_emails(); -+ $user_emails = array_map(function($v) { return $v['email']; }, $user_emails); -+ $is_organizer = true; -+ -+ foreach ($event['attendees'] as $attendee) { -+ if (in_array_nocase($attendee['email'], $user_emails)) { -+ $is_organizer = false; -+ break; -+ } -+ } -+ -+ if ($event['status'] == 'CANCELLED') { -+ $status = !empty($is_organizer) ? 5 : 7; -+ } -+ else { -+ $status = !empty($is_organizer) ? 1 : 3; -+ } -+ } -+ -+ $result['meetingStatus'] = $status; -+ } -+ -+ /** - * Converts libkolab alarms spec. into a number of minutes - */ - protected function from_kolab_alarm($event) --- -2.13.0 -
View file
0003-Add-important-note-about-uid-and-changed-fields-in-G.patch
Deleted
@@ -1,29 +0,0 @@ -From c2cdb863178c682f544ffbfa9d7d1635c3714de2 Mon Sep 17 00:00:00 2001 -From: Aleksander Machniak <machniak@kolabsys.com> -Date: Tue, 20 Jun 2017 10:46:35 +0200 -Subject: [PATCH 3/4] Add important note about uid and changed fields in GAL - config - ---- - config/config.inc.php.dist | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/config/config.inc.php.dist b/config/config.inc.php.dist -index 2433475..5e66f59 100644 ---- a/config/config.inc.php.dist -+++ b/config/config.inc.php.dist -@@ -54,6 +54,11 @@ $config['activesync_gal_fieldmap'] = null; - - // List of device types that will sync the LDAP addressbook(s) as a normal folder. - // For devices that do not support GAL searching, e.g. Outlook. -+// Note: To make the LDAP addressbook sources working we need two additional -+// fields ('uid' and 'changed') specified in the fieldmap array -+// of the LDAP configuration ('ldap_public' option). For example: -+// 'uid' => 'nsuniqueid', -+// 'changed' => 'modifytimestamp', - // Examples: - // array('windowsoutlook') # enable for Oultook only - // true # enable for all --- -2.13.0 -
View file
0004-T2519-Fix-Recurrence-element-structure.patch
Deleted
@@ -1,32 +0,0 @@ -From 4e805ba57d9911e2382c11fb043d6b827de7e369 Mon Sep 17 00:00:00 2001 -From: Aleksander Machniak <machniak@kolabsys.com> -Date: Tue, 27 Jun 2017 10:14:27 +0000 -Subject: [PATCH 4/4] T2519: Fix Recurrence element structure - -For example DayOfWeek=0 is invalid. We make sure no such "empty" values are set. ---- - lib/kolab_sync_data.php | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php -index b03d04b..c03be25 100644 ---- a/lib/kolab_sync_data.php -+++ b/lib/kolab_sync_data.php -@@ -1562,8 +1562,13 @@ abstract class kolab_sync_data implements Syncroton_Data_IData - break; - } - -+ // Skip all empty values (T2519) -+ if ($recurrence['type'] != self::RECUR_TYPE_DAILY) { -+ $recurrence = array_filter($recurrence); -+ } -+ - // required field -- $recurrence['interval'] = $r['INTERVAL'] ? $r['INTERVAL'] : 1; -+ $recurrence['interval'] = $r['INTERVAL'] ?: 1; - - if (!empty($r['UNTIL'])) { - $recurrence['until'] = self::date_from_kolab($r['UNTIL']); --- -2.13.0 -
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +kolab-syncroton (2.3.6-0~kolab1) unstable; urgency=low + + * Release 2.3.6 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Wed, 19 Jul 2017 15:13:40 +0200 + kolab-syncroton (2.3.5-0~kolab4) unstable; urgency=low * Allow a GAL to be distributed from LDAP, for Outlook over Activesync
View file
debian.series
Changed
@@ -1,4 +0,0 @@ -0001-T2477-GAL-for-Outlook.patch -p1 -0002-Fix-MeetingStatus-value-Bifrost-T34257.patch -p1 -0003-Add-important-note-about-uid-and-changed-fields-in-G.patch -p1 -0004-T2519-Fix-Recurrence-element-structure.patch -p1
View file
kolab-syncroton-2.3.5.tar.gz/config/config.inc.php.dist -> kolab-syncroton-2.3.6.tar.gz/config/config.inc.php.dist
Changed
@@ -52,6 +52,25 @@ */ $config['activesync_gal_fieldmap'] = null; +// List of device types that will sync the LDAP addressbook(s) as a normal folder. +// For devices that do not support GAL searching, e.g. Outlook. +// Note: To make the LDAP addressbook sources working we need two additional +// fields ('uid' and 'changed') specified in the fieldmap array +// of the LDAP configuration ('ldap_public' option). For example: +// 'uid' => 'nsuniqueid', +// 'changed' => 'modifytimestamp', +// Examples: +// array('windowsoutlook') # enable for Oultook only +// true # enable for all +$config['activesync_gal_sync'] = false; + +// GAL cache. As reading all contacts from LDAP may be slow, caching is recommended. +$config['activesync_gal_cache'] = 'db'; + +// TTL of GAL cache entries. Technically this causes that synchronized +// contacts will not be updated (queried) often than the specified interval. +$config['activesync_gal_cache_ttl'] = '1d'; + // List of Roundcube plugins // WARNING: Not all plugins used in Roundcube can be listed here $config['activesync_plugins'] = array(); @@ -89,6 +108,16 @@ // action and enable folder hierarchies only on device types known to support it. $config['activesync_multifolder_blacklist'] = null; +// Blacklist overwrites for specified object type. If set to an array +// it will have a precedence over 'activesync_multifolder_blacklist' list only for that type. +// Note: Outlook does not support multiple folders for contacts, +// in that case use $config['activesync_multifolder_blacklist_contact'] = array('windowsoutlook'); +$config['activesync_multifolder_blacklist_mail'] = null; +$config['activesync_multifolder_blacklist_event'] = null; +$config['activesync_multifolder_blacklist_contact'] = null; +$config['activesync_multifolder_blacklist_note'] = null; +$config['activesync_multifolder_blacklist_task'] = null; + // Enables adding sender name in the From: header of send email // when a device uses email address only (e.g. iOS devices) $config['activesync_fix_from'] = false;
View file
kolab-syncroton-2.3.5.tar.gz/lib/kolab_sync.php -> kolab-syncroton-2.3.6.tar.gz/lib/kolab_sync.php
Changed
@@ -46,7 +46,7 @@ public $password; const CHARSET = 'UTF-8'; - const VERSION = "2.3.5"; + const VERSION = "2.3.6"; /** @@ -389,7 +389,7 @@ $this->logger->set_username($username); - $user_debug = $this->config->get('activesync_user_debug'); + $user_debug = $this->config->get('per_user_logging'); $user_log = $user_debug || $this->config->get('activesync_user_log'); if (!$user_log) {
View file
kolab-syncroton-2.3.5.tar.gz/lib/kolab_sync_data.php -> kolab-syncroton-2.3.6.tar.gz/lib/kolab_sync_data.php
Changed
@@ -247,16 +247,18 @@ */ protected function isMultiFolder() { - $blacklist = rcube::get_instance()->config->get('activesync_multifolder_blacklist'); + $config = rcube::get_instance()->config; + $blacklist = $config->get('activesync_multifolder_blacklist_' . $this->modelName); - if (is_array($blacklist)) { - $is_multifolder = !in_array_nocase($this->device->devicetype, $blacklist); + if (!is_array($blacklist)) { + $blacklist = $config->get('activesync_multifolder_blacklist'); } - else { - $is_multifolder = in_array_nocase($this->device->devicetype, $this->ext_devices); + + if (is_array($blacklist)) { + return !$this->deviceTypeFilter($blacklist); } - return $is_multifolder; + return in_array_nocase($this->device->devicetype, $this->ext_devices); } /** @@ -482,7 +484,7 @@ throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); } - return $entry['uid']; + return $entry['_serverId']; } /** @@ -503,13 +505,13 @@ } $entry = $this->toKolab($entry, $folderId, $oldEntry); - $entry = $this->updateObject($folderId, $serverId, $entry); + $entry = $this->updateObject($folderId, $serverId, $entry); if (empty($entry)) { throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); } - return $entry['uid']; + return $entry['_serverId']; } /** @@ -600,8 +602,8 @@ if (!is_array($uids)) { $error = true; } - else { - $result = array_merge($result, $uids); + else if (!empty($uids)) { + $result = array_merge($result, $this->applyServerId($uids, $folder)); } break; } @@ -639,8 +641,8 @@ case self::RESULT_UID: $uids = $folder->get_uids($tag_filter); - if (is_array($uids)) { - $result = array_unique(array_merge($result, $uids)); + if (is_array($uids) && !empty($uids)) { + $result = array_unique(array_merge($result, $this->applyServerId($uids, $folder))); } break; @@ -749,7 +751,7 @@ $data[$relation['uid']] = array( 'name' => $relation['name'], 'changed' => $relation['changed']->format('U'), - 'members' => implode("\n", $relation['members']), + 'members' => implode("\n", (array)$relation['members']), ); } @@ -908,17 +910,6 @@ */ public function hasChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState) { - // Try to detect change in multi-folder mode and throw exception - // so device will re-sync folders hierarchy - // @TODO: this is a temp solution until we have real hierarchy - // changes detection fort Ping/Hartbeat - $is_multifolder = $this->isMultiFolder(); - if (($is_multifolder && $folder->serverId == $this->defaultRootFolder) - || (!$is_multifolder && $folder->type >= 12) - ) { - throw new Syncroton_Exception_NotFound('Folder not found'); - } - try { if ($this->getChangedEntriesCount($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype)) { return true; @@ -953,10 +944,37 @@ $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid); $folder = $this->getFolderObject($foldername); - if ($folder && $folder->valid && ($object = $folder->get_object($entryid))) { - $object['_folderid'] = $folderid; + if ($folder && $folder->valid) { + $crc = null; + $uid = $entryid; + + // See self::serverId() for full explanation + // Use (slower) UID prefix matching... + if (preg_match('/^CRC([0-9A-Fa-f]{8})(.+)$/', $uid, $matches)) { + $crc = $matches[1]; + $uid = $matches[2]; + + if (strlen($entryid) >= 64) { + foreach ($folder->select(array(array('uid', '~*', $uid))) as $object) { + if (($object['uid'] == $uid || strpos($object['uid'], $uid) === 0) + && $crc == $this->objectCRC($object['uid'], $folder) + ) { + $object['_folderid'] = $folderid; + return $object; + } + } + + continue; + } + } - return $object; + // Or (faster) strict UID matching... + if (($object = $folder->get_object($uid)) + && ($crc === null || $crc == $this->objectCRC($object['uid'], $folder)) + ) { + $object['_folderid'] = $folderid; + return $object; + } } } } @@ -990,6 +1008,8 @@ $this->setKolabTags($data['uid'], $tags); } + $data['_serverId'] = $this->serverId($data['uid'], $folder); + return $data; } } @@ -1015,6 +1035,8 @@ $this->setKolabTags($data['uid'], $tags); } + $data['_serverId'] = $this->serverId($object['uid'], $folder); + return $data; } } @@ -1030,7 +1052,7 @@ if ($object) { $folder = $this->getFolderObject($object['_mailbox']); - if ($folder && $folder->valid && $folder->delete($entryid)) { + if ($folder && $folder->valid && $folder->delete($object['uid'])) { if ($this->tag_categories) { $this->setKolabTags($object['uid'], null); } @@ -1506,7 +1528,7 @@ */ protected function recurrence_from_kolab($collection, $data, &$result, $type = 'Event') { - if (empty($data['recurrence'])) { + if (empty($data['recurrence']) || !empty($data['recurrence_date'])) { return; } @@ -1569,10 +1591,18 @@ $recurrence['monthOfYear'] = $month; } break; + + default: + return; + } + + // Skip all empty values (T2519) + if ($recurrence['type'] != self::RECUR_TYPE_DAILY) { + $recurrence = array_filter($recurrence); } // required field - $recurrence['interval'] = $r['INTERVAL'] ? $r['INTERVAL'] : 1; + $recurrence['interval'] = $r['INTERVAL'] ?: 1; if (!empty($r['UNTIL'])) { $recurrence['until'] = self::date_from_kolab($r['UNTIL']); @@ -1676,9 +1706,11 @@ // exceptions (modified occurences) foreach ((array)$data['recurrence']['EXCEPTIONS'] as $exception) { $exception['_mailbox'] = $data['_mailbox'];
View file
kolab-syncroton-2.3.5.tar.gz/lib/kolab_sync_data_calendar.php -> kolab-syncroton-2.3.6.tar.gz/lib/kolab_sync_data_calendar.php
Changed
@@ -308,7 +308,7 @@ } // Event meeting status - $result['meetingStatus'] = intval(!empty($result['attendees'])); + $this->meeting_status_from_kolab($collection, $event, $result); // Recurrence (and exceptions) $this->recurrence_from_kolab($collection, $event, $result); @@ -413,14 +413,6 @@ continue 2; } break; - - case 'uid': - // If UID is too long, use auto-generated UID (#1034) - // It's because UID is used as ServerId which cannot be longer than 64 chars - if (strlen($value) > 64) { - $value = null; - } - break; } $this->setKolabDataItem($event, $name, $value); @@ -543,6 +535,43 @@ } /** + * Set MeetingStatus according to event data + */ + protected function meeting_status_from_kolab($collection, $event, &$result) + { + // 0 - The event is an appointment, which has no attendees. + // 1 - The event is a meeting and the user is the meeting organizer. + // 3 - This event is a meeting, and the user is not the meeting organizer. + // 5 - The meeting has been canceled and the user was the meeting organizer. + // 7 - The meeting has been canceled. The user was not the meeting organizer. + $status = 0; + + if (!empty($event['attendees'])) { + // Find out if the user is an organizer + // TODO: Delegation/aliases support + $user_emails = kolab_sync::get_instance()->user->list_emails(); + $user_emails = array_map(function($v) { return $v['email']; }, $user_emails); + $is_organizer = true; + + foreach ($event['attendees'] as $attendee) { + if (in_array_nocase($attendee['email'], $user_emails)) { + $is_organizer = false; + break; + } + } + + if ($event['status'] == 'CANCELLED') { + $status = !empty($is_organizer) ? 5 : 7; + } + else { + $status = !empty($is_organizer) ? 1 : 3; + } + } + + $result['meetingStatus'] = $status; + } + + /** * Converts libkolab alarms spec. into a number of minutes */ protected function from_kolab_alarm($event)
View file
kolab-syncroton-2.3.5.tar.gz/lib/kolab_sync_data_contacts.php -> kolab-syncroton-2.3.6.tar.gz/lib/kolab_sync_data_contacts.php
Changed
@@ -4,7 +4,7 @@ +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | - | Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> | + | Copyright (C) 2011-2017, Kolab Systems AG <contact@kolabsys.com> | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU Affero General Public License as published | @@ -124,6 +124,25 @@ */ protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED; + /** + * Identifier of special Global Address List folder + * + * @var string + */ + protected $galFolder = 'GAL'; + + /** + * Name of special Global Address List folder + * + * @var string + */ + protected $galFolderName = 'Global Address Book'; + + protected $galPrefix = 'GAL:'; + protected $galSources; + protected $galResult; + protected $galCache; + /** * Creates model object @@ -136,6 +155,10 @@ $data = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId); $result = array(); + if (empty($data)) { + throw new Syncroton_Exception_NotFound("Contact $serverId not found"); + } + // Contacts namespace fields foreach ($this->mapping as $key => $name) { $value = $this->getKolabDataItem($data, $name); @@ -169,8 +192,13 @@ // email address(es): email1Address, email2Address, email3Address for ($x=0; $x<3; $x++) { - if (!empty($data['email'][$x]) && !empty($data['email'][$x]['address'])) { - $result['email' . ($x+1) . 'Address'] = $data['email'][$x]['address']; + if ($email = $data['email'][$x]) { + if (is_array($email)) { + $email = $email['address']; + } + if ($email) { + $result['email' . ($x+1) . 'Address'] = $email; + } } } @@ -267,6 +295,148 @@ } /** + * Return list of supported folders for this backend + * + * @return array + */ + public function getAllFolders() + { + $list = parent::getAllFolders(); + + if ($this->isMultiFolder() && $this->hasGAL()) { + $list[$this->galFolder] = new Syncroton_Model_Folder(array( + 'displayName' => $this->galFolderName, // @TODO: localization? + 'serverId' => $this->galFolder, + 'parentId' => 0, + 'type' => 14, + )); + } + + return $list; + } + + /** + * Updates a folder + */ + public function updateFolder(Syncroton_Model_IFolder $folder) + { + if ($folder->serverId === $this->galFolder && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Updating GAL folder is not possible"); + } + + return parent::updateFolder($folder); + } + + /** + * Deletes a folder + */ + public function deleteFolder($folder) + { + if ($folder instanceof Syncroton_Model_IFolder) { + $folder = $folder->serverId; + } + + if ($folder === $this->galFolder && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Deleting GAL folder is not possible"); + } + + return parent::deleteFolder($folder); + } + + /** + * Empty folder (remove all entries and optionally subfolders) + * + * @param string $folderId Folder identifier + * @param array $options Options + */ + public function emptyFolderContents($folderid, $options) + { + if ($folderid === $this->galFolder && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Emptying GAL folder is not possible"); + } + + return parent::emptyFolderContents($folderid, $options); + } + + /** + * Moves object into another location (folder) + * + * @param string $srcFolderId Source folder identifier + * @param string $serverId Object identifier + * @param string $dstFolderId Destination folder identifier + * + * @throws Syncroton_Exception_Status + * @return string New object identifier + */ + public function moveItem($srcFolderId, $serverId, $dstFolderId) + { + if (strpos($serverId, $this->galPrefix) === 0 && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Moving GAL entries is not possible"); + } + + if ($srcFolderId === $this->galFolder && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Moving/Deleting GAL entries is not possible"); + } + + if ($dstFolderId === $this->galFolder && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Creating GAL entries is not possible"); + } + + return parent::moveItem($srcFolderId, $serverId, $dstFolderId); + } + + /** + * Add entry + * + * @param string $folderId Folder identifier + * @param Syncroton_Model_IEntry $entry Entry object + * + * @return string ID of the created entry + */ + public function createEntry($folderId, Syncroton_Model_IEntry $entry) + { + if ($folderId === $this->galFolder && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Creating GAL entries is not possible"); + } + + return parent::createEntry($folderId, $entry); + } + + /** + * update existing entry + * + * @param string $folderId + * @param string $serverId + * @param SimpleXMLElement $entry + * + * @return string ID of the updated entry + */ + public function updateEntry($folderId, $serverId, Syncroton_Model_IEntry $entry) + { + if (strpos($serverId, $this->galPrefix) === 0 && $this->hasGAL()) { + throw new Syncroton_Exception_AccessDenied("Updating GAL entries is not possible"); + } + + return parent::updateEntry($folderId, $serverId, $entry); + } + + /** + * delete entry + * + * @param string $folderId + * @param string $serverId + * @param array $collectionData + */ + public function deleteEntry($folderId, $serverId, $collectionData) + {
View file
kolab-syncroton-2.3.5.tar.gz/lib/kolab_sync_data_email.php -> kolab-syncroton-2.3.6.tar.gz/lib/kolab_sync_data_email.php
Changed
@@ -1311,7 +1311,17 @@ $body = rcube_enriched::to_html($body); } else { - $body = '<pre>' . $body . '</pre>'; + // Roundcube >= 1.2 + if (class_exists('rcube_text2html')) { + $flowed = $part->ctype_parameters['format'] == 'flowed'; + $delsp = $part->ctype_parameters['delsp'] == 'yes'; + $options = array('flowed' => $flowed, 'wrap' => false, 'delsp' => $delsp); + $text2html = new rcube_text2html($body, false, $options); + $body = '<html><body>' . $text2html->get_html() . '</body></html>'; + } + else { + $body = '<html><body><pre>' . $body . '</pre></body></html>'; + } } } else {
View file
kolab-syncroton-2.3.5.tar.gz/lib/kolab_sync_data_gal.php -> kolab-syncroton-2.3.6.tar.gz/lib/kolab_sync_data_gal.php
Changed
@@ -42,7 +42,7 @@ * * @var array */ - protected $address_books = array(); + protected static $address_books = array(); /** * Mapping from ActiveSync Contacts namespace fields @@ -193,7 +193,7 @@ // @TODO: caching with Options->RebuildResults support - $books = $this->get_address_sources(); + $books = self::get_address_sources(); $mode = 2; // use prefix mode $fields = $rcube->config->get('contactlist_fields'); @@ -202,7 +202,7 @@ } foreach ($books as $idx => $book) { - $book = $this->get_address_book($idx); + $book = self::get_address_book($idx); if (!$book) { continue; @@ -284,14 +284,14 @@ * * @return rcube_contacts Address book object */ - protected function get_address_book($id) + public static function get_address_book($id) { $config = rcube::get_instance()->config; $ldap_config = (array) $config->get('ldap_public'); // use existing instance - if (isset($this->address_books[$id]) && ($this->address_books[$id] instanceof rcube_addressbook)) { - $book = $this->address_books[$id]; + if (isset(self::$address_books[$id]) && (self::$address_books[$id] instanceof rcube_addressbook)) { + $book = self::$address_books[$id]; } else if ($id && $ldap_config[$id]) { $book = new rcube_ldap($ldap_config[$id], $config->get('ldap_debug'), @@ -313,7 +313,7 @@ $book->set_sort_order($sort_col); */ // add to the 'books' array for shutdown function - $this->address_books[$id] = $book; + self::$address_books[$id] = $book; return $book; } @@ -324,7 +324,7 @@ * * @return array Address books array */ - protected function get_address_sources() + public static function get_address_sources() { $config = rcube::get_instance()->config; $ldap_config = (array) $config->get('ldap_public'); @@ -338,21 +338,12 @@ foreach ((array)$async_books as $id) { $prop = $ldap_config[$id]; - // handle misconfiguration - if (empty($prop) || !is_array($prop)) { - continue; + if (!empty($prop) && is_array($prop)) { + $list[$id] = array( + 'id' => $id, + 'name' => $prop['name'], + ); } - - $list[$id] = array( - 'id' => $id, - 'name' => $prop['name'], - ); -/* - // register source for shutdown function - if (!is_object($this->address_books[$id])) - $this->address_books[$id] = $list[$id]; - } -*/ } return $list;
View file
kolab-syncroton-2.3.5.tar.gz/lib/kolab_sync_timezone_converter.php -> kolab-syncroton-2.3.6.tar.gz/lib/kolab_sync_timezone_converter.php
Changed
@@ -1,17 +1,33 @@ <?php /** - * Tine 2.0 - * - * @package ActiveSync - * @license http://www.tine20.org/licenses/agpl-nonus.txt AGPL Version 1 (Non-US) - * NOTE: According to sec. 8 of the AFFERO GENERAL PUBLIC LICENSE (AGPL), - * Version 1, the distribution of the Tine 2.0 ActiveSync module in or to the - * United States of America is excluded from the scope of this license. - * @copyright Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de) - * @author Jonas Fischer <j.fischer@metaways.de> - */ + +--------------------------------------------------------------------------+ + | Kolab Sync (ActiveSync for Kolab) | + | | + | Copyright (C) 2011-2017, Kolab Systems AG <contact@kolabsys.com> | + | Copyright (C) 2008-2012, Metaways Infosystems GmbH | + | | + | This program is free software: you can redistribute it and/or modify | + | it under the terms of the GNU Affero General Public License as published | + | by the Free Software Foundation, either version 3 of the License, or | + | (at your option) any later version. | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU Affero General Public License for more details. | + | | + | You should have received a copy of the GNU Affero General Public License | + | along with this program. If not, see <http://www.gnu.org/licenses/> | + +--------------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + | Author: Jonas Fischer <j.fischer@metaways.de> | + +--------------------------------------------------------------------------+ +*/ +/** + * Activesync timezone converter + */ class kolab_sync_timezone_converter { /** @@ -52,7 +68,6 @@ /** * don't clone. Use the singleton. - * */ private function __clone() { @@ -73,7 +88,7 @@ } /** - * Returns an array of timezones that match to the {@param $_offsets} + * Returns a list of timezones that match to the {@param $_offsets} * * If {@see $_expectedTimezone} is set then the method will terminate as soon * as the expected timezone has matched and the expected timezone will be the @@ -114,12 +129,6 @@ } } -// $this->_log(__METHOD__, __LINE__, 'Matching timezones: '.print_r($timezones, true)); - -// if (empty($timezones)) { -// throw new ActiveSync_TimezoneNotFoundException('No timezone found for the given offsets'); -// } - return $timezones; } @@ -146,33 +155,12 @@ } /** - * Unpacks {@param $_packedTimezoneInfo} using {@see unpackTimezoneInfo} and then - * calls {@see getTimezoneForOffsets} with the unpacked timezone info + * Return packed string for given {@param $_timezone} * - * @param String $_packedTimezoneInfo - * @return String [timezone abbreviation e.g. CET, MST etc.] + * @param string $_timezone Timezone identifier + * @param string|int $_startDate Start date * - */ -// public function getTimezoneForPackedTimezoneInfo($_packedTimezoneInfo) -// { -// $offsets = $this->_unpackTimezoneInfo($_packedTimezoneInfo); -// $matchingTimezones = $this->getTimezoneForOffsets($offsets); -// $maxMatches = 0; -// $matchingAbbr = null; -// foreach ($matchingTimezones as $abbr => $timezones) { -// if (count($timezones) > $maxMatches) { -// $maxMatches = count($timezones); -// $matchingAbbr = $abbr; -// } -// } -// return $matchingAbbr; -// } - - /** - * Return packed string for given {@param $_timezone} - * @param String $_timezone - * @param String | int | null $_startDate - * @return String + * @return string Packed timezone offsets */ public function encodeTimezone($_timezone, $_startDate = null) { @@ -183,15 +171,17 @@ } $offsets = $this->getOffsetsForTimezone($_timezone, $_startDate); + return $this->_packTimezoneInfo($offsets); } /** - * get offsets for given timezone + * Get offsets for given timezone * - * @param string $_timezone - * @param $_startDate - * @return array + * @param string $_timezone Timezone identifier + * @param string|int $_startDate Start date + * + * @return array Timezone offsets */ public function getOffsetsForTimezone($_timezone, $_startDate = null) { @@ -206,7 +196,6 @@ $timezone = new DateTimeZone($_timezone); } catch (Exception $e) { -// $this->_log(__METHOD__, __LINE__, ": could not instantiate timezone {$_timezone}: {$e->getMessage()}"); return null; } @@ -217,13 +206,13 @@ if ($daylightTransition) { $offsets = $this->_generateOffsetsForTransition($offsets, $standardTransition, 'standard'); $offsets = $this->_generateOffsetsForTransition($offsets, $daylightTransition, 'daylight'); - $offsets['standardHour'] += $daylightTransition['offset']/3600; - $offsets['daylightHour'] += $standardTransition['offset']/3600; //@todo how do we get the standardBias (is usually 0)? //$offsets['standardBias'] = ... $offsets['daylightBias'] = ($daylightTransition['offset'] - $standardTransition['offset'])/60*-1; + $offsets['standardHour'] -= $offsets['daylightBias'] / 60; + $offsets['daylightHour'] += $offsets['daylightBias'] / 60; } } @@ -234,21 +223,26 @@ } /** + * Get offsets for timezone transition * + * @param array $_offsets Timezone offsets + * @param array $_transition Timezone transition information + * @param string $_type 'standard' or 'daylight' * - * @param array $_offsets - * @param array $_transition - * @param String $_type * @return array */ - protected function _generateOffsetsForTransition(Array $_offsets, Array $_transition, $_type) + protected function _generateOffsetsForTransition(array $_offsets, array $_transition, $_type) { - $transitionDateParsed = getdate($_transition['ts']); + $transitionDateParsed = new DateTime($_transition['time']); + + if ($_transition['offset']) { + $transitionDateParsed->modify($_transition['offset'] . ' seconds'); + } - $_offsets[$_type . 'Month'] = $transitionDateParsed['mon']; - $_offsets[$_type . 'DayOfWeek'] = $transitionDateParsed['wday']; - $_offsets[$_type . 'Minute'] = $transitionDateParsed['minutes']; - $_offsets[$_type . 'Hour'] = $transitionDateParsed['hours']; + $_offsets[$_type . 'Month'] = (int) $transitionDateParsed->format('n'); + $_offsets[$_type . 'DayOfWeek'] = (int) $transitionDateParsed->format('w'); + $_offsets[$_type . 'Minute'] = (int) $transitionDateParsed->format('i'); + $_offsets[$_type . 'Hour'] = (int) $transitionDateParsed->format('G'); for ($i=5; $i>0; $i--) { if ($this->_isNthOcurrenceOfWeekdayInMonth($_transition['ts'], $i)) { @@ -306,8 +300,8 @@ * Check if the given {@param $_standardTransition} and {@param $_daylightTransition} * match to the object property {@see $_offsets} * - * @param Array $standardTransition - * @param Array $daylightTransition
View file
kolab-syncroton-2.3.5.tar.gz/tests/timezone_converter.php -> kolab-syncroton-2.3.6.tar.gz/tests/timezone_converter.php
Changed
@@ -12,10 +12,80 @@ $converter = timezone_converter_test::getInstance(); $input = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w=='; - $output = $converter->getListOfTimezones($input, 'UTC'); + $output = $converter->getListOfTimezones($input); $this->assertTrue(is_array($output)); } + + function test_get_timezone() + { + $converter = timezone_converter_test::getInstance(); + $datetime = new DateTime('2017-01-01T12:00:00Z'); + + $offsets = $converter->getOffsetsForTimezone('UTC', $datetime); + $output = $converter->getTimezone($offsets, 'UTC'); + + $this->assertSame('UTC', $output); + + $offsets = $converter->getOffsetsForTimezone('Europe/Warsaw', $datetime); + $output = $converter->getTimezone($offsets, 'Europe/Warsaw'); + + $this->assertSame('Europe/Warsaw', $output); + + $offsets = $converter->getOffsetsForTimezone('America/Los_angeles', $datetime); + $output = $converter->getTimezone($offsets, 'America/Los_Angeles'); + + $this->assertSame('America/Los_Angeles', $output); + } + + function test_get_offsets_for_timezone() + { + $converter = timezone_converter_test::getInstance(); + $datetime = new DateTime('2017-01-01T12:00:00Z'); + + $output = $converter->getOffsetsForTimezone('UTC', $datetime); + + $this->assertSame($output['bias'], 0); + $this->assertSame($output['standardBias'], 0); + $this->assertSame($output['daylightBias'], 0); + $this->assertSame($output['standardMonth'], 0); + $this->assertSame($output['daylightMonth'], 0); + + $output = $converter->getOffsetsForTimezone('Europe/Warsaw', $datetime); + + $this->assertSame($output['standardBias'], 0); + $this->assertSame($output['standardMonth'], 10); + $this->assertSame($output['standardDay'], 5); + $this->assertSame($output['standardHour'], 3); + $this->assertSame($output['daylightBias'], -60); + $this->assertSame($output['daylightMonth'], 3); + $this->assertSame($output['daylightDay'], 5); + $this->assertSame($output['daylightHour'], 2); + + $output = $converter->getOffsetsForTimezone('America/Los_Angeles', $datetime); + + $this->assertSame($output['bias'], 480); + $this->assertSame($output['standardBias'], 0); + $this->assertSame($output['standardMonth'], 11); + $this->assertSame($output['standardDay'], 1); + $this->assertSame($output['standardHour'], 2); + $this->assertSame($output['daylightBias'], -60); + $this->assertSame($output['daylightMonth'], 3); + $this->assertSame($output['daylightDay'], 2); + $this->assertSame($output['daylightHour'], 2); + + $output = $converter->getOffsetsForTimezone('Atlantic/Azores', $datetime); + + $this->assertSame($output['bias'], 60); + $this->assertSame($output['standardBias'], 0); + $this->assertSame($output['standardMonth'], 10); + $this->assertSame($output['standardDay'], 5); + $this->assertSame($output['standardHour'], 1); + $this->assertSame($output['daylightBias'], -60); + $this->assertSame($output['daylightMonth'], 3); + $this->assertSame($output['daylightDay'], 5); + $this->assertSame($output['daylightHour'], 0); + } } class timezone_converter_test extends kolab_sync_timezone_converter
View file
kolab-syncroton.dsc
Changed
@@ -2,7 +2,7 @@ Source: kolab-syncroton Binary: kolab-syncroton Architecture: all -Version: 2.3.5-0~kolab4 +Version: 2.3.6-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Homepage: http://www.kolab.org/ @@ -12,5 +12,5 @@ Package-List: kolab-syncroton deb utils extra Files: - 00000000000000000000000000000000 0 kolab-syncroton-2.3.5.tar.gz + 00000000000000000000000000000000 0 kolab-syncroton-2.3.6.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.