several fixes for z-push 2.5 and iOS 12.3:

- send not invitations as calendar-events, just email meeting requests, as they double the events with z-push 2.5 and iOS 12.3
- send all participants incl. organizer as participants, as Exchange also does that and they are otherwise lacking on Android
- fix meeting requests without CLASS:PUBLIC got imported as private events
- better logging for ChangeMessage
This commit is contained in:
Ralf Becker 2019-06-14 21:12:05 +02:00
parent 471742f7ec
commit 3346976e22
2 changed files with 28 additions and 14 deletions

View File

@ -2510,6 +2510,7 @@ class calendar_ical extends calendar_boupdate
'recur_type' => MCAL_RECUR_NONE, 'recur_type' => MCAL_RECUR_NONE,
'recur_exception' => array(), 'recur_exception' => array(),
'priority' => 0, // iCalendar default is 0=undefined, not EGroupware 5=normal 'priority' => 0, // iCalendar default is 0=undefined, not EGroupware 5=normal
'public' => 1,
); );
// we need to parse DTSTART, DTEND or DURATION (in that order!) first // we need to parse DTSTART, DTEND or DURATION (in that order!) first
foreach (array_merge( foreach (array_merge(

View File

@ -5,8 +5,8 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @package calendar * @package calendar
* @subpackage esync * @subpackage esync
* @author Ralf Becker <rb@stylite.de> * @author Ralf Becker <rb@egroupware.org>
* @author Klaus Leithoff <kl@stylite.de> * @author Klaus Leithoff
* @author Philip Herbert <philip@knauber.de> * @author Philip Herbert <philip@knauber.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
@ -18,10 +18,11 @@ use EGroupware\Api\Acl;
/** /**
* Required for TZID <--> AS timezone blob test, if script is called directly via URL * Required for TZID <--> AS timezone blob test, if script is called directly via URL
*/ */
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) if (isset($_SERVER['SCRIPT_FILENAME']) && realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__)
{ {
interface activesync_plugin_write {} interface activesync_plugin_write {}
interface activesync_plugin_meeting_requests {} interface activesync_plugin_meeting_requests {}
class ZLog { static function Write($level, $msg) { unset($level, $msg); }}
} }
/** /**
@ -195,8 +196,10 @@ class calendar_zpush implements activesync_plugin_write, activesync_plugin_meeti
'daywise' => false, 'daywise' => false,
'date_format' => 'server', 'date_format' => 'server',
// default = not rejected, current user return NO meeting requests (status=unknown), as they are returned via email! // default = not rejected, current user return NO meeting requests (status=unknown), as they are returned via email!
//'filter' => $user == $GLOBALS['egw_info']['user']['account_id'] ? (is_array($not_uids) ? 'unknown' : 'not-unknown') : 'default', // with filter="default" iOS 12.3 and z-push 2.5 shows events double: 1. email/meeting-request and 2. calendar entry itself
'filter' => $user == $GLOBALS['egw_info']['user']['account_id'] ? (is_array($not_uids) ? 'unknown' : 'default') : 'default', // ToDo: use filter="default", if user does NOT have email or email-notfications in calendar
'filter' => $user == $GLOBALS['egw_info']['user']['account_id'] ? (is_array($not_uids) ? 'unknown' : 'not-unknown') : 'default',
//'filter' => $user == $GLOBALS['egw_info']['user']['account_id'] ? (is_array($not_uids) ? 'unknown' : 'default') : 'default',
// @todo return only etag relevant information (seems not to work ...) // @todo return only etag relevant information (seems not to work ...)
//'cols' => array('egw_cal.cal_id', 'cal_start', 'recur_type', 'cal_modified', 'cal_uid', 'cal_etag'), //'cols' => array('egw_cal.cal_id', 'cal_start', 'recur_type', 'cal_modified', 'cal_uid', 'cal_etag'),
'query' => array('cal_recurrence' => 0), // do NOT return recurrence exceptions 'query' => array('cal_recurrence' => 0), // do NOT return recurrence exceptions
@ -383,7 +386,7 @@ class calendar_zpush implements activesync_plugin_write, activesync_plugin_meeti
} }
$message->organizer = $event['organizer']; $message->organizer = $event['organizer'];
$message->sensitivity = $event['public'] ? 0 : 2; // 0=normal, 1=personal, 2=private, 3=confidential $message->sensitivity = !isset($event['public']) || $event['public'] ? 0 : 2; // 0=normal, 1=personal, 2=private, 3=confidential
// busystatus=(0=free|1=tentative|2=busy|3=out-of-office), EGw has non_blocking=0|1 // busystatus=(0=free|1=tentative|2=busy|3=out-of-office), EGw has non_blocking=0|1
$message->busystatus = $event['non_blocking'] ? 0 : 2; $message->busystatus = $event['non_blocking'] ? 0 : 2;
@ -464,13 +467,16 @@ class calendar_zpush implements activesync_plugin_write, activesync_plugin_meeti
if ($event['id'] && isset($event['participants'][$uid])) if ($event['id'] && isset($event['participants'][$uid]))
{ {
$ret = $this->calendar->set_status($event, $uid, $status) ? $event['id'] : false; $ret = $this->calendar->set_status($event, $uid, $status) ? $event['id'] : false;
$msg = $ret ? "status '$status' set for event #$ret" : "could NOT set status '$status' for event #$event[id]";
ZLog::Write(LOGLEVEL_DEBUG, __METHOD__.'('.array2string($requestid).", '$folderid', $response) $msg, returning ".array2string($ret));
} }
else else
{ {
$event['participants'][$uid] = $status; $event['participants'][$uid] = $status;
$ret = $this->calendar->update($event, true); // true = ignore conflicts, as there seems no conflict handling in AS $ret = $this->calendar->update($event, true); // true = ignore conflicts, as there seems no conflict handling in AS
$msg = $ret ? "new event #$ret created" : "could NOT create event";
ZLog::Write(LOGLEVEL_DEBUG, __LINE__.': '.__METHOD__.'('.array2string($requestid).", '$folderid', $response) $msg, returning ".array2string($ret));
} }
ZLog::Write(LOGLEVEL_DEBUG, __METHOD__.'('.array2string($requestid).", '$folderid', $response) returning ".array2string($ret));
return $ret; return $ret;
} }
@ -1102,8 +1108,7 @@ class calendar_zpush implements activesync_plugin_write, activesync_plugin_meeti
$message->attendees = array(); $message->attendees = array();
foreach($event['participants'] as $uid => $status) foreach($event['participants'] as $uid => $status)
{ {
// AS does NOT want calendar owner as participant // we send all participants (incl. organizer), as this is what Exchange also does
if ($uid == $account) continue;
$quantity = $role = null; $quantity = $role = null;
calendar_so::split_status($status, $quantity, $role); calendar_so::split_status($status, $quantity, $role);
@ -1435,6 +1440,10 @@ END:VTIMEZONE
{ {
foreach(array('dststart' => $daylight,'dstend' => $standard) as $prefix => $comp) foreach(array('dststart' => $daylight,'dstend' => $standard) as $prefix => $comp)
{ {
// fix RRULE order
$comp['RRULE'] = preg_replace('/FREQ=YEARLY;BYMONTH=(\d+);BYDAY=(.*)/',
'FREQ=YEARLY;BYDAY=$2;BYMONTH=$1', $comp['RRULE']);
if (preg_match('/FREQ=YEARLY;BYDAY=(.*);BYMONTH=(\d+)/',$comp['RRULE'],$matches)) if (preg_match('/FREQ=YEARLY;BYDAY=(.*);BYMONTH=(\d+)/',$comp['RRULE'],$matches))
{ {
$data[$prefix.'month'] = (int)$matches[2]; $data[$prefix.'month'] = (int)$matches[2];
@ -1665,7 +1674,7 @@ END:VTIMEZONE
* *
* You need to comment implements activesync_plugin_write * You need to comment implements activesync_plugin_write
*/ */
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) // some tests if (isset($_SERVER['SCRIPT_FILENAME']) && realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__) // some tests
{ {
$GLOBALS['egw_info'] = array( $GLOBALS['egw_info'] = array(
'flags' => array( 'flags' => array(
@ -1689,7 +1698,9 @@ if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE_
// TZID => AS timezone blobs reported by various devices // TZID => AS timezone blobs reported by various devices
foreach(array( foreach(array(
'Europe/Berlin' => 'xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAMAAAAAAAAAxP///w==', // Exchange 2016 Europe/Berlin
'Europe/Berlin' => 'xP///1cALgAgAEUAdQByAG8AcABlACAAUwB0AGEAbgBkAGEAcgBkACAAVABpAG0AZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAACgAVQBUAEMAKwAwADEAOgAwADAAKQAgAEEAbQBzAHQAZQByAGQAYQBtACwAIABCAGUAcgBsAGkAbgAsACAAQgAAAAMAAAAFAAIAAAAAAAAAxP///w==',
//'Europe/Berlin' => 'xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAMAAAAAAAAAxP///w==',
'Europe/Helsinki' => 'iP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAQAAAAAAAAAxP///w==', 'Europe/Helsinki' => 'iP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAQAAAAAAAAAxP///w==',
'Asia/Tokyo' => '5P3//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///w==', 'Asia/Tokyo' => '5P3//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///w==',
'Atlantic/Azores' => 'PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==', 'Atlantic/Azores' => 'PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==',
@ -1711,7 +1722,7 @@ if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE_
//echo "$tz=<pre>".print_r($as_tz,true)."</pre>\n"; //echo "$tz=<pre>".print_r($as_tz,true)."</pre>\n";
$as_tz_org = calendar_zpush::_getTZFromSyncBlob(base64_decode($sync_blob)); $as_tz_org = calendar_zpush::_getTZFromSyncBlob(base64_decode($sync_blob));
//echo "sync_blob=<pre>".print_r($as_tz_org,true)."</pre>\n"; echo "sync_blob=<pre>".print_r($as_tz_org,true)."</pre>\n";
// find matching timezone from as data // find matching timezone from as data
// this returns the FIRST match, which is in case of Pacific/Auckland eg. Antarctica/McMurdo ;-) // this returns the FIRST match, which is in case of Pacific/Auckland eg. Antarctica/McMurdo ;-)
@ -1728,7 +1739,9 @@ if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE_
foreach(array('year','month','day','week','hour','minute','second') as $postfix) foreach(array('year','month','day','week','hour','minute','second') as $postfix)
{ {
$failed = $n && $as_tz_org[$prefix.$postfix] !== $as_tz[$prefix.$postfix]; $failed = $n && $as_tz_org[$prefix.$postfix] !== $as_tz[$prefix.$postfix];
$parts[] = ($failed?'<font color="red">':'').$arr[$prefix.$postfix].($failed?'</font>':''); $parts[] = ($failed?'<font color="red">':'').
"<span title='$postfix'>".$arr[$prefix.$postfix].'</span>'.
($failed?'</font>':'');
} }
echo implode(' ', $parts).(!$n?'<br/>':''); echo implode(' ', $parts).(!$n?'<br/>':'');
} }