diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 9880da57..b2e79abb 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -595,6 +595,24 @@ class calendar extends rcube_plugin 'title' => rcube::Q($this->gettext('birthdayscalendarsources')), 'content' => join(html::br(), $sources), ); + + $field_id = 'rcmfd_birthdays_alarm'; + $select_type = new html_select(array('name' => '_birthdays_alarm_type', 'id' => $field_id)); + $select_type->add($this->gettext('none'), ''); + foreach ($this->driver->alarm_types as $type) { + $select_type->add(rcube_label(strtolower("alarm{$type}option"), 'libcalendaring'), $type); + } + + $input_value = new html_inputfield(array('name' => '_birthdays_alarm_value', 'id' => $field_id . 'value', 'size' => 3)); + $select_offset = new html_select(array('name' => '_birthdays_alarm_offset', 'id' => $field_id . 'offset')); + foreach (array('-M','-H','-D') as $trigger) + $select_offset->add(rcube_label('trigger' . $trigger, 'libcalendaring'), $trigger); + + $preset = libcalendaring::parse_alaram_value($this->rc->config->get('calendar_birthdays_alarm_offset', '-1D')); + $p['blocks']['birthdays']['options']['birthdays_alarmoffset'] = array( + 'title' => html::label($field_id . 'value', rcube::Q($this->gettext('showalarms'))), + 'content' => $select_type->show($this->rc->config->get('calendar_birthdays_alarm_type', '')) . ' ' . $input_value->show($preset[0]) . ' ' . $select_offset->show($preset[1]), + ); } return $p; @@ -616,6 +634,9 @@ class calendar extends rcube_plugin $alarm_offset = get_input_value('_alarm_offset', RCUBE_INPUT_POST); $default_alarm = $alarm_offset[0] . intval(get_input_value('_alarm_value', RCUBE_INPUT_POST)) . $alarm_offset[1]; + $birthdays_alarm_offset = get_input_value('_birthdays_alarm_offset', RCUBE_INPUT_POST); + $birthdays_alarm_value = $birthdays_alarm_offset[0] . intval(get_input_value('_birthdays_alarm_value', RCUBE_INPUT_POST)) . $birthdays_alarm_offset[1]; + $p['prefs'] = array( 'calendar_default_view' => get_input_value('_default_view', RCUBE_INPUT_POST), 'calendar_timeslots' => intval(get_input_value('_timeslots', RCUBE_INPUT_POST)), @@ -631,6 +652,8 @@ class calendar extends rcube_plugin 'calendar_time_format' => null, 'calendar_contact_birthdays' => get_input_value('_contact_birthdays', RCUBE_INPUT_POST) ? true : false, 'calendar_birthday_adressbooks' => array_filter((array)get_input_value('_birthday_adressbooks', RCUBE_INPUT_POST)), + 'calendar_birthdays_alarm_type' => get_input_value('_birthdays_alarm_type', RCUBE_INPUT_POST), + 'calendar_birthdays_alarm_offset' => $birthdays_alarm_value, ); // categories @@ -1012,13 +1035,34 @@ class calendar extends rcube_plugin public function pending_alarms($p) { $this->load_driver(); - if ($alarms = $this->driver->pending_alarms($p['time'] ?: time())) { + $time = $p['time'] ?: time(); + if ($alarms = $this->driver->pending_alarms($time)) { foreach ($alarms as $alarm) { $alarm['id'] = 'cal:' . $alarm['id']; // prefix ID with cal: $p['alarms'][] = $alarm; } } + // get alarms for birthdays calendar + if ($this->rc->config->get('calendar_contact_birthdays') && $this->rc->config->get('calendar_birthdays_alarm_type') == 'DISPLAY') { + $cache = $this->rc->get_cache('calendar.birthdayalarms', 'db'); + + foreach ($this->driver->load_birthday_events($time, $time + 86400 * 60) as $e) { + $alarm = libcalendaring::get_next_alarm($e); + + // overwrite alarm time with snooze value (or null if dismissed) + if ($dismissed = $cache->get($e['id'])) + $alarm['time'] = $dismissed['notifyat']; + + // add to list if alarm is set + if ($alarm && $alarm['time'] && $alarm['time'] <= $time) { + $e['id'] = 'cal:bday:' . $e['id']; + $e['notifyat'] = $alarm['time']; + $p['alarms'][] = $e; + } + } + } + return $p; } @@ -1029,8 +1073,12 @@ class calendar extends rcube_plugin { $this->load_driver(); foreach ((array)$p['ids'] as $id) { - if (strpos($id, 'cal:') === 0) + if (strpos($id, 'cal:bday:') === 0) { + $p['success'] |= $this->driver->dismiss_birthday_alarm(substr($id, 9), $p['snooze']); + } + else if (strpos($id, 'cal:') === 0) { $p['success'] |= $this->driver->dismiss_alarm(substr($id, 4), $p['snooze']); + } } return $p; diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php index 1f6b2587..a7ad0e56 100644 --- a/plugins/calendar/drivers/calendar_driver.php +++ b/plugins/calendar/drivers/calendar_driver.php @@ -429,6 +429,10 @@ abstract class calendar_driver $cache = $rcmail->get_cache('calendar.birthdays', 'db', 3600); $cache->expunge(); + $alarm_type = $rcmail->config->get('calendar_birthdays_alarm_type', ''); + $alarm_offset = $rcmail->config->get('calendar_birthdays_alarm_offset', '-1D'); + $alarms = $alarm_type ? $alarm_offset . ':' . $alarm_type : null; + // let the user select the address books to consider in prefs $selected_sources = $rcmail->config->get('calendar_birthday_adressbooks'); $sources = $selected_sources ?: array_keys($rcmail->get_address_sources(false, true)); @@ -493,14 +497,14 @@ abstract class calendar_driver if ($bday <= $end && $bday >= $start) { $age = $year - $birthyear; $event = array( - 'id' => md5('bday_' . $contact['id']), + 'id' => md5('bday_' . $contact['id'] . $year), 'calendar' => self::BIRTHDAY_CALENDAR_ID, 'title' => $event_title, 'description' => $rcmail->gettext(array('name' => 'birthdayage', 'vars' => array('age' => $age)), 'calendar'), // Add more contact information to description block? 'allday' => true, 'start' => $bday, - // TODO: add alarms (configurable?) + 'alarms' => $alarms, ); $event['end'] = clone $bday; $event['end']->add(new DateInterval('PT1H')); @@ -519,4 +523,23 @@ abstract class calendar_driver return $events; } + /** + * Store alarm dismissal for birtual birthay events + * + * @param string Event identifier + * @param integer Suspend the alarm for this number of seconds + */ + public function dismiss_birthday_alarm($event_id, $snooze = 0) + { + $rcmail = rcmail::get_instance(); + $cache = $rcmail->get_cache('calendar.birthdayalarms', 'db', 86400 * 30); + $cache->remove($event_id); + + // compute new notification time or disable if not snoozed + $notifyat = $snooze > 0 ? time() + $snooze : null; + $cache->set($event_id, array('snooze' => $snooze, 'notifyat' => $notifyat)); + + return true; + } + } diff --git a/plugins/calendar/drivers/database/database_driver.php b/plugins/calendar/drivers/database/database_driver.php index 18fed049..0c2d030e 100644 --- a/plugins/calendar/drivers/database/database_driver.php +++ b/plugins/calendar/drivers/database/database_driver.php @@ -139,7 +139,7 @@ class database_driver extends calendar_driver 'name' => $this->cal->gettext('birthdays'), 'listname' => $this->cal->gettext('birthdays'), 'color' => $prefs['color'], - 'showalarms' => $prefs['showalarms'], + 'showalarms' => (bool)$this->rc->config->get('calendar_birthdays_alarm_type'), 'active' => !in_array($id, $hidden), 'class_name' => 'birthdays', 'readonly' => true, @@ -187,12 +187,12 @@ class database_driver extends calendar_driver { // birthday calendar properties are saved in user prefs if ($prop['id'] == self::BIRTHDAY_CALENDAR_ID) { - $prefs = $this->rc->config->get('birthday_calendar', array('color' => '87CEFA')); + $prefs['birthday_calendar'] = $this->rc->config->get('birthday_calendar', array('color' => '87CEFA')); if (isset($prop['color'])) - $prefs['color'] = $prop['color']; + $prefs['birthday_calendar']['color'] = $prop['color']; if (isset($prop['showalarms'])) - $prefs['showalarms'] = $prop['showalarms'] ? true : false; - $this->rc->user->save_prefs(array('birthday_calendar' => $prefs)); + $prefs['calendar_birthdays_alarm_type'] = $prop['showalarms'] ? $this->alarm_types[0] : ''; + $this->rc->user->save_prefs($prefs); return true; } diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index 87a5f022..dd85ffc0 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -155,8 +155,8 @@ class kolab_driver extends calendar_driver 'name' => $this->cal->gettext('birthdays'), 'listname' => $this->cal->gettext('birthdays'), 'color' => $prefs[$id]['color'], - 'showalarms' => $prefs[$id]['showalarms'], 'active' => $prefs[$id]['active'], + 'showalarms' => (bool)$this->rc->config->get('calendar_birthdays_alarm_type'), 'class_name' => 'birthdays', 'readonly' => true, 'default' => false, @@ -276,7 +276,10 @@ class kolab_driver extends calendar_driver if (isset($prop['color'])) $prefs['kolab_calendars'][$id]['color'] = $prop['color']; - if (isset($prop['showalarms'])) + + if (isset($prop['showalarms']) && $id == self::BIRTHDAY_CALENDAR_ID) + $prefs['calendar_birthdays_alarm_type'] = $prop['showalarms'] ? $this->alarm_types[0] : ''; + else if (isset($prop['showalarms'])) $prefs['kolab_calendars'][$id]['showalarms'] = $prop['showalarms'] ? true : false; if (!empty($prefs['kolab_calendars'][$id]))