There’s an issue with free/busy calendars in Lightning (Thunderbird 60.3.3).
Due to its cause (see below) this bug should affect other clients too…
This is how to reproduce it:
- open Lightning eGW calendar
- create a new event
- click on “Invite partecipants” button to open the corresponding dialog
- insert the partecipant email
- some users have their free/busy (FB) calendar populated, while other appears empty
After debugging Lightning requests and responses I’ve found that partecipants FB calendar is populated for all users, but it always contains only a single event: the last one in chronological order.
That explains why some users have an empty FB calendar and some others not: if the last event is outside the shown range, it simply won’t appear.
Once found the issue I’ve digged down to the code, landing to function calendar_ical.aggregate_periods()
in file calendar/inc/class.calendar_ical.inc.php
which is supposed to “aggregate” an array of events to remove the overlapping ones.
There’s an error in first lines of that function, where uasort()
function is used to sort events by start date:
public function aggregate_periods(array $events, $start, $end)
{
// sort by start datetime
uasort($events, function($a, $b)
{
$diff = $a['start'] < $b['start'];
return !$diff ? 0 : ($diff < 0 ? -1 : 1);
});
$diff
is a boolean, so it will never be < 0
, thus the sort callback will never return -1
.
This way the code will sort the events in reverse chronological order, which is not expected by the rest of the code, which will all events but the last.
The function must be changed like this:
public function aggregate_periods(array $events, $start, $end)
{
// sort by start datetime
uasort($events, function($a, $b)
{
$diff = $a['start'] - $b['start'];
return $diff == 0 ? 0 : ($diff < 0 ? -1 : 1);
});
After applying this fix the FB calendar correctly contains all the user events.
My patch also contains a fix for attribute parsing in functions calendar_groupdav.put()
and calendar_groupdav.post()
.
In both function there’s a cleanup code like this:
foreach ($content_type as $attribute)
{
trim($attribute);
list($key, $value) = explode('=', $attribute);
switch (strtolower($key))
{
case 'charset':
$charset = strtoupper(substr($value,1,-1));
}
}
Here the trim() call is useless, because trim() is a function and its return value is discarded.
It should read like this: $attribute = trim($attribute)
, but this won’t correctly handle possibly malformed strings like $attribute = " charset = utf-8"
.
This is a safer implementation:
foreach ($content_type as $attribute)
{
list($key, $value) = explode('=', $attribute);
switch (strtolower(trim($key)))
{
case 'charset':
$charset = strtoupper(trim($value));
}
}
Hope you’ll include my patch within your code .
PS: I don’t understand why the original code strtoupper(substr($value,1,-1))
strips the first and last chars of “charset” attribute.
On my side $attribute = " charset=utf-8"
(with a leading space) so the original code set $charset
to the wrong value "TF-"
…
egw_17.1.20181205_patch.txt (1.6 KB)