PHP8 compatibility fixes
Summary: PHP8 fixes, CS fixes, short array syntax, indentation Reviewers: #roundcube_kolab_plugins_developers Subscribers: #roundcube_kolab_plugins_developers Tags: #roundcube_kolab_plugins Differential Revision: https://git.kolab.org/D2185
This commit is contained in:
parent
fba24494dd
commit
87fbaea696
28 changed files with 10577 additions and 9546 deletions
File diff suppressed because it is too large
Load diff
|
@ -24,7 +24,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.0",
|
"php": ">=5.4.0",
|
||||||
"roundcube/plugin-installer": ">=0.1.3",
|
"roundcube/plugin-installer": ">=0.1.3",
|
||||||
"kolab/libcalendaring": ">=3.4.0",
|
"kolab/libcalendaring": ">=3.4.0",
|
||||||
"kolab/libkolab": ">=3.4.0"
|
"kolab/libkolab": ">=3.4.0"
|
||||||
|
|
|
@ -111,23 +111,24 @@ abstract class calendar_driver
|
||||||
public $attachments = false;
|
public $attachments = false;
|
||||||
public $undelete = false;
|
public $undelete = false;
|
||||||
public $history = false;
|
public $history = false;
|
||||||
public $categoriesimmutable = false;
|
public $alarm_types = ['DISPLAY'];
|
||||||
public $alarm_types = array('DISPLAY');
|
|
||||||
public $alarm_absolute = true;
|
public $alarm_absolute = true;
|
||||||
|
public $categoriesimmutable = false;
|
||||||
public $last_error;
|
public $last_error;
|
||||||
|
|
||||||
protected $default_categories = array(
|
protected $default_categories = [
|
||||||
'Personal' => 'c0c0c0',
|
'Personal' => 'c0c0c0',
|
||||||
'Work' => 'ff0000',
|
'Work' => 'ff0000',
|
||||||
'Family' => '00ff00',
|
'Family' => '00ff00',
|
||||||
'Holiday' => 'ff6600',
|
'Holiday' => 'ff6600',
|
||||||
);
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of available calendars from this source
|
* Get a list of available calendars from this source
|
||||||
*
|
*
|
||||||
* @param integer Bitmask defining filter criterias.
|
* @param int $filter Bitmask defining filter criterias.
|
||||||
* See FILTER_* constants for possible values.
|
* See FILTER_* constants for possible values.
|
||||||
|
*
|
||||||
* @return array List of calendars
|
* @return array List of calendars
|
||||||
*/
|
*/
|
||||||
abstract function list_calendars($filter = 0);
|
abstract function list_calendars($filter = 0);
|
||||||
|
@ -135,10 +136,11 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Create a new calendar assigned to the current user
|
* Create a new calendar assigned to the current user
|
||||||
*
|
*
|
||||||
* @param array Hash array with calendar properties
|
* @param array $prop Hash array with calendar properties
|
||||||
* name: Calendar name
|
* name: Calendar name
|
||||||
* color: The color of the calendar
|
* color: The color of the calendar
|
||||||
* showalarms: True if alarms are enabled
|
* showalarms: True if alarms are enabled
|
||||||
|
*
|
||||||
* @return mixed ID of the calendar on success, False on error
|
* @return mixed ID of the calendar on success, False on error
|
||||||
*/
|
*/
|
||||||
abstract function create_calendar($prop);
|
abstract function create_calendar($prop);
|
||||||
|
@ -146,39 +148,43 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Update properties of an existing calendar
|
* Update properties of an existing calendar
|
||||||
*
|
*
|
||||||
* @param array Hash array with calendar properties
|
* @param array $prop Hash array with calendar properties
|
||||||
* id: Calendar Identifier
|
* id: Calendar Identifier
|
||||||
* name: Calendar name
|
* name: Calendar name
|
||||||
* color: The color of the calendar
|
* color: The color of the calendar
|
||||||
* showalarms: True if alarms are enabled (if supported)
|
* showalarms: True if alarms are enabled (if supported)
|
||||||
* @return boolean True on success, Fales on failure
|
*
|
||||||
|
* @return bool True on success, Fales on failure
|
||||||
*/
|
*/
|
||||||
abstract function edit_calendar($prop);
|
abstract function edit_calendar($prop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set active/subscribed state of a calendar
|
* Set active/subscribed state of a calendar
|
||||||
*
|
*
|
||||||
* @param array Hash array with calendar properties
|
* @param array $prop Hash array with calendar properties
|
||||||
* id: Calendar Identifier
|
* id: Calendar Identifier
|
||||||
* active: True if calendar is active, false if not
|
* active: True if calendar is active, false if not
|
||||||
* @return boolean True on success, Fales on failure
|
*
|
||||||
|
* @return bool True on success, Fales on failure
|
||||||
*/
|
*/
|
||||||
abstract function subscribe_calendar($prop);
|
abstract function subscribe_calendar($prop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the given calendar with all its contents
|
* Delete the given calendar with all its contents
|
||||||
*
|
*
|
||||||
* @param array Hash array with calendar properties
|
* @param array $prop Hash array with calendar properties
|
||||||
* id: Calendar Identifier
|
* id: Calendar Identifier
|
||||||
* @return boolean True on success, Fales on failure
|
*
|
||||||
|
* @return bool True on success, Fales on failure
|
||||||
*/
|
*/
|
||||||
abstract function delete_calendar($prop);
|
abstract function delete_calendar($prop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for shared or otherwise not listed calendars the user has access
|
* Search for shared or otherwise not listed calendars the user has access
|
||||||
*
|
*
|
||||||
* @param string Search string
|
* @param string $query Search string
|
||||||
* @param string Section/source to search
|
* @param string $source Section/source to search
|
||||||
|
*
|
||||||
* @return array List of calendars
|
* @return array List of calendars
|
||||||
*/
|
*/
|
||||||
abstract function search_calendars($query, $source);
|
abstract function search_calendars($query, $source);
|
||||||
|
@ -186,7 +192,8 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Add a single event to the database
|
* Add a single event to the database
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties (see header of this file)
|
* @param array $event Hash array with event properties (see header of this file)
|
||||||
|
*
|
||||||
* @return mixed New event ID on success, False on error
|
* @return mixed New event ID on success, False on error
|
||||||
*/
|
*/
|
||||||
abstract function new_event($event);
|
abstract function new_event($event);
|
||||||
|
@ -194,18 +201,20 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Update an event entry with the given data
|
* Update an event entry with the given data
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties (see header of this file)
|
* @param array $event Hash array with event properties (see header of this file)
|
||||||
* @return boolean True on success, False on error
|
*
|
||||||
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
abstract function edit_event($event);
|
abstract function edit_event($event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended event editing with possible changes to the argument
|
* Extended event editing with possible changes to the argument
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties
|
* @param array &$event Hash array with event properties
|
||||||
* @param string New participant status
|
* @param string $status New participant status
|
||||||
* @param array List of hash arrays with updated attendees
|
* @param array $attendees List of hash arrays with updated attendees
|
||||||
* @return boolean True on success, False on error
|
*
|
||||||
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function edit_rsvp(&$event, $status, $attendees)
|
public function edit_rsvp(&$event, $status, $attendees)
|
||||||
{
|
{
|
||||||
|
@ -215,9 +224,10 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Update the participant status for the given attendee
|
* Update the participant status for the given attendee
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties
|
* @param array &$event Hash array with event properties
|
||||||
* @param array List of hash arrays each represeting an updated attendee
|
* @param array $attendees List of hash arrays each represeting an updated attendee
|
||||||
* @return boolean True on success, False on error
|
*
|
||||||
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function update_attendees(&$event, $attendees)
|
public function update_attendees(&$event, $attendees)
|
||||||
{
|
{
|
||||||
|
@ -227,45 +237,47 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Move a single event
|
* Move a single event
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties:
|
* @param array $event Hash array with event properties:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
* start: Event start date/time as DateTime object
|
* start: Event start date/time as DateTime object
|
||||||
* end: Event end date/time as DateTime object
|
* end: Event end date/time as DateTime object
|
||||||
* allday: Boolean flag if this is an all-day event
|
* allday: Boolean flag if this is an all-day event
|
||||||
* @return boolean True on success, False on error
|
*
|
||||||
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
abstract function move_event($event);
|
abstract function move_event($event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize a single event
|
* Resize a single event
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties:
|
* @param array $event Hash array with event properties:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
* start: Event start date/time as DateTime object with timezone
|
* start: Event start date/time as DateTime object with timezone
|
||||||
* end: Event end date/time as DateTime object with timezone
|
* end: Event end date/time as DateTime object with timezone
|
||||||
* @return boolean True on success, False on error
|
*
|
||||||
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
abstract function resize_event($event);
|
abstract function resize_event($event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a single event from the database
|
* Remove a single event from the database
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties:
|
* @param array $event Hash array with event properties:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
* @param boolean Remove event irreversible (mark as deleted otherwise,
|
* @param bool $force Remove event irreversible (mark as deleted otherwise,
|
||||||
* if supported by the backend)
|
* if supported by the backend)
|
||||||
*
|
*
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
abstract function remove_event($event, $force = true);
|
abstract function remove_event($event, $force = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores a single deleted event (if supported)
|
* Restores a single deleted event (if supported)
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties:
|
* @param array $event Hash array with event properties:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
*
|
*
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function restore_event($event)
|
public function restore_event($event)
|
||||||
{
|
{
|
||||||
|
@ -275,14 +287,14 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Return data of a single event
|
* Return data of a single event
|
||||||
*
|
*
|
||||||
* @param mixed UID string or hash array with event properties:
|
* @param mixed $event UID string or hash array with event properties:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
* uid: Event UID
|
* uid: Event UID
|
||||||
* _instance: Instance identifier in combination with uid (optional)
|
* _instance: Instance identifier in combination with uid (optional)
|
||||||
* calendar: Calendar identifier (optional)
|
* calendar: Calendar identifier (optional)
|
||||||
* @param integer Bitmask defining the scope to search events in.
|
* @param int $scope Bitmask defining the scope to search events in.
|
||||||
* See FILTER_* constants for possible values.
|
* See FILTER_* constants for possible values.
|
||||||
* @param boolean If true, recurrence exceptions shall be added
|
* @param bool $full If true, recurrence exceptions shall be added
|
||||||
*
|
*
|
||||||
* @return array Event object as hash array
|
* @return array Event object as hash array
|
||||||
*/
|
*/
|
||||||
|
@ -291,12 +303,13 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Get events from source.
|
* Get events from source.
|
||||||
*
|
*
|
||||||
* @param integer Date range start (unix timestamp)
|
* @param int $start Date range start (unix timestamp)
|
||||||
* @param integer Date range end (unix timestamp)
|
* @param int $end Date range end (unix timestamp)
|
||||||
* @param string Search query (optional)
|
* @param string $query Search query (optional)
|
||||||
* @param mixed List of calendar IDs to load events from (either as array or comma-separated string)
|
* @param mixed $calendars List of calendar IDs to load events from (either as array or comma-separated string)
|
||||||
* @param boolean Include virtual/recurring events (optional)
|
* @param bool $virtual Include virtual/recurring events (optional)
|
||||||
* @param integer Only list events modified since this time (unix timestamp)
|
* @param int $modifiedsince Only list events modified since this time (unix timestamp)
|
||||||
|
*
|
||||||
* @return array A list of event objects (see header of this file for struct of an event)
|
* @return array A list of event objects (see header of this file for struct of an event)
|
||||||
*/
|
*/
|
||||||
abstract function load_events($start, $end, $query = null, $calendars = null, $virtual = 1, $modifiedsince = null);
|
abstract function load_events($start, $end, $query = null, $calendars = null, $virtual = 1, $modifiedsince = null);
|
||||||
|
@ -304,9 +317,10 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Get number of events in the given calendar
|
* Get number of events in the given calendar
|
||||||
*
|
*
|
||||||
* @param mixed List of calendar IDs to count events (either as array or comma-separated string)
|
* @param mixed $calendars List of calendar IDs to count events (either as array or comma-separated string)
|
||||||
* @param integer Date range start (unix timestamp)
|
* @param int $start Date range start (unix timestamp)
|
||||||
* @param integer Date range end (unix timestamp)
|
* @param int $end Date range end (unix timestamp)
|
||||||
|
*
|
||||||
* @return array Hash array with counts grouped by calendar ID
|
* @return array Hash array with counts grouped by calendar ID
|
||||||
*/
|
*/
|
||||||
abstract function count_events($calendars, $start, $end = null);
|
abstract function count_events($calendars, $start, $end = null);
|
||||||
|
@ -314,8 +328,9 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Get a list of pending alarms to be displayed to the user
|
* Get a list of pending alarms to be displayed to the user
|
||||||
*
|
*
|
||||||
* @param integer Current time (unix timestamp)
|
* @param int $time Current time (unix timestamp)
|
||||||
* @param mixed List of calendar IDs to show alarms for (either as array or comma-separated string)
|
* @param mixed $calendars List of calendar IDs to show alarms for (either as array or comma-separated string)
|
||||||
|
*
|
||||||
* @return array A list of alarms, each encoded as hash array:
|
* @return array A list of alarms, each encoded as hash array:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
* uid: Unique identifier of this event
|
* uid: Unique identifier of this event
|
||||||
|
@ -331,30 +346,33 @@ abstract class calendar_driver
|
||||||
* (User) feedback after showing an alarm notification
|
* (User) feedback after showing an alarm notification
|
||||||
* This should mark the alarm as 'shown' or snooze it for the given amount of time
|
* This should mark the alarm as 'shown' or snooze it for the given amount of time
|
||||||
*
|
*
|
||||||
* @param string Event identifier
|
* @param string $event_id Event identifier
|
||||||
* @param integer Suspend the alarm for this number of seconds
|
* @param int $snooze Suspend the alarm for this number of seconds
|
||||||
*/
|
*/
|
||||||
abstract function dismiss_alarm($event_id, $snooze = 0);
|
abstract function dismiss_alarm($event_id, $snooze = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the given event object for validity
|
* Check the given event object for validity
|
||||||
*
|
*
|
||||||
* @param array Event object as hash array
|
* @param array $event Event object as hash array
|
||||||
|
*
|
||||||
* @return boolean True if valid, false if not
|
* @return boolean True if valid, false if not
|
||||||
*/
|
*/
|
||||||
public function validate($event)
|
public function validate($event)
|
||||||
{
|
{
|
||||||
$valid = true;
|
$valid = true;
|
||||||
|
|
||||||
if (!is_object($event['start']) || !is_a($event['start'], 'DateTime'))
|
if (empty($event['start']) || !is_object($event['start']) || !is_a($event['start'], 'DateTime')) {
|
||||||
$valid = false;
|
$valid = false;
|
||||||
if (!is_object($event['end']) || !is_a($event['end'], 'DateTime'))
|
}
|
||||||
|
|
||||||
|
if (empty($event['end']) || !is_object($event['end']) || !is_a($event['end'], 'DateTime')) {
|
||||||
$valid = false;
|
$valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
return $valid;
|
return $valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get list of event's attachments.
|
* Get list of event's attachments.
|
||||||
* Drivers can return list of attachments as event property.
|
* Drivers can return list of attachments as event property.
|
||||||
|
@ -443,9 +461,9 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Fetch free/busy information from a person within the given range
|
* Fetch free/busy information from a person within the given range
|
||||||
*
|
*
|
||||||
* @param string E-mail address of attendee
|
* @param string $email E-mail address of attendee
|
||||||
* @param integer Requested period start date/time as unix timestamp
|
* @param int $start Requested period start date/time as unix timestamp
|
||||||
* @param integer Requested period end date/time as unix timestamp
|
* @param int $end Requested period end date/time as unix timestamp
|
||||||
*
|
*
|
||||||
* @return array List of busy timeslots within the requested range
|
* @return array List of busy timeslots within the requested range
|
||||||
*/
|
*/
|
||||||
|
@ -457,16 +475,17 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Create instances of a recurring event
|
* Create instances of a recurring event
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties
|
* @param array $event Hash array with event properties
|
||||||
* @param object DateTime Start date of the recurrence window
|
* @param DateTime $start Start date of the recurrence window
|
||||||
* @param object DateTime End date of the recurrence window
|
* @param DateTime $end End date of the recurrence window
|
||||||
|
*
|
||||||
* @return array List of recurring event instances
|
* @return array List of recurring event instances
|
||||||
*/
|
*/
|
||||||
public function get_recurring_events($event, $start, $end = null)
|
public function get_recurring_events($event, $start, $end = null)
|
||||||
{
|
{
|
||||||
$events = array();
|
$events = [];
|
||||||
|
|
||||||
if ($event['recurrence']) {
|
if (!empty($event['recurrence'])) {
|
||||||
// include library class
|
// include library class
|
||||||
require_once(dirname(__FILE__) . '/../lib/calendar_recurrence.php');
|
require_once(dirname(__FILE__) . '/../lib/calendar_recurrence.php');
|
||||||
|
|
||||||
|
@ -551,7 +570,7 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Return full data of a specific revision of an event
|
* Return full data of a specific revision of an event
|
||||||
*
|
*
|
||||||
* @param mixed UID string or hash array with event properties:
|
* @param mixed $event UID string or hash array with event properties:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
* calendar: Calendar identifier
|
* calendar: Calendar identifier
|
||||||
* @param mixed $rev Revision number
|
* @param mixed $rev Revision number
|
||||||
|
@ -568,7 +587,7 @@ abstract class calendar_driver
|
||||||
* Command the backend to restore a certain revision of an event.
|
* Command the backend to restore a certain revision of an event.
|
||||||
* This shall replace the current event with an older version.
|
* This shall replace the current event with an older version.
|
||||||
*
|
*
|
||||||
* @param mixed UID string or hash array with event properties:
|
* @param mixed $event UID string or hash array with event properties:
|
||||||
* id: Event identifier
|
* id: Event identifier
|
||||||
* calendar: Calendar identifier
|
* calendar: Calendar identifier
|
||||||
* @param mixed $rev Revision number
|
* @param mixed $rev Revision number
|
||||||
|
@ -580,19 +599,18 @@ abstract class calendar_driver
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function to produce driver-specific calendar create/edit form
|
* Callback function to produce driver-specific calendar create/edit form
|
||||||
*
|
*
|
||||||
* @param string Request action 'form-edit|form-new'
|
* @param string $action Request action 'form-edit|form-new'
|
||||||
* @param array Calendar properties (e.g. id, color)
|
* @param array $calendar Calendar properties (e.g. id, color)
|
||||||
* @param array Edit form fields
|
* @param array $formfields Edit form fields
|
||||||
*
|
*
|
||||||
* @return string HTML content of the form
|
* @return string HTML content of the form
|
||||||
*/
|
*/
|
||||||
public function calendar_form($action, $calendar, $formfields)
|
public function calendar_form($action, $calendar, $formfields)
|
||||||
{
|
{
|
||||||
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
|
$table = new html_table(['cols' => 2, 'class' => 'propform']);
|
||||||
|
|
||||||
foreach ($formfields as $col => $colprop) {
|
foreach ($formfields as $col => $colprop) {
|
||||||
$label = !empty($colprop['label']) ? $colprop['label'] : $rcmail->gettext("$domain.$col");
|
$label = !empty($colprop['label']) ? $colprop['label'] : $rcmail->gettext("$domain.$col");
|
||||||
|
@ -610,17 +628,18 @@ abstract class calendar_driver
|
||||||
* This is a default implementation using Roundcube's address book API.
|
* This is a default implementation using Roundcube's address book API.
|
||||||
* It can be overriden with a more optimized version by the individual drivers.
|
* It can be overriden with a more optimized version by the individual drivers.
|
||||||
*
|
*
|
||||||
* @param integer Event's new start (unix timestamp)
|
* @param int $start Event's new start (unix timestamp)
|
||||||
* @param integer Event's new end (unix timestamp)
|
* @param int $end Event's new end (unix timestamp)
|
||||||
* @param string Search query (optional)
|
* @param string $search Search query (optional)
|
||||||
* @param integer Only list events modified since this time (unix timestamp)
|
* @param int $modifiedsince Only list events modified since this time (unix timestamp)
|
||||||
|
*
|
||||||
* @return array A list of event records
|
* @return array A list of event records
|
||||||
*/
|
*/
|
||||||
public function load_birthday_events($start, $end, $search = null, $modifiedsince = null)
|
public function load_birthday_events($start, $end, $search = null, $modifiedsince = null)
|
||||||
{
|
{
|
||||||
// ignore update requests for simplicity reasons
|
// ignore update requests for simplicity reasons
|
||||||
if (!empty($modifiedsince)) {
|
if (!empty($modifiedsince)) {
|
||||||
return array();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to DateTime for comparisons
|
// convert to DateTime for comparisons
|
||||||
|
@ -630,7 +649,7 @@ abstract class calendar_driver
|
||||||
$year = $start->format('Y');
|
$year = $start->format('Y');
|
||||||
$year2 = $end->format('Y');
|
$year2 = $end->format('Y');
|
||||||
|
|
||||||
$events = array();
|
$events = [];
|
||||||
$search = mb_strtolower($search);
|
$search = mb_strtolower($search);
|
||||||
$rcmail = rcmail::get_instance();
|
$rcmail = rcmail::get_instance();
|
||||||
$cache = $rcmail->get_cache('calendar.birthdays', 'db', 3600);
|
$cache = $rcmail->get_cache('calendar.birthdays', 'db', 3600);
|
||||||
|
@ -643,6 +662,7 @@ abstract class calendar_driver
|
||||||
// let the user select the address books to consider in prefs
|
// let the user select the address books to consider in prefs
|
||||||
$selected_sources = $rcmail->config->get('calendar_birthday_adressbooks');
|
$selected_sources = $rcmail->config->get('calendar_birthday_adressbooks');
|
||||||
$sources = $selected_sources ?: array_keys($rcmail->get_address_sources(false, true));
|
$sources = $selected_sources ?: array_keys($rcmail->get_address_sources(false, true));
|
||||||
|
|
||||||
foreach ($sources as $source) {
|
foreach ($sources as $source) {
|
||||||
$abook = $rcmail->get_address_book($source);
|
$abook = $rcmail->get_address_book($source);
|
||||||
|
|
||||||
|
@ -651,14 +671,19 @@ abstract class calendar_driver
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip collected recipients/senders addressbooks
|
||||||
|
if (is_a($abook, 'rcube_addresses')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$abook->set_pagesize(10000);
|
$abook->set_pagesize(10000);
|
||||||
|
|
||||||
// check for cached results
|
// check for cached results
|
||||||
$cache_records = array();
|
$cache_records = [];
|
||||||
$cached = $cache->get($source);
|
$cached = $cache->get($source);
|
||||||
|
|
||||||
// iterate over (cached) contacts
|
// iterate over (cached) contacts
|
||||||
foreach (($cached ?: $abook->search('*', '', 2, true, true, array('birthday'))) as $contact) {
|
foreach (($cached ?: $abook->search('*', '', 2, true, true, ['birthday'])) as $contact) {
|
||||||
$event = self::parse_contact($contact, $source);
|
$event = self::parse_contact($contact, $source);
|
||||||
|
|
||||||
if (empty($event)) {
|
if (empty($event)) {
|
||||||
|
@ -667,11 +692,11 @@ abstract class calendar_driver
|
||||||
|
|
||||||
// add stripped record to cache
|
// add stripped record to cache
|
||||||
if (empty($cached)) {
|
if (empty($cached)) {
|
||||||
$cache_records[] = array(
|
$cache_records[] = [
|
||||||
'ID' => $contact['ID'],
|
'ID' => $contact['ID'],
|
||||||
'name' => $event['_displayname'],
|
'name' => $event['_displayname'],
|
||||||
'birthday' => $event['start']->format('Y-m-d'),
|
'birthday' => $event['start']->format('Y-m-d'),
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter by search term (only name is involved here)
|
// filter by search term (only name is involved here)
|
||||||
|
@ -701,9 +726,12 @@ abstract class calendar_driver
|
||||||
// if this is not the first occurence modify event details
|
// if this is not the first occurence modify event details
|
||||||
// but not when this is "all birthdays feed" request
|
// but not when this is "all birthdays feed" request
|
||||||
if ($year2 - $year < 10 && ($age = ($this_year - $byear))) {
|
if ($year2 - $year < 10 && ($age = ($this_year - $byear))) {
|
||||||
$event['description'] = $rcmail->gettext(array('name' => 'birthdayage', 'vars' => array('age' => $age)), 'calendar');
|
$label = ['name' => 'birthdayage', 'vars' => ['age' => $age]];
|
||||||
|
|
||||||
|
$event['description'] = $rcmail->gettext($label, 'calendar');
|
||||||
$event['start'] = $bday;
|
$event['start'] = $bday;
|
||||||
$event['end'] = clone $bday;
|
$event['end'] = clone $bday;
|
||||||
|
|
||||||
unset($event['recurrence']);
|
unset($event['recurrence']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,7 +755,7 @@ abstract class calendar_driver
|
||||||
public function get_birthday_event($id)
|
public function get_birthday_event($id)
|
||||||
{
|
{
|
||||||
// decode $id
|
// decode $id
|
||||||
list(,$source,$contact_id,$year) = explode(':', rcube_ldap::dn_decode($id));
|
list(, $source, $contact_id, $year) = explode(':', rcube_ldap::dn_decode($id));
|
||||||
|
|
||||||
$rcmail = rcmail::get_instance();
|
$rcmail = rcmail::get_instance();
|
||||||
|
|
||||||
|
@ -744,7 +772,7 @@ abstract class calendar_driver
|
||||||
* @param array $contact Contact data
|
* @param array $contact Contact data
|
||||||
* @param string $source Addressbook source ID
|
* @param string $source Addressbook source ID
|
||||||
*
|
*
|
||||||
* @return array Birthday event data
|
* @return array|null Birthday event data
|
||||||
*/
|
*/
|
||||||
public static function parse_contact($contact, $source)
|
public static function parse_contact($contact, $source)
|
||||||
{
|
{
|
||||||
|
@ -752,7 +780,7 @@ abstract class calendar_driver
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($contact['birthday'])) {
|
if (!empty($contact['birthday']) && is_array($contact['birthday'])) {
|
||||||
$contact['birthday'] = reset($contact['birthday']);
|
$contact['birthday'] = reset($contact['birthday']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,22 +796,25 @@ abstract class calendar_driver
|
||||||
$bday->_dateonly = true;
|
$bday->_dateonly = true;
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error([
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'file' => __FILE__,
|
||||||
'message' => 'BIRTHDAY PARSE ERROR: ' . $e->getMessage()),
|
'line' => __LINE__,
|
||||||
true, false);
|
'message' => 'BIRTHDAY PARSE ERROR: ' . $e->getMessage()
|
||||||
|
],
|
||||||
|
true, false
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$rcmail = rcmail::get_instance();
|
$rcmail = rcmail::get_instance();
|
||||||
$birthyear = $bday->format('Y');
|
$birthyear = $bday->format('Y');
|
||||||
$display_name = rcube_addressbook::compose_display_name($contact);
|
$display_name = rcube_addressbook::compose_display_name($contact);
|
||||||
$label = array('name' => 'birthdayeventtitle', 'vars' => array('name' => $display_name));
|
$label = ['name' => 'birthdayeventtitle', 'vars' => ['name' => $display_name]];
|
||||||
$event_title = $rcmail->gettext($label, 'calendar');
|
$event_title = $rcmail->gettext($label, 'calendar');
|
||||||
$uid = rcube_ldap::dn_encode('bday:' . $source . ':' . $contact['ID'] . ':' . $birthyear);
|
$uid = rcube_ldap::dn_encode('bday:' . $source . ':' . $contact['ID'] . ':' . $birthyear);
|
||||||
|
|
||||||
$event = array(
|
return [
|
||||||
'id' => $uid,
|
'id' => $uid,
|
||||||
'uid' => $uid,
|
'uid' => $uid,
|
||||||
'calendar' => self::BIRTHDAY_CALENDAR_ID,
|
'calendar' => self::BIRTHDAY_CALENDAR_ID,
|
||||||
|
@ -792,19 +823,17 @@ abstract class calendar_driver
|
||||||
'allday' => true,
|
'allday' => true,
|
||||||
'start' => $bday,
|
'start' => $bday,
|
||||||
'end' => clone $bday,
|
'end' => clone $bday,
|
||||||
'recurrence' => array('FREQ' => 'YEARLY', 'INTERVAL' => 1),
|
'recurrence' => ['FREQ' => 'YEARLY', 'INTERVAL' => 1],
|
||||||
'free_busy' => 'free',
|
'free_busy' => 'free',
|
||||||
'_displayname' => $display_name,
|
'_displayname' => $display_name,
|
||||||
);
|
];
|
||||||
|
|
||||||
return $event;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store alarm dismissal for birtual birthay events
|
* Store alarm dismissal for birtual birthay events
|
||||||
*
|
*
|
||||||
* @param string Event identifier
|
* @param string $event_id Event identifier
|
||||||
* @param integer Suspend the alarm for this number of seconds
|
* @param int $snooze Suspend the alarm for this number of seconds
|
||||||
*/
|
*/
|
||||||
public function dismiss_birthday_alarm($event_id, $snooze = 0)
|
public function dismiss_birthday_alarm($event_id, $snooze = 0)
|
||||||
{
|
{
|
||||||
|
@ -814,7 +843,7 @@ abstract class calendar_driver
|
||||||
|
|
||||||
// compute new notification time or disable if not snoozed
|
// compute new notification time or disable if not snoozed
|
||||||
$notifyat = $snooze > 0 ? time() + $snooze : null;
|
$notifyat = $snooze > 0 ? time() + $snooze : null;
|
||||||
$cache->set($event_id, array('snooze' => $snooze, 'notifyat' => $notifyat));
|
$cache->set($event_id, ['snooze' => $snooze, 'notifyat' => $notifyat]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -822,7 +851,8 @@ abstract class calendar_driver
|
||||||
/**
|
/**
|
||||||
* Handler for user_delete plugin hook
|
* Handler for user_delete plugin hook
|
||||||
*
|
*
|
||||||
* @param array Hash array with hook arguments
|
* @param array $args Hash array with hook arguments
|
||||||
|
*
|
||||||
* @return array Return arguments for plugin hooks
|
* @return array Return arguments for plugin hooks
|
||||||
*/
|
*/
|
||||||
public function user_delete($args)
|
public function user_delete($args)
|
||||||
|
|
|
@ -136,7 +136,7 @@ class database_driver extends calendar_driver
|
||||||
$hidden = array_filter(explode(',', $this->rc->config->get('hidden_calendars', '')));
|
$hidden = array_filter(explode(',', $this->rc->config->get('hidden_calendars', '')));
|
||||||
$id = self::BIRTHDAY_CALENDAR_ID;
|
$id = self::BIRTHDAY_CALENDAR_ID;
|
||||||
|
|
||||||
if (!$active || !in_array($id, $hidden)) {
|
if (empty($active) || !in_array($id, $hidden)) {
|
||||||
$calendars[$id] = array(
|
$calendars[$id] = array(
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'name' => $this->cal->gettext('birthdays'),
|
'name' => $this->cal->gettext('birthdays'),
|
||||||
|
@ -172,7 +172,7 @@ class database_driver extends calendar_driver
|
||||||
$this->rc->user->ID,
|
$this->rc->user->ID,
|
||||||
$prop['name'],
|
$prop['name'],
|
||||||
strval($prop['color']),
|
strval($prop['color']),
|
||||||
$prop['showalarms'] ? 1 : 0
|
!empty($prop['showalarms']) ? 1 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
|
@ -321,24 +321,24 @@ class database_driver extends calendar_driver
|
||||||
. " VALUES (?, $now, $now, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
. " VALUES (?, $now, $now, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
$event['calendar'],
|
$event['calendar'],
|
||||||
strval($event['uid']),
|
strval($event['uid']),
|
||||||
intval($event['recurrence_id']),
|
isset($event['recurrence_id']) ? intval($event['recurrence_id']) : 0,
|
||||||
strval($event['_instance']),
|
isset($event['_instance']) ? strval($event['_instance']) : '',
|
||||||
intval($event['isexception']),
|
isset($event['isexception']) ? intval($event['isexception']) : 0,
|
||||||
$event['start']->format(self::DB_DATE_FORMAT),
|
$event['start']->format(self::DB_DATE_FORMAT),
|
||||||
$event['end']->format(self::DB_DATE_FORMAT),
|
$event['end']->format(self::DB_DATE_FORMAT),
|
||||||
intval($event['all_day']),
|
intval($event['all_day']),
|
||||||
$event['_recurrence'],
|
$event['_recurrence'],
|
||||||
strval($event['title']),
|
strval($event['title']),
|
||||||
strval($event['description']),
|
isset($event['description']) ? strval($event['description']) : '',
|
||||||
strval($event['location']),
|
isset($event['location']) ? strval($event['location']) : '',
|
||||||
join(',', (array)$event['categories']),
|
isset($event['categories']) ? join(',', (array) $event['categories']) : '',
|
||||||
strval($event['url']),
|
isset($event['url']) ? strval($event['url']) : '',
|
||||||
intval($event['free_busy']),
|
intval($event['free_busy']),
|
||||||
intval($event['priority']),
|
intval($event['priority']),
|
||||||
intval($event['sensitivity']),
|
intval($event['sensitivity']),
|
||||||
strval($event['status']),
|
isset($event['status']) ? strval($event['status']) : '',
|
||||||
$event['attendees'],
|
$event['attendees'],
|
||||||
$event['alarms'],
|
isset($event['alarms']) ? $event['alarms'] : null,
|
||||||
$event['notifyat']
|
$event['notifyat']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -381,7 +381,7 @@ class database_driver extends calendar_driver
|
||||||
|
|
||||||
// increment sequence number
|
// increment sequence number
|
||||||
if (empty($event['sequence']) && $reschedule) {
|
if (empty($event['sequence']) && $reschedule) {
|
||||||
$event['sequence'] = max($event['sequence'], $old['sequence']) + 1;
|
$event['sequence'] = $old['sequence'] + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify a recurring event, check submitted savemode to do the right things
|
// modify a recurring event, check submitted savemode to do the right things
|
||||||
|
@ -389,11 +389,12 @@ class database_driver extends calendar_driver
|
||||||
$master = $old['recurrence_id'] ? $this->get_event(array('id' => $old['recurrence_id'])) : $old;
|
$master = $old['recurrence_id'] ? $this->get_event(array('id' => $old['recurrence_id'])) : $old;
|
||||||
|
|
||||||
// keep saved exceptions (not submitted by the client)
|
// keep saved exceptions (not submitted by the client)
|
||||||
if ($old['recurrence']['EXDATE']) {
|
if (!empty($old['recurrence']['EXDATE'])) {
|
||||||
$event['recurrence']['EXDATE'] = $old['recurrence']['EXDATE'];
|
$event['recurrence']['EXDATE'] = $old['recurrence']['EXDATE'];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($event['_savemode']) {
|
$savemode = isset($event['_savemode']) ? $event['_savemode'] : null;
|
||||||
|
switch ($savemode) {
|
||||||
case 'new':
|
case 'new':
|
||||||
$event['uid'] = $this->cal->generate_uid();
|
$event['uid'] = $this->cal->generate_uid();
|
||||||
return $this->new_event($event);
|
return $this->new_event($event);
|
||||||
|
@ -582,10 +583,12 @@ class database_driver extends calendar_driver
|
||||||
|
|
||||||
// iterate through the list of properties considered 'significant' for scheduling
|
// iterate through the list of properties considered 'significant' for scheduling
|
||||||
foreach (self::$scheduling_properties as $prop) {
|
foreach (self::$scheduling_properties as $prop) {
|
||||||
$a = $old[$prop];
|
$a = isset($old[$prop]) ? $old[$prop] : null;
|
||||||
$b = $event[$prop];
|
$b = isset($event[$prop]) ? $event[$prop] : null;
|
||||||
|
|
||||||
if ($event['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
|
if (!empty($event['allday']) && ($prop == 'start' || $prop == 'end')
|
||||||
|
&& $a instanceof DateTime && $b instanceof DateTime
|
||||||
|
) {
|
||||||
$a = $a->format('Y-m-d');
|
$a = $a->format('Y-m-d');
|
||||||
$b = $b->format('Y-m-d');
|
$b = $b->format('Y-m-d');
|
||||||
}
|
}
|
||||||
|
@ -596,10 +599,10 @@ class database_driver extends calendar_driver
|
||||||
$b = array_filter($b);
|
$b = array_filter($b);
|
||||||
|
|
||||||
// advanced rrule comparison: no rescheduling if series was shortened
|
// advanced rrule comparison: no rescheduling if series was shortened
|
||||||
if ($a['COUNT'] && $b['COUNT'] && $b['COUNT'] < $a['COUNT']) {
|
if (!empty($a['COUNT']) && !empty($b['COUNT']) && $b['COUNT'] < $a['COUNT']) {
|
||||||
unset($a['COUNT'], $b['COUNT']);
|
unset($a['COUNT'], $b['COUNT']);
|
||||||
}
|
}
|
||||||
else if ($a['UNTIL'] && $b['UNTIL'] && $b['UNTIL'] < $a['UNTIL']) {
|
else if (!empty($a['UNTIL']) && !empty($b['UNTIL']) && $b['UNTIL'] < $a['UNTIL']) {
|
||||||
unset($a['UNTIL'], $b['UNTIL']);
|
unset($a['UNTIL'], $b['UNTIL']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,24 +655,24 @@ class database_driver extends calendar_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
// compose vcalendar-style recurrencue rule from structured data
|
// compose vcalendar-style recurrencue rule from structured data
|
||||||
$rrule = $event['recurrence'] ? libcalendaring::to_rrule($event['recurrence']) : '';
|
$rrule = !empty($event['recurrence']) ? libcalendaring::to_rrule($event['recurrence']) : '';
|
||||||
|
|
||||||
|
$sensitivity = strtolower($event['sensitivity']);
|
||||||
|
$free_busy = strtolower($event['free_busy']);
|
||||||
|
|
||||||
$event['_recurrence'] = rtrim($rrule, ';');
|
$event['_recurrence'] = rtrim($rrule, ';');
|
||||||
$event['free_busy'] = intval($this->free_busy_map[strtolower($event['free_busy'])]);
|
$event['free_busy'] = isset($this->free_busy_map[$free_busy]) ? $this->free_busy_map[$free_busy] : null;
|
||||||
$event['sensitivity'] = intval($this->sensitivity_map[strtolower($event['sensitivity'])]);
|
$event['sensitivity'] = isset($this->sensitivity_map[$sensitivity]) ? $this->sensitivity_map[$sensitivity] : null;
|
||||||
|
$event['all_day'] = !empty($event['allday']) ? 1 : 0;
|
||||||
|
|
||||||
if ($event['free_busy'] == 'tentative') {
|
if ($event['free_busy'] == 'tentative') {
|
||||||
$event['status'] = 'TENTATIVE';
|
$event['status'] = 'TENTATIVE';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($event['allday'])) {
|
|
||||||
$event['all_day'] = $event['allday'] ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute absolute time to notify the user
|
// compute absolute time to notify the user
|
||||||
$event['notifyat'] = $this->_get_notification($event);
|
$event['notifyat'] = $this->_get_notification($event);
|
||||||
|
|
||||||
if (is_array($event['valarms'])) {
|
if (!empty($event['valarms'])) {
|
||||||
$event['alarms'] = $this->serialize_alarms($event['valarms']);
|
$event['alarms'] = $this->serialize_alarms($event['valarms']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +692,7 @@ class database_driver extends calendar_driver
|
||||||
*/
|
*/
|
||||||
private function _get_notification($event)
|
private function _get_notification($event)
|
||||||
{
|
{
|
||||||
if ($event['valarms'] && $event['start'] > new DateTime()) {
|
if (!empty($event['valarms']) && $event['start'] > new DateTime()) {
|
||||||
$alarm = libcalendaring::get_next_alarm($event);
|
$alarm = libcalendaring::get_next_alarm($event);
|
||||||
|
|
||||||
if ($alarm['time'] && in_array($alarm['action'], $this->alarm_types)) {
|
if ($alarm['time'] && in_array($alarm['action'], $this->alarm_types)) {
|
||||||
|
@ -714,26 +717,23 @@ class database_driver extends calendar_driver
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($set_cols as $col) {
|
foreach ($set_cols as $col) {
|
||||||
if (is_object($event[$col]) && is_a($event[$col], 'DateTime')) {
|
if (!empty($event[$col]) && is_a($event[$col], 'DateTime')) {
|
||||||
$sql_args[$col] = $event[$col]->format(self::DB_DATE_FORMAT);
|
$sql_args[$col] = $event[$col]->format(self::DB_DATE_FORMAT);
|
||||||
}
|
}
|
||||||
else if (is_array($event[$col])) {
|
|
||||||
$sql_args[$col] = join(',', $event[$col]);
|
|
||||||
}
|
|
||||||
else if (array_key_exists($col, $event)) {
|
else if (array_key_exists($col, $event)) {
|
||||||
$sql_args[$col] = $event[$col];
|
$sql_args[$col] = is_array($event[$col]) ? join(',', $event[$col]) : $event[$col];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['_recurrence']) {
|
if (!empty($event['_recurrence'])) {
|
||||||
$sql_args['recurrence'] = $event['_recurrence'];
|
$sql_args['recurrence'] = $event['_recurrence'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['_instance']) {
|
if (!empty($event['_instance'])) {
|
||||||
$sql_args['instance'] = $event['_instance'];
|
$sql_args['instance'] = $event['_instance'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['_fromcalendar'] && $event['_fromcalendar'] != $event['calendar']) {
|
if (!empty($event['_fromcalendar']) && $event['_fromcalendar'] != $event['calendar']) {
|
||||||
$sql_args['calendar_id'] = $event['calendar'];
|
$sql_args['calendar_id'] = $event['calendar'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,7 +763,7 @@ class database_driver extends calendar_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove attachments
|
// remove attachments
|
||||||
if ($success && !empty($event['deleted_attachments'])) {
|
if ($success && !empty($event['deleted_attachments']) && is_array($event['deleted_attachments'])) {
|
||||||
foreach ($event['deleted_attachments'] as $attachment) {
|
foreach ($event['deleted_attachments'] as $attachment) {
|
||||||
$this->remove_attachment($attachment, $event['id']);
|
$this->remove_attachment($attachment, $event['id']);
|
||||||
}
|
}
|
||||||
|
@ -822,7 +822,7 @@ class database_driver extends calendar_driver
|
||||||
|
|
||||||
// skip exceptions
|
// skip exceptions
|
||||||
// TODO: merge updated data from master event
|
// TODO: merge updated data from master event
|
||||||
if ($exdata[$datestr]) {
|
if (!empty($exdata[$datestr])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,7 +831,7 @@ class database_driver extends calendar_driver
|
||||||
$next_end->add($duration);
|
$next_end->add($duration);
|
||||||
|
|
||||||
$notify_at = $this->_get_notification(array(
|
$notify_at = $this->_get_notification(array(
|
||||||
'alarms' => $event['alarms'],
|
'alarms' => !empty($event['alarms']) ? $event['alarms'] : null,
|
||||||
'start' => $next_start,
|
'start' => $next_start,
|
||||||
'end' => $next_end,
|
'end' => $next_end,
|
||||||
'status' => $event['status']
|
'status' => $event['status']
|
||||||
|
@ -860,13 +860,13 @@ class database_driver extends calendar_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop adding events for inifinite recurrence after 20 years
|
// stop adding events for inifinite recurrence after 20 years
|
||||||
if (++$count > 999 || (!$recurrence->recurEnd && !$recurrence->recurCount && $next_start->format('Y') > date('Y') + 20)) {
|
if (++$count > 999 || (empty($recurrence->recurEnd) && empty($recurrence->recurCount) && $next_start->format('Y') > date('Y') + 20)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all exceptions after recurrence end
|
// remove all exceptions after recurrence end
|
||||||
if ($next_end && !empty($exceptions)) {
|
if (!empty($next_end) && !empty($exceptions)) {
|
||||||
$this->rc->db->query(
|
$this->rc->db->query(
|
||||||
"DELETE FROM `{$this->db_events}`"
|
"DELETE FROM `{$this->db_events}`"
|
||||||
. " WHERE `recurrence_id` = ? AND `isexception` = 1 AND `start` > ?"
|
. " WHERE `recurrence_id` = ? AND `isexception` = 1 AND `start` > ?"
|
||||||
|
@ -1025,11 +1025,11 @@ class database_driver extends calendar_driver
|
||||||
*/
|
*/
|
||||||
public function get_event($event, $scope = 0, $full = false)
|
public function get_event($event, $scope = 0, $full = false)
|
||||||
{
|
{
|
||||||
$id = is_array($event) ? ($event['id'] ?: $event['uid']) : $event;
|
$id = is_array($event) ? (!empty($event['id']) ? $event['id'] : $event['uid']) : $event;
|
||||||
$cal = is_array($event) ? $event['calendar'] : null;
|
$cal = is_array($event) && !empty($event['calendar']) ? $event['calendar'] : null;
|
||||||
$col = is_array($event) && is_numeric($id) ? 'event_id' : 'uid';
|
$col = is_array($event) && is_numeric($id) ? 'event_id' : 'uid';
|
||||||
|
|
||||||
if ($this->cache[$id]) {
|
if (!empty($this->cache[$id])) {
|
||||||
return $this->cache[$id];
|
return $this->cache[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,15 +1039,15 @@ class database_driver extends calendar_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
$where_add = '';
|
$where_add = '';
|
||||||
if (is_array($event) && !$event['id'] && !empty($event['_instance'])) {
|
if (is_array($event) && empty($event['id']) && !empty($event['_instance'])) {
|
||||||
$where_add = " AND e.instance = " . $this->rc->db->quote($event['_instance']);
|
$where_add = " AND e.instance = " . $this->rc->db->quote($event['_instance']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($scope & self::FILTER_ACTIVE) {
|
if ($scope & self::FILTER_ACTIVE) {
|
||||||
$calendars = $this->calendars;
|
$calendars = [];
|
||||||
foreach ($calendars as $idx => $cal) {
|
foreach ($this->calendars as $idx => $cal) {
|
||||||
if (!$cal['active']) {
|
if (!empty($cal['active'])) {
|
||||||
unset($calendars[$idx]);
|
$calendars[] = $idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$cals = join(',', $calendars);
|
$cals = join(',', $calendars);
|
||||||
|
@ -1099,11 +1099,12 @@ class database_driver extends calendar_driver
|
||||||
|
|
||||||
// compose (slow) SQL query for searching
|
// compose (slow) SQL query for searching
|
||||||
// FIXME: improve searching using a dedicated col and normalized values
|
// FIXME: improve searching using a dedicated col and normalized values
|
||||||
|
$sql_add = '';
|
||||||
if ($query) {
|
if ($query) {
|
||||||
foreach (array('title','location','description','categories','attendees') as $col) {
|
foreach (array('title','location','description','categories','attendees') as $col) {
|
||||||
$sql_query[] = $this->rc->db->ilike($col, '%'.$query.'%');
|
$sql_query[] = $this->rc->db->ilike($col, '%'.$query.'%');
|
||||||
}
|
}
|
||||||
$sql_add = " AND (" . join(' OR ', $sql_query) . ")";
|
$sql_add .= " AND (" . join(' OR ', $sql_query) . ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$virtual) {
|
if (!$virtual) {
|
||||||
|
@ -1155,7 +1156,7 @@ class database_driver extends calendar_driver
|
||||||
|
|
||||||
// add events from the address books birthday calendar
|
// add events from the address books birthday calendar
|
||||||
if (in_array(self::BIRTHDAY_CALENDAR_ID, $calendars) && empty($query)) {
|
if (in_array(self::BIRTHDAY_CALENDAR_ID, $calendars) && empty($query)) {
|
||||||
$events = array_merge($events, $this->load_birthday_events($start, $end, $search, $modifiedsince));
|
$events = array_merge($events, $this->load_birthday_events($start, $end, null, $modifiedsince));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $events;
|
return $events;
|
||||||
|
@ -1229,7 +1230,7 @@ class database_driver extends calendar_driver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['_attachments'] > 0) {
|
if (!empty($event['_attachments'])) {
|
||||||
$event['attachments'] = (array)$this->list_attachments($event);
|
$event['attachments'] = (array)$this->list_attachments($event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1398,7 +1399,7 @@ class database_driver extends calendar_driver
|
||||||
. "SELECT `event_id` FROM `{$this->db_events}`"
|
. "SELECT `event_id` FROM `{$this->db_events}`"
|
||||||
. " WHERE `event_id` = ? AND `calendar_id` IN ({$this->calendar_ids}))",
|
. " WHERE `event_id` = ? AND `calendar_id` IN ({$this->calendar_ids}))",
|
||||||
$id,
|
$id,
|
||||||
$event['recurrence_id'] ? $event['recurrence_id'] : $event['id']
|
!empty($event['recurrence_id']) ? $event['recurrence_id'] : $event['id']
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($result && ($arr = $this->rc->db->fetch_assoc($result))) {
|
if ($result && ($arr = $this->rc->db->fetch_assoc($result))) {
|
||||||
|
|
|
@ -33,34 +33,39 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
public $alarms = false;
|
public $alarms = false;
|
||||||
public $history = false;
|
public $history = false;
|
||||||
public $subscriptions = true;
|
public $subscriptions = true;
|
||||||
public $categories = array();
|
public $categories = [];
|
||||||
public $storage;
|
public $storage;
|
||||||
|
|
||||||
public $type = 'event';
|
public $type = 'event';
|
||||||
|
|
||||||
protected $cal;
|
protected $cal;
|
||||||
protected $events = array();
|
protected $events = [];
|
||||||
protected $search_fields = array('title', 'description', 'location', 'attendees', 'categories');
|
protected $search_fields = ['title', 'description', 'location', 'attendees', 'categories'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method to instantiate a kolab_calendar object
|
* Factory method to instantiate a kolab_calendar object
|
||||||
*
|
*
|
||||||
* @param string Calendar ID (encoded IMAP folder name)
|
* @param string Calendar ID (encoded IMAP folder name)
|
||||||
* @param object calendar plugin object
|
* @param object Calendar plugin object
|
||||||
* @return object kolab_calendar instance
|
*
|
||||||
|
* @return kolab_calendar Self instance
|
||||||
*/
|
*/
|
||||||
public static function factory($id, $calendar)
|
public static function factory($id, $calendar)
|
||||||
{
|
{
|
||||||
$imap = $calendar->rc->get_storage();
|
$imap = $calendar->rc->get_storage();
|
||||||
$imap_folder = kolab_storage::id_decode($id);
|
$imap_folder = kolab_storage::id_decode($id);
|
||||||
$info = $imap->folder_info($imap_folder, true);
|
$info = $imap->folder_info($imap_folder, true);
|
||||||
if (empty($info) || $info['noselect'] || strpos(kolab_storage::folder_type($imap_folder), 'event') !== 0) {
|
|
||||||
|
if (
|
||||||
|
empty($info)
|
||||||
|
|| !empty($info['noselect'])
|
||||||
|
|| strpos(kolab_storage::folder_type($imap_folder), 'event') !== 0
|
||||||
|
) {
|
||||||
return new kolab_user_calendar($imap_folder, $calendar);
|
return new kolab_user_calendar($imap_folder, $calendar);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return new kolab_calendar($imap_folder, $calendar);
|
return new kolab_calendar($imap_folder, $calendar);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* Default constructor
|
||||||
|
@ -90,24 +95,26 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$rights = $this->storage->get_myrights();
|
$rights = $this->storage->get_myrights();
|
||||||
if ($rights && !PEAR::isError($rights)) {
|
if ($rights && !PEAR::isError($rights)) {
|
||||||
$this->rights = $rights;
|
$this->rights = $rights;
|
||||||
if (strpos($rights, 't') !== false || strpos($rights, 'd') !== false)
|
if (strpos($rights, 't') !== false || strpos($rights, 'd') !== false) {
|
||||||
$this->editable = strpos($rights, 'i');;
|
$this->editable = strpos($rights, 'i');;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// user-specific alarms settings win
|
// user-specific alarms settings win
|
||||||
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
|
$prefs = $this->cal->rc->config->get('kolab_calendars', []);
|
||||||
if (isset($prefs[$this->id]['showalarms']))
|
if (isset($prefs[$this->id]['showalarms'])) {
|
||||||
$this->alarms = $prefs[$this->id]['showalarms'];
|
$this->alarms = $prefs[$this->id]['showalarms'];
|
||||||
else if (isset($prefs[$old_id]['showalarms']))
|
}
|
||||||
|
else if (isset($prefs[$old_id]['showalarms'])) {
|
||||||
$this->alarms = $prefs[$old_id]['showalarms'];
|
$this->alarms = $prefs[$old_id]['showalarms'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->default = $this->storage->default;
|
$this->default = $this->storage->default;
|
||||||
$this->subtype = $this->storage->subtype;
|
$this->subtype = $this->storage->subtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for the IMAP folder name
|
* Getter for the IMAP folder name
|
||||||
*
|
*
|
||||||
|
@ -126,7 +133,6 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return color to display this calendar
|
* Return color to display this calendar
|
||||||
*/
|
*/
|
||||||
|
@ -138,10 +144,11 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
// calendar color is stored in user prefs (temporary solution)
|
// calendar color is stored in user prefs (temporary solution)
|
||||||
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
|
$prefs = $this->cal->rc->config->get('kolab_calendars', []);
|
||||||
|
|
||||||
if (!empty($prefs[$this->id]) && !empty($prefs[$this->id]['color']))
|
if (!empty($prefs[$this->id]) && !empty($prefs[$this->id]['color'])) {
|
||||||
return $prefs[$this->id]['color'];
|
return $prefs[$this->id]['color'];
|
||||||
|
}
|
||||||
|
|
||||||
return $default ?: 'cc0000';
|
return $default ?: 'cc0000';
|
||||||
}
|
}
|
||||||
|
@ -152,18 +159,17 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
public function get_caldav_url()
|
public function get_caldav_url()
|
||||||
{
|
{
|
||||||
if ($template = $this->cal->rc->config->get('calendar_caldav_url', null)) {
|
if ($template = $this->cal->rc->config->get('calendar_caldav_url', null)) {
|
||||||
return strtr($template, array(
|
return strtr($template, [
|
||||||
'%h' => $_SERVER['HTTP_HOST'],
|
'%h' => $_SERVER['HTTP_HOST'],
|
||||||
'%u' => urlencode($this->cal->rc->get_user_name()),
|
'%u' => urlencode($this->cal->rc->get_user_name()),
|
||||||
'%i' => urlencode($this->storage->get_uid()),
|
'%i' => urlencode($this->storage->get_uid()),
|
||||||
'%n' => urlencode($this->name),
|
'%n' => urlencode($this->name),
|
||||||
));
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update properties of this calendar folder
|
* Update properties of this calendar folder
|
||||||
*
|
*
|
||||||
|
@ -192,12 +198,12 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$master_id = preg_replace('/-\d{8}(T\d{6})?$/', '', $id);
|
$master_id = preg_replace('/-\d{8}(T\d{6})?$/', '', $id);
|
||||||
|
|
||||||
// directly access storage object
|
// directly access storage object
|
||||||
if (!$this->events[$id] && $master_id == $id && ($record = $this->storage->get_object($id))) {
|
if (empty($this->events[$id]) && $master_id == $id && ($record = $this->storage->get_object($id))) {
|
||||||
$this->events[$id] = $this->_to_driver_event($record, true);
|
$this->events[$id] = $this->_to_driver_event($record, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe a recurring instance is requested
|
// maybe a recurring instance is requested
|
||||||
if (!$this->events[$id] && $master_id != $id) {
|
if (empty($this->events[$id]) && $master_id != $id) {
|
||||||
$instance_id = substr($id, strlen($master_id) + 1);
|
$instance_id = substr($id, strlen($master_id) + 1);
|
||||||
|
|
||||||
if ($record = $this->storage->get_object($master_id)) {
|
if ($record = $this->storage->get_object($master_id)) {
|
||||||
|
@ -206,20 +212,21 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
|
|
||||||
if ($master) {
|
if ($master) {
|
||||||
// check for match in top-level exceptions (aka loose single occurrences)
|
// check for match in top-level exceptions (aka loose single occurrences)
|
||||||
if ($master['_formatobj'] && ($instance = $master['_formatobj']->get_instance($instance_id))) {
|
if (!empty($master['_formatobj']) && ($instance = $master['_formatobj']->get_instance($instance_id))) {
|
||||||
$this->events[$id] = $this->_to_driver_event($instance, false, true, $master);
|
$this->events[$id] = $this->_to_driver_event($instance, false, true, $master);
|
||||||
}
|
}
|
||||||
// check for match on the first instance already
|
// check for match on the first instance already
|
||||||
else if ($master['_instance'] && $master['_instance'] == $instance_id) {
|
else if (!empty($master['_instance']) && $master['_instance'] == $instance_id) {
|
||||||
$this->events[$id] = $master;
|
$this->events[$id] = $master;
|
||||||
}
|
}
|
||||||
else if (is_array($master['recurrence'])) {
|
else if (!empty($master['recurrence'])) {
|
||||||
|
$start_date = $master['start'];
|
||||||
// For performance reasons we'll get only the specific instance
|
// For performance reasons we'll get only the specific instance
|
||||||
if (($date = substr($id, strlen($master_id) + 1, 8)) && strlen($date) == 8 && is_numeric($date)) {
|
if (($date = substr($id, strlen($master_id) + 1, 8)) && strlen($date) == 8 && is_numeric($date)) {
|
||||||
$start_date = new DateTime($date . 'T000000', $master['start']->getTimezone());
|
$start_date = new DateTime($date . 'T000000', $master['start']->getTimezone());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->get_recurring_events($record, $start_date ?: $master['start'], null, $id, 1);
|
$this->get_recurring_events($record, $start_date, null, $id, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,8 +240,9 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
*/
|
*/
|
||||||
public function get_attachment_body($id, $event)
|
public function get_attachment_body($id, $event)
|
||||||
{
|
{
|
||||||
if (!$this->ready)
|
if (!$this->ready) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$data = $this->storage->get_attachment($event['id'], $id);
|
$data = $this->storage->get_attachment($event['id'], $id);
|
||||||
|
|
||||||
|
@ -250,15 +258,16 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param integer Event's new start (unix timestamp)
|
* @param int Event's new start (unix timestamp)
|
||||||
* @param integer Event's new end (unix timestamp)
|
* @param int Event's new end (unix timestamp)
|
||||||
* @param string Search query (optional)
|
* @param string Search query (optional)
|
||||||
* @param boolean Include virtual events (optional)
|
* @param bool Include virtual events (optional)
|
||||||
* @param array Additional parameters to query storage
|
* @param array Additional parameters to query storage
|
||||||
* @param array Additional query to filter events
|
* @param array Additional query to filter events
|
||||||
|
*
|
||||||
* @return array A list of event records
|
* @return array A list of event records
|
||||||
*/
|
*/
|
||||||
public function list_events($start, $end, $search = null, $virtual = 1, $query = array(), $filter_query = null)
|
public function list_events($start, $end, $search = null, $virtual = 1, $query = [], $filter_query = null)
|
||||||
{
|
{
|
||||||
// convert to DateTime for comparisons
|
// convert to DateTime for comparisons
|
||||||
// #5190: make the range a little bit wider
|
// #5190: make the range a little bit wider
|
||||||
|
@ -280,40 +289,38 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$user_emails = $this->cal->get_user_emails();
|
$user_emails = $this->cal->get_user_emails();
|
||||||
|
|
||||||
// query Kolab storage
|
// query Kolab storage
|
||||||
$query[] = array('dtstart', '<=', $end);
|
$query[] = ['dtstart', '<=', $end];
|
||||||
$query[] = array('dtend', '>=', $start);
|
$query[] = ['dtend', '>=', $start];
|
||||||
|
|
||||||
if (is_array($filter_query)) {
|
if (is_array($filter_query)) {
|
||||||
$query = array_merge($query, $filter_query);
|
$query = array_merge($query, $filter_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$words = [];
|
||||||
|
$partstat_exclude = [];
|
||||||
|
$events = [];
|
||||||
|
|
||||||
if (!empty($search)) {
|
if (!empty($search)) {
|
||||||
$search = mb_strtolower($search);
|
$search = mb_strtolower($search);
|
||||||
$words = rcube_utils::tokenize_string($search, 1);
|
$words = rcube_utils::tokenize_string($search, 1);
|
||||||
foreach (rcube_utils::normalize_string($search, true) as $word) {
|
foreach (rcube_utils::normalize_string($search, true) as $word) {
|
||||||
$query[] = array('words', 'LIKE', $word);
|
$query[] = ['words', 'LIKE', $word];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
$words = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
// set partstat filter to skip pending and declined invitations
|
// set partstat filter to skip pending and declined invitations
|
||||||
if (empty($filter_query) && $this->cal->rc->config->get('kolab_invitation_calendars')
|
if (empty($filter_query)
|
||||||
|
&& $this->cal->rc->config->get('kolab_invitation_calendars')
|
||||||
&& $this->get_namespace() != 'other'
|
&& $this->get_namespace() != 'other'
|
||||||
) {
|
) {
|
||||||
$partstat_exclude = array('NEEDS-ACTION','DECLINED');
|
$partstat_exclude = ['NEEDS-ACTION', 'DECLINED'];
|
||||||
}
|
|
||||||
else {
|
|
||||||
$partstat_exclude = array();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$events = array();
|
|
||||||
foreach ($this->storage->select($query) as $record) {
|
foreach ($this->storage->select($query) as $record) {
|
||||||
$event = $this->_to_driver_event($record, !$virtual, false);
|
$event = $this->_to_driver_event($record, !$virtual, false);
|
||||||
|
|
||||||
// remember seen categories
|
// remember seen categories
|
||||||
if ($event['categories']) {
|
if (!empty($event['categories'])) {
|
||||||
$cat = is_array($event['categories']) ? $event['categories'][0] : $event['categories'];
|
$cat = is_array($event['categories']) ? $event['categories'][0] : $event['categories'];
|
||||||
$this->categories[$cat]++;
|
$this->categories[$cat]++;
|
||||||
}
|
}
|
||||||
|
@ -322,6 +329,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
if ($event['start'] <= $end && $event['end'] >= $start) {
|
if ($event['start'] <= $end && $event['end'] >= $start) {
|
||||||
unset($event['_attendees']);
|
unset($event['_attendees']);
|
||||||
$add = true;
|
$add = true;
|
||||||
|
|
||||||
// skip the first instance of a recurring event if listed in exdate
|
// skip the first instance of a recurring event if listed in exdate
|
||||||
if ($virtual && !empty($event['recurrence']['EXDATE'])) {
|
if ($virtual && !empty($event['recurrence']['EXDATE'])) {
|
||||||
$event_date = $event['start']->format('Ymd');
|
$event_date = $event['start']->format('Ymd');
|
||||||
|
@ -339,28 +347,33 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
// find and merge exception for the first instance
|
// find and merge exception for the first instance
|
||||||
if ($virtual && !empty($event['recurrence']) && is_array($event['recurrence']['EXCEPTIONS'])) {
|
if ($virtual && !empty($event['recurrence']) && !empty($event['recurrence']['EXCEPTIONS'])) {
|
||||||
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
||||||
if ($event['_instance'] == $exception['_instance']) {
|
if ($event['_instance'] == $exception['_instance']) {
|
||||||
unset($exception['calendar'], $exception['className'], $exception['_folder_id']);
|
unset($exception['calendar'], $exception['className'], $exception['_folder_id']);
|
||||||
// clone date objects from main event before adjusting them with exception data
|
// clone date objects from main event before adjusting them with exception data
|
||||||
if (is_object($event['start'])) $event['start'] = clone $record['start'];
|
if (is_object($event['start'])) {
|
||||||
if (is_object($event['end'])) $event['end'] = clone $record['end'];
|
$event['start'] = clone $record['start'];
|
||||||
|
}
|
||||||
|
if (is_object($event['end'])) {
|
||||||
|
$event['end'] = clone $record['end'];
|
||||||
|
}
|
||||||
kolab_driver::merge_exception_data($event, $exception);
|
kolab_driver::merge_exception_data($event, $exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($add)
|
if ($add) {
|
||||||
$events[] = $event;
|
$events[] = $event;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// resolve recurring events
|
// resolve recurring events
|
||||||
if ($record['recurrence'] && $virtual == 1) {
|
if (!empty($record['recurrence']) && $virtual == 1) {
|
||||||
$events = array_merge($events, $this->get_recurring_events($record, $start, $end));
|
$events = array_merge($events, $this->get_recurring_events($record, $start, $end));
|
||||||
}
|
}
|
||||||
// add top-level exceptions (aka loose single occurrences)
|
// add top-level exceptions (aka loose single occurrences)
|
||||||
else if (is_array($record['exceptions'])) {
|
else if (!empty($record['exceptions'])) {
|
||||||
foreach ($record['exceptions'] as $ex) {
|
foreach ($record['exceptions'] as $ex) {
|
||||||
$component = $this->_to_driver_event($ex, false, false, $record);
|
$component = $this->_to_driver_event($ex, false, false, $record);
|
||||||
if ($component['start'] <= $end && $component['end'] >= $start) {
|
if ($component['start'] <= $end && $component['end'] >= $start) {
|
||||||
|
@ -385,9 +398,12 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
// partstat filter
|
// partstat filter
|
||||||
if (count($partstat_exclude) && is_array($event['attendees'])) {
|
if (count($partstat_exclude) && !empty($event['attendees'])) {
|
||||||
foreach ($event['attendees'] as $attendee) {
|
foreach ($event['attendees'] as $attendee) {
|
||||||
if (in_array($attendee['email'], $user_emails) && in_array($attendee['status'], $partstat_exclude)) {
|
if (
|
||||||
|
in_array($attendee['email'], $user_emails)
|
||||||
|
&& in_array($attendee['status'], $partstat_exclude)
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,11 +425,11 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
/**
|
/**
|
||||||
* Get number of events in the given calendar
|
* Get number of events in the given calendar
|
||||||
*
|
*
|
||||||
* @param integer Date range start (unix timestamp)
|
* @param int Date range start (unix timestamp)
|
||||||
* @param integer Date range end (unix timestamp)
|
* @param int Date range end (unix timestamp)
|
||||||
* @param array Additional query to filter events
|
* @param array Additional query to filter events
|
||||||
*
|
*
|
||||||
* @return integer Count
|
* @return int Count
|
||||||
*/
|
*/
|
||||||
public function count_events($start, $end = null, $filter_query = null)
|
public function count_events($start, $end = null, $filter_query = null)
|
||||||
{
|
{
|
||||||
|
@ -434,16 +450,17 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
// query Kolab storage
|
// query Kolab storage
|
||||||
$query[] = array('dtend', '>=', $start);
|
$query[] = ['dtend', '>=', $start];
|
||||||
|
|
||||||
if ($end)
|
if ($end) {
|
||||||
$query[] = array('dtstart', '<=', $end);
|
$query[] = ['dtstart', '<=', $end];
|
||||||
|
}
|
||||||
|
|
||||||
// add query to exclude pending/declined invitations
|
// add query to exclude pending/declined invitations
|
||||||
if (empty($filter_query)) {
|
if (empty($filter_query)) {
|
||||||
foreach ($this->cal->get_user_emails() as $email) {
|
foreach ($this->cal->get_user_emails() as $email) {
|
||||||
$query[] = array('tags', '!=', 'x-partstat:' . $email . ':needs-action');
|
$query[] = ['tags', '!=', 'x-partstat:' . $email . ':needs-action'];
|
||||||
$query[] = array('tags', '!=', 'x-partstat:' . $email . ':declined');
|
$query[] = ['tags', '!=', 'x-partstat:' . $email . ':declined'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_array($filter_query)) {
|
else if (is_array($filter_query)) {
|
||||||
|
@ -459,15 +476,16 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
*
|
*
|
||||||
* @see calendar_driver::new_event()
|
* @see calendar_driver::new_event()
|
||||||
*
|
*
|
||||||
* @return mixed The created record ID on success, False on error
|
* @return array|false The created record ID on success, False on error
|
||||||
*/
|
*/
|
||||||
public function insert_event($event)
|
public function insert_event($event)
|
||||||
{
|
{
|
||||||
if (!is_array($event))
|
if (!is_array($event)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// email links are stored separately
|
// email links are stored separately
|
||||||
$links = $event['links'];
|
$links = !empty($event['links']) ? $event['links'] : [];
|
||||||
unset($event['links']);
|
unset($event['links']);
|
||||||
|
|
||||||
//generate new event from RC input
|
//generate new event from RC input
|
||||||
|
@ -475,11 +493,12 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$saved = $this->storage->save($object, 'event');
|
$saved = $this->storage->save($object, 'event');
|
||||||
|
|
||||||
if (!$saved) {
|
if (!$saved) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error([
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error saving event object to Kolab server"
|
||||||
'message' => "Error saving event object to Kolab server"),
|
],
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
$saved = false;
|
$saved = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -488,7 +507,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$object['links'] = $links;
|
$object['links'] = $links;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
|
$this->events = [$event['uid'] => $this->_to_driver_event($object, true)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $saved;
|
return $saved;
|
||||||
|
@ -499,28 +518,31 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
*
|
*
|
||||||
* @see calendar_driver::new_event()
|
* @see calendar_driver::new_event()
|
||||||
*
|
*
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function update_event($event, $exception_id = null)
|
public function update_event($event, $exception_id = null)
|
||||||
{
|
{
|
||||||
$updated = false;
|
$updated = false;
|
||||||
$old = $this->storage->get_object($event['uid'] ?: $event['id']);
|
$old = $this->storage->get_object(!empty($event['uid']) ? $event['uid'] : $event['id']);
|
||||||
if (!$old || PEAR::isError($old))
|
|
||||||
|
if (!$old || PEAR::isError($old)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// email links are stored separately
|
// email links are stored separately
|
||||||
$links = $event['links'];
|
$links = !empty($event['links']) ? $event['links'] : [];
|
||||||
unset($event['links']);
|
unset($event['links']);
|
||||||
|
|
||||||
$object = $this->_from_driver_event($event, $old);
|
$object = $this->_from_driver_event($event, $old);
|
||||||
$saved = $this->storage->save($object, 'event', $old['uid']);
|
$saved = $this->storage->save($object, 'event', $old['uid']);
|
||||||
|
|
||||||
if (!$saved) {
|
if (!$saved) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error([
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error saving event object to Kolab server"
|
||||||
'message' => "Error saving event object to Kolab server"),
|
],
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// save links in configuration.relation object
|
// save links in configuration.relation object
|
||||||
|
@ -529,7 +551,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
$updated = true;
|
$updated = true;
|
||||||
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
|
$this->events = [$event['uid'] => $this->_to_driver_event($object, true)];
|
||||||
|
|
||||||
// refresh local cache with recurring instances
|
// refresh local cache with recurring instances
|
||||||
if ($exception_id) {
|
if ($exception_id) {
|
||||||
|
@ -545,17 +567,19 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
*
|
*
|
||||||
* @see calendar_driver::remove_event()
|
* @see calendar_driver::remove_event()
|
||||||
*
|
*
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function delete_event($event, $force = true)
|
public function delete_event($event, $force = true)
|
||||||
{
|
{
|
||||||
$deleted = $this->storage->delete($event['uid'] ?: $event['id'], $force);
|
$deleted = $this->storage->delete(!empty($event['uid']) ? $event['uid'] : $event['id'], $force);
|
||||||
|
|
||||||
if (!$deleted) {
|
if (!$deleted) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error([
|
||||||
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'message' => sprintf("Error deleting event object '%s' from Kolab server", $event['id'])),
|
'message' => sprintf("Error deleting event object '%s' from Kolab server", $event['id'])
|
||||||
true, false);
|
],
|
||||||
|
true, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $deleted;
|
return $deleted;
|
||||||
|
@ -566,7 +590,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
*
|
*
|
||||||
* @see calendar_driver::undelete_event()
|
* @see calendar_driver::undelete_event()
|
||||||
*
|
*
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function restore_event($event)
|
public function restore_event($event)
|
||||||
{
|
{
|
||||||
|
@ -576,12 +600,13 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
if ($this->storage->undelete($uid)) {
|
if ($this->storage->undelete($uid)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rcube::raise_error(array(
|
rcube::raise_error([
|
||||||
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'message' => sprintf("Error undeleting the event object '%s' from the Kolab server", $event['id'])),
|
'message' => sprintf("Error undeleting the event object '%s' from the Kolab server", $event['id'])
|
||||||
true, false);
|
],
|
||||||
}
|
true, false
|
||||||
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -617,14 +642,17 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
*/
|
*/
|
||||||
public function get_recurring_events($event, $start, $end = null, $event_id = null, $limit = null)
|
public function get_recurring_events($event, $start, $end = null, $event_id = null, $limit = null)
|
||||||
{
|
{
|
||||||
$object = $event['_formatobj'];
|
if (empty($event['_formatobj'])) {
|
||||||
if (!$object) {
|
$rec = $this->storage->get_object(!empty($event['uid']) ? $event['uid'] : $event['id']);
|
||||||
$rec = $this->storage->get_object($event['uid'] ?: $event['id']);
|
|
||||||
$object = $rec['_formatobj'];
|
$object = $rec['_formatobj'];
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$object = $event['_formatobj'];
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_object($object))
|
if (!is_object($object)) {
|
||||||
return array();
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// determine a reasonable end date if none given
|
// determine a reasonable end date if none given
|
||||||
if (!$end) {
|
if (!$end) {
|
||||||
|
@ -632,27 +660,32 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$end->add(new DateInterval('P100Y'));
|
$end->add(new DateInterval('P100Y'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read recurrence exceptions first
|
||||||
|
$events = [];
|
||||||
|
$exdata = [];
|
||||||
|
$futuredata = [];
|
||||||
|
$recurrence_id_format = libcalendaring::recurrence_id_format($event);
|
||||||
|
|
||||||
|
if (!empty($event['recurrence'])) {
|
||||||
// copy the recurrence rule from the master event (to be used in the UI)
|
// copy the recurrence rule from the master event (to be used in the UI)
|
||||||
$recurrence_rule = $event['recurrence'];
|
$recurrence_rule = $event['recurrence'];
|
||||||
unset($recurrence_rule['EXCEPTIONS'], $recurrence_rule['EXDATE']);
|
unset($recurrence_rule['EXCEPTIONS'], $recurrence_rule['EXDATE']);
|
||||||
|
|
||||||
// read recurrence exceptions first
|
if (!empty($event['recurrence']['EXCEPTIONS'])) {
|
||||||
$events = array();
|
|
||||||
$exdata = array();
|
|
||||||
$futuredata = array();
|
|
||||||
$recurrence_id_format = libcalendaring::recurrence_id_format($event);
|
|
||||||
|
|
||||||
if (is_array($event['recurrence']['EXCEPTIONS'])) {
|
|
||||||
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
||||||
if (!$exception['_instance'])
|
if (empty($exception['_instance'])) {
|
||||||
$exception['_instance'] = libcalendaring::recurrence_instance_identifier($exception, $event['allday']);
|
$exception['_instance'] = libcalendaring::recurrence_instance_identifier($exception, !empty($event['allday']));
|
||||||
|
}
|
||||||
|
|
||||||
$rec_event = $this->_to_driver_event($exception, false, false, $event);
|
$rec_event = $this->_to_driver_event($exception, false, false, $event);
|
||||||
$rec_event['id'] = $event['uid'] . '-' . $exception['_instance'];
|
$rec_event['id'] = $event['uid'] . '-' . $exception['_instance'];
|
||||||
$rec_event['isexception'] = 1;
|
$rec_event['isexception'] = 1;
|
||||||
|
|
||||||
// found the specifically requested instance: register exception (single occurrence wins)
|
// found the specifically requested instance: register exception (single occurrence wins)
|
||||||
if ($rec_event['id'] == $event_id && (!$this->events[$event_id] || $this->events[$event_id]['thisandfuture'])) {
|
if (
|
||||||
|
$rec_event['id'] == $event_id
|
||||||
|
&& (empty($this->events[$event_id]) || !empty($this->events[$event_id]['thisandfuture']))
|
||||||
|
) {
|
||||||
$rec_event['recurrence'] = $recurrence_rule;
|
$rec_event['recurrence'] = $recurrence_rule;
|
||||||
$rec_event['recurrence_id'] = $event['uid'];
|
$rec_event['recurrence_id'] = $event['uid'];
|
||||||
$this->events[$rec_event['id']] = $rec_event;
|
$this->events[$rec_event['id']] = $rec_event;
|
||||||
|
@ -660,18 +693,19 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
|
|
||||||
// remember this exception's date
|
// remember this exception's date
|
||||||
$exdate = substr($exception['_instance'], 0, 8);
|
$exdate = substr($exception['_instance'], 0, 8);
|
||||||
if (!$exdata[$exdate] || $exdata[$exdate]['thisandfuture']) {
|
if (empty($exdata[$exdate]) || !empty($exdata[$exdate]['thisandfuture'])) {
|
||||||
$exdata[$exdate] = $rec_event;
|
$exdata[$exdate] = $rec_event;
|
||||||
}
|
}
|
||||||
if ($rec_event['thisandfuture']) {
|
if (!empty($rec_event['thisandfuture'])) {
|
||||||
$futuredata[$exdate] = $rec_event;
|
$futuredata[$exdate] = $rec_event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// found the specifically requested instance, exiting...
|
// found the specifically requested instance, exiting...
|
||||||
if ($event_id && !empty($this->events[$event_id])) {
|
if ($event_id && !empty($this->events[$event_id])) {
|
||||||
return array($this->events[$event_id]);
|
return [$this->events[$event_id]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check first occurrence, it might have been moved
|
// Check first occurrence, it might have been moved
|
||||||
|
@ -697,11 +731,12 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$instance_id = $next_event['start']->format($recurrence_id_format);
|
$instance_id = $next_event['start']->format($recurrence_id_format);
|
||||||
|
|
||||||
// use this event data for future recurring instances
|
// use this event data for future recurring instances
|
||||||
if ($futuredata[$datestr])
|
if (!empty($futuredata[$datestr])) {
|
||||||
$overlay_data = $futuredata[$datestr];
|
$overlay_data = $futuredata[$datestr];
|
||||||
|
}
|
||||||
|
|
||||||
$rec_id = $event['uid'] . '-' . $instance_id;
|
$rec_id = $event['uid'] . '-' . $instance_id;
|
||||||
$exception = $exdata[$datestr] ?: $overlay_data;
|
$exception = !empty($exdata[$datestr]) ? $exdata[$datestr] : $overlay_data;
|
||||||
$event_start = $next_event['start'];
|
$event_start = $next_event['start'];
|
||||||
$event_end = $next_event['end'];
|
$event_end = $next_event['end'];
|
||||||
|
|
||||||
|
@ -719,8 +754,10 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$rec_event['_instance'] = $instance_id;
|
$rec_event['_instance'] = $instance_id;
|
||||||
$rec_event['_count'] = $i + 1;
|
$rec_event['_count'] = $i + 1;
|
||||||
|
|
||||||
if ($exception) // copy data from exception
|
if ($exception) {
|
||||||
|
// copy data from exception
|
||||||
kolab_driver::merge_exception_data($rec_event, $exception);
|
kolab_driver::merge_exception_data($rec_event, $exception);
|
||||||
|
}
|
||||||
|
|
||||||
$rec_event['id'] = $rec_id;
|
$rec_event['id'] = $rec_id;
|
||||||
$rec_event['recurrence_id'] = $event['uid'];
|
$rec_event['recurrence_id'] = $event['uid'];
|
||||||
|
@ -737,13 +774,16 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
return $events;
|
return $events;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ($next_event['start'] > $end) // stop loop if out of range
|
else if ($next_event['start'] > $end) {
|
||||||
|
// stop loop if out of range
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// avoid endless recursion loops
|
// avoid endless recursion loops
|
||||||
if (++$i > 100000)
|
if (++$i > 100000) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $events;
|
return $events;
|
||||||
}
|
}
|
||||||
|
@ -769,7 +809,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ns == 'other' || !$this->cal->rc->config->get('kolab_invitation_calendars')) {
|
if ($ns == 'other' || !$this->cal->rc->config->get('kolab_invitation_calendars')) {
|
||||||
$record = kolab_driver::add_partstat_class($record, array('NEEDS-ACTION', 'DECLINED'), $this->get_owner());
|
$record = kolab_driver::add_partstat_class($record, ['NEEDS-ACTION', 'DECLINED'], $this->get_owner());
|
||||||
|
|
||||||
// Modify invitation status class name, when invitation calendars are disabled
|
// Modify invitation status class name, when invitation calendars are disabled
|
||||||
// we'll use opacity only for declined/needs-action events
|
// we'll use opacity only for declined/needs-action events
|
||||||
|
@ -778,15 +818,15 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
|
|
||||||
// add instance identifier to first occurrence (master event)
|
// add instance identifier to first occurrence (master event)
|
||||||
$recurrence_id_format = libcalendaring::recurrence_id_format($master_event ? $master_event : $record);
|
$recurrence_id_format = libcalendaring::recurrence_id_format($master_event ? $master_event : $record);
|
||||||
if (!$noinst && $record['recurrence'] && !$record['recurrence_id'] && !$record['_instance']) {
|
if (!$noinst && !empty($record['recurrence']) && empty($record['recurrence_id']) && empty($record['_instance'])) {
|
||||||
$record['_instance'] = $record['start']->format($recurrence_id_format);
|
$record['_instance'] = $record['start']->format($recurrence_id_format);
|
||||||
}
|
}
|
||||||
else if (is_a($record['recurrence_date'], 'DateTime')) {
|
else if (isset($record['recurrence_date']) && is_a($record['recurrence_date'], 'DateTime')) {
|
||||||
$record['_instance'] = $record['recurrence_date']->format($recurrence_id_format);
|
$record['_instance'] = $record['recurrence_date']->format($recurrence_id_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up exception data
|
// clean up exception data
|
||||||
if ($record['recurrence'] && is_array($record['recurrence']['EXCEPTIONS'])) {
|
if (!empty($record['recurrence']) && !empty($record['recurrence']['EXCEPTIONS'])) {
|
||||||
array_walk($record['recurrence']['EXCEPTIONS'], function(&$exception) {
|
array_walk($record['recurrence']['EXCEPTIONS'], function(&$exception) {
|
||||||
unset($exception['_mailbox'], $exception['_msguid'], $exception['_formatobj'], $exception['_attachments']);
|
unset($exception['_mailbox'], $exception['_msguid'], $exception['_formatobj'], $exception['_attachments']);
|
||||||
});
|
});
|
||||||
|
@ -799,24 +839,24 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
* Convert the given event record into a data structure that can be passed to Kolab_Storage backend for saving
|
* Convert the given event record into a data structure that can be passed to Kolab_Storage backend for saving
|
||||||
* (opposite of self::_to_driver_event())
|
* (opposite of self::_to_driver_event())
|
||||||
*/
|
*/
|
||||||
private function _from_driver_event($event, $old = array())
|
private function _from_driver_event($event, $old = [])
|
||||||
{
|
{
|
||||||
// set current user as ORGANIZER
|
// set current user as ORGANIZER
|
||||||
if ($identity = $this->cal->rc->user->list_emails(true)) {
|
if ($identity = $this->cal->rc->user->list_emails(true)) {
|
||||||
$event['attendees'] = (array) $event['attendees'];
|
$event['attendees'] = !empty($event['attendees']) ? $event['attendees'] : [];
|
||||||
$found = false;
|
$found = false;
|
||||||
|
|
||||||
// there can be only resources on attendees list (T1484)
|
// there can be only resources on attendees list (T1484)
|
||||||
// let's check the existence of an organizer
|
// let's check the existence of an organizer
|
||||||
foreach ($event['attendees'] as $attendee) {
|
foreach ($event['attendees'] as $attendee) {
|
||||||
if ($attendee['role'] == 'ORGANIZER') {
|
if (!empty($attendee['role']) && $attendee['role'] == 'ORGANIZER') {
|
||||||
$found = true;
|
$found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$found) {
|
if (!$found) {
|
||||||
$event['attendees'][] = array('role' => 'ORGANIZER', 'name' => $identity['name'], 'email' => $identity['email']);
|
$event['attendees'][] = ['role' => 'ORGANIZER', 'name' => $identity['name'], 'email' => $identity['email']];
|
||||||
}
|
}
|
||||||
|
|
||||||
$event['_owner'] = $identity['email'];
|
$event['_owner'] = $identity['email'];
|
||||||
|
@ -824,12 +864,12 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
|
|
||||||
// remove EXDATE values if RDATE is given
|
// remove EXDATE values if RDATE is given
|
||||||
if (!empty($event['recurrence']['RDATE'])) {
|
if (!empty($event['recurrence']['RDATE'])) {
|
||||||
$event['recurrence']['EXDATE'] = array();
|
$event['recurrence']['EXDATE'] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove recurrence information (e.g. EXDATES and EXCEPTIONS) entirely
|
// remove recurrence information (e.g. EXDATES and EXCEPTIONS) entirely
|
||||||
if ($event['recurrence'] && empty($event['recurrence']['FREQ']) && empty($event['recurrence']['RDATE'])) {
|
if (!empty($event['recurrence']) && empty($event['recurrence']['FREQ']) && empty($event['recurrence']['RDATE'])) {
|
||||||
$event['recurrence'] = array();
|
$event['recurrence'] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep 'comment' from initial itip invitation
|
// keep 'comment' from initial itip invitation
|
||||||
|
@ -847,7 +887,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
$cleanup_fn($event);
|
$cleanup_fn($event);
|
||||||
|
|
||||||
// clean up exception data
|
// clean up exception data
|
||||||
if (is_array($event['exceptions'])) {
|
if (!empty($event['exceptions'])) {
|
||||||
array_walk($event['exceptions'], function(&$exception) use ($cleanup_fn) {
|
array_walk($event['exceptions'], function(&$exception) use ($cleanup_fn) {
|
||||||
unset($exception['_mailbox'], $exception['_msguid'], $exception['_formatobj']);
|
unset($exception['_mailbox'], $exception['_msguid'], $exception['_formatobj']);
|
||||||
$cleanup_fn($exception);
|
$cleanup_fn($exception);
|
||||||
|
@ -855,10 +895,11 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy meta data (starting with _) from old object
|
// copy meta data (starting with _) from old object
|
||||||
foreach ((array)$old as $key => $val) {
|
foreach ((array) $old as $key => $val) {
|
||||||
if (!isset($event[$key]) && $key[0] == '_')
|
if (!isset($event[$key]) && $key[0] == '_') {
|
||||||
$event[$key] = $val;
|
$event[$key] = $val;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $event;
|
return $event;
|
||||||
}
|
}
|
||||||
|
@ -870,9 +911,14 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
{
|
{
|
||||||
$hits = 0;
|
$hits = 0;
|
||||||
foreach ($this->search_fields as $col) {
|
foreach ($this->search_fields as $col) {
|
||||||
$sval = is_array($event[$col]) ? self::_complex2string($event[$col]) : $event[$col];
|
if (empty($event[$col])) {
|
||||||
if (empty($sval))
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sval = is_array($event[$col]) ? self::_complex2string($event[$col]) : $event[$col];
|
||||||
|
if (empty($sval)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// do a simple substring matching (to be improved)
|
// do a simple substring matching (to be improved)
|
||||||
$val = mb_strtolower($sval);
|
$val = mb_strtolower($sval);
|
||||||
|
@ -890,7 +936,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
*/
|
*/
|
||||||
private static function _complex2string($prop)
|
private static function _complex2string($prop)
|
||||||
{
|
{
|
||||||
static $ignorekeys = array('role','status','rsvp');
|
static $ignorekeys = ['role', 'status', 'rsvp'];
|
||||||
|
|
||||||
$out = '';
|
$out = '';
|
||||||
if (is_array($prop)) {
|
if (is_array($prop)) {
|
||||||
|
@ -909,5 +955,4 @@ class kolab_calendar extends kolab_storage_folder_api
|
||||||
|
|
||||||
return rtrim($out);
|
return rtrim($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,8 +30,8 @@ class kolab_invitation_calendar
|
||||||
public $editable = false;
|
public $editable = false;
|
||||||
public $attachments = false;
|
public $attachments = false;
|
||||||
public $subscriptions = false;
|
public $subscriptions = false;
|
||||||
public $partstats = array('unknown');
|
public $partstats = ['unknown'];
|
||||||
public $categories = array();
|
public $categories = [];
|
||||||
public $name = 'Invitations';
|
public $name = 'Invitations';
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,23 +45,26 @@ class kolab_invitation_calendar
|
||||||
|
|
||||||
switch ($this->id) {
|
switch ($this->id) {
|
||||||
case kolab_driver::INVITATIONS_CALENDAR_PENDING:
|
case kolab_driver::INVITATIONS_CALENDAR_PENDING:
|
||||||
$this->partstats = array('NEEDS-ACTION');
|
$this->partstats = ['NEEDS-ACTION'];
|
||||||
$this->name = $this->cal->gettext('invitationspending');
|
$this->name = $this->cal->gettext('invitationspending');
|
||||||
if (!empty($_REQUEST['_quickview']))
|
|
||||||
|
if (!empty($_REQUEST['_quickview'])) {
|
||||||
$this->partstats[] = 'TENTATIVE';
|
$this->partstats[] = 'TENTATIVE';
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kolab_driver::INVITATIONS_CALENDAR_DECLINED:
|
case kolab_driver::INVITATIONS_CALENDAR_DECLINED:
|
||||||
$this->partstats = array('DECLINED');
|
$this->partstats = ['DECLINED'];
|
||||||
$this->name = $this->cal->gettext('invitationsdeclined');
|
$this->name = $this->cal->gettext('invitationsdeclined');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// user-specific alarms settings win
|
// user-specific alarms settings win
|
||||||
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
|
$prefs = $this->cal->rc->config->get('kolab_calendars', []);
|
||||||
if (isset($prefs[$this->id]['showalarms']))
|
if (isset($prefs[$this->id]['showalarms'])) {
|
||||||
$this->alarms = $prefs[$this->id]['showalarms'];
|
$this->alarms = $prefs[$this->id]['showalarms'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for a nice and human readable name for this calendar
|
* Getter for a nice and human readable name for this calendar
|
||||||
|
@ -128,10 +131,11 @@ class kolab_invitation_calendar
|
||||||
public function get_color()
|
public function get_color()
|
||||||
{
|
{
|
||||||
// calendar color is stored in local user prefs
|
// calendar color is stored in local user prefs
|
||||||
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
|
$prefs = $this->cal->rc->config->get('kolab_calendars', []);
|
||||||
|
|
||||||
if (!empty($prefs[$this->id]) && !empty($prefs[$this->id]['color']))
|
if (!empty($prefs[$this->id]) && !empty($prefs[$this->id]['color'])) {
|
||||||
return $prefs[$this->id]['color'];
|
return $prefs[$this->id]['color'];
|
||||||
|
}
|
||||||
|
|
||||||
return 'ffffff';
|
return 'ffffff';
|
||||||
}
|
}
|
||||||
|
@ -147,12 +151,12 @@ class kolab_invitation_calendar
|
||||||
/**
|
/**
|
||||||
* Check activation status of this folder
|
* Check activation status of this folder
|
||||||
*
|
*
|
||||||
* @return boolean True if enabled, false if not
|
* @return bool True if enabled, false if not
|
||||||
*/
|
*/
|
||||||
public function is_active()
|
public function is_active()
|
||||||
{
|
{
|
||||||
$prefs = $this->cal->rc->config->get('kolab_calendars', array()); // read local prefs
|
$prefs = $this->cal->rc->config->get('kolab_calendars', []); // read local prefs
|
||||||
return (bool)$prefs[$this->id]['active'];
|
return !empty($prefs[$this->id]['active']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,7 +194,7 @@ class kolab_invitation_calendar
|
||||||
public function get_recurring_events($event, $start, $end = null, $event_id = null, $limit = null)
|
public function get_recurring_events($event, $start, $end = null, $event_id = null, $limit = null)
|
||||||
{
|
{
|
||||||
// forward call to the actual storage folder
|
// forward call to the actual storage folder
|
||||||
if ($event['_folder_id']) {
|
if (!empty($event['_folder_id'])) {
|
||||||
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
||||||
if ($cal && $cal->ready) {
|
if ($cal && $cal->ready) {
|
||||||
return $cal->get_recurring_events($event, $start, $end, $event_id, $limit);
|
return $cal->get_recurring_events($event, $start, $end, $event_id, $limit);
|
||||||
|
@ -227,39 +231,45 @@ class kolab_invitation_calendar
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param integer Event's new start (unix timestamp)
|
* @param int Event's new start (unix timestamp)
|
||||||
* @param integer Event's new end (unix timestamp)
|
* @param int Event's new end (unix timestamp)
|
||||||
* @param string Search query (optional)
|
* @param string Search query (optional)
|
||||||
* @param boolean Include virtual events (optional)
|
* @param bool Include virtual events (optional)
|
||||||
* @param array Additional parameters to query storage
|
* @param array Additional parameters to query storage
|
||||||
*
|
*
|
||||||
* @return array A list of event records
|
* @return array A list of event records
|
||||||
*/
|
*/
|
||||||
public function list_events($start, $end, $search = null, $virtual = 1, $query = array())
|
public function list_events($start, $end, $search = null, $virtual = 1, $query = [])
|
||||||
{
|
{
|
||||||
// get email addresses of the current user
|
// get email addresses of the current user
|
||||||
$user_emails = $this->cal->get_user_emails();
|
$user_emails = $this->cal->get_user_emails();
|
||||||
$subquery = array();
|
$subquery = [];
|
||||||
|
|
||||||
foreach ($user_emails as $email) {
|
foreach ($user_emails as $email) {
|
||||||
foreach ($this->partstats as $partstat) {
|
foreach ($this->partstats as $partstat) {
|
||||||
$subquery[] = array('tags', '=', 'x-partstat:' . $email . ':' . strtolower($partstat));
|
$subquery[] = ['tags', '=', 'x-partstat:' . $email . ':' . strtolower($partstat)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$events = [];
|
||||||
|
|
||||||
// aggregate events from all calendar folders
|
// aggregate events from all calendar folders
|
||||||
$events = array();
|
|
||||||
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
|
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
|
||||||
$cal = $this->_get_calendar($foldername);
|
$cal = $this->_get_calendar($foldername);
|
||||||
if (!$cal || $cal->get_namespace() == 'other')
|
if (!$cal || $cal->get_namespace() == 'other') {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($cal->list_events($start, $end, $search, 1, $query, array(array($subquery, 'OR'))) as $event) {
|
foreach ($cal->list_events($start, $end, $search, 1, $query, [[$subquery, 'OR']]) as $event) {
|
||||||
$match = false;
|
$match = false;
|
||||||
|
|
||||||
// post-filter events to match out partstats
|
// post-filter events to match out partstats
|
||||||
if (is_array($event['attendees'])) {
|
if (!empty($event['attendees'])) {
|
||||||
foreach ($event['attendees'] as $attendee) {
|
foreach ($event['attendees'] as $attendee) {
|
||||||
if (in_array($attendee['email'], $user_emails) && in_array($attendee['status'], $this->partstats)) {
|
if (
|
||||||
|
in_array($attendee['email'], $user_emails)
|
||||||
|
&& in_array($attendee['status'], $this->partstats)
|
||||||
|
) {
|
||||||
$match = true;
|
$match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -267,7 +277,8 @@ class kolab_invitation_calendar
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($match) {
|
if ($match) {
|
||||||
$events[$event['id'] ?: $event['uid']] = $this->_mod_event($event, $cal->id);
|
$uid = !empty($event['id']) ? $event['id'] : $event['uid'];
|
||||||
|
$events[$uid] = $this->_mod_event($event, $cal->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,34 +292,36 @@ class kolab_invitation_calendar
|
||||||
/**
|
/**
|
||||||
* Get number of events in the given calendar
|
* Get number of events in the given calendar
|
||||||
*
|
*
|
||||||
* @param integer Date range start (unix timestamp)
|
* @param int Date range start (unix timestamp)
|
||||||
* @param integer Date range end (unix timestamp)
|
* @param int Date range end (unix timestamp)
|
||||||
* @param array Additional query to filter events
|
* @param array Additional query to filter events
|
||||||
*
|
*
|
||||||
* @return integer Count
|
* @return int Count
|
||||||
*/
|
*/
|
||||||
public function count_events($start, $end = null, $filter = null)
|
public function count_events($start, $end = null, $filter = null)
|
||||||
{
|
{
|
||||||
// get email addresses of the current user
|
// get email addresses of the current user
|
||||||
$user_emails = $this->cal->get_user_emails();
|
$user_emails = $this->cal->get_user_emails();
|
||||||
$subquery = array();
|
$subquery = [];
|
||||||
|
|
||||||
foreach ($user_emails as $email) {
|
foreach ($user_emails as $email) {
|
||||||
foreach ($this->partstats as $partstat) {
|
foreach ($this->partstats as $partstat) {
|
||||||
$subquery[] = array('tags', '=', 'x-partstat:' . $email . ':' . strtolower($partstat));
|
$subquery[] = ['tags', '=', 'x-partstat:' . $email . ':' . strtolower($partstat)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$filter = array(
|
$filter = [
|
||||||
array('tags','!=','x-status:cancelled'),
|
['tags', '!=', 'x-status:cancelled'],
|
||||||
array($subquery, 'OR')
|
[$subquery, 'OR']
|
||||||
);
|
];
|
||||||
|
|
||||||
// aggregate counts from all calendar folders
|
// aggregate counts from all calendar folders
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
|
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
|
||||||
$cal = $this->_get_calendar($foldername);
|
$cal = $this->_get_calendar($foldername);
|
||||||
if (!$cal || $cal->get_namespace() == 'other')
|
if (!$cal || $cal->get_namespace() == 'other') {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$count += $cal->count_events($start, $end, $filter);
|
$count += $cal->count_events($start, $end, $filter);
|
||||||
}
|
}
|
||||||
|
@ -363,7 +376,7 @@ class kolab_invitation_calendar
|
||||||
public function update_event($event, $exception_id = null)
|
public function update_event($event, $exception_id = null)
|
||||||
{
|
{
|
||||||
// forward call to the actual storage folder
|
// forward call to the actual storage folder
|
||||||
if ($event['_folder_id']) {
|
if (!empty($event['_folder_id'])) {
|
||||||
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
||||||
if ($cal && $cal->ready) {
|
if ($cal && $cal->ready) {
|
||||||
return $cal->update_event($event, $exception_id);
|
return $cal->update_event($event, $exception_id);
|
||||||
|
@ -381,7 +394,7 @@ class kolab_invitation_calendar
|
||||||
public function delete_event($event, $force = true)
|
public function delete_event($event, $force = true)
|
||||||
{
|
{
|
||||||
// forward call to the actual storage folder
|
// forward call to the actual storage folder
|
||||||
if ($event['_folder_id']) {
|
if (!empty($event['_folder_id'])) {
|
||||||
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
||||||
if ($cal && $cal->ready) {
|
if ($cal && $cal->ready) {
|
||||||
return $cal->delete_event($event, $force);
|
return $cal->delete_event($event, $force);
|
||||||
|
@ -399,7 +412,7 @@ class kolab_invitation_calendar
|
||||||
public function restore_event($event)
|
public function restore_event($event)
|
||||||
{
|
{
|
||||||
// forward call to the actual storage folder
|
// forward call to the actual storage folder
|
||||||
if ($event['_folder_id']) {
|
if (!empty($event['_folder_id'])) {
|
||||||
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
$cal = $this->cal->driver->get_calendar($event['_folder_id']);
|
||||||
if ($cal && $cal->ready) {
|
if ($cal && $cal->ready) {
|
||||||
return $cal->restore_event($event);
|
return $cal->restore_event($event);
|
||||||
|
|
|
@ -29,8 +29,8 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
public $attachments = false;
|
public $attachments = false;
|
||||||
public $subscriptions = false;
|
public $subscriptions = false;
|
||||||
|
|
||||||
protected $userdata = array();
|
protected $userdata = [];
|
||||||
protected $timeindex = array();
|
protected $timeindex = [];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +50,8 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
$this->storage = $user_or_folder;
|
$this->storage = $user_or_folder;
|
||||||
$this->userdata = $this->storage->ldaprec;
|
$this->userdata = $this->storage->ldaprec;
|
||||||
}
|
}
|
||||||
else { // get user record from LDAP
|
else {
|
||||||
|
// get user record from LDAP
|
||||||
$this->storage = new kolab_storage_folder_user($user_or_folder);
|
$this->storage = new kolab_storage_folder_user($user_or_folder);
|
||||||
$this->userdata = $this->storage->ldaprec;
|
$this->userdata = $this->storage->ldaprec;
|
||||||
}
|
}
|
||||||
|
@ -66,11 +67,12 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
$this->parent = ''; // user calendars are top level
|
$this->parent = ''; // user calendars are top level
|
||||||
|
|
||||||
// user-specific alarms settings win
|
// user-specific alarms settings win
|
||||||
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
|
$prefs = $this->cal->rc->config->get('kolab_calendars', []);
|
||||||
if (isset($prefs[$this->id]['showalarms']))
|
if (isset($prefs[$this->id]['showalarms'])) {
|
||||||
$this->alarms = $prefs[$this->id]['showalarms'];
|
$this->alarms = $prefs[$this->id]['showalarms'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for a nice and human readable name for this calendar
|
* Getter for a nice and human readable name for this calendar
|
||||||
|
@ -79,7 +81,11 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
*/
|
*/
|
||||||
public function get_name()
|
public function get_name()
|
||||||
{
|
{
|
||||||
return $this->userdata['displayname'] ?: ($this->userdata['name'] ?: $this->userdata['mail']);
|
if (!empty($this->userdata['displayname'])) {
|
||||||
|
return $this->userdata['displayname'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return !empty($this->userdata['name']) ? $this->userdata['name'] : $this->userdata['mail'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,7 +105,15 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
*/
|
*/
|
||||||
public function get_title()
|
public function get_title()
|
||||||
{
|
{
|
||||||
return trim($this->userdata['displayname'] . '; ' . $this->userdata['mail'], '; ');
|
$title = [];
|
||||||
|
|
||||||
|
if (!empty($this->userdata['displayname'])) {
|
||||||
|
$title[] = $this->userdata['displayname'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$title[] = $this->userdata['mail'];
|
||||||
|
|
||||||
|
return implode('; ', $title);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,10 +142,11 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
public function get_color($default = null)
|
public function get_color($default = null)
|
||||||
{
|
{
|
||||||
// calendar color is stored in local user prefs
|
// calendar color is stored in local user prefs
|
||||||
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
|
$prefs = $this->cal->rc->config->get('kolab_calendars', []);
|
||||||
|
|
||||||
if (!empty($prefs[$this->id]) && !empty($prefs[$this->id]['color']))
|
if (!empty($prefs[$this->id]) && !empty($prefs[$this->id]['color'])) {
|
||||||
return $prefs[$this->id]['color'];
|
return $prefs[$this->id]['color'];
|
||||||
|
}
|
||||||
|
|
||||||
return $default ?: 'cc0000';
|
return $default ?: 'cc0000';
|
||||||
}
|
}
|
||||||
|
@ -172,7 +187,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
public function get_event($id)
|
public function get_event($id)
|
||||||
{
|
{
|
||||||
// TODO: implement this
|
// TODO: implement this
|
||||||
return $this->events[$id];
|
return isset($this->events[$id]) ? $this->events[$id] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,11 +196,11 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
*/
|
*/
|
||||||
public function get_attachment_body($id, $event)
|
public function get_attachment_body($id, $event)
|
||||||
{
|
{
|
||||||
if (!$event['calendar'] && ($ev = $this->get_event($event['id']))) {
|
if (empty($event['calendar']) && ($ev = $this->get_event($event['id']))) {
|
||||||
$event['calendar'] = $ev['calendar'];
|
$event['calendar'] = $ev['calendar'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['calendar'] && ($cal = $this->cal->get_calendar($event['calendar']))) {
|
if (!empty($event['calendar']) && ($cal = $this->cal->get_calendar($event['calendar']))) {
|
||||||
return $cal->get_attachment_body($id, $event);
|
return $cal->get_attachment_body($id, $event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,16 +208,16 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param integer Event's new start (unix timestamp)
|
* @param int Event's new start (unix timestamp)
|
||||||
* @param integer Event's new end (unix timestamp)
|
* @param int Event's new end (unix timestamp)
|
||||||
* @param string Search query (optional)
|
* @param string Search query (optional)
|
||||||
* @param boolean Include virtual events (optional)
|
* @param bool Include virtual events (optional)
|
||||||
* @param array Additional parameters to query storage
|
* @param array Additional parameters to query storage
|
||||||
* @param array Additional query to filter events
|
* @param array Additional query to filter events
|
||||||
*
|
*
|
||||||
* @return array A list of event records
|
* @return array A list of event records
|
||||||
*/
|
*/
|
||||||
public function list_events($start, $end, $search = null, $virtual = 1, $query = array(), $filter_query = null)
|
public function list_events($start, $end, $search = null, $virtual = 1, $query = [], $filter_query = null)
|
||||||
{
|
{
|
||||||
// convert to DateTime for comparisons
|
// convert to DateTime for comparisons
|
||||||
try {
|
try {
|
||||||
|
@ -219,6 +234,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
}
|
}
|
||||||
|
|
||||||
$limit_changed = null;
|
$limit_changed = null;
|
||||||
|
|
||||||
if (!empty($query)) {
|
if (!empty($query)) {
|
||||||
foreach ($query as $q) {
|
foreach ($query as $q) {
|
||||||
if ($q[0] == 'changed' && $q[1] == '>=') {
|
if ($q[0] == 'changed' && $q[1] == '>=') {
|
||||||
|
@ -232,7 +248,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
foreach (kolab_storage::list_user_folders($this->userdata, 'event', 2) as $foldername) {
|
foreach (kolab_storage::list_user_folders($this->userdata, 'event', 2) as $foldername) {
|
||||||
$cal = new kolab_calendar($foldername, $this->cal);
|
$cal = new kolab_calendar($foldername, $this->cal);
|
||||||
foreach ($cal->list_events($start, $end, $search, 1) as $event) {
|
foreach ($cal->list_events($start, $end, $search, 1) as $event) {
|
||||||
$uid = $event['id'] ?: $event['uid'];
|
$uid = !empty($event['id']) ? $event['id'] : $event['uid'];
|
||||||
$this->events[$uid] = $event;
|
$this->events[$uid] = $event;
|
||||||
$this->timeindex[$this->time_key($event)] = $uid;
|
$this->timeindex[$this->time_key($event)] = $uid;
|
||||||
}
|
}
|
||||||
|
@ -244,11 +260,14 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
$this->fetch_freebusy($limit_changed);
|
$this->fetch_freebusy($limit_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
$events = array();
|
$events = [];
|
||||||
foreach ($this->events as $event) {
|
foreach ($this->events as $event) {
|
||||||
// list events in requested time window
|
// list events in requested time window
|
||||||
if ($event['start'] <= $end_dt && $event['end'] >= $start_dt &&
|
if (
|
||||||
(!$limit_changed || !$event['changed'] || $event['changed'] >= $limit_changed)) {
|
$event['start'] <= $end_dt
|
||||||
|
&& $event['end'] >= $start_dt
|
||||||
|
&& (!$limit_changed || empty($event['changed']) || $event['changed'] >= $limit_changed)
|
||||||
|
) {
|
||||||
$events[] = $event;
|
$events[] = $event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,8 +281,8 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
/**
|
/**
|
||||||
* Get number of events in the given calendar
|
* Get number of events in the given calendar
|
||||||
*
|
*
|
||||||
* @param integer Date range start (unix timestamp)
|
* @param int Date range start (unix timestamp)
|
||||||
* @param integer Date range end (unix timestamp)
|
* @param int Date range end (unix timestamp)
|
||||||
* @param array Additional query to filter events
|
* @param array Additional query to filter events
|
||||||
*
|
*
|
||||||
* @return integer Count
|
* @return integer Count
|
||||||
|
@ -281,10 +300,10 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
{
|
{
|
||||||
// ask kolab server first
|
// ask kolab server first
|
||||||
try {
|
try {
|
||||||
$request_config = array(
|
$request_config = [
|
||||||
'store_body' => true,
|
'store_body' => true,
|
||||||
'follow_redirects' => true,
|
'follow_redirects' => true,
|
||||||
);
|
];
|
||||||
$request = libkolab::http_request(kolab_storage::get_freebusy_url($this->userdata['mail']), 'GET', $request_config);
|
$request = libkolab::http_request(kolab_storage::get_freebusy_url($this->userdata['mail']), 'GET', $request_config);
|
||||||
$response = $request->send();
|
$response = $request->send();
|
||||||
|
|
||||||
|
@ -294,70 +313,72 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
$response = $request->send();
|
$response = $request->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($response->getStatus() == 200)
|
if ($response->getStatus() == 200) {
|
||||||
$fbdata = $response->getBody();
|
$fbdata = $response->getBody();
|
||||||
|
}
|
||||||
|
|
||||||
unset($request, $response);
|
unset($request, $response);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error([
|
||||||
'code' => 900,
|
'code' => 900, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'type' => 'php',
|
'message' => "Error fetching free/busy information: " . $e->getMessage()
|
||||||
'file' => __FILE__,
|
],
|
||||||
'line' => __LINE__,
|
true, false
|
||||||
'message' => "Error fetching free/busy information: " . $e->getMessage()),
|
);
|
||||||
true, false);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$statusmap = array(
|
$statusmap = [
|
||||||
'FREE' => 'free',
|
'FREE' => 'free',
|
||||||
'BUSY' => 'busy',
|
'BUSY' => 'busy',
|
||||||
'BUSY-TENTATIVE' => 'tentative',
|
'BUSY-TENTATIVE' => 'tentative',
|
||||||
'X-OUT-OF-OFFICE' => 'outofoffice',
|
'X-OUT-OF-OFFICE' => 'outofoffice',
|
||||||
'OOF' => 'outofoffice',
|
'OOF' => 'outofoffice',
|
||||||
);
|
];
|
||||||
$titlemap = array(
|
|
||||||
|
$titlemap = [
|
||||||
'FREE' => $this->cal->gettext('availfree'),
|
'FREE' => $this->cal->gettext('availfree'),
|
||||||
'BUSY' => $this->cal->gettext('availbusy'),
|
'BUSY' => $this->cal->gettext('availbusy'),
|
||||||
'BUSY-TENTATIVE' => $this->cal->gettext('availtentative'),
|
'BUSY-TENTATIVE' => $this->cal->gettext('availtentative'),
|
||||||
'X-OUT-OF-OFFICE' => $this->cal->gettext('availoutofoffice'),
|
'X-OUT-OF-OFFICE' => $this->cal->gettext('availoutofoffice'),
|
||||||
);
|
];
|
||||||
|
|
||||||
// rcube::console('_fetch_freebusy', kolab_storage::get_freebusy_url($this->userdata['mail']), $fbdata);
|
// rcube::console('_fetch_freebusy', kolab_storage::get_freebusy_url($this->userdata['mail']), $fbdata);
|
||||||
|
|
||||||
// parse free-busy information
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
if ($fbdata) {
|
|
||||||
|
// parse free-busy information
|
||||||
|
if (!empty($fbdata)) {
|
||||||
$ical = $this->cal->get_ical();
|
$ical = $this->cal->get_ical();
|
||||||
$ical->import($fbdata);
|
$ical->import($fbdata);
|
||||||
if ($fb = $ical->freebusy) {
|
if ($fb = $ical->freebusy) {
|
||||||
// consider 'changed >= X' queries
|
// consider 'changed >= X' queries
|
||||||
if ($limit_changed && $fb['created'] && $fb['created'] < $limit_changed) {
|
if ($limit_changed && !empty($fb['created']) && $fb['created'] < $limit_changed) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($fb['periods'] as $tuple) {
|
foreach ($fb['periods'] as $tuple) {
|
||||||
list($from, $to, $type) = $tuple;
|
list($from, $to, $type) = $tuple;
|
||||||
$event = array(
|
$event = [
|
||||||
'uid' => md5($this->id . $from->format('U') . '/' . $to->format('U')),
|
'uid' => md5($this->id . $from->format('U') . '/' . $to->format('U')),
|
||||||
'calendar' => $this->id,
|
'calendar' => $this->id,
|
||||||
'changed' => $fb['created'] ?: new DateTime(),
|
'changed' => !empty($fb['created']) ? $fb['created'] : new DateTime(),
|
||||||
'title' => $this->get_name() . ' ' . ($titlemap[$type] ?: $type),
|
'title' => $this->get_name() . ' ' . (!empty($titlemap[$type]) ? $titlemap[$type] : $type),
|
||||||
'start' => $from,
|
'start' => $from,
|
||||||
'end' => $to,
|
'end' => $to,
|
||||||
'free_busy' => $statusmap[$type] ?: 'busy',
|
'free_busy' => !empty($statusmap[$type]) ? $statusmap[$type] : 'busy',
|
||||||
'className' => 'fc-type-freebusy',
|
'className' => 'fc-type-freebusy',
|
||||||
'organizer' => array(
|
'organizer' => [
|
||||||
'email' => $this->userdata['mail'],
|
'email' => $this->userdata['mail'],
|
||||||
'name' => $this->userdata['displayname'],
|
'name' => isset($this->userdata['displayname']) ? $this->userdata['displayname'] : null,
|
||||||
),
|
],
|
||||||
);
|
];
|
||||||
|
|
||||||
// avoid duplicate entries
|
// avoid duplicate entries
|
||||||
$key = $this->time_key($event);
|
$key = $this->time_key($event);
|
||||||
if (!$this->timeindex[$key]) {
|
if (empty($this->timeindex[$key])) {
|
||||||
$this->events[$event['uid']] = $event;
|
$this->events[$event['uid']] = $event;
|
||||||
$this->timeindex[$key] = $event['uid'];
|
$this->timeindex[$key] = $event['uid'];
|
||||||
$count++;
|
$count++;
|
||||||
|
@ -393,7 +414,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
* Update a specific event record
|
* Update a specific event record
|
||||||
*
|
*
|
||||||
* @see calendar_driver::new_event()
|
* @see calendar_driver::new_event()
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function update_event($event, $exception_id = null)
|
public function update_event($event, $exception_id = null)
|
||||||
{
|
{
|
||||||
|
@ -404,7 +425,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
* Delete an event record
|
* Delete an event record
|
||||||
*
|
*
|
||||||
* @see calendar_driver::remove_event()
|
* @see calendar_driver::remove_event()
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function delete_event($event, $force = true)
|
public function delete_event($event, $force = true)
|
||||||
{
|
{
|
||||||
|
@ -415,7 +436,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
* Restore deleted event record
|
* Restore deleted event record
|
||||||
*
|
*
|
||||||
* @see calendar_driver::undelete_event()
|
* @see calendar_driver::undelete_event()
|
||||||
* @return boolean True on success, False on error
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function restore_event($event)
|
public function restore_event($event)
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,13 +41,15 @@ class resources_driver_ldap extends resources_driver
|
||||||
/**
|
/**
|
||||||
* Fetch resource objects to be displayed for booking
|
* Fetch resource objects to be displayed for booking
|
||||||
*
|
*
|
||||||
* @param string Search query (optional)
|
* @param string $query Search query (optional)
|
||||||
|
* @param int $num Max size of the result
|
||||||
|
*
|
||||||
* @return array List of resource records available for booking
|
* @return array List of resource records available for booking
|
||||||
*/
|
*/
|
||||||
public function load_resources($query = null, $num = 5000)
|
public function load_resources($query = null, $num = 5000)
|
||||||
{
|
{
|
||||||
if (!($ldap = $this->connect())) {
|
if (!($ldap = $this->connect())) {
|
||||||
return array();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: apply paging
|
// TODO: apply paging
|
||||||
|
@ -72,7 +74,8 @@ class resources_driver_ldap extends resources_driver
|
||||||
/**
|
/**
|
||||||
* Return properties of a single resource
|
* Return properties of a single resource
|
||||||
*
|
*
|
||||||
* @param string Unique resource identifier
|
* @param string $id Unique resource identifier
|
||||||
|
*
|
||||||
* @return array Resource object as hash array
|
* @return array Resource object as hash array
|
||||||
*/
|
*/
|
||||||
public function get_resource($dn)
|
public function get_resource($dn)
|
||||||
|
@ -93,7 +96,8 @@ class resources_driver_ldap extends resources_driver
|
||||||
/**
|
/**
|
||||||
* Return properties of a resource owner
|
* Return properties of a resource owner
|
||||||
*
|
*
|
||||||
* @param string Owner identifier
|
* @param string $dn Owner identifier
|
||||||
|
*
|
||||||
* @return array Resource object as hash array
|
* @return array Resource object as hash array
|
||||||
*/
|
*/
|
||||||
public function get_resource_owner($dn)
|
public function get_resource_owner($dn)
|
||||||
|
@ -116,15 +120,15 @@ class resources_driver_ldap extends resources_driver
|
||||||
{
|
{
|
||||||
$rec['ID'] = rcube_ldap::dn_decode($rec['ID']);
|
$rec['ID'] = rcube_ldap::dn_decode($rec['ID']);
|
||||||
|
|
||||||
$attributes = array();
|
$attributes = [];
|
||||||
|
|
||||||
foreach ((array) $rec['attributes'] as $sattr) {
|
foreach ((array) $rec['attributes'] as $sattr) {
|
||||||
$sattr = trim($sattr);
|
$sattr = trim($sattr);
|
||||||
if ($sattr && $sattr[0] === '{') {
|
if (!empty($sattr) && $sattr[0] === '{') {
|
||||||
$attr = @json_decode($sattr, true);
|
$attr = @json_decode($sattr, true);
|
||||||
$attributes += $attr;
|
$attributes += $attr;
|
||||||
}
|
}
|
||||||
else if ($sattr && empty($rec['description'])) {
|
else if (!empty($sattr) && empty($rec['description'])) {
|
||||||
$rec['description'] = $sattr;
|
$rec['description'] = $sattr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +137,7 @@ class resources_driver_ldap extends resources_driver
|
||||||
|
|
||||||
// force $rec['members'] to be an array
|
// force $rec['members'] to be an array
|
||||||
if (!empty($rec['members']) && !is_array($rec['members'])) {
|
if (!empty($rec['members']) && !is_array($rec['members'])) {
|
||||||
$rec['members'] = array($rec['members']);
|
$rec['members'] = [$rec['members']];
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove unused cruft
|
// remove unused cruft
|
||||||
|
@ -150,5 +154,4 @@ class resources_driver_ldap extends resources_driver
|
||||||
|
|
||||||
return $this->ldap->ready ? $this->ldap : null;
|
return $this->ldap->ready ? $this->ldap : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -39,7 +39,8 @@ abstract class resources_driver
|
||||||
/**
|
/**
|
||||||
* Fetch resource objects to be displayed for booking
|
* Fetch resource objects to be displayed for booking
|
||||||
*
|
*
|
||||||
* @param string Search query (optional)
|
* @param string $query Search query (optional)
|
||||||
|
*
|
||||||
* @return array List of resource records available for booking
|
* @return array List of resource records available for booking
|
||||||
*/
|
*/
|
||||||
abstract public function load_resources($query = null);
|
abstract public function load_resources($query = null);
|
||||||
|
@ -47,7 +48,8 @@ abstract class resources_driver
|
||||||
/**
|
/**
|
||||||
* Return properties of a single resource
|
* Return properties of a single resource
|
||||||
*
|
*
|
||||||
* @param string Unique resource identifier
|
* @param string $id Unique resource identifier
|
||||||
|
*
|
||||||
* @return array Resource object as hash array
|
* @return array Resource object as hash array
|
||||||
*/
|
*/
|
||||||
abstract public function get_resource($id);
|
abstract public function get_resource($id);
|
||||||
|
@ -55,7 +57,8 @@ abstract class resources_driver
|
||||||
/**
|
/**
|
||||||
* Return properties of a resource owner
|
* Return properties of a resource owner
|
||||||
*
|
*
|
||||||
* @param string Owner identifier
|
* @param string $id Owner identifier
|
||||||
|
*
|
||||||
* @return array Resource object as hash array
|
* @return array Resource object as hash array
|
||||||
*/
|
*/
|
||||||
public function get_resource_owner($id)
|
public function get_resource_owner($id)
|
||||||
|
@ -69,20 +72,23 @@ abstract class resources_driver
|
||||||
* The default implementation extracts the resource's email address
|
* The default implementation extracts the resource's email address
|
||||||
* and fetches free-busy data using the calendar backend driver.
|
* and fetches free-busy data using the calendar backend driver.
|
||||||
*
|
*
|
||||||
* @param integer Event's new start (unix timestamp)
|
* @param string $id Calendar identifier
|
||||||
* @param integer Event's new end (unix timestamp)
|
* @param int $start Event's new start (unix timestamp)
|
||||||
|
* @param int $end Event's new end (unix timestamp)
|
||||||
|
*
|
||||||
* @return array A list of event objects (see calendar_driver specification)
|
* @return array A list of event objects (see calendar_driver specification)
|
||||||
*/
|
*/
|
||||||
public function get_resource_calendar($id, $start, $end)
|
public function get_resource_calendar($id, $start, $end)
|
||||||
{
|
{
|
||||||
$events = array();
|
$events = [];
|
||||||
$rec = $this->get_resource($id);
|
$rec = $this->get_resource($id);
|
||||||
if ($rec && !empty($rec['email']) && $this->cal->driver) {
|
|
||||||
$fbtypemap = array(
|
if ($rec && !empty($rec['email']) && !empty($this->cal->driver)) {
|
||||||
|
$fbtypemap = [
|
||||||
calendar::FREEBUSY_BUSY => 'busy',
|
calendar::FREEBUSY_BUSY => 'busy',
|
||||||
calendar::FREEBUSY_TENTATIVE => 'tentative',
|
calendar::FREEBUSY_TENTATIVE => 'tentative',
|
||||||
calendar::FREEBUSY_OOF => 'outofoffice',
|
calendar::FREEBUSY_OOF => 'outofoffice',
|
||||||
);
|
];
|
||||||
|
|
||||||
// if the backend has free-busy information
|
// if the backend has free-busy information
|
||||||
$fblist = $this->cal->driver->get_freebusy_list($rec['email'], $start, $end);
|
$fblist = $this->cal->driver->get_freebusy_list($rec['email'], $start, $end);
|
||||||
|
@ -92,16 +98,16 @@ abstract class resources_driver
|
||||||
if ($type == calendar::FREEBUSY_FREE || $type == calendar::FREEBUSY_UNKNOWN) {
|
if ($type == calendar::FREEBUSY_FREE || $type == calendar::FREEBUSY_UNKNOWN) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($from < $end && $to > $start) {
|
if ($from < $end && $to > $start) {
|
||||||
$event = array(
|
$events[] = [
|
||||||
'id' => sha1($id . $from . $to),
|
'id' => sha1($id . $from . $to),
|
||||||
'title' => $rec['name'],
|
'title' => $rec['name'],
|
||||||
'start' => new DateTime('@' . $from),
|
'start' => new DateTime('@' . $from),
|
||||||
'end' => new DateTime('@' . $to),
|
'end' => new DateTime('@' . $to),
|
||||||
'status' => $fbtypemap[$type],
|
'status' => $fbtypemap[$type],
|
||||||
'calendar' => '_resource',
|
'calendar' => '_resource',
|
||||||
);
|
];
|
||||||
$events[] = $event;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,9 @@ class calendar_itip extends libcalendaring_itip
|
||||||
$status = parent::get_itip_status($event, $existing);
|
$status = parent::get_itip_status($event, $existing);
|
||||||
|
|
||||||
// don't ask for deleting events when declining
|
// don't ask for deleting events when declining
|
||||||
if ($this->rc->config->get('kolab_invitation_calendars'))
|
if ($this->rc->config->get('kolab_invitation_calendars')) {
|
||||||
$status['saved'] = false;
|
$status['saved'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +56,8 @@ class calendar_itip extends libcalendaring_itip
|
||||||
/**
|
/**
|
||||||
* Find invitation record by token
|
* Find invitation record by token
|
||||||
*
|
*
|
||||||
* @param string Invitation token
|
* @param string $token Invitation token
|
||||||
|
*
|
||||||
* @return mixed Invitation record as hash array or False if not found
|
* @return mixed Invitation record as hash array or False if not found
|
||||||
*/
|
*/
|
||||||
public function get_invitation($token)
|
public function get_invitation($token)
|
||||||
|
@ -65,6 +67,7 @@ class calendar_itip extends libcalendaring_itip
|
||||||
if ($result && ($rec = $this->rc->db->fetch_assoc($result))) {
|
if ($result && ($rec = $this->rc->db->fetch_assoc($result))) {
|
||||||
$rec['event'] = unserialize($rec['event']);
|
$rec['event'] = unserialize($rec['event']);
|
||||||
$rec['attendee'] = $parts['attendee'];
|
$rec['attendee'] = $parts['attendee'];
|
||||||
|
|
||||||
return $rec;
|
return $rec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,16 +78,17 @@ class calendar_itip extends libcalendaring_itip
|
||||||
/**
|
/**
|
||||||
* Update the attendee status of the given invitation record
|
* Update the attendee status of the given invitation record
|
||||||
*
|
*
|
||||||
* @param array Invitation record as fetched with calendar_itip::get_invitation()
|
* @param array $invitation Invitation record as fetched with calendar_itip::get_invitation()
|
||||||
* @param string Attendee email address
|
* @param string $email Attendee email address
|
||||||
* @param string New attendee status
|
* @param string $newstatus New attendee status
|
||||||
*/
|
*/
|
||||||
public function update_invitation($invitation, $email, $newstatus)
|
public function update_invitation($invitation, $email, $newstatus)
|
||||||
{
|
{
|
||||||
if (is_string($invitation))
|
if (is_string($invitation)) {
|
||||||
$invitation = $this->get_invitation($invitation);
|
$invitation = $this->get_invitation($invitation);
|
||||||
|
}
|
||||||
|
|
||||||
if ($invitation['token'] && $invitation['event']) {
|
if (!empty($invitation['token']) && !empty($invitation['event'])) {
|
||||||
// update attendee record in event data
|
// update attendee record in event data
|
||||||
foreach ($invitation['event']['attendees'] as $i => $attendee) {
|
foreach ($invitation['event']['attendees'] as $i => $attendee) {
|
||||||
if ($attendee['role'] == 'ORGANIZER') {
|
if ($attendee['role'] == 'ORGANIZER') {
|
||||||
|
@ -92,72 +96,82 @@ class calendar_itip extends libcalendaring_itip
|
||||||
}
|
}
|
||||||
else if ($attendee['email'] == $email) {
|
else if ($attendee['email'] == $email) {
|
||||||
// nothing to be done here
|
// nothing to be done here
|
||||||
if ($attendee['status'] == $newstatus)
|
if ($attendee['status'] == $newstatus) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
$invitation['event']['attendees'][$i]['status'] = $newstatus;
|
$invitation['event']['attendees'][$i]['status'] = $newstatus;
|
||||||
$this->sender = $attendee;
|
$this->sender = $attendee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$invitation['event']['changed'] = new DateTime();
|
$invitation['event']['changed'] = new DateTime();
|
||||||
|
|
||||||
// send iTIP REPLY message to organizer
|
// send iTIP REPLY message to organizer
|
||||||
if ($organizer) {
|
if (!empty($organizer)) {
|
||||||
$status = strtolower($newstatus);
|
$status = strtolower($newstatus);
|
||||||
if ($this->send_itip_message($invitation['event'], 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status))
|
if ($this->send_itip_message($invitation['event'], 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status)) {
|
||||||
$this->rc->output->command('display_message', $this->plugin->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation');
|
$mailto = !empty($organizer['name']) ? $organizer['name'] : $organizer['email'];
|
||||||
else
|
$message = $this->plugin->gettext([
|
||||||
|
'name' => 'sentresponseto',
|
||||||
|
'vars' => ['mailto' => $mailto]
|
||||||
|
]);
|
||||||
|
$this->rc->output->command('display_message', $message, 'confirmation');
|
||||||
|
}
|
||||||
|
else {
|
||||||
$this->rc->output->command('display_message', $this->plugin->gettext('itipresponseerror'), 'error');
|
$this->rc->output->command('display_message', $this->plugin->gettext('itipresponseerror'), 'error');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update record in DB
|
// update record in DB
|
||||||
$query = $this->rc->db->query(
|
$query = $this->rc->db->query(
|
||||||
"UPDATE $this->db_itipinvitations
|
"UPDATE $this->db_itipinvitations SET `event` = ? WHERE `token` = ?",
|
||||||
SET `event` = ?
|
|
||||||
WHERE `token` = ?",
|
|
||||||
self::serialize_event($invitation['event']),
|
self::serialize_event($invitation['event']),
|
||||||
$invitation['token']
|
$invitation['token']
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($this->rc->db->affected_rows($query))
|
if ($this->rc->db->affected_rows($query)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create iTIP invitation token for later replies via URL
|
* Create iTIP invitation token for later replies via URL
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties
|
* @param array $event Hash array with event properties
|
||||||
* @param string Attendee email address
|
* @param string $attendee Attendee email address
|
||||||
|
*
|
||||||
* @return string Invitation token
|
* @return string Invitation token
|
||||||
*/
|
*/
|
||||||
public function store_invitation($event, $attendee)
|
public function store_invitation($event, $attendee)
|
||||||
{
|
{
|
||||||
static $stored = array();
|
static $stored = [];
|
||||||
|
|
||||||
if (!$event['uid'] || !$attendee)
|
if (empty($event['uid']) || !$attendee) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// generate token for this invitation
|
// generate token for this invitation
|
||||||
$token = $this->generate_token($event, $attendee);
|
$token = $this->generate_token($event, $attendee);
|
||||||
$base = substr($token, 0, 40);
|
$base = substr($token, 0, 40);
|
||||||
|
|
||||||
// already stored this
|
// already stored this
|
||||||
if ($stored[$base])
|
if (!empty($stored[$base])) {
|
||||||
return $token;
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
// delete old entry
|
// delete old entry
|
||||||
$this->rc->db->query("DELETE FROM $this->db_itipinvitations WHERE `token` = ?", $base);
|
$this->rc->db->query("DELETE FROM $this->db_itipinvitations WHERE `token` = ?", $base);
|
||||||
|
|
||||||
$event_uid = $event['uid'] . ($event['_instance'] ? '-' . $event['_instance'] : '');
|
$event_uid = $event['uid'] . (!empty($event['_instance']) ? '-' . $event['_instance'] : '');
|
||||||
|
|
||||||
$query = $this->rc->db->query(
|
$query = $this->rc->db->query(
|
||||||
"INSERT INTO $this->db_itipinvitations
|
"INSERT INTO $this->db_itipinvitations"
|
||||||
(`token`, `event_uid`, `user_id`, `event`, `expires`)
|
. " (`token`, `event_uid`, `user_id`, `event`, `expires`)"
|
||||||
VALUES(?, ?, ?, ?, ?)",
|
. " VALUES(?, ?, ?, ?, ?)",
|
||||||
$base,
|
$base,
|
||||||
$event_uid,
|
$event_uid,
|
||||||
$this->rc->user->ID,
|
$this->rc->user->ID,
|
||||||
|
@ -176,17 +190,16 @@ class calendar_itip extends libcalendaring_itip
|
||||||
/**
|
/**
|
||||||
* Mark invitations for the given event as cancelled
|
* Mark invitations for the given event as cancelled
|
||||||
*
|
*
|
||||||
* @param array Hash array with event properties
|
* @param array $event Hash array with event properties
|
||||||
*/
|
*/
|
||||||
public function cancel_itip_invitation($event)
|
public function cancel_itip_invitation($event)
|
||||||
{
|
{
|
||||||
$event_uid = $event['uid'] . ($event['_instance'] ? '-' . $event['_instance'] : '');
|
$event_uid = $event['uid'] . (!empty($event['_instance']) ? '-' . $event['_instance'] : '');
|
||||||
|
|
||||||
// flag invitation record as cancelled
|
// flag invitation record as cancelled
|
||||||
$this->rc->db->query(
|
$this->rc->db->query(
|
||||||
"UPDATE $this->db_itipinvitations
|
"UPDATE $this->db_itipinvitations SET `cancelled` = 1"
|
||||||
SET `cancelled` = 1
|
. " WHERE `event_uid` = ? AND `user_id` = ?",
|
||||||
WHERE `event_uid` = ? AND `user_id` = ?",
|
|
||||||
$event_uid,
|
$event_uid,
|
||||||
$this->rc->user->ID
|
$this->rc->user->ID
|
||||||
);
|
);
|
||||||
|
@ -195,12 +208,12 @@ class calendar_itip extends libcalendaring_itip
|
||||||
/**
|
/**
|
||||||
* Generate an invitation request token for the given event and attendee
|
* Generate an invitation request token for the given event and attendee
|
||||||
*
|
*
|
||||||
* @param array Event hash array
|
* @param array $event Event hash array
|
||||||
* @param string Attendee email address
|
* @param string $attendee Attendee email address
|
||||||
*/
|
*/
|
||||||
public function generate_token($event, $attendee)
|
public function generate_token($event, $attendee)
|
||||||
{
|
{
|
||||||
$event_uid = $event['uid'] . ($event['_instance'] ? '-' . $event['_instance'] : '');
|
$event_uid = $event['uid'] . (!empty($event['_instance']) ? '-' . $event['_instance'] : '');
|
||||||
$base = sha1($event_uid . ';' . $this->rc->user->ID);
|
$base = sha1($event_uid . ';' . $this->rc->user->ID);
|
||||||
$mail = base64_encode($attendee);
|
$mail = base64_encode($attendee);
|
||||||
$hash = substr(md5($base . $mail . $this->rc->config->get('des_key')), 0, 6);
|
$hash = substr(md5($base . $mail . $this->rc->config->get('des_key')), 0, 6);
|
||||||
|
@ -211,7 +224,8 @@ class calendar_itip extends libcalendaring_itip
|
||||||
/**
|
/**
|
||||||
* Decode the given iTIP request token and return its parts
|
* Decode the given iTIP request token and return its parts
|
||||||
*
|
*
|
||||||
* @param string Request token to decode
|
* @param string $token Request token to decode
|
||||||
|
*
|
||||||
* @return mixed Hash array with parts or False if invalid
|
* @return mixed Hash array with parts or False if invalid
|
||||||
*/
|
*/
|
||||||
public function decode_token($token)
|
public function decode_token($token)
|
||||||
|
@ -220,7 +234,7 @@ class calendar_itip extends libcalendaring_itip
|
||||||
|
|
||||||
// validate and return parts
|
// validate and return parts
|
||||||
if ($mail && $hash && $hash == substr(md5($base . $mail . $this->rc->config->get('des_key')), 0, 6)) {
|
if ($mail && $hash && $hash == substr(md5($base . $mail . $this->rc->config->get('des_key')), 0, 6)) {
|
||||||
return array('base' => $base, 'attendee' => base64_decode($mail));
|
return ['base' => $base, 'attendee' => base64_decode($mail)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -232,9 +246,13 @@ class calendar_itip extends libcalendaring_itip
|
||||||
private static function serialize_event($event)
|
private static function serialize_event($event)
|
||||||
{
|
{
|
||||||
$ev = $event;
|
$ev = $event;
|
||||||
|
|
||||||
|
if (!empty($ev['description'])) {
|
||||||
$ev['description'] = abbreviate_string($ev['description'], 100);
|
$ev['description'] = abbreviate_string($ev['description'], 100);
|
||||||
unset($ev['attachments']);
|
|
||||||
return serialize($ev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unset($ev['attachments']);
|
||||||
|
|
||||||
|
return serialize($ev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@ class calendar_recurrence extends libcalendaring_recurrence
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* Default constructor
|
||||||
*
|
*
|
||||||
* @param object calendar The calendar plugin instance
|
* @param calendar $cal The calendar plugin instance
|
||||||
* @param array The event object to operate on
|
* @param array $event The event object to operate on
|
||||||
*/
|
*/
|
||||||
function __construct($cal, $event)
|
function __construct($cal, $event)
|
||||||
{
|
{
|
||||||
|
@ -41,10 +41,12 @@ class calendar_recurrence extends libcalendaring_recurrence
|
||||||
|
|
||||||
$this->event = $event;
|
$this->event = $event;
|
||||||
|
|
||||||
if (is_object($event['start']) && is_object($event['end']))
|
if (is_object($event['start']) && is_object($event['end'])) {
|
||||||
$this->duration = $event['start']->diff($event['end']);
|
$this->duration = $event['start']->diff($event['end']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$event['start']->_dateonly = !empty($event['allday']);
|
||||||
|
|
||||||
$event['start']->_dateonly |= $event['allday'];
|
|
||||||
$this->init($event['recurrence'], $event['start']);
|
$this->init($event['recurrence'], $event['start']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,5 +86,4 @@ class calendar_recurrence extends libcalendaring_recurrence
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1196,5 +1196,4 @@ class kolab_addressbook extends rcube_plugin
|
||||||
$this->rc->user->save_prefs(array('calendar_birthday_adressbooks' => $bday_addressbooks));
|
$this->rc->user->save_prefs(array('calendar_birthday_adressbooks' => $bday_addressbooks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,19 +52,45 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
'gender' => array('limit' => 1),
|
'gender' => array('limit' => 1),
|
||||||
'birthday' => array('limit' => 1),
|
'birthday' => array('limit' => 1),
|
||||||
'anniversary' => array('limit' => 1),
|
'anniversary' => array('limit' => 1),
|
||||||
'profession' => array('type' => 'text', 'size' => 40, 'maxlength' => 80, 'limit' => 1,
|
'profession' => array(
|
||||||
'label' => 'kolab_addressbook.profession', 'category' => 'personal'),
|
'type' => 'text',
|
||||||
|
'size' => 40,
|
||||||
|
'maxlength' => 80,
|
||||||
|
'limit' => 1,
|
||||||
|
'label' => 'kolab_addressbook.profession',
|
||||||
|
'category' => 'personal'
|
||||||
|
),
|
||||||
'manager' => array('limit' => null),
|
'manager' => array('limit' => null),
|
||||||
'assistant' => array('limit' => null),
|
'assistant' => array('limit' => null),
|
||||||
'spouse' => array('limit' => 1),
|
'spouse' => array('limit' => 1),
|
||||||
'children' => array('type' => 'text', 'size' => 40, 'maxlength' => 80, 'limit' => null,
|
'children' => array(
|
||||||
'label' => 'kolab_addressbook.children', 'category' => 'personal'),
|
'type' => 'text',
|
||||||
'freebusyurl' => array('type' => 'text', 'size' => 40, 'limit' => 1,
|
'size' => 40,
|
||||||
'label' => 'kolab_addressbook.freebusyurl'),
|
'maxlength' => 80,
|
||||||
'pgppublickey' => array('type' => 'textarea', 'size' => 70, 'rows' => 10, 'limit' => 1,
|
'limit' => null,
|
||||||
'label' => 'kolab_addressbook.pgppublickey'),
|
'label' => 'kolab_addressbook.children',
|
||||||
'pkcs7publickey' => array('type' => 'textarea', 'size' => 70, 'rows' => 10, 'limit' => 1,
|
'category' => 'personal'
|
||||||
'label' => 'kolab_addressbook.pkcs7publickey'),
|
),
|
||||||
|
'freebusyurl' => array(
|
||||||
|
'type' => 'text',
|
||||||
|
'size' => 40,
|
||||||
|
'limit' => 1,
|
||||||
|
'label' => 'kolab_addressbook.freebusyurl'
|
||||||
|
),
|
||||||
|
'pgppublickey' => array(
|
||||||
|
'type' => 'textarea',
|
||||||
|
'size' => 70,
|
||||||
|
'rows' => 10,
|
||||||
|
'limit' => 1,
|
||||||
|
'label' => 'kolab_addressbook.pgppublickey'
|
||||||
|
),
|
||||||
|
'pkcs7publickey' => array(
|
||||||
|
'type' => 'textarea',
|
||||||
|
'size' => 70,
|
||||||
|
'rows' => 10,
|
||||||
|
'limit' => 1,
|
||||||
|
'label' => 'kolab_addressbook.pkcs7publickey'
|
||||||
|
),
|
||||||
'notes' => array('limit' => 1),
|
'notes' => array('limit' => 1),
|
||||||
'photo' => array('limit' => 1),
|
'photo' => array('limit' => 1),
|
||||||
// TODO: define more Kolab-specific fields such as: language, latitude, longitude, crypto settings
|
// TODO: define more Kolab-specific fields such as: language, latitude, longitude, crypto settings
|
||||||
|
@ -132,6 +158,7 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
// extend coltypes configuration
|
// extend coltypes configuration
|
||||||
$format = kolab_format::factory('contact');
|
$format = kolab_format::factory('contact');
|
||||||
|
|
||||||
$this->coltypes['phone']['subtypes'] = array_keys($format->phonetypes);
|
$this->coltypes['phone']['subtypes'] = array_keys($format->phonetypes);
|
||||||
$this->coltypes['address']['subtypes'] = array_keys($format->addresstypes);
|
$this->coltypes['address']['subtypes'] = array_keys($format->addresstypes);
|
||||||
|
|
||||||
|
@ -139,9 +166,10 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
// set localized labels for proprietary cols
|
// set localized labels for proprietary cols
|
||||||
foreach ($this->coltypes as $col => $prop) {
|
foreach ($this->coltypes as $col => $prop) {
|
||||||
if (is_string($prop['label']))
|
if (is_string($prop['label'])) {
|
||||||
$this->coltypes[$col]['label'] = $rcube->gettext($prop['label']);
|
$this->coltypes[$col]['label'] = $rcube->gettext($prop['label']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fetch objects from the given IMAP folder
|
// fetch objects from the given IMAP folder
|
||||||
$this->storagefolder = kolab_storage::get_folder($this->imap_folder);
|
$this->storagefolder = kolab_storage::get_folder($this->imap_folder);
|
||||||
|
@ -157,11 +185,12 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
$rights = $this->storagefolder->get_myrights();
|
$rights = $this->storagefolder->get_myrights();
|
||||||
if ($rights && !PEAR::isError($rights)) {
|
if ($rights && !PEAR::isError($rights)) {
|
||||||
$this->rights = $rights;
|
$this->rights = $rights;
|
||||||
if (strpos($rights, 'i') !== false && strpos($rights, 't') !== false)
|
if (strpos($rights, 'i') !== false && strpos($rights, 't') !== false) {
|
||||||
$this->readonly = false;
|
$this->readonly = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->action = rcube::get_instance()->action;
|
$this->action = rcube::get_instance()->action;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +283,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
$this->gid = $gid;
|
$this->gid = $gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a search string for future listings
|
* Save a search string for future listings
|
||||||
*
|
*
|
||||||
|
@ -265,7 +293,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
$this->filter = $filter;
|
$this->filter = $filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for saved search properties
|
* Getter for saved search properties
|
||||||
*
|
*
|
||||||
|
@ -276,7 +303,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return $this->filter;
|
return $this->filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset saved results and search parameters
|
* Reset saved results and search parameters
|
||||||
*/
|
*/
|
||||||
|
@ -286,7 +312,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
$this->filter = null;
|
$this->filter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all active contact groups of this source
|
* List all active contact groups of this source
|
||||||
*
|
*
|
||||||
|
@ -312,13 +337,12 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return array_values($groups);
|
return array_values($groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List the current set of contact records
|
* List the current set of contact records
|
||||||
*
|
*
|
||||||
* @param array List of cols to show
|
* @param array List of cols to show
|
||||||
* @param int Only return this number of records, use negative values for tail
|
* @param int Only return this number of records, use negative values for tail
|
||||||
* @param boolean True to skip the count query (select only)
|
* @param bool True to skip the count query (select only)
|
||||||
*
|
*
|
||||||
* @return array Indexed list of contact records, each a hash array
|
* @return array Indexed list of contact records, each a hash array
|
||||||
*/
|
*/
|
||||||
|
@ -409,7 +433,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return $this->result;
|
return $this->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search records
|
* Search records
|
||||||
*
|
*
|
||||||
|
@ -420,11 +443,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
* 1 - strict (=),
|
* 1 - strict (=),
|
||||||
* 2 - prefix (abc*)
|
* 2 - prefix (abc*)
|
||||||
* 4 - include groups (if supported)
|
* 4 - include groups (if supported)
|
||||||
* @param boolean $select True if results are requested, False if count only
|
* @param bool $select True if results are requested, False if count only
|
||||||
* @param boolean $nocount True to skip the count query (select only)
|
* @param bool $nocount True to skip the count query (select only)
|
||||||
* @param array $required List of fields that cannot be empty
|
* @param array $required List of fields that cannot be empty
|
||||||
*
|
*
|
||||||
* @return object rcube_result_set List of contact records and 'count' value
|
* @return rcube_result_set List of contact records and 'count' value
|
||||||
*/
|
*/
|
||||||
public function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array())
|
public function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array())
|
||||||
{
|
{
|
||||||
|
@ -445,18 +468,21 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
$fields = $this->search_fields;
|
$fields = $this->search_fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_array($fields))
|
if (!is_array($fields)) {
|
||||||
$fields = array($fields);
|
$fields = array($fields);
|
||||||
if (!is_array($required) && !empty($required))
|
}
|
||||||
|
if (!is_array($required) && !empty($required)) {
|
||||||
$required = array($required);
|
$required = array($required);
|
||||||
|
}
|
||||||
|
|
||||||
// advanced search
|
// advanced search
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
$advanced = true;
|
$advanced = true;
|
||||||
$value = array_map('mb_strtolower', $value);
|
$value = array_map('mb_strtolower', $value);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
$value = mb_strtolower($value);
|
$value = mb_strtolower($value);
|
||||||
|
}
|
||||||
|
|
||||||
$scount = count($fields);
|
$scount = count($fields);
|
||||||
// build key name regexp
|
// build key name regexp
|
||||||
|
@ -526,19 +552,18 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return $this->list_records();
|
return $this->list_records();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh saved search results after data has changed
|
* Refresh saved search results after data has changed
|
||||||
*/
|
*/
|
||||||
public function refresh_search()
|
public function refresh_search()
|
||||||
{
|
{
|
||||||
if ($this->filter)
|
if ($this->filter) {
|
||||||
$this->search($this->filter['fields'], $this->filter['value'], $this->filter['mode']);
|
$this->search($this->filter['fields'], $this->filter['value'], $this->filter['mode']);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->get_search_set();
|
return $this->get_search_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Count number of available contacts in database
|
* Count number of available contacts in database
|
||||||
*
|
*
|
||||||
|
@ -560,7 +585,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
|
return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the last result set
|
* Return the last result set
|
||||||
*
|
*
|
||||||
|
@ -571,15 +595,15 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return $this->result;
|
return $this->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a specific contact record
|
* Get a specific contact record
|
||||||
*
|
*
|
||||||
* @param mixed record identifier(s)
|
* @param mixed Record identifier(s)
|
||||||
* @param boolean True to return record as associative array, otherwise a result set is returned
|
* @param bool True to return record as associative array, otherwise a result set is returned
|
||||||
|
*
|
||||||
* @return mixed Result object with all record fields or False if not found
|
* @return mixed Result object with all record fields or False if not found
|
||||||
*/
|
*/
|
||||||
public function get_record($id, $assoc=false)
|
public function get_record($id, $assoc = false)
|
||||||
{
|
{
|
||||||
$rec = null;
|
$rec = null;
|
||||||
$uid = $this->id2uid($id);
|
$uid = $this->id2uid($id);
|
||||||
|
@ -612,11 +636,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get group assignments of a specific contact record
|
* Get group assignments of a specific contact record
|
||||||
*
|
*
|
||||||
* @param mixed Record identifier
|
* @param mixed Record identifier
|
||||||
|
*
|
||||||
* @return array List of assigned groups as ID=>Name pairs
|
* @return array List of assigned groups as ID=>Name pairs
|
||||||
*/
|
*/
|
||||||
public function get_record_groups($id)
|
public function get_record_groups($id)
|
||||||
|
@ -624,28 +648,33 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
$out = array();
|
$out = array();
|
||||||
$this->_fetch_groups();
|
$this->_fetch_groups();
|
||||||
|
|
||||||
foreach ((array)$this->groupmembers[$id] as $gid) {
|
if (!empty($this->groupmembers[$id])) {
|
||||||
if ($group = $this->distlists[$gid])
|
foreach ((array) $this->groupmembers[$id] as $gid) {
|
||||||
|
if (!empty($this->distlists[$gid])) {
|
||||||
|
$group = $this->distlists[$gid];
|
||||||
$out[$gid] = $group['name'];
|
$out[$gid] = $group['name'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new contact record
|
* Create a new contact record
|
||||||
*
|
*
|
||||||
* @param array Assoziative array with save data
|
* @param array Associative array with save data
|
||||||
* Keys: Field name with optional section in the form FIELD:SECTION
|
* Keys: Field name with optional section in the form FIELD:SECTION
|
||||||
* Values: Field value. Can be either a string or an array of strings for multiple values
|
* Values: Field value. Can be either a string or an array of strings for multiple values
|
||||||
* @param boolean True to check for duplicates first
|
* @param bool True to check for duplicates first
|
||||||
|
*
|
||||||
* @return mixed The created record ID on success, False on error
|
* @return mixed The created record ID on success, False on error
|
||||||
*/
|
*/
|
||||||
public function insert($save_data, $check=false)
|
public function insert($save_data, $check=false)
|
||||||
{
|
{
|
||||||
if (!is_array($save_data))
|
if (!is_array($save_data)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$insert_id = $existing = false;
|
$insert_id = $existing = false;
|
||||||
|
|
||||||
|
@ -682,15 +711,15 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return $insert_id;
|
return $insert_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a specific contact record
|
* Update a specific contact record
|
||||||
*
|
*
|
||||||
* @param mixed Record identifier
|
* @param mixed Record identifier
|
||||||
* @param array Assoziative array with save data
|
* @param array Associative array with save data
|
||||||
* Keys: Field name with optional section in the form FIELD:SECTION
|
* Keys: Field name with optional section in the form FIELD:SECTION
|
||||||
* Values: Field value. Can be either a string or an array of strings for multiple values
|
* Values: Field value. Can be either a string or an array of strings for multiple values
|
||||||
* @return boolean True on success, False on error
|
*
|
||||||
|
* @return bool True on success, False on error
|
||||||
*/
|
*/
|
||||||
public function update($id, $save_data)
|
public function update($id, $save_data)
|
||||||
{
|
{
|
||||||
|
@ -700,10 +729,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
if (!$this->storagefolder->save($object, 'contact', $old['uid'])) {
|
if (!$this->storagefolder->save($object, 'contact', $old['uid'])) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error saving contact object to Kolab server"
|
||||||
'message' => "Error saving contact object to Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$updated = true;
|
$updated = true;
|
||||||
|
@ -715,12 +745,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return $updated;
|
return $updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark one or more contact records as deleted
|
* Mark one or more contact records as deleted
|
||||||
*
|
*
|
||||||
* @param array Record identifiers
|
* @param array Record identifiers
|
||||||
* @param boolean Remove record(s) irreversible (mark as deleted otherwise)
|
* @param bool Remove record(s) irreversible (mark as deleted otherwise)
|
||||||
*
|
*
|
||||||
* @return int Number of records deleted
|
* @return int Number of records deleted
|
||||||
*/
|
*/
|
||||||
|
@ -728,8 +757,9 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
{
|
{
|
||||||
$this->_fetch_groups();
|
$this->_fetch_groups();
|
||||||
|
|
||||||
if (!is_array($ids))
|
if (!is_array($ids)) {
|
||||||
$ids = explode(',', $ids);
|
$ids = explode(',', $ids);
|
||||||
|
}
|
||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
|
@ -739,17 +769,19 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
if (!$deleted) {
|
if (!$deleted) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error deleting a contact object $uid from the Kolab server"
|
||||||
'message' => "Error deleting a contact object $uid from the Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// remove from distribution lists
|
// remove from distribution lists
|
||||||
foreach ((array)$this->groupmembers[$id] as $gid) {
|
foreach ((array) $this->groupmembers[$id] as $gid) {
|
||||||
if (!$is_mailto || $gid == $this->gid)
|
if (!$is_mailto || $gid == $this->gid) {
|
||||||
$this->remove_from_group($gid, $id);
|
$this->remove_from_group($gid, $id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// clear internal cache
|
// clear internal cache
|
||||||
unset($this->groupmembers[$id]);
|
unset($this->groupmembers[$id]);
|
||||||
|
@ -761,7 +793,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
return $count;
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undelete one or more contact records.
|
* Undelete one or more contact records.
|
||||||
* Only possible just after delete (see 2nd argument of delete() method).
|
* Only possible just after delete (see 2nd argument of delete() method).
|
||||||
|
@ -772,8 +803,9 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
*/
|
*/
|
||||||
public function undelete($ids)
|
public function undelete($ids)
|
||||||
{
|
{
|
||||||
if (!is_array($ids))
|
if (!is_array($ids)) {
|
||||||
$ids = explode(',', $ids);
|
$ids = explode(',', $ids);
|
||||||
|
}
|
||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
|
@ -783,17 +815,17 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error undeleting a contact object $uid from the Kolab server"
|
||||||
'message' => "Error undeleting a contact object $uid from the Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $count;
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all records from the database
|
* Remove all records from the database
|
||||||
*
|
*
|
||||||
|
@ -809,7 +841,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close connection to source
|
* Close connection to source
|
||||||
* Called on script shutdown
|
* Called on script shutdown
|
||||||
|
@ -818,11 +849,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a contact group with the given name
|
* Create a contact group with the given name
|
||||||
*
|
*
|
||||||
* @param string The group name
|
* @param string The group name
|
||||||
|
*
|
||||||
* @return mixed False on error, array with record props in success
|
* @return mixed False on error, array with record props in success
|
||||||
*/
|
*/
|
||||||
function create_group($name)
|
function create_group($name)
|
||||||
|
@ -838,10 +869,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
if (!$saved) {
|
if (!$saved) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error saving distribution-list object to Kolab server"
|
||||||
'message' => "Error saving distribution-list object to Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -857,7 +889,8 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
* Delete the given group and all linked group members
|
* Delete the given group and all linked group members
|
||||||
*
|
*
|
||||||
* @param string Group identifier
|
* @param string Group identifier
|
||||||
* @return boolean True on success, false if no data was changed
|
*
|
||||||
|
* @return bool True on success, false if no data was changed
|
||||||
*/
|
*/
|
||||||
function delete_group($gid)
|
function delete_group($gid)
|
||||||
{
|
{
|
||||||
|
@ -870,10 +903,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
if (!$deleted) {
|
if (!$deleted) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error deleting distribution-list object from the Kolab server"
|
||||||
'message' => "Error deleting distribution-list object from the Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$result = true;
|
$result = true;
|
||||||
|
@ -889,7 +923,7 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
* @param string New name to set for this group
|
* @param string New name to set for this group
|
||||||
* @param string New group identifier (if changed, otherwise don't set)
|
* @param string New group identifier (if changed, otherwise don't set)
|
||||||
*
|
*
|
||||||
* @return boolean New name on success, false if no data was changed
|
* @return bool New name on success, false if no data was changed
|
||||||
*/
|
*/
|
||||||
function rename_group($gid, $newname, &$newid)
|
function rename_group($gid, $newname, &$newid)
|
||||||
{
|
{
|
||||||
|
@ -903,10 +937,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
if (!$saved) {
|
if (!$saved) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error saving distribution-list object to Kolab server"
|
||||||
'message' => "Error saving distribution-list object to Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,17 +1000,21 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($added)
|
if ($added) {
|
||||||
$saved = $this->storagefolder->save($list, 'distribution-list', $list['uid']);
|
$saved = $this->storagefolder->save($list, 'distribution-list', $list['uid']);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
$saved = true;
|
$saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$saved) {
|
if (!$saved) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error saving distribution-list to Kolab server"
|
||||||
'message' => "Error saving distribution-list to Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
|
|
||||||
$added = false;
|
$added = false;
|
||||||
$this->set_error(self::ERROR_SAVING, 'errorsaving');
|
$this->set_error(self::ERROR_SAVING, 'errorsaving');
|
||||||
}
|
}
|
||||||
|
@ -995,18 +1034,21 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
*/
|
*/
|
||||||
function remove_from_group($gid, $ids)
|
function remove_from_group($gid, $ids)
|
||||||
{
|
{
|
||||||
if (!is_array($ids))
|
if (!is_array($ids)) {
|
||||||
$ids = explode(',', $ids);
|
$ids = explode(',', $ids);
|
||||||
|
}
|
||||||
|
|
||||||
$this->_fetch_groups();
|
$this->_fetch_groups();
|
||||||
if (!($list = $this->distlists[$gid]))
|
if (!($list = $this->distlists[$gid])) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$new_member = array();
|
$new_member = array();
|
||||||
foreach ((array)$list['member'] as $member) {
|
foreach ((array)$list['member'] as $member) {
|
||||||
if (!in_array($member['ID'], $ids))
|
if (!in_array($member['ID'], $ids)) {
|
||||||
$new_member[] = $member;
|
$new_member[] = $member;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// write distribution list back to server
|
// write distribution list back to server
|
||||||
$list['member'] = $new_member;
|
$list['member'] = $new_member;
|
||||||
|
@ -1014,10 +1056,11 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
if (!$saved) {
|
if (!$saved) {
|
||||||
rcube::raise_error(array(
|
rcube::raise_error(array(
|
||||||
'code' => 600, 'type' => 'php',
|
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||||
'file' => __FILE__, 'line' => __LINE__,
|
'message' => "Error saving distribution-list object to Kolab server"
|
||||||
'message' => "Error saving distribution-list object to Kolab server"),
|
),
|
||||||
true, false);
|
true, false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// remove group assigments in local cache
|
// remove group assigments in local cache
|
||||||
|
@ -1039,7 +1082,7 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
* @param array Associative array with contact data to save
|
* @param array Associative array with contact data to save
|
||||||
* @param bool Attempt to fix/complete data automatically
|
* @param bool Attempt to fix/complete data automatically
|
||||||
*
|
*
|
||||||
* @return boolean True if input is valid, False if not.
|
* @return bool True if input is valid, False if not.
|
||||||
*/
|
*/
|
||||||
public function validate(&$save_data, $autofix = false)
|
public function validate(&$save_data, $autofix = false)
|
||||||
{
|
{
|
||||||
|
@ -1245,15 +1288,23 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
}
|
}
|
||||||
|
|
||||||
// photo is stored as separate attachment
|
// photo is stored as separate attachment
|
||||||
if ($record['photo'] && strlen($record['photo']) < 255 && ($att = $record['_attachments'][$record['photo']])) {
|
if ($record['photo'] && strlen($record['photo']) < 255 && !empty($record['_attachments'][$record['photo']])) {
|
||||||
|
$att = $record['_attachments'][$record['photo']];
|
||||||
// only fetch photo content if requested
|
// only fetch photo content if requested
|
||||||
if ($this->action == 'photo')
|
if ($this->action == 'photo') {
|
||||||
$record['photo'] = $att['content'] ? $att['content'] : $this->storagefolder->get_attachment($record['uid'], $att['id']);
|
if (!empty($att['content'])) {
|
||||||
|
$record['photo'] = $att['content'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$record['photo'] = $this->storagefolder->get_attachment($record['uid'], $att['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// truncate publickey value for display
|
// truncate publickey value for display
|
||||||
if ($record['pgppublickey'] && $this->action == 'show')
|
if (!empty($record['pgppublickey']) && $this->action == 'show') {
|
||||||
$record['pgppublickey'] = substr($record['pgppublickey'], 0, 140) . '...';
|
$record['pgppublickey'] = substr($record['pgppublickey'], 0, 140) . '...';
|
||||||
|
}
|
||||||
|
|
||||||
// remove empty fields
|
// remove empty fields
|
||||||
$record = array_filter($record);
|
$record = array_filter($record);
|
||||||
|
@ -1269,10 +1320,12 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
*/
|
*/
|
||||||
private function _from_rcube_contact($contact, $old = array())
|
private function _from_rcube_contact($contact, $old = array())
|
||||||
{
|
{
|
||||||
if (!$contact['uid'] && $contact['ID'])
|
if (!$contact['uid'] && $contact['ID']) {
|
||||||
$contact['uid'] = $this->id2uid($contact['ID']);
|
$contact['uid'] = $this->id2uid($contact['ID']);
|
||||||
else if (!$contact['uid'] && $old['uid'])
|
}
|
||||||
|
else if (!$contact['uid'] && $old['uid']) {
|
||||||
$contact['uid'] = $old['uid'];
|
$contact['uid'] = $old['uid'];
|
||||||
|
}
|
||||||
|
|
||||||
$contact['im'] = array_filter($this->get_col_values('im', $contact, true));
|
$contact['im'] = array_filter($this->get_col_values('im', $contact, true));
|
||||||
|
|
||||||
|
@ -1295,8 +1348,9 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
foreach ((array)$values as $adr) {
|
foreach ((array)$values as $adr) {
|
||||||
// skip empty address
|
// skip empty address
|
||||||
$adr = array_filter($adr);
|
$adr = array_filter($adr);
|
||||||
if (empty($adr))
|
if (empty($adr)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$addresses[] = array(
|
$addresses[] = array(
|
||||||
'type' => $type,
|
'type' => $type,
|
||||||
|
@ -1318,9 +1372,10 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
|
|
||||||
// copy meta data (starting with _) from old object
|
// copy meta data (starting with _) from old object
|
||||||
foreach ((array)$old as $key => $val) {
|
foreach ((array)$old as $key => $val) {
|
||||||
if (!isset($contact[$key]) && $key[0] == '_')
|
if (!isset($contact[$key]) && $key[0] == '_') {
|
||||||
$contact[$key] = $val;
|
$contact[$key] = $val;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// convert one-item-array elements into string element
|
// convert one-item-array elements into string element
|
||||||
// this is needed e.g. to properly import birthday field
|
// this is needed e.g. to properly import birthday field
|
||||||
|
@ -1334,7 +1389,12 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
unset($contact['vcard']);
|
unset($contact['vcard']);
|
||||||
|
|
||||||
// add empty values for some fields which can be removed in the UI
|
// add empty values for some fields which can be removed in the UI
|
||||||
return array_filter($contact) + array('nickname' => '', 'birthday' => '', 'anniversary' => '', 'freebusyurl' => '', 'photo' => $contact['photo']);
|
return array_filter($contact) + array(
|
||||||
|
'nickname' => '',
|
||||||
|
'birthday' => '',
|
||||||
|
'anniversary' => '',
|
||||||
|
'freebusyurl' => '',
|
||||||
|
'photo' => $contact['photo']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,14 +118,15 @@ class libcalendaring_itip
|
||||||
// compose a list of all event attendees
|
// compose a list of all event attendees
|
||||||
$attendees_list = array();
|
$attendees_list = array();
|
||||||
foreach ((array)$event['attendees'] as $attendee) {
|
foreach ((array)$event['attendees'] as $attendee) {
|
||||||
$attendees_list[] = ($attendee['name'] && $attendee['email']) ?
|
$attendees_list[] = (!empty($attendee['name']) && !empty($attendee['email'])) ?
|
||||||
$attendee['name'] . ' <' . $attendee['email'] . '>' :
|
$attendee['name'] . ' <' . $attendee['email'] . '>' :
|
||||||
($attendee['name'] ? $attendee['name'] : $attendee['email']);
|
(!empty($attendee['name']) ? $attendee['name'] : $attendee['email']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$recurrence_info = '';
|
$recurrence_info = '';
|
||||||
if (!empty($event['recurrence_id'])) {
|
if (!empty($event['recurrence_id'])) {
|
||||||
$recurrence_info = "\n\n** " . $this->gettext($event['thisandfuture'] ? 'itipmessagefutureoccurrence' : 'itipmessagesingleoccurrence') . ' **';
|
$msg = $this->gettext(!empty($event['thisandfuture']) ? 'itipmessagefutureoccurrence' : 'itipmessagesingleoccurrence');
|
||||||
|
$recurrence_info = "\n\n** $msg **";
|
||||||
}
|
}
|
||||||
else if (!empty($event['recurrence'])) {
|
else if (!empty($event['recurrence'])) {
|
||||||
$recurrence_info = sprintf("\n%s: %s", $this->gettext('recurring'), $this->lib->recurrence_text($event['recurrence']));
|
$recurrence_info = sprintf("\n%s: %s", $this->gettext('recurring'), $this->lib->recurrence_text($event['recurrence']));
|
||||||
|
@ -139,7 +140,7 @@ class libcalendaring_itip
|
||||||
'attendees' => join(",\n ", $attendees_list),
|
'attendees' => join(",\n ", $attendees_list),
|
||||||
'sender' => $this->sender['name'],
|
'sender' => $this->sender['name'],
|
||||||
'organizer' => $this->sender['name'],
|
'organizer' => $this->sender['name'],
|
||||||
'description' => $event['description'],
|
'description' => isset($event['description']) ? $event['description'] : '',
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -243,8 +244,14 @@ class libcalendaring_itip
|
||||||
// set RSVP for every attendee
|
// set RSVP for every attendee
|
||||||
else if ($method == 'REQUEST') {
|
else if ($method == 'REQUEST') {
|
||||||
foreach ($event['attendees'] as $i => $attendee) {
|
foreach ($event['attendees'] as $i => $attendee) {
|
||||||
if (($rsvp || !isset($attendee['rsvp'])) && ($attendee['status'] != 'DELEGATED' && $attendee['role'] != 'NON-PARTICIPANT')) {
|
if (
|
||||||
$event['attendees'][$i]['rsvp']= (bool)$rsvp;
|
($rsvp || !isset($attendee['rsvp']))
|
||||||
|
&& (
|
||||||
|
(empty($attendee['status']) || $attendee['status'] != 'DELEGATED')
|
||||||
|
&& $attendee['role'] != 'NON-PARTICIPANT'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$event['attendees'][$i]['rsvp']= (bool) $rsvp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +300,7 @@ class libcalendaring_itip
|
||||||
// attach ics file for this event
|
// attach ics file for this event
|
||||||
$ical = libcalendaring::get_ical();
|
$ical = libcalendaring::get_ical();
|
||||||
$ics = $ical->export(array($event), $method, false, $method == 'REQUEST' && $this->plugin->driver ? array($this->plugin->driver, 'get_attachment_body') : false);
|
$ics = $ical->export(array($event), $method, false, $method == 'REQUEST' && $this->plugin->driver ? array($this->plugin->driver, 'get_attachment_body') : false);
|
||||||
$filename = $event['_type'] == 'task' ? 'todo.ics' : 'event.ics';
|
$filename = !empty($event['_type']) && $event['_type'] == 'task' ? 'todo.ics' : 'event.ics';
|
||||||
$message->addAttachment($ics, 'text/calendar', $filename, false, '8bit', '', RCUBE_CHARSET . "; method=" . $method);
|
$message->addAttachment($ics, 'text/calendar', $filename, false, '8bit', '', RCUBE_CHARSET . "; method=" . $method);
|
||||||
|
|
||||||
return $message;
|
return $message;
|
||||||
|
@ -521,7 +528,7 @@ class libcalendaring_itip
|
||||||
|
|
||||||
protected function get_itip_diff($event, $existing)
|
protected function get_itip_diff($event, $existing)
|
||||||
{
|
{
|
||||||
if (empty($event) || empty($existing) || empty($event['message_uid'])) {
|
if (empty($event) || empty($existing) || empty($event['message_uid']) || empty($event['mime_id'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,14 +563,14 @@ class libcalendaring_itip
|
||||||
$attendee['status'] = 'ACCEPTED'; // sometimes is not set for exceptions
|
$attendee['status'] = 'ACCEPTED'; // sometimes is not set for exceptions
|
||||||
$existing['attendees'][$idx] = $attendee;
|
$existing['attendees'][$idx] = $attendee;
|
||||||
}
|
}
|
||||||
$existing_attendees[] = $attendee['email'].$attendee['name'];
|
$existing_attendees[] = $attendee['email'] . (isset($attendee['name']) ? $attendee['name'] : '');
|
||||||
}
|
}
|
||||||
foreach ((array) $itip['attendees'] as $idx => $attendee) {
|
foreach ((array) $itip['attendees'] as $idx => $attendee) {
|
||||||
if ($attendee['email'] && ($_status = $status[strtolower($attendee['email'])])) {
|
if (!empty($attendee['email']) && !empty($status[strtolower($attendee['email'])])) {
|
||||||
$attendee['status'] = $_status;
|
$attendee['status'] = $status[strtolower($attendee['email'])];
|
||||||
$itip['attendees'][$idx] = $attendee;
|
$itip['attendees'][$idx] = $attendee;
|
||||||
}
|
}
|
||||||
$itip_attendees[] = $attendee['email'].$attendee['name'];
|
$itip_attendees[] = $attendee['email'] . (isset($attendee['name']) ? $attendee['name'] : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($itip_attendees != $existing_attendees) {
|
if ($itip_attendees != $existing_attendees) {
|
||||||
|
@ -598,13 +605,15 @@ class libcalendaring_itip
|
||||||
{
|
{
|
||||||
$buttons = array();
|
$buttons = array();
|
||||||
$dom_id = asciiwords($event['uid'], true);
|
$dom_id = asciiwords($event['uid'], true);
|
||||||
|
|
||||||
$rsvp_status = 'unknown';
|
$rsvp_status = 'unknown';
|
||||||
|
$rsvp_buttons = '';
|
||||||
|
|
||||||
// pass some metadata about the event and trigger the asynchronous status check
|
// pass some metadata about the event and trigger the asynchronous status check
|
||||||
$changed = is_object($event['changed']) ? $event['changed'] : $message_date;
|
$changed = is_object($event['changed']) ? $event['changed'] : $message_date;
|
||||||
$metadata = array(
|
$metadata = array(
|
||||||
'uid' => $event['uid'],
|
'uid' => $event['uid'],
|
||||||
'_instance' => $event['_instance'],
|
'_instance' => isset($event['_instance']) ? $event['_instance'] : null,
|
||||||
'changed' => $changed ? $changed->format('U') : 0,
|
'changed' => $changed ? $changed->format('U') : 0,
|
||||||
'sequence' => intval($event['sequence']),
|
'sequence' => intval($event['sequence']),
|
||||||
'method' => $method,
|
'method' => $method,
|
||||||
|
@ -744,7 +753,7 @@ class libcalendaring_itip
|
||||||
}
|
}
|
||||||
|
|
||||||
// add itip reply message controls
|
// add itip reply message controls
|
||||||
$rsvp_buttons .= html::div('itip-reply-controls', $this->itip_rsvp_options_ui($dom_id, $metadata['nosave']));
|
$rsvp_buttons .= html::div('itip-reply-controls', $this->itip_rsvp_options_ui($dom_id, !empty($metadata['nosave'])));
|
||||||
|
|
||||||
$buttons[] = html::div(array('id' => 'rsvp-'.$dom_id, 'class' => 'rsvp-buttons', 'style' => 'display:none'), $rsvp_buttons);
|
$buttons[] = html::div(array('id' => 'rsvp-'.$dom_id, 'class' => 'rsvp-buttons', 'style' => 'display:none'), $rsvp_buttons);
|
||||||
$buttons[] = html::div(array('id' => 'update-'.$dom_id, 'style' => 'display:none'), $update_button);
|
$buttons[] = html::div(array('id' => 'update-'.$dom_id, 'style' => 'display:none'), $update_button);
|
||||||
|
@ -759,8 +768,8 @@ class libcalendaring_itip
|
||||||
$title = $this->gettext('itipcancellation');
|
$title = $this->gettext('itipcancellation');
|
||||||
$event_prop = array_filter(array(
|
$event_prop = array_filter(array(
|
||||||
'uid' => $event['uid'],
|
'uid' => $event['uid'],
|
||||||
'_instance' => $event['_instance'],
|
'_instance' => isset($event['_instance']) ? $event['_instance'] : null,
|
||||||
'_savemode' => $event['_savemode'],
|
'_savemode' => isset($event['_savemode']) ? $event['_savemode'] : null,
|
||||||
));
|
));
|
||||||
|
|
||||||
// 1. remove the event from our calendar
|
// 1. remove the event from our calendar
|
||||||
|
@ -786,7 +795,7 @@ class libcalendaring_itip
|
||||||
}
|
}
|
||||||
|
|
||||||
// append generic import button
|
// append generic import button
|
||||||
if ($import_button) {
|
if (!empty($import_button)) {
|
||||||
$buttons[] = html::div(array('id' => 'import-'.$dom_id, 'style' => 'display:none'), $import_button);
|
$buttons[] = html::div(array('id' => 'import-'.$dom_id, 'style' => 'display:none'), $import_button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,13 +824,16 @@ class libcalendaring_itip
|
||||||
{
|
{
|
||||||
$attrib += array('type' => 'button');
|
$attrib += array('type' => 'button');
|
||||||
|
|
||||||
if (!$actions)
|
if (!$actions) {
|
||||||
$actions = $this->rsvp_actions;
|
$actions = $this->rsvp_actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
$buttons = '';
|
||||||
|
|
||||||
foreach ($actions as $method) {
|
foreach ($actions as $method) {
|
||||||
$buttons .= html::tag('input', array(
|
$buttons .= html::tag('input', array(
|
||||||
'type' => $attrib['type'],
|
'type' => $attrib['type'],
|
||||||
'name' => $attrib['iname'],
|
'name' => !empty($attrib['iname']) ? $attrib['iname'] : null,
|
||||||
'class' => 'button',
|
'class' => 'button',
|
||||||
'rel' => $method,
|
'rel' => $method,
|
||||||
'value' => $this->gettext('itip' . $method),
|
'value' => $this->gettext('itip' . $method),
|
||||||
|
@ -923,7 +935,7 @@ class libcalendaring_itip
|
||||||
$table->add('label', $this->gettext('recurring'));
|
$table->add('label', $this->gettext('recurring'));
|
||||||
$table->add('recurrence', $this->lib->recurrence_text($event['recurrence']));
|
$table->add('recurrence', $this->lib->recurrence_text($event['recurrence']));
|
||||||
}
|
}
|
||||||
if ($location = trim($event['location'])) {
|
if (isset($event['location']) && ($location = trim($event['location']))) {
|
||||||
$table->add('label', $this->gettext('location'));
|
$table->add('label', $this->gettext('location'));
|
||||||
$table->add('location', rcube::Q($location));
|
$table->add('location', rcube::Q($location));
|
||||||
}
|
}
|
||||||
|
@ -931,11 +943,11 @@ class libcalendaring_itip
|
||||||
$table->add('label', $this->gettext('sensitivity'));
|
$table->add('label', $this->gettext('sensitivity'));
|
||||||
$table->add('sensitivity', ucfirst($this->gettext($sensitivity)) . '!');
|
$table->add('sensitivity', ucfirst($this->gettext($sensitivity)) . '!');
|
||||||
}
|
}
|
||||||
if ($event['status'] == 'COMPLETED' || $event['status'] == 'CANCELLED') {
|
if (!empty($event['status']) && ($event['status'] == 'COMPLETED' || $event['status'] == 'CANCELLED')) {
|
||||||
$table->add('label', $this->gettext('status'));
|
$table->add('label', $this->gettext('status'));
|
||||||
$table->add('status', $this->gettext('status-' . strtolower($event['status'])));
|
$table->add('status', $this->gettext('status-' . strtolower($event['status'])));
|
||||||
}
|
}
|
||||||
if ($comment = trim($event['comment'])) {
|
if (isset($event['comment']) && ($comment = trim($event['comment']))) {
|
||||||
$table->add('label', $this->gettext('comment'));
|
$table->add('label', $this->gettext('comment'));
|
||||||
$table->add('location', rcube::Q($comment));
|
$table->add('location', rcube::Q($comment));
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,15 +61,15 @@ class libcalendaring_recurrence
|
||||||
|
|
||||||
$this->set_start($start);
|
$this->set_start($start);
|
||||||
|
|
||||||
if (is_array($recurrence['EXDATE'])) {
|
if (!empty($recurrence['EXDATE'])) {
|
||||||
foreach ($recurrence['EXDATE'] as $exdate) {
|
foreach ((array) $recurrence['EXDATE'] as $exdate) {
|
||||||
if (is_a($exdate, 'DateTime')) {
|
if (is_a($exdate, 'DateTime')) {
|
||||||
$this->engine->addException($exdate->format('Y'), $exdate->format('n'), $exdate->format('j'));
|
$this->engine->addException($exdate->format('Y'), $exdate->format('n'), $exdate->format('j'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_array($recurrence['RDATE'])) {
|
if (!empty($recurrence['RDATE'])) {
|
||||||
foreach ($recurrence['RDATE'] as $rdate) {
|
foreach ((array) $recurrence['RDATE'] as $rdate) {
|
||||||
if (is_a($rdate, 'DateTime')) {
|
if (is_a($rdate, 'DateTime')) {
|
||||||
$this->engine->addRDate($rdate->format('Y'), $rdate->format('n'), $rdate->format('j'));
|
$this->engine->addRDate($rdate->format('Y'), $rdate->format('n'), $rdate->format('j'));
|
||||||
}
|
}
|
||||||
|
@ -160,9 +160,10 @@ class libcalendaring_recurrence
|
||||||
$start = clone $this->start;
|
$start = clone $this->start;
|
||||||
$orig_start = clone $this->start;
|
$orig_start = clone $this->start;
|
||||||
$r = $this->recurrence;
|
$r = $this->recurrence;
|
||||||
$interval = intval($r['INTERVAL'] ?: 1);
|
$interval = !empty($r['INTERVAL']) ? intval($r['INTERVAL']) : 1;
|
||||||
|
$frequency = isset($this->recurrence['FREQ']) ? $this->recurrence['FREQ'] : null;
|
||||||
|
|
||||||
switch ($this->recurrence['FREQ']) {
|
switch ($frequency) {
|
||||||
case 'WEEKLY':
|
case 'WEEKLY':
|
||||||
if (empty($this->recurrence['BYDAY'])) {
|
if (empty($this->recurrence['BYDAY'])) {
|
||||||
return $start;
|
return $start;
|
||||||
|
@ -193,7 +194,7 @@ class libcalendaring_recurrence
|
||||||
|
|
||||||
$r = $this->recurrence;
|
$r = $this->recurrence;
|
||||||
$r['INTERVAL'] = $interval;
|
$r['INTERVAL'] = $interval;
|
||||||
if ($r['COUNT']) {
|
if (!empty($r['COUNT'])) {
|
||||||
// Increase count so we do not stop the loop to early
|
// Increase count so we do not stop the loop to early
|
||||||
$r['COUNT'] += 100;
|
$r['COUNT'] += 100;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,19 +187,20 @@ class libcalendaring extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public function adjust_timezone($dt, $dateonly = false)
|
public function adjust_timezone($dt, $dateonly = false)
|
||||||
{
|
{
|
||||||
if (is_numeric($dt))
|
if (is_numeric($dt)) {
|
||||||
$dt = new DateTime('@'.$dt);
|
$dt = new DateTime('@'.$dt);
|
||||||
else if (is_string($dt))
|
}
|
||||||
|
else if (is_string($dt)) {
|
||||||
$dt = rcube_utils::anytodatetime($dt);
|
$dt = rcube_utils::anytodatetime($dt);
|
||||||
|
}
|
||||||
|
|
||||||
if ($dt instanceof DateTime && !($dt->_dateonly || $dateonly)) {
|
if ($dt instanceof DateTime && empty($dt->_dateonly) && !$dateonly) {
|
||||||
$dt->setTimezone($this->timezone);
|
$dt->setTimezone($this->timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $dt;
|
return $dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -290,10 +291,11 @@ class libcalendaring extends rcube_plugin
|
||||||
public function event_date_text($event, $tzinfo = false)
|
public function event_date_text($event, $tzinfo = false)
|
||||||
{
|
{
|
||||||
$fromto = '--';
|
$fromto = '--';
|
||||||
|
$is_task = !empty($event['_type']) && $event['_type'] == 'task';
|
||||||
|
|
||||||
// handle task objects
|
// handle task objects
|
||||||
if ($event['_type'] == 'task' && is_object($event['due'])) {
|
if ($is_task && !empty($event['due']) && is_object($event['due'])) {
|
||||||
$date_format = $event['due']->_dateonly ? self::to_php_date_format($this->rc->config->get('calendar_date_format', $this->defaults['calendar_date_format'])) : null;
|
$date_format = !empty($event['due']->_dateonly) ? self::to_php_date_format($this->rc->config->get('calendar_date_format', $this->defaults['calendar_date_format'])) : null;
|
||||||
$fromto = $this->rc->format_date($event['due'], $date_format, false);
|
$fromto = $this->rc->format_date($event['due'], $date_format, false);
|
||||||
|
|
||||||
// add timezone information
|
// add timezone information
|
||||||
|
@ -351,18 +353,21 @@ class libcalendaring extends rcube_plugin
|
||||||
$select_type = new html_select(array('name' => 'alarmtype[]', 'class' => 'edit-alarm-type form-control', 'id' => $attrib['id']));
|
$select_type = new html_select(array('name' => 'alarmtype[]', 'class' => 'edit-alarm-type form-control', 'id' => $attrib['id']));
|
||||||
$select_offset = new html_select(array('name' => 'alarmoffset[]', 'class' => 'edit-alarm-offset form-control'));
|
$select_offset = new html_select(array('name' => 'alarmoffset[]', 'class' => 'edit-alarm-offset form-control'));
|
||||||
$select_related = new html_select(array('name' => 'alarmrelated[]', 'class' => 'edit-alarm-related form-control'));
|
$select_related = new html_select(array('name' => 'alarmrelated[]', 'class' => 'edit-alarm-related form-control'));
|
||||||
$object_type = $attrib['_type'] ?: 'event';
|
$object_type = !empty($attrib['_type']) ? $attrib['_type'] : 'event';
|
||||||
|
|
||||||
$select_type->add($this->gettext('none'), '');
|
$select_type->add($this->gettext('none'), '');
|
||||||
foreach ($alarm_types as $type)
|
foreach ($alarm_types as $type) {
|
||||||
$select_type->add($this->gettext(strtolower("alarm{$type}option")), $type);
|
$select_type->add($this->gettext(strtolower("alarm{$type}option")), $type);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (array('-M','-H','-D','+M','+H','+D') as $trigger)
|
foreach (array('-M','-H','-D','+M','+H','+D') as $trigger) {
|
||||||
$select_offset->add($this->gettext('trigger' . $trigger), $trigger);
|
$select_offset->add($this->gettext('trigger' . $trigger), $trigger);
|
||||||
|
}
|
||||||
|
|
||||||
$select_offset->add($this->gettext('trigger0'), '0');
|
$select_offset->add($this->gettext('trigger0'), '0');
|
||||||
if ($absolute_time)
|
if ($absolute_time) {
|
||||||
$select_offset->add($this->gettext('trigger@'), '@');
|
$select_offset->add($this->gettext('trigger@'), '@');
|
||||||
|
}
|
||||||
|
|
||||||
$select_related->add($this->gettext('relatedstart'), 'start');
|
$select_related->add($this->gettext('relatedstart'), 'start');
|
||||||
$select_related->add($this->gettext('relatedend' . $object_type), 'end');
|
$select_related->add($this->gettext('relatedend' . $object_type), 'end');
|
||||||
|
@ -399,7 +404,7 @@ class libcalendaring extends rcube_plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// return cached result
|
// return cached result
|
||||||
if (is_array($_emails[$user])) {
|
if (isset($_emails[$user])) {
|
||||||
return $_emails[$user];
|
return $_emails[$user];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,12 +807,13 @@ class libcalendaring extends rcube_plugin
|
||||||
return rcmail::get_instance()->format_date($dt, $format);
|
return rcmail::get_instance()->format_date($dt, $format);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (is_array($rrule['EXDATE']) && !empty($rrule['EXDATE'])) {
|
if (!empty($rrule['EXDATE']) && is_array($rrule['EXDATE'])) {
|
||||||
$exdates = array_map($format_fn, $rrule['EXDATE']);
|
$exdates = array_map($format_fn, $rrule['EXDATE']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($rrule['FREQ']) && !empty($rrule['RDATE'])) {
|
if (empty($rrule['FREQ']) && !empty($rrule['RDATE'])) {
|
||||||
$rdates = array_map($format_fn, $rrule['RDATE']);
|
$rdates = array_map($format_fn, $rrule['RDATE']);
|
||||||
|
$more = false;
|
||||||
|
|
||||||
if (!empty($exdates)) {
|
if (!empty($exdates)) {
|
||||||
$rdates = array_diff($rdates, $exdates);
|
$rdates = array_diff($rdates, $exdates);
|
||||||
|
@ -818,8 +824,7 @@ class libcalendaring extends rcube_plugin
|
||||||
$more = true;
|
$more = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->gettext('ondate') . ' ' . join(', ', $rdates)
|
return $this->gettext('ondate') . ' ' . join(', ', $rdates) . ($more ? '...' : '');
|
||||||
. ($more ? '...' : '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$output = sprintf('%s %d ', $this->gettext('every'), $rrule['INTERVAL'] ?: 1);
|
$output = sprintf('%s %d ', $this->gettext('every'), $rrule['INTERVAL'] ?: 1);
|
||||||
|
@ -839,10 +844,10 @@ class libcalendaring extends rcube_plugin
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rrule['COUNT']) {
|
if (!empty($rrule['COUNT'])) {
|
||||||
$until = $this->gettext(array('name' => 'forntimes', 'vars' => array('nr' => $rrule['COUNT'])));
|
$until = $this->gettext(array('name' => 'forntimes', 'vars' => array('nr' => $rrule['COUNT'])));
|
||||||
}
|
}
|
||||||
else if ($rrule['UNTIL']) {
|
else if (!empty($rrule['UNTIL'])) {
|
||||||
$until = $this->gettext('recurrencend') . ' ' . $this->rc->format_date($rrule['UNTIL'], $format);
|
$until = $this->gettext('recurrencend') . ' ' . $this->rc->format_date($rrule['UNTIL'], $format);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -852,13 +857,13 @@ class libcalendaring extends rcube_plugin
|
||||||
$output .= ', ' . $until;
|
$output .= ', ' . $until;
|
||||||
|
|
||||||
if (!empty($exdates)) {
|
if (!empty($exdates)) {
|
||||||
|
$more = false;
|
||||||
if (count($exdates) > $limit) {
|
if (count($exdates) > $limit) {
|
||||||
$exdates = array_slice($exdates, 0, $limit);
|
$exdates = array_slice($exdates, 0, $limit);
|
||||||
$more = true;
|
$more = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$output .= '; ' . $this->gettext('except') . ' ' . join(', ', $exdates)
|
$output .= '; ' . $this->gettext('except') . ' ' . join(', ', $exdates) . ($more ? '...' : '');
|
||||||
. ($more ? '...' : '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
|
@ -1056,16 +1061,16 @@ class libcalendaring extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public function to_client_recurrence($recurrence, $allday = false)
|
public function to_client_recurrence($recurrence, $allday = false)
|
||||||
{
|
{
|
||||||
if ($recurrence['UNTIL']) {
|
if (!empty($recurrence['UNTIL'])) {
|
||||||
$recurrence['UNTIL'] = $this->adjust_timezone($recurrence['UNTIL'], $allday)->format('c');
|
$recurrence['UNTIL'] = $this->adjust_timezone($recurrence['UNTIL'], $allday)->format('c');
|
||||||
}
|
}
|
||||||
|
|
||||||
// format RDATE values
|
// format RDATE values
|
||||||
if (is_array($recurrence['RDATE'])) {
|
if (!empty($recurrence['RDATE'])) {
|
||||||
$libcal = $this;
|
$libcal = $this;
|
||||||
$recurrence['RDATE'] = array_map(function($rdate) use ($libcal) {
|
$recurrence['RDATE'] = array_map(function($rdate) use ($libcal) {
|
||||||
return $libcal->adjust_timezone($rdate, true)->format('c');
|
return $libcal->adjust_timezone($rdate, true)->format('c');
|
||||||
}, $recurrence['RDATE']);
|
}, (array) $recurrence['RDATE']);
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($recurrence['EXCEPTIONS']);
|
unset($recurrence['EXCEPTIONS']);
|
||||||
|
@ -1082,7 +1087,7 @@ class libcalendaring extends rcube_plugin
|
||||||
$recurrence['UNTIL'] = new DateTime($recurrence['UNTIL'], $this->timezone);
|
$recurrence['UNTIL'] = new DateTime($recurrence['UNTIL'], $this->timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($recurrence) && is_array($recurrence['RDATE'])) {
|
if (is_array($recurrence) && !empty($recurrence['RDATE'])) {
|
||||||
$tz = $this->timezone;
|
$tz = $this->timezone;
|
||||||
$recurrence['RDATE'] = array_map(function($rdate) use ($tz, $start) {
|
$recurrence['RDATE'] = array_map(function($rdate) use ($tz, $start) {
|
||||||
try {
|
try {
|
||||||
|
@ -1195,7 +1200,7 @@ class libcalendaring extends rcube_plugin
|
||||||
$headers = $imap->get_message_headers($uid);
|
$headers = $imap->get_message_headers($uid);
|
||||||
$parser = $this->get_ical();
|
$parser = $this->get_ical();
|
||||||
|
|
||||||
if ($part->ctype_parameters['charset']) {
|
if (!empty($part->ctype_parameters['charset'])) {
|
||||||
$charset = $part->ctype_parameters['charset'];
|
$charset = $part->ctype_parameters['charset'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1238,8 +1243,9 @@ class libcalendaring extends rcube_plugin
|
||||||
$level = explode('.', $part->mime_id);
|
$level = explode('.', $part->mime_id);
|
||||||
|
|
||||||
while (array_pop($level) !== null) {
|
while (array_pop($level) !== null) {
|
||||||
$parent = $message->mime_parts[join('.', $level) ?: 0];
|
$id = join('.', $level) ?: 0;
|
||||||
if ($parent->mimetype == 'multipart/report') {
|
$parent = !empty($message->mime_parts[$id]) ? $message->mime_parts[$id] : null;
|
||||||
|
if ($parent && $parent->mimetype == 'multipart/report') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1248,7 +1254,7 @@ class libcalendaring extends rcube_plugin
|
||||||
return (
|
return (
|
||||||
in_array($part->mimetype, array('text/calendar', 'text/x-vcalendar', 'application/ics')) ||
|
in_array($part->mimetype, array('text/calendar', 'text/x-vcalendar', 'application/ics')) ||
|
||||||
// Apple sends files as application/x-any (!?)
|
// Apple sends files as application/x-any (!?)
|
||||||
($part->mimetype == 'application/x-any' && $part->filename && preg_match('/\.ics$/i', $part->filename))
|
($part->mimetype == 'application/x-any' && !empty($part->filename) && preg_match('/\.ics$/i', $part->filename))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1288,7 +1294,7 @@ class libcalendaring extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public static function recurrence_id_format($event)
|
public static function recurrence_id_format($event)
|
||||||
{
|
{
|
||||||
return $event['allday'] ? 'Ymd' : 'Ymd\THis';
|
return !empty($event['allday']) ? 'Ymd' : 'Ymd\THis';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1301,13 +1307,13 @@ class libcalendaring extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public static function recurrence_instance_identifier($event, $allday = null)
|
public static function recurrence_instance_identifier($event, $allday = null)
|
||||||
{
|
{
|
||||||
$instance_date = $event['recurrence_date'] ?: $event['start'];
|
$instance_date = !empty($event['recurrence_date']) ? $event['recurrence_date'] : $event['start'];
|
||||||
|
|
||||||
if ($instance_date && is_a($instance_date, 'DateTime')) {
|
if ($instance_date instanceof DateTime) {
|
||||||
// According to RFC5545 (3.8.4.4) RECURRENCE-ID format should
|
// According to RFC5545 (3.8.4.4) RECURRENCE-ID format should
|
||||||
// be date/date-time depending on the main event type, not the exception
|
// be date/date-time depending on the main event type, not the exception
|
||||||
if ($allday === null) {
|
if ($allday === null) {
|
||||||
$allday = $event['allday'];
|
$allday = !empty($event['allday']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $instance_date->format($allday ? 'Ymd' : 'Ymd\THis');
|
return $instance_date->format($allday ? 'Ymd' : 'Ymd\THis');
|
||||||
|
@ -1547,5 +1553,4 @@ class libcalendaring extends rcube_plugin
|
||||||
'c' => '',
|
'c' => '',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,7 +577,7 @@ class libvcalendar implements Iterator
|
||||||
$schedule_agent = $attendee['schedule-agent'];
|
$schedule_agent = $attendee['schedule-agent'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ($attendee['email'] != $event['organizer']['email']) {
|
else if (empty($event['organizer']) || $attendee['email'] != $event['organizer']['email']) {
|
||||||
$event['attendees'][] = $attendee;
|
$event['attendees'][] = $attendee;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -756,7 +756,7 @@ class libvcalendar implements Iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
// For date-only we'll keep the date and time intact
|
// For date-only we'll keep the date and time intact
|
||||||
if ($date->_dateonly) {
|
if (!empty($date->_dateonly)) {
|
||||||
$dt = new DateTime(null, $this->timezone);
|
$dt = new DateTime(null, $this->timezone);
|
||||||
$dt->setDate($date->format('Y'), $date->format('n'), $date->format('j'));
|
$dt->setDate($date->format('Y'), $date->format('n'), $date->format('j'));
|
||||||
$dt->setTime($date->format('G'), $date->format('i'), 0);
|
$dt->setTime($date->format('G'), $date->format('i'), 0);
|
||||||
|
|
|
@ -48,7 +48,7 @@ class kolab_attachments_handler
|
||||||
*/
|
*/
|
||||||
public function files_list($attrib = array())
|
public function files_list($attrib = array())
|
||||||
{
|
{
|
||||||
if (!$attrib['id']) {
|
if (empty($attrib['id'])) {
|
||||||
$attrib['id'] = 'kolabattachmentlist';
|
$attrib['id'] = 'kolabattachmentlist';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class kolab_attachments_handler
|
||||||
public function files_form($attrib = array())
|
public function files_form($attrib = array())
|
||||||
{
|
{
|
||||||
// add ID if not given
|
// add ID if not given
|
||||||
if (!$attrib['id']) {
|
if (empty($attrib['id'])) {
|
||||||
$attrib['id'] = 'kolabuploadform';
|
$attrib['id'] = 'kolabuploadform';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ class kolab_attachments_handler
|
||||||
public function files_drop_area($attrib = array())
|
public function files_drop_area($attrib = array())
|
||||||
{
|
{
|
||||||
// add ID if not given
|
// add ID if not given
|
||||||
if (!$attrib['id']) {
|
if (empty($attrib['id'])) {
|
||||||
$attrib['id'] = 'kolabfiledroparea';
|
$attrib['id'] = 'kolabfiledroparea';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ class kolab_attachments_handler
|
||||||
$recid = $id_prefix . rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
|
$recid = $id_prefix . rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
|
||||||
$uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GPC);
|
$uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GPC);
|
||||||
|
|
||||||
if (!is_array($_SESSION[$session_key]) || $_SESSION[$session_key]['id'] != $recid) {
|
if (empty($_SESSION[$session_key]) || $_SESSION[$session_key]['id'] != $recid) {
|
||||||
$_SESSION[$session_key] = array();
|
$_SESSION[$session_key] = array();
|
||||||
$_SESSION[$session_key]['id'] = $recid;
|
$_SESSION[$session_key]['id'] = $recid;
|
||||||
$_SESSION[$session_key]['attachments'] = array();
|
$_SESSION[$session_key]['attachments'] = array();
|
||||||
|
@ -151,13 +151,16 @@ class kolab_attachments_handler
|
||||||
unset($attachment['status'], $attachment['abort']);
|
unset($attachment['status'], $attachment['abort']);
|
||||||
$this->rc->session->append($session_key . '.attachments', $id, $attachment);
|
$this->rc->session->append($session_key . '.attachments', $id, $attachment);
|
||||||
|
|
||||||
if (($icon = $_SESSION[$session_key . '_deleteicon']) && is_file($icon)) {
|
if (!empty($_SESSION[$session_key . '_deleteicon'])
|
||||||
|
&& ($icon = $_SESSION[$session_key . '_deleteicon'])
|
||||||
|
&& is_file($icon)
|
||||||
|
) {
|
||||||
$button = html::img(array(
|
$button = html::img(array(
|
||||||
'src' => $icon,
|
'src' => $icon,
|
||||||
'alt' => $this->rc->gettext('delete')
|
'alt' => $this->rc->gettext('delete')
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
else if ($_SESSION[$session_key . '_textbuttons']) {
|
else if (!empty($_SESSION[$session_key . '_textbuttons'])) {
|
||||||
$button = rcube::Q($this->rc->gettext('delete'));
|
$button = rcube::Q($this->rc->gettext('delete'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -181,7 +184,8 @@ class kolab_attachments_handler
|
||||||
'onclick' => 'return false', // sprintf("return %s.command('load-attachment','rcmfile%s', this, event)", rcmail_output::JS_OBJECT_NAME, $id),
|
'onclick' => 'return false', // sprintf("return %s.command('load-attachment','rcmfile%s', this, event)", rcmail_output::JS_OBJECT_NAME, $id),
|
||||||
), $link_content);
|
), $link_content);
|
||||||
|
|
||||||
$content .= $_SESSION[$session_key . '_icon_pos'] == 'left' ? $delete_link.$content_link : $content_link.$delete_link;
|
$left = !empty($_SESSION[$session_key . '_icon_pos']) && $_SESSION[$session_key . '_icon_pos'] == 'left';
|
||||||
|
$content = $left ? $delete_link.$content_link : $content_link.$delete_link;
|
||||||
|
|
||||||
$this->rc->output->command('add2attachment_list', "rcmfile$id", array(
|
$this->rc->output->command('add2attachment_list', "rcmfile$id", array(
|
||||||
'html' => $content,
|
'html' => $content,
|
||||||
|
@ -196,7 +200,7 @@ class kolab_attachments_handler
|
||||||
$msg = $this->rc->gettext(array('name' => 'filesizeerror', 'vars' => array(
|
$msg = $this->rc->gettext(array('name' => 'filesizeerror', 'vars' => array(
|
||||||
'size' => $this->rc->show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
|
'size' => $this->rc->show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
|
||||||
}
|
}
|
||||||
else if ($attachment['error']) {
|
else if (!empty($attachment['error'])) {
|
||||||
$msg = $attachment['error'];
|
$msg = $attachment['error'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -211,11 +215,13 @@ class kolab_attachments_handler
|
||||||
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
// if filesize exceeds post_max_size then $_FILES array is empty,
|
// if filesize exceeds post_max_size then $_FILES array is empty,
|
||||||
// show filesizeerror instead of fileuploaderror
|
// show filesizeerror instead of fileuploaderror
|
||||||
if ($maxsize = ini_get('post_max_size'))
|
if ($maxsize = ini_get('post_max_size')) {
|
||||||
$msg = $this->rc->gettext(array('name' => 'filesizeerror', 'vars' => array(
|
$msg = $this->rc->gettext(array('name' => 'filesizeerror', 'vars' => array(
|
||||||
'size' => $this->rc->show_bytes(parse_bytes($maxsize)))));
|
'size' => $this->rc->show_bytes(parse_bytes($maxsize)))));
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
$msg = $this->rc->gettext('fileuploaderror');
|
$msg = $this->rc->gettext('fileuploaderror');
|
||||||
|
}
|
||||||
|
|
||||||
$this->rc->output->command('display_message', $msg, 'error');
|
$this->rc->output->command('display_message', $msg, 'error');
|
||||||
$this->rc->output->command('remove_from_attachment_list', $uploadid);
|
$this->rc->output->command('remove_from_attachment_list', $uploadid);
|
||||||
|
@ -233,7 +239,7 @@ class kolab_attachments_handler
|
||||||
{
|
{
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
|
|
||||||
if ($attachment && $attachment['body']) {
|
if ($attachment && !empty($attachment['body'])) {
|
||||||
// allow post-processing of the attachment body
|
// allow post-processing of the attachment body
|
||||||
$part = new rcube_message_part;
|
$part = new rcube_message_part;
|
||||||
$part->filename = $attachment['name'];
|
$part->filename = $attachment['name'];
|
||||||
|
|
|
@ -93,5 +93,4 @@ class kolab_bonnie_api
|
||||||
{
|
{
|
||||||
return $this->client->execute($method, $params);
|
return $this->client->execute($method, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -235,5 +235,4 @@ class kolab_bonnie_api_client
|
||||||
|
|
||||||
rcube::write_log('bonnie', join(";\n", $msg));
|
rcube::write_log('bonnie', join(";\n", $msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -151,5 +151,4 @@ class kolab_format_task extends kolab_format_xcal
|
||||||
|
|
||||||
return array_unique($tags);
|
return array_unique($tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,5 +150,4 @@ class kolab_storage_dataset implements Iterator, ArrayAccess, Countable
|
||||||
{
|
{
|
||||||
return !empty($this->index[$this->iteratorkey]);
|
return !empty($this->index[$this->iteratorkey]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,15 @@ class libkolab extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
function storage_init($p)
|
function storage_init($p)
|
||||||
{
|
{
|
||||||
$p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE X-KOLAB-MIME-VERSION MESSAGE-ID');
|
$kolab_headers = 'X-KOLAB-TYPE X-KOLAB-MIME-VERSION MESSAGE-ID';
|
||||||
|
|
||||||
|
if (!empty($p['fetch_headers'])) {
|
||||||
|
$p['fetch_headers'] .= ' ' . $kolab_headers;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$p['fetch_headers'] = $kolab_headers;
|
||||||
|
}
|
||||||
|
|
||||||
return $p;
|
return $p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,8 +118,8 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
. " VALUES (?, ?, ?, ?)",
|
. " VALUES (?, ?, ?, ?)",
|
||||||
$this->rc->user->ID,
|
$this->rc->user->ID,
|
||||||
strval($prop['name']),
|
strval($prop['name']),
|
||||||
strval($prop['color']),
|
isset($prop['color']) ? strval($prop['color']) : '',
|
||||||
$prop['showalarms'] ? 1 : 0
|
!empty($prop['showalarms']) ? 1 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
|
@ -143,8 +143,8 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
"UPDATE " . $this->db_lists . " SET `name` = ?, `color` = ?, `showalarms` = ?"
|
"UPDATE " . $this->db_lists . " SET `name` = ?, `color` = ?, `showalarms` = ?"
|
||||||
. " WHERE `tasklist_id` = ? AND `user_id` = ?",
|
. " WHERE `tasklist_id` = ? AND `user_id` = ?",
|
||||||
strval($prop['name']),
|
strval($prop['name']),
|
||||||
strval($prop['color']),
|
isset($prop['color']) ? strval($prop['color']) : '',
|
||||||
$prop['showalarms'] ? 1 : 0,
|
!empty($prop['showalarms']) ? 1 : 0,
|
||||||
$prop['id'],
|
$prop['id'],
|
||||||
$this->rc->user->ID
|
$this->rc->user->ID
|
||||||
);
|
);
|
||||||
|
@ -163,7 +163,7 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
{
|
{
|
||||||
$hidden = array_flip(explode(',', $this->rc->config->get('hidden_tasklists', '')));
|
$hidden = array_flip(explode(',', $this->rc->config->get('hidden_tasklists', '')));
|
||||||
|
|
||||||
if ($prop['active']) {
|
if (!empty($prop['active'])) {
|
||||||
unset($hidden[$prop['id']]);
|
unset($hidden[$prop['id']]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -291,11 +291,12 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
$sql_add = '';
|
$sql_add = '';
|
||||||
|
|
||||||
// add filter criteria
|
// add filter criteria
|
||||||
if ($filter['from'] || ($filter['mask'] & tasklist::FILTER_MASK_TODAY)) {
|
if ($filter) {
|
||||||
$sql_add .= " AND (`date` IS NULL OR `date` >= ?)";
|
if (!empty($filter['from']) || ($filter['mask'] & tasklist::FILTER_MASK_TODAY)) {
|
||||||
$datefrom = $filter['from'];
|
$sql_add .= " AND (`date` IS NULL OR `date` >= " . $this->rc->db->quote($filter['from']) . ")";
|
||||||
}
|
}
|
||||||
if ($filter['to']) {
|
|
||||||
|
if (!empty($filter['to'])) {
|
||||||
if ($filter['mask'] & tasklist::FILTER_MASK_OVERDUE) {
|
if ($filter['mask'] & tasklist::FILTER_MASK_OVERDUE) {
|
||||||
$sql_add .= " AND (`date` IS NOT NULL AND `date` <= " . $this->rc->db->quote($filter['to']) . ")";
|
$sql_add .= " AND (`date` IS NOT NULL AND `date` <= " . $this->rc->db->quote($filter['to']) . ")";
|
||||||
}
|
}
|
||||||
|
@ -304,11 +305,6 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// special case 'today': also show all events with date before today
|
|
||||||
if ($filter['mask'] & tasklist::FILTER_MASK_TODAY) {
|
|
||||||
$datefrom = date('Y-m-d', 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($filter['mask'] & tasklist::FILTER_MASK_NODATE) {
|
if ($filter['mask'] & tasklist::FILTER_MASK_NODATE) {
|
||||||
$sql_add = " AND `date` IS NULL";
|
$sql_add = " AND `date` IS NULL";
|
||||||
}
|
}
|
||||||
|
@ -335,21 +331,21 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
$sql_add = " AND (" . join(" OR ", $sql_query) . ")";
|
$sql_add = " AND (" . join(" OR ", $sql_query) . ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($filter['since'] && is_numeric($filter['since'])) {
|
if (!empty($filter['since']) && is_numeric($filter['since'])) {
|
||||||
$sql_add .= " AND `changed` >= " . $this->rc->db->quote(date('Y-m-d H:i:s', $filter['since']));
|
$sql_add .= " AND `changed` >= " . $this->rc->db->quote(date('Y-m-d H:i:s', $filter['since']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($filter['uid']) {
|
if (!empty($filter['uid'])) {
|
||||||
$sql_add .= " AND `uid` IN (" . implode(',', array_map(array($this->rc->db, 'quote'), $filter['uid'])) . ")";
|
$sql_add .= " AND `uid` IN (" . implode(',', array_map(array($this->rc->db, 'quote'), $filter['uid'])) . ")";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$tasks = array();
|
$tasks = array();
|
||||||
if (!empty($list_ids)) {
|
if (!empty($list_ids)) {
|
||||||
$result = $this->rc->db->query("SELECT * FROM " . $this->db_tasks
|
$result = $this->rc->db->query("SELECT * FROM " . $this->db_tasks
|
||||||
. " WHERE `tasklist_id` IN (" . join(',', $list_ids) . ")"
|
. " WHERE `tasklist_id` IN (" . join(',', $list_ids) . ")"
|
||||||
. " AND `del` = 0" . $sql_add
|
. " AND `del` = 0" . $sql_add
|
||||||
. " ORDER BY `parent_id`, `task_id` ASC",
|
. " ORDER BY `parent_id`, `task_id` ASC"
|
||||||
$datefrom
|
|
||||||
);
|
);
|
||||||
|
|
||||||
while ($result && ($rec = $this->rc->db->fetch_assoc($result))) {
|
while ($result && ($rec = $this->rc->db->fetch_assoc($result))) {
|
||||||
|
@ -375,12 +371,12 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
$prop['uid'] = $prop;
|
$prop['uid'] = $prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
$query_col = $prop['id'] ? 'task_id' : 'uid';
|
$query_col = !empty($prop['id']) ? 'task_id' : 'uid';
|
||||||
|
|
||||||
$result = $this->rc->db->query("SELECT * FROM " . $this->db_tasks
|
$result = $this->rc->db->query("SELECT * FROM " . $this->db_tasks
|
||||||
. " WHERE `tasklist_id` IN (" . $this->list_ids . ")"
|
. " WHERE `tasklist_id` IN (" . $this->list_ids . ")"
|
||||||
. " AND `$query_col` = ? AND `del` = 0",
|
. " AND `$query_col` = ? AND `del` = 0",
|
||||||
$prop['id'] ? $prop['id'] : $prop['uid']
|
!empty($prop['id']) ? $prop['id'] : $prop['uid']
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($result && ($rec = $this->rc->db->fetch_assoc($result))) {
|
if ($result && ($rec = $this->rc->db->fetch_assoc($result))) {
|
||||||
|
@ -557,15 +553,15 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
public function create_task($prop)
|
public function create_task($prop)
|
||||||
{
|
{
|
||||||
// check list permissions
|
// check list permissions
|
||||||
$list_id = $prop['list'] ? $prop['list'] : reset(array_keys($this->lists));
|
$list_id = !empty($prop['list']) ? $prop['list'] : reset(array_keys($this->lists));
|
||||||
if (!$this->lists[$list_id] || $this->lists[$list_id]['readonly']) {
|
if (empty($this->lists[$list_id]) || !empty($this->lists[$list_id]['readonly'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($prop['valarms'])) {
|
if (!empty($prop['valarms'])) {
|
||||||
$prop['alarms'] = $this->serialize_alarms($prop['valarms']);
|
$prop['alarms'] = $this->serialize_alarms($prop['valarms']);
|
||||||
}
|
}
|
||||||
if (is_array($prop['recurrence'])) {
|
if (!empty($prop['recurrence'])) {
|
||||||
$prop['recurrence'] = $this->serialize_recurrence($prop['recurrence']);
|
$prop['recurrence'] = $this->serialize_recurrence($prop['recurrence']);
|
||||||
}
|
}
|
||||||
if (array_key_exists('complete', $prop)) {
|
if (array_key_exists('complete', $prop)) {
|
||||||
|
@ -594,13 +590,13 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
$prop['time'],
|
$prop['time'],
|
||||||
$prop['startdate'],
|
$prop['startdate'],
|
||||||
$prop['starttime'],
|
$prop['starttime'],
|
||||||
strval($prop['description']),
|
isset($prop['description']) ? strval($prop['description']) : '',
|
||||||
join(',', (array)$prop['tags']),
|
!empty($prop['tags']) ? join(',', (array)$prop['tags']) : '',
|
||||||
$prop['flagged'] ? 1 : 0,
|
!empty($prop['flagged']) ? 1 : 0,
|
||||||
$prop['complete'] ?: 0,
|
!empty($prop['complete']) ?: 0,
|
||||||
strval($prop['status']),
|
strval($prop['status']),
|
||||||
$prop['alarms'],
|
isset($prop['alarms']) ? $prop['alarms'] : '',
|
||||||
$prop['recurrence'],
|
isset($prop['recurrence']) ? $prop['recurrence'] : '',
|
||||||
$notify_at
|
$notify_at
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -621,10 +617,10 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
*/
|
*/
|
||||||
public function edit_task($prop)
|
public function edit_task($prop)
|
||||||
{
|
{
|
||||||
if (is_array($prop['valarms'])) {
|
if (isset($prop['valarms'])) {
|
||||||
$prop['alarms'] = $this->serialize_alarms($prop['valarms']);
|
$prop['alarms'] = $this->serialize_alarms($prop['valarms']);
|
||||||
}
|
}
|
||||||
if (is_array($prop['recurrence'])) {
|
if (isset($prop['recurrence'])) {
|
||||||
$prop['recurrence'] = $this->serialize_recurrence($prop['recurrence']);
|
$prop['recurrence'] = $this->serialize_recurrence($prop['recurrence']);
|
||||||
}
|
}
|
||||||
if (array_key_exists('complete', $prop)) {
|
if (array_key_exists('complete', $prop)) {
|
||||||
|
@ -655,7 +651,7 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
// moved from another list
|
// moved from another list
|
||||||
if ($prop['_fromlist'] && ($newlist = $prop['list'])) {
|
if (!empty($prop['_fromlist']) && ($newlist = $prop['list'])) {
|
||||||
$sql_set[] = $this->rc->db->quote_identifier('tasklist_id') . '=' . $this->rc->db->quote($newlist);
|
$sql_set[] = $this->rc->db->quote_identifier('tasklist_id') . '=' . $this->rc->db->quote($newlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,10 +731,10 @@ class tasklist_database_driver extends tasklist_driver
|
||||||
*/
|
*/
|
||||||
private function _get_notification($task)
|
private function _get_notification($task)
|
||||||
{
|
{
|
||||||
if ($task['valarms'] && !$this->is_complete($task)) {
|
if (!empty($task['valarms']) && !$this->is_complete($task)) {
|
||||||
$alarm = libcalendaring::get_next_alarm($task, 'task');
|
$alarm = libcalendaring::get_next_alarm($task, 'task');
|
||||||
|
|
||||||
if ($alarm['time'] && in_array($alarm['action'], $this->alarm_types)) {
|
if (!empty($alarm['time']) && in_array($alarm['action'], $this->alarm_types)) {
|
||||||
return date('Y-m-d H:i:s', $alarm['time']);
|
return date('Y-m-d H:i:s', $alarm['time']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
private $collapsed_tasks = array();
|
private $collapsed_tasks = array();
|
||||||
private $message_tasks = array();
|
private $message_tasks = array();
|
||||||
|
private $task_titles = array();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,7 +140,7 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// add 'Create event' item to message menu
|
// add 'Create event' item to message menu
|
||||||
if ($this->api->output->type == 'html' && $_GET['_rel'] != 'task') {
|
if ($this->api->output->type == 'html' && (empty($_GET['_rel']) || $_GET['_rel'] != 'task')) {
|
||||||
$this->api->add_content(html::tag('li', array('role' => 'menuitem'),
|
$this->api->add_content(html::tag('li', array('role' => 'menuitem'),
|
||||||
$this->api->output->button(array(
|
$this->api->output->button(array(
|
||||||
'command' => 'tasklist-create-from-mail',
|
'command' => 'tasklist-create-from-mail',
|
||||||
|
@ -155,7 +156,7 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->rc->output->ajax_call && !$this->rc->output->env['framed']) {
|
if (!$this->rc->output->ajax_call && empty($this->rc->output->env['framed'])) {
|
||||||
$this->load_ui();
|
$this->load_ui();
|
||||||
$this->ui->init();
|
$this->ui->init();
|
||||||
}
|
}
|
||||||
|
@ -181,7 +182,7 @@ class tasklist extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
private function load_driver()
|
private function load_driver()
|
||||||
{
|
{
|
||||||
if (is_object($this->driver)) {
|
if (!empty($this->driver)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,15 +210,16 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
// force notify if hidden + active
|
// force notify if hidden + active
|
||||||
$itip_send_option = (int)$this->rc->config->get('calendar_itip_send_option', 3);
|
$itip_send_option = (int)$this->rc->config->get('calendar_itip_send_option', 3);
|
||||||
if ($itip_send_option === 1 && empty($rec['_reportpartstat']))
|
if ($itip_send_option === 1 && empty($rec['_reportpartstat'])) {
|
||||||
$rec['_notify'] = 1;
|
$rec['_notify'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case 'new':
|
case 'new':
|
||||||
$oldrec = null;
|
$oldrec = null;
|
||||||
$rec = $this->prepare_task($rec);
|
$rec = $this->prepare_task($rec);
|
||||||
$rec['uid'] = $this->generate_uid();
|
$rec['uid'] = $this->generate_uid();
|
||||||
$temp_id = $rec['tempid'];
|
$temp_id = !empty($rec['tempid']) ? $rec['tempid'] : null;
|
||||||
if ($success = $this->driver->create_task($rec)) {
|
if ($success = $this->driver->create_task($rec)) {
|
||||||
$refresh = $this->driver->get_task($rec);
|
$refresh = $this->driver->get_task($rec);
|
||||||
if ($temp_id) $refresh['tempid'] = $temp_id;
|
if ($temp_id) $refresh['tempid'] = $temp_id;
|
||||||
|
@ -514,7 +516,7 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// send out notifications
|
// send out notifications
|
||||||
if ($success && $rec['_notify'] && ($rec['attendees'] || $oldrec['attendees'])) {
|
if ($success && !empty($rec['_notify']) && ($rec['attendees'] || $oldrec['attendees'])) {
|
||||||
// make sure we have the complete record
|
// make sure we have the complete record
|
||||||
$task = $action == 'delete' ? $oldrec : $this->driver->get_task($rec);
|
$task = $action == 'delete' ? $oldrec : $this->driver->get_task($rec);
|
||||||
|
|
||||||
|
@ -528,7 +530,7 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($success && $rec['_reportpartstat'] && $rec['_reportpartstat'] != 'NEEDS-ACTION') {
|
if ($success && !empty($rec['_reportpartstat']) && $rec['_reportpartstat'] != 'NEEDS-ACTION') {
|
||||||
// get the full record after update
|
// get the full record after update
|
||||||
if (!$task) {
|
if (!$task) {
|
||||||
$task = $this->driver->get_task($rec);
|
$task = $this->driver->get_task($rec);
|
||||||
|
@ -556,7 +558,7 @@ class tasklist extends rcube_plugin
|
||||||
$this->rc->output->command('plugin.unlock_saving', $success);
|
$this->rc->output->command('plugin.unlock_saving', $success);
|
||||||
|
|
||||||
if ($refresh) {
|
if ($refresh) {
|
||||||
if ($refresh['id']) {
|
if (!empty($refresh['id'])) {
|
||||||
$this->encode_task($refresh);
|
$this->encode_task($refresh);
|
||||||
}
|
}
|
||||||
else if (is_array($refresh)) {
|
else if (is_array($refresh)) {
|
||||||
|
@ -575,8 +577,8 @@ class tasklist extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
private function load_itip()
|
private function load_itip()
|
||||||
{
|
{
|
||||||
if (!$this->itip) {
|
if (empty($this->itip)) {
|
||||||
require_once realpath(__DIR__ . '/../libcalendaring/lib/libcalendaring_itip.php');
|
require_once __DIR__ . '/../libcalendaring/lib/libcalendaring_itip.php';
|
||||||
$this->itip = new libcalendaring_itip($this, 'tasklist');
|
$this->itip = new libcalendaring_itip($this, 'tasklist');
|
||||||
$this->itip->set_rsvp_actions(array('accepted','declined','delegated'));
|
$this->itip->set_rsvp_actions(array('accepted','declined','delegated'));
|
||||||
$this->itip->set_rsvp_status(array('accepted','tentative','declined','delegated','in-process','completed'));
|
$this->itip->set_rsvp_status(array('accepted','tentative','declined','delegated','in-process','completed'));
|
||||||
|
@ -591,7 +593,7 @@ class tasklist extends rcube_plugin
|
||||||
private function prepare_task($rec)
|
private function prepare_task($rec)
|
||||||
{
|
{
|
||||||
// try to be smart and extract date from raw input
|
// try to be smart and extract date from raw input
|
||||||
if ($rec['raw']) {
|
if (!empty($rec['raw'])) {
|
||||||
foreach (array('today','tomorrow','sunday','monday','tuesday','wednesday','thursday','friday','saturday','sun','mon','tue','wed','thu','fri','sat') as $word) {
|
foreach (array('today','tomorrow','sunday','monday','tuesday','wednesday','thursday','friday','saturday','sun','mon','tue','wed','thu','fri','sat') as $word) {
|
||||||
$locwords[] = '/^' . preg_quote(mb_strtolower($this->gettext($word))) . '\b/i';
|
$locwords[] = '/^' . preg_quote(mb_strtolower($this->gettext($word))) . '\b/i';
|
||||||
$normwords[] = $word;
|
$normwords[] = $word;
|
||||||
|
@ -675,7 +677,7 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the submitted alarm values
|
// convert the submitted alarm values
|
||||||
if ($rec['valarms']) {
|
if (!empty($rec['valarms'])) {
|
||||||
$valarms = array();
|
$valarms = array();
|
||||||
foreach (libcalendaring::from_client_alarms($rec['valarms']) as $alarm) {
|
foreach (libcalendaring::from_client_alarms($rec['valarms']) as $alarm) {
|
||||||
// alarms can only work with a date (either task start, due or absolute alarm date)
|
// alarms can only work with a date (either task start, due or absolute alarm date)
|
||||||
|
@ -701,7 +703,7 @@ class tasklist extends rcube_plugin
|
||||||
// translate count into an absolute end date.
|
// translate count into an absolute end date.
|
||||||
// why? because when shifting completed tasks to the next recurrence,
|
// why? because when shifting completed tasks to the next recurrence,
|
||||||
// the initial start date to count from gets lost.
|
// the initial start date to count from gets lost.
|
||||||
if ($rec['recurrence']['COUNT']) {
|
if (!empty($rec['recurrence']['COUNT'])) {
|
||||||
$engine = libcalendaring::get_recurrence();
|
$engine = libcalendaring::get_recurrence();
|
||||||
$engine->init($rec['recurrence'], $refdate);
|
$engine->init($rec['recurrence'], $refdate);
|
||||||
if ($until = $engine->end()) {
|
if ($until = $engine->end()) {
|
||||||
|
@ -717,7 +719,7 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
$attachments = array();
|
$attachments = array();
|
||||||
$taskid = $rec['id'];
|
$taskid = $rec['id'];
|
||||||
if (is_array($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY]['id'] == $taskid) {
|
if (!empty($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY]['id'] == $taskid) {
|
||||||
if (!empty($_SESSION[self::SESSION_KEY]['attachments'])) {
|
if (!empty($_SESSION[self::SESSION_KEY]['attachments'])) {
|
||||||
foreach ($_SESSION[self::SESSION_KEY]['attachments'] as $id => $attachment) {
|
foreach ($_SESSION[self::SESSION_KEY]['attachments'] as $id => $attachment) {
|
||||||
if (is_array($rec['attachments']) && in_array($id, $rec['attachments'])) {
|
if (is_array($rec['attachments']) && in_array($id, $rec['attachments'])) {
|
||||||
|
@ -736,14 +738,17 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert invalid data
|
// convert invalid data
|
||||||
if (isset($rec['attendees']) && !is_array($rec['attendees']))
|
if (isset($rec['attendees']) && !is_array($rec['attendees'])) {
|
||||||
$rec['attendees'] = array();
|
$rec['attendees'] = array();
|
||||||
|
}
|
||||||
|
|
||||||
foreach ((array)$rec['attendees'] as $i => $attendee) {
|
if (!empty($rec['attendees'])) {
|
||||||
|
foreach ((array) $rec['attendees'] as $i => $attendee) {
|
||||||
if (is_string($attendee['rsvp'])) {
|
if (is_string($attendee['rsvp'])) {
|
||||||
$rec['attendees'][$i]['rsvp'] = $attendee['rsvp'] == 'true' || $attendee['rsvp'] == '1';
|
$rec['attendees'][$i]['rsvp'] = $attendee['rsvp'] == 'true' || $attendee['rsvp'] == '1';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// copy the task status to my attendee partstat
|
// copy the task status to my attendee partstat
|
||||||
if (!empty($rec['_reportpartstat'])) {
|
if (!empty($rec['_reportpartstat'])) {
|
||||||
|
@ -1000,7 +1005,7 @@ class tasklist extends rcube_plugin
|
||||||
$list += array('showalarms' => true, 'active' => true, 'editable' => true);
|
$list += array('showalarms' => true, 'active' => true, 'editable' => true);
|
||||||
if ($insert_id = $this->driver->create_list($list)) {
|
if ($insert_id = $this->driver->create_list($list)) {
|
||||||
$list['id'] = $insert_id;
|
$list['id'] = $insert_id;
|
||||||
if (!$list['_reload']) {
|
if (empty($list['_reload'])) {
|
||||||
$this->load_ui();
|
$this->load_ui();
|
||||||
$list['html'] = $this->ui->tasklist_list_item($insert_id, $list, $jsenv);
|
$list['html'] = $this->ui->tasklist_list_item($insert_id, $list, $jsenv);
|
||||||
$list += (array)$jsenv[$insert_id];
|
$list += (array)$jsenv[$insert_id];
|
||||||
|
@ -1048,7 +1053,7 @@ class tasklist extends rcube_plugin
|
||||||
$results[] = $prop;
|
$results[] = $prop;
|
||||||
}
|
}
|
||||||
// report more results available
|
// report more results available
|
||||||
if ($this->driver->search_more_results) {
|
if (!empty($this->driver->search_more_results)) {
|
||||||
$this->rc->output->show_message('autocompletemore', 'notice');
|
$this->rc->output->show_message('autocompletemore', 'notice');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,10 +1061,12 @@ class tasklist extends rcube_plugin
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($success)
|
if ($success) {
|
||||||
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
$this->rc->output->show_message('tasklist.errorsaving', 'error');
|
$this->rc->output->show_message('tasklist.errorsaving', 'error');
|
||||||
|
}
|
||||||
|
|
||||||
$this->rc->output->command('plugin.unlock_saving');
|
$this->rc->output->command('plugin.unlock_saving');
|
||||||
}
|
}
|
||||||
|
@ -1074,10 +1081,11 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
foreach ($this->driver->get_lists() as $list) {
|
foreach ($this->driver->get_lists() as $list) {
|
||||||
if ($list['active'])
|
if (!empty($list['active'])) {
|
||||||
$lists[] = $list['id'];
|
$lists[] = $list['id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$counts = $this->driver->count_tasks($lists);
|
$counts = $this->driver->count_tasks($lists);
|
||||||
$this->rc->output->command('plugin.update_counts', $counts);
|
$this->rc->output->command('plugin.update_counts', $counts);
|
||||||
}
|
}
|
||||||
|
@ -1161,7 +1169,7 @@ class tasklist extends rcube_plugin
|
||||||
$data = $this->task_tree = $this->task_titles = array();
|
$data = $this->task_tree = $this->task_titles = array();
|
||||||
|
|
||||||
foreach ($records as $rec) {
|
foreach ($records as $rec) {
|
||||||
if ($rec['parent_id']) {
|
if (!empty($rec['parent_id'])) {
|
||||||
$this->task_tree[$rec['id']] = $rec['parent_id'];
|
$this->task_tree[$rec['id']] = $rec['parent_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1224,19 +1232,21 @@ class tasklist extends rcube_plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rec['valarms']) {
|
if (!empty($rec['valarms'])) {
|
||||||
$rec['alarms_text'] = libcalendaring::alarms_text($rec['valarms']);
|
$rec['alarms_text'] = libcalendaring::alarms_text($rec['valarms']);
|
||||||
$rec['valarms'] = libcalendaring::to_client_alarms($rec['valarms']);
|
$rec['valarms'] = libcalendaring::to_client_alarms($rec['valarms']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rec['recurrence']) {
|
if (!empty($rec['recurrence'])) {
|
||||||
$rec['recurrence_text'] = $this->lib->recurrence_text($rec['recurrence']);
|
$rec['recurrence_text'] = $this->lib->recurrence_text($rec['recurrence']);
|
||||||
$rec['recurrence'] = $this->lib->to_client_recurrence($rec['recurrence'], $rec['time'] || $rec['starttime']);
|
$rec['recurrence'] = $this->lib->to_client_recurrence($rec['recurrence'], $rec['time'] || $rec['starttime']);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ((array)$rec['attachments'] as $k => $attachment) {
|
if (!empty($rec['attachments'])) {
|
||||||
|
foreach ((array) $rec['attachments'] as $k => $attachment) {
|
||||||
$rec['attachments'][$k]['classname'] = rcube_utils::file2class($attachment['mimetype'], $attachment['name']);
|
$rec['attachments'][$k]['classname'] = rcube_utils::file2class($attachment['mimetype'], $attachment['name']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// convert link URIs references into structs
|
// convert link URIs references into structs
|
||||||
if (array_key_exists('links', $rec)) {
|
if (array_key_exists('links', $rec)) {
|
||||||
|
@ -1283,11 +1293,13 @@ class tasklist extends rcube_plugin
|
||||||
{
|
{
|
||||||
$rec['_depth'] = 0;
|
$rec['_depth'] = 0;
|
||||||
$parent_titles = array();
|
$parent_titles = array();
|
||||||
$parent_id = $this->task_tree[$rec['id']];
|
$parent_id = isset($this->task_tree[$rec['id']]) ? $this->task_tree[$rec['id']] : null;
|
||||||
while ($parent_id) {
|
while ($parent_id) {
|
||||||
$rec['_depth']++;
|
$rec['_depth']++;
|
||||||
|
if (isset($this->task_titles[$parent_id])) {
|
||||||
array_unshift($parent_titles, $this->task_titles[$parent_id]);
|
array_unshift($parent_titles, $this->task_titles[$parent_id]);
|
||||||
$parent_id = $this->task_tree[$parent_id];
|
}
|
||||||
|
$parent_id = isset($this->task_tree[$parent_id]) ? $this->task_tree[$parent_id] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($parent_titles)) {
|
if (count($parent_titles)) {
|
||||||
|
@ -1702,7 +1714,7 @@ class tasklist extends rcube_plugin
|
||||||
header("Content-Disposition: inline; filename=\"". $plugin['filename'] ."\"");
|
header("Content-Disposition: inline; filename=\"". $plugin['filename'] ."\"");
|
||||||
|
|
||||||
$this->get_ical()->export($plugin['result'], '', true,
|
$this->get_ical()->export($plugin['result'], '', true,
|
||||||
$plugins['attachments'] ? array($this->driver, 'get_attachment_body') : null);
|
!empty($plugin['attachments']) ? array($this->driver, 'get_attachment_body') : null);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1927,7 +1939,7 @@ class tasklist extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public function mail_message_load($p)
|
public function mail_message_load($p)
|
||||||
{
|
{
|
||||||
if (!$p['object']->headers->others['x-kolab-type']) {
|
if (empty($p['object']->headers->others['x-kolab-type'])) {
|
||||||
$this->load_driver();
|
$this->load_driver();
|
||||||
$this->message_tasks = $this->driver->get_message_related_tasks($p['object']->headers, $p['object']->folder);
|
$this->message_tasks = $this->driver->get_message_related_tasks($p['object']->headers, $p['object']->folder);
|
||||||
|
|
||||||
|
@ -1950,7 +1962,7 @@ class tasklist extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public function get_ical()
|
public function get_ical()
|
||||||
{
|
{
|
||||||
if (!$this->ical) {
|
if (empty($this->ical)) {
|
||||||
$this->ical = libcalendaring::get_ical();
|
$this->ical = libcalendaring::get_ical();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2442,7 +2454,7 @@ class tasklist extends rcube_plugin
|
||||||
if ($task['flagged']) {
|
if ($task['flagged']) {
|
||||||
$object['priority'] = 1;
|
$object['priority'] = 1;
|
||||||
}
|
}
|
||||||
else if (!$task['priority']) {
|
else if (empty($task['priority'])) {
|
||||||
$object['priority'] = 0;
|
$object['priority'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,9 @@ class tasklist_ui
|
||||||
|
|
||||||
// get user identity to create default attendee
|
// get user identity to create default attendee
|
||||||
foreach ($this->rc->user->list_emails() as $rec) {
|
foreach ($this->rc->user->list_emails() as $rec) {
|
||||||
if (!$identity)
|
if (empty($identity)) {
|
||||||
$identity = $rec;
|
$identity = $rec;
|
||||||
|
}
|
||||||
|
|
||||||
$identity['emails'][] = $rec['email'];
|
$identity['emails'][] = $rec['email'];
|
||||||
$settings['identities'][$rec['identity_id']] = $rec['email'];
|
$settings['identities'][$rec['identity_id']] = $rec['email'];
|
||||||
|
@ -184,14 +185,15 @@ class tasklist_ui
|
||||||
|
|
||||||
$html = '';
|
$html = '';
|
||||||
foreach ((array)$lists as $id => $prop) {
|
foreach ((array)$lists as $id => $prop) {
|
||||||
if ($attrib['activeonly'] && !$prop['active'])
|
if (!empty($attrib['activeonly']) && empty($prop['active'])) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$html .= html::tag('li', array(
|
$html .= html::tag('li', array(
|
||||||
'id' => 'rcmlitasklist' . rcube_utils::html_identifier($id),
|
'id' => 'rcmlitasklist' . rcube_utils::html_identifier($id),
|
||||||
'class' => $prop['group'],
|
'class' => isset($prop['group']) ? $prop['group'] : null,
|
||||||
),
|
),
|
||||||
$this->tasklist_list_item($id, $prop, $jsenv, $attrib['activeonly'])
|
$this->tasklist_list_item($id, $prop, $jsenv, !empty($attrib['activeonly']))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +243,7 @@ class tasklist_ui
|
||||||
public function tasklist_list_item($id, $prop, &$jsenv, $activeonly = false)
|
public function tasklist_list_item($id, $prop, &$jsenv, $activeonly = false)
|
||||||
{
|
{
|
||||||
// enrich list properties with settings from the driver
|
// enrich list properties with settings from the driver
|
||||||
if (!$prop['virtual']) {
|
if (empty($prop['virtual'])) {
|
||||||
unset($prop['user_id']);
|
unset($prop['user_id']);
|
||||||
$prop['alarms'] = $this->plugin->driver->alarms;
|
$prop['alarms'] = $this->plugin->driver->alarms;
|
||||||
$prop['undelete'] = $this->plugin->driver->undelete;
|
$prop['undelete'] = $this->plugin->driver->undelete;
|
||||||
|
@ -253,17 +255,27 @@ class tasklist_ui
|
||||||
}
|
}
|
||||||
|
|
||||||
$classes = array('tasklist');
|
$classes = array('tasklist');
|
||||||
$title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
|
$title = '';
|
||||||
html_entity_decode($prop['name'], ENT_COMPAT, RCUBE_CHARSET) : '');
|
|
||||||
|
|
||||||
if ($prop['virtual'])
|
if (!empty($prop['title'])) {
|
||||||
|
$title = $prop['title'];
|
||||||
|
}
|
||||||
|
else if (empty($prop['listname']) || $prop['name'] != $prop['listname'] || strlen($prop['name']) > 25) {
|
||||||
|
html_entity_decode($prop['name'], ENT_COMPAT, RCUBE_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($prop['virtual'])) {
|
||||||
$classes[] = 'virtual';
|
$classes[] = 'virtual';
|
||||||
else if (!$prop['editable'])
|
}
|
||||||
|
else if (empty($prop['editable'])) {
|
||||||
$classes[] = 'readonly';
|
$classes[] = 'readonly';
|
||||||
if ($prop['subscribed'])
|
}
|
||||||
|
if (!empty($prop['subscribed'])) {
|
||||||
$classes[] = 'subscribed';
|
$classes[] = 'subscribed';
|
||||||
if ($prop['class'])
|
}
|
||||||
|
if (!empty($prop['class'])) {
|
||||||
$classes[] = $prop['class'];
|
$classes[] = $prop['class'];
|
||||||
|
}
|
||||||
|
|
||||||
if (!$activeonly || $prop['active']) {
|
if (!$activeonly || $prop['active']) {
|
||||||
$label_id = 'tl:' . $id;
|
$label_id = 'tl:' . $id;
|
||||||
|
@ -277,9 +289,10 @@ class tasklist_ui
|
||||||
));
|
));
|
||||||
|
|
||||||
return html::div(join(' ', $classes),
|
return html::div(join(' ', $classes),
|
||||||
html::a(array('class' => 'listname', 'title' => $title, 'href' => '#', 'id' => $label_id), $prop['listname'] ?: $prop['name']) .
|
html::a(array('class' => 'listname', 'title' => $title, 'href' => '#', 'id' => $label_id),
|
||||||
($prop['virtual'] ? '' : $chbox . html::span('actions',
|
!empty($prop['listname']) ? $prop['listname'] : $prop['name']) .
|
||||||
($prop['removable'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->plugin->gettext('removelist')), ' ') : '')
|
(!empty($prop['virtual']) ? '' : $chbox . html::span('actions',
|
||||||
|
(!empty($prop['removable']) ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->plugin->gettext('removelist')), ' ') : '')
|
||||||
. html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->plugin->gettext('focusview'), 'role' => 'checkbox', 'aria-checked' => 'false'), ' ')
|
. html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->plugin->gettext('focusview'), 'role' => 'checkbox', 'aria-checked' => 'false'), ' ')
|
||||||
. (isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->plugin->gettext('tasklistsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '')
|
. (isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->plugin->gettext('tasklistsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '')
|
||||||
)
|
)
|
||||||
|
@ -319,17 +332,20 @@ class tasklist_ui
|
||||||
$select = new html_select($attrib);
|
$select = new html_select($attrib);
|
||||||
$default = null;
|
$default = null;
|
||||||
|
|
||||||
|
if (!empty($attrib['extra'])) {
|
||||||
foreach ((array) $attrib['extra'] as $id => $name) {
|
foreach ((array) $attrib['extra'] as $id => $name) {
|
||||||
$select->add($name, $id);
|
$select->add($name, $id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ((array)$this->plugin->driver->get_lists() as $id => $prop) {
|
foreach ((array) $this->plugin->driver->get_lists() as $id => $prop) {
|
||||||
if ($prop['editable'] || strpos($prop['rights'], 'i') !== false) {
|
if (!empty($prop['editable']) || strpos($prop['rights'], 'i') !== false) {
|
||||||
$select->add($prop['name'], $id);
|
$select->add($prop['name'], $id);
|
||||||
if (!$default || $prop['default'])
|
if (!$default || !empty($prop['default'])) {
|
||||||
$default = $id;
|
$default = $id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $select->show($default);
|
return $select->show($default);
|
||||||
}
|
}
|
||||||
|
@ -421,7 +437,12 @@ class tasklist_ui
|
||||||
$attrib += array('id' => 'rcmtasktagsedit');
|
$attrib += array('id' => 'rcmtasktagsedit');
|
||||||
$this->register_gui_object('edittagline', $attrib['id']);
|
$this->register_gui_object('edittagline', $attrib['id']);
|
||||||
|
|
||||||
$input = new html_inputfield(array('name' => 'tags[]', 'class' => 'tag', 'size' => $attrib['size'], 'tabindex' => $attrib['tabindex']));
|
$input = new html_inputfield(array(
|
||||||
|
'name' => 'tags[]',
|
||||||
|
'class' => 'tag',
|
||||||
|
'size' => !empty($attrib['size']) ? $attrib['size'] : null,
|
||||||
|
'tabindex' => isset($attrib['tabindex']) ? $attrib['tabindex'] : null,
|
||||||
|
));
|
||||||
unset($attrib['tabindex']);
|
unset($attrib['tabindex']);
|
||||||
return html::div($attrib, $input->show(''));
|
return html::div($attrib, $input->show(''));
|
||||||
}
|
}
|
||||||
|
@ -461,9 +482,21 @@ class tasklist_ui
|
||||||
*/
|
*/
|
||||||
function attendees_form($attrib = array())
|
function attendees_form($attrib = array())
|
||||||
{
|
{
|
||||||
$input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'size' => $attrib['size'], 'class' => 'form-control'));
|
$input = new html_inputfield(array(
|
||||||
$textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment',
|
'name' => 'participant',
|
||||||
'rows' => 4, 'cols' => 55, 'title' => $this->plugin->gettext('itipcommenttitle'), 'class' => 'form-control'));
|
'id' => 'edit-attendee-name',
|
||||||
|
'size' => !empty($attrib['size']) ? $attrib['size'] : null,
|
||||||
|
'class' => 'form-control'
|
||||||
|
));
|
||||||
|
|
||||||
|
$textarea = new html_textarea(array(
|
||||||
|
'name' => 'comment',
|
||||||
|
'id' => 'edit-attendees-comment',
|
||||||
|
'rows' => 4,
|
||||||
|
'cols' => 55,
|
||||||
|
'title' => $this->plugin->gettext('itipcommenttitle'),
|
||||||
|
'class' => 'form-control'
|
||||||
|
));
|
||||||
|
|
||||||
return html::div($attrib,
|
return html::div($attrib,
|
||||||
html::div('form-searchbar', $input->show() . " " .
|
html::div('form-searchbar', $input->show() . " " .
|
||||||
|
@ -488,7 +521,7 @@ class tasklist_ui
|
||||||
*/
|
*/
|
||||||
function tasks_import_form($attrib = array())
|
function tasks_import_form($attrib = array())
|
||||||
{
|
{
|
||||||
if (!$attrib['id']) {
|
if (empty($attrib['id'])) {
|
||||||
$attrib['id'] = 'rcmImportForm';
|
$attrib['id'] = 'rcmImportForm';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,7 +536,7 @@ class tasklist_ui
|
||||||
'id' => 'importfile',
|
'id' => 'importfile',
|
||||||
'type' => 'file',
|
'type' => 'file',
|
||||||
'name' => '_data',
|
'name' => '_data',
|
||||||
'size' => $attrib['uploadfieldsize'],
|
'size' => !empty($attrib['uploadfieldsize']) ? $attrib['uploadfieldsize'] : null,
|
||||||
'accept' => $accept
|
'accept' => $accept
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -537,11 +570,11 @@ class tasklist_ui
|
||||||
*/
|
*/
|
||||||
function tasks_export_form($attrib = array())
|
function tasks_export_form($attrib = array())
|
||||||
{
|
{
|
||||||
if (!$attrib['id']) {
|
if (empty($attrib['id'])) {
|
||||||
$attrib['id'] = 'rcmTaskExportForm';
|
$attrib['id'] = 'rcmTaskExportForm';
|
||||||
}
|
}
|
||||||
|
|
||||||
$html .= html::div('form-section form-group row',
|
$html = html::div('form-section form-group row',
|
||||||
html::label(array('for' => 'task-export-list', 'class' => 'col-sm-4 col-form-label'), $this->plugin->gettext('list'))
|
html::label(array('for' => 'task-export-list', 'class' => 'col-sm-4 col-form-label'), $this->plugin->gettext('list'))
|
||||||
. html::div('col-sm-8', $this->tasklist_select(array(
|
. html::div('col-sm-8', $this->tasklist_select(array(
|
||||||
'name' => 'source',
|
'name' => 'source',
|
||||||
|
|
Loading…
Add table
Reference in a new issue