예제 #1
0
 /**
  * libcalendaring::parse_alarm_value()
  */
 function test_parse_alarm_value()
 {
     $alarm = libcalendaring::parse_alarm_value('-15M');
     $this->assertEquals('15', $alarm[0]);
     $this->assertEquals('-M', $alarm[1]);
     $this->assertEquals('-PT15M', $alarm[3]);
     $alarm = libcalendaring::parse_alarm_value('-PT5H');
     $this->assertEquals('5', $alarm[0]);
     $this->assertEquals('-H', $alarm[1]);
     $alarm = libcalendaring::parse_alarm_value('P0DT1H0M0S');
     $this->assertEquals('1', $alarm[0]);
     $this->assertEquals('+H', $alarm[1]);
     // FIXME: this should return something like (1140 + 120 + 30)M
     $alarm = libcalendaring::parse_alarm_value('-P1DT2H30M');
     // $this->assertEquals('1590', $alarm[0]);
     // $this->assertEquals('-M',   $alarm[1]);
     $alarm = libcalendaring::parse_alarm_value('@1420722000');
     $this->assertInstanceOf('DateTime', $alarm[0]);
 }
예제 #2
0
 /**
  * Process the alarms values submitted by the client
  */
 public static function from_client_alarms($valarms)
 {
     return array_map(function ($alarm) {
         if ($alarm['trigger'][0] == '@') {
             try {
                 $alarm['trigger'] = new DateTime($alarm['trigger']);
                 $alarm['trigger']->setTimezone(new DateTimeZone('UTC'));
             } catch (Exception $e) {
                 /* handle this ? */
             }
         } else {
             if ($trigger = libcalendaring::parse_alarm_value($alarm['trigger'])) {
                 $alarm['trigger'] = $trigger[3];
             }
         }
         return $alarm;
     }, (array) $valarms);
 }
예제 #3
0
 /**
  * Handler for preferences_list hook.
  * Adds options blocks into Calendar settings sections in Preferences.
  *
  * @param array Original parameters
  * @return array Modified parameters
  */
 function preferences_list($p)
 {
     if ($p['section'] != 'calendar') {
         return $p;
     }
     $no_override = array_flip((array) $this->rc->config->get('dont_override'));
     $p['blocks']['view']['name'] = $this->gettext('mainoptions');
     if (!isset($no_override['calendar_default_view'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         $field_id = 'rcmfd_default_view';
         $select = new html_select(array('name' => '_default_view', 'id' => $field_id));
         $select->add($this->gettext('day'), "agendaDay");
         $select->add($this->gettext('week'), "agendaWeek");
         $select->add($this->gettext('month'), "month");
         $select->add($this->gettext('agenda'), "table");
         $p['blocks']['view']['options']['default_view'] = array('title' => html::label($field_id, rcube::Q($this->gettext('default_view'))), 'content' => $select->show($this->rc->config->get('calendar_default_view', $this->defaults['calendar_default_view'])));
     }
     if (!isset($no_override['calendar_timeslots'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         $field_id = 'rcmfd_timeslot';
         $choices = array('1', '2', '3', '4', '6');
         $select = new html_select(array('name' => '_timeslots', 'id' => $field_id));
         $select->add($choices);
         $p['blocks']['view']['options']['timeslots'] = array('title' => html::label($field_id, rcube::Q($this->gettext('timeslots'))), 'content' => $select->show(strval($this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']))));
     }
     if (!isset($no_override['calendar_first_day'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         $field_id = 'rcmfd_firstday';
         $select = new html_select(array('name' => '_first_day', 'id' => $field_id));
         $select->add($this->gettext('sunday'), '0');
         $select->add($this->gettext('monday'), '1');
         $select->add($this->gettext('tuesday'), '2');
         $select->add($this->gettext('wednesday'), '3');
         $select->add($this->gettext('thursday'), '4');
         $select->add($this->gettext('friday'), '5');
         $select->add($this->gettext('saturday'), '6');
         $p['blocks']['view']['options']['first_day'] = array('title' => html::label($field_id, rcube::Q($this->gettext('first_day'))), 'content' => $select->show(strval($this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']))));
     }
     if (!isset($no_override['calendar_first_hour'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         $time_format = $this->rc->config->get('time_format', libcalendaring::to_php_date_format($this->rc->config->get('calendar_time_format', $this->defaults['calendar_time_format'])));
         $select_hours = new html_select();
         for ($h = 0; $h < 24; $h++) {
             $select_hours->add(date($time_format, mktime($h, 0, 0)), $h);
         }
         $field_id = 'rcmfd_firsthour';
         $p['blocks']['view']['options']['first_hour'] = array('title' => html::label($field_id, rcube::Q($this->gettext('first_hour'))), 'content' => $select_hours->show($this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']), array('name' => '_first_hour', 'id' => $field_id)));
     }
     if (!isset($no_override['calendar_work_start'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         $field_id = 'rcmfd_workstart';
         $p['blocks']['view']['options']['workinghours'] = array('title' => html::label($field_id, rcube::Q($this->gettext('workinghours'))), 'content' => $select_hours->show($this->rc->config->get('calendar_work_start', $this->defaults['calendar_work_start']), array('name' => '_work_start', 'id' => $field_id)) . ' &mdash; ' . $select_hours->show($this->rc->config->get('calendar_work_end', $this->defaults['calendar_work_end']), array('name' => '_work_end', 'id' => $field_id)));
     }
     if (!isset($no_override['calendar_event_coloring'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         $field_id = 'rcmfd_coloring';
         $select_colors = new html_select(array('name' => '_event_coloring', 'id' => $field_id));
         $select_colors->add($this->gettext('coloringmode0'), 0);
         $select_colors->add($this->gettext('coloringmode1'), 1);
         $select_colors->add($this->gettext('coloringmode2'), 2);
         $select_colors->add($this->gettext('coloringmode3'), 3);
         $p['blocks']['view']['options']['eventcolors'] = array('title' => html::label($field_id . 'value', rcube::Q($this->gettext('eventcoloring'))), 'content' => $select_colors->show($this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring'])));
     }
     // loading driver is expensive, don't do it if not needed
     $this->load_driver();
     if (!isset($no_override['calendar_default_alarm_type']) || !isset($no_override['calendar_default_alarm_offset'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         $alarm_type = $alarm_offset = '';
         if (!isset($no_override['calendar_default_alarm_type'])) {
             $field_id = 'rcmfd_alarm';
             $select_type = new html_select(array('name' => '_alarm_type', 'id' => $field_id));
             $select_type->add($this->gettext('none'), '');
             foreach ($this->driver->alarm_types as $type) {
                 $select_type->add($this->rc->gettext(strtolower("alarm{$type}option"), 'libcalendaring'), $type);
             }
             $alarm_type = $select_type->show($this->rc->config->get('calendar_default_alarm_type', ''));
         }
         if (!isset($no_override['calendar_default_alarm_offset'])) {
             $field_id = 'rcmfd_alarm';
             $input_value = new html_inputfield(array('name' => '_alarm_value', 'id' => $field_id . 'value', 'size' => 3));
             $select_offset = new html_select(array('name' => '_alarm_offset', 'id' => $field_id . 'offset'));
             foreach (array('-M', '-H', '-D', '+M', '+H', '+D') as $trigger) {
                 $select_offset->add($this->rc->gettext('trigger' . $trigger, 'libcalendaring'), $trigger);
             }
             $preset = libcalendaring::parse_alarm_value($this->rc->config->get('calendar_default_alarm_offset', '-15M'));
             $alarm_offset = $input_value->show($preset[0]) . ' ' . $select_offset->show($preset[1]);
         }
         $p['blocks']['view']['options']['alarmtype'] = array('title' => html::label($field_id, rcube::Q($this->gettext('defaultalarmtype'))), 'content' => $alarm_type . ' ' . $alarm_offset);
     }
     if (!isset($no_override['calendar_default_calendar'])) {
         if (!$p['current']) {
             $p['blocks']['view']['content'] = true;
             return $p;
         }
         // default calendar selection
         $field_id = 'rcmfd_default_calendar';
         $select_cal = new html_select(array('name' => '_default_calendar', 'id' => $field_id, 'is_escaped' => true));
         foreach ((array) $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL) as $id => $prop) {
             $select_cal->add($prop['name'], strval($id));
             if ($prop['default']) {
                 $default_calendar = $id;
             }
         }
         $p['blocks']['view']['options']['defaultcalendar'] = array('title' => html::label($field_id . 'value', rcube::Q($this->gettext('defaultcalendar'))), 'content' => $select_cal->show($this->rc->config->get('calendar_default_calendar', $default_calendar)));
     }
     $p['blocks']['itip']['name'] = $this->gettext('itipoptions');
     // Invitations handling
     if (!isset($no_override['calendar_itip_after_action'])) {
         if (!$p['current']) {
             $p['blocks']['itip']['content'] = true;
             return $p;
         }
         $field_id = 'rcmfd_after_action';
         $select = new html_select(array('name' => '_after_action', 'id' => $field_id, 'onchange' => "\$('#{$field_id}_select')[this.value == 4 ? 'show' : 'hide']()"));
         $select->add($this->gettext('afternothing'), '');
         $select->add($this->gettext('aftertrash'), 1);
         $select->add($this->gettext('afterdelete'), 2);
         $select->add($this->gettext('afterflagdeleted'), 3);
         $select->add($this->gettext('aftermoveto'), 4);
         $val = $this->rc->config->get('calendar_itip_after_action', $this->defaults['calendar_itip_after_action']);
         if ($val !== null && $val !== '' && !is_int($val)) {
             $folder = $val;
             $val = 4;
         }
         $folders = $this->rc->folder_selector(array('id' => $field_id . '_select', 'name' => '_after_action_folder', 'maxlength' => 30, 'folder_filter' => 'mail', 'folder_rights' => 'w', 'style' => $val !== 4 ? 'display:none' : ''));
         $p['blocks']['itip']['options']['after_action'] = array('title' => html::label($field_id, rcube::Q($this->gettext('afteraction'))), 'content' => $select->show($val) . $folders->show($folder));
     }
     // category definitions
     if (!$this->driver->nocategories && !isset($no_override['calendar_categories'])) {
         $p['blocks']['categories']['name'] = $this->gettext('categories');
         if (!$p['current']) {
             $p['blocks']['categories']['content'] = true;
             return $p;
         }
         $categories = (array) $this->driver->list_categories();
         $categories_list = '';
         foreach ($categories as $name => $color) {
             $key = md5($name);
             $field_class = 'rcmfd_category_' . str_replace(' ', '_', $name);
             $category_remove = new html_inputfield(array('type' => 'button', 'value' => 'X', 'class' => 'button', 'onclick' => '$(this).parent().remove()', 'title' => $this->gettext('remove_category')));
             $category_name = new html_inputfield(array('name' => "_categories[{$key}]", 'class' => $field_class, 'size' => 30, 'disabled' => $this->driver->categoriesimmutable));
             $category_color = new html_inputfield(array('name' => "_colors[{$key}]", 'class' => "{$field_class} colors", 'size' => 6));
             $hidden = $this->driver->categoriesimmutable ? html::tag('input', array('type' => 'hidden', 'name' => "_categories[{$key}]", 'value' => $name)) : '';
             $categories_list .= html::div(null, $hidden . $category_name->show($name) . '&nbsp;' . $category_color->show($color) . '&nbsp;' . $category_remove->show());
         }
         $p['blocks']['categories']['options']['category_' . $name] = array('content' => html::div(array('id' => 'calendarcategories'), $categories_list));
         $field_id = 'rcmfd_new_category';
         $new_category = new html_inputfield(array('name' => '_new_category', 'id' => $field_id, 'size' => 30));
         $add_category = new html_inputfield(array('type' => 'button', 'class' => 'button', 'value' => $this->gettext('add_category'), 'onclick' => "rcube_calendar_add_category()"));
         $p['blocks']['categories']['options']['categories'] = array('content' => $new_category->show('') . '&nbsp;' . $add_category->show());
         $this->rc->output->add_script('function rcube_calendar_add_category(){
       var name = $("#rcmfd_new_category").val();
       if (name.length) {
         var input = $("<input>").attr("type", "text").attr("name", "_categories[]").attr("size", 30).val(name);
         var color = $("<input>").attr("type", "text").attr("name", "_colors[]").attr("size", 6).addClass("colors").val("000000");
         var button = $("<input>").attr("type", "button").attr("value", "X").addClass("button").click(function(){ $(this).parent().remove() });
         $("<div>").append(input).append("&nbsp;").append(color).append("&nbsp;").append(button).appendTo("#calendarcategories");
         color.miniColors({ colorValues:(rcmail.env.mscolors || []) });
         $("#rcmfd_new_category").val("");
       }
     }');
         $this->rc->output->add_script('$("#rcmfd_new_category").keypress(function(event){
       if (event.which == 13) {
         rcube_calendar_add_category();
         event.preventDefault();
       }
     });
     ', 'docready');
         // load miniColors js/css files
         jqueryui::miniColors();
     }
     // virtual birthdays calendar
     if (!isset($no_override['calendar_contact_birthdays'])) {
         $p['blocks']['birthdays']['name'] = $this->gettext('birthdayscalendar');
         if (!$p['current']) {
             $p['blocks']['birthdays']['content'] = true;
             return $p;
         }
         $field_id = 'rcmfd_contact_birthdays';
         $input = new html_checkbox(array('name' => '_contact_birthdays', 'id' => $field_id, 'value' => 1, 'onclick' => '$(".calendar_birthday_props").prop("disabled",!this.checked)'));
         $p['blocks']['birthdays']['options']['contact_birthdays'] = array('title' => html::label($field_id, $this->gettext('displaybirthdayscalendar')), 'content' => $input->show($this->rc->config->get('calendar_contact_birthdays') ? 1 : 0));
         $input_attrib = array('class' => 'calendar_birthday_props', 'disabled' => !$this->rc->config->get('calendar_contact_birthdays'));
         $sources = array();
         $checkbox = new html_checkbox(array('name' => '_birthday_adressbooks[]') + $input_attrib);
         foreach ($this->rc->get_address_sources(false, true) as $source) {
             $active = in_array($source['id'], (array) $this->rc->config->get('calendar_birthday_adressbooks', array())) ? $source['id'] : '';
             $sources[] = html::label(null, $checkbox->show($active, array('value' => $source['id'])) . '&nbsp;' . rcube::Q($source['realname'] ?: $source['name']));
         }
         $p['blocks']['birthdays']['options']['birthday_adressbooks'] = array('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) + $input_attrib);
         $select_type->add($this->gettext('none'), '');
         foreach ($this->driver->alarm_types as $type) {
             $select_type->add($this->rc->gettext(strtolower("alarm{$type}option"), 'libcalendaring'), $type);
         }
         $input_value = new html_inputfield(array('name' => '_birthdays_alarm_value', 'id' => $field_id . 'value', 'size' => 3) + $input_attrib);
         $select_offset = new html_select(array('name' => '_birthdays_alarm_offset', 'id' => $field_id . 'offset') + $input_attrib);
         foreach (array('-M', '-H', '-D') as $trigger) {
             $select_offset->add($this->rc->gettext('trigger' . $trigger, 'libcalendaring'), $trigger);
         }
         $preset = libcalendaring::parse_alarm_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]) . '&nbsp;' . $select_offset->show($preset[1]));
     }
     return $p;
 }
예제 #4
0
 /**
  * Build a valid iCal format block from the given event
  *
  * @param  array    Hash array with event/task properties from libkolab
  * @param  object   VCalendar object to append event to or false for directly sending data to stdout
  * @param  callable Callback function to fetch attachment contents, false if no attachment export
  * @param  object   RECURRENCE-ID property when serializing a recurrence exception
  */
 private function _to_ical($event, $vcal, $get_attachment, $recurrence_id = null)
 {
     $type = $event['_type'] ?: 'event';
     $vcal_creator = new VObject\Component\VCalendar();
     $ve = $vcal_creator->createComponent($this->type_component_map[$type]);
     $ve->add('UID', $event['uid']);
     // set DTSTAMP according to RFC 5545, 3.8.7.2.
     $dtstamp = !empty($event['changed']) && !empty($this->method) ? $event['changed'] : new DateTime();
     $ve->add('DTSTAMP', $dtstamp);
     if ($event['allday']) {
         $ve->DTSTAMP['VALUE'] = 'DATE';
     }
     if (!empty($event['created'])) {
         $ve->add('CREATED', $event['created']);
     }
     if (!empty($event['changed'])) {
         $ve->add('LAST-MODIFIED', $event['changed']);
     }
     if (!empty($event['start'])) {
         $ve->add('DTSTART', $event['start']);
     }
     if ($event['allday']) {
         $ve->DTSTART['VALUE'] = 'DATE';
     }
     if (!empty($event['end'])) {
         $ve->add('DTEND', $event['end']);
     }
     if ($event['allday']) {
         $ve->DTEND['VALUE'] = 'DATE';
     }
     if (!empty($event['due'])) {
         $ve->add('DUE', $event['due']);
     }
     // we're exporting a recurrence instance only
     if (!$recurrence_id && $event['recurrence_date'] && $event['recurrence_date'] instanceof DateTime) {
         $recurrence_id = $vcal_creator->createProperty('RECURRENCE-ID');
         $recurrence_id->setDateTime($event['recurrence_date']);
         if ($event['allday']) {
             $recurrence_id['VALUE'] = 'DATE';
         }
         if ($event['thisandfuture']) {
             $recurrence_id->add('RANGE', 'THISANDFUTURE');
         }
     }
     if ($recurrence_id) {
         $ve->add($recurrence_id);
     }
     $ve->add('SUMMARY', $event['title']);
     if ($event['location']) {
         $ve->add('LOCATION', $event['location']);
     }
     if ($event['description']) {
         $ve->add('DESCRIPTION', strtr($event['description'], array("\r\n" => "\n", "\r" => "\n")));
     }
     // normalize line endings
     if (isset($event['sequence'])) {
         $ve->add('SEQUENCE', $event['sequence']);
     }
     if ($event['recurrence'] && !$recurrence_id) {
         $exdates = $rdates = null;
         if (isset($event['recurrence']['EXDATE'])) {
             $exdates = $event['recurrence']['EXDATE'];
             unset($event['recurrence']['EXDATE']);
             // don't serialize EXDATEs into RRULE value
         }
         if (isset($event['recurrence']['RDATE'])) {
             $rdates = $event['recurrence']['RDATE'];
             unset($event['recurrence']['RDATE']);
             // don't serialize RDATEs into RRULE value
         }
         if ($event['recurrence']['FREQ']) {
             $ve->add('RRULE', libcalendaring::to_rrule($event['recurrence'], (bool) $event['allday']));
         }
         // add EXDATEs each one per line (for Thunderbird Lightning)
         if (is_array($exdates)) {
             foreach ($exdates as $ex) {
                 $ve->add('EXDATE', $ex);
             }
         }
         // add RDATEs
         if (is_array($rdates) && !empty($rdates)) {
             $ve->RDATE = $rdates;
         }
     }
     if ($event['categories']) {
         $ve->add('CATEGORIES', (array) $event['categories']);
     }
     if (!empty($event['free_busy'])) {
         $ve->add('TRANSP', $event['free_busy'] == 'free' ? 'TRANSPARENT' : 'OPAQUE');
         // for Outlook clients we provide the X-MICROSOFT-CDO-BUSYSTATUS property
         if (stripos($this->agent, 'outlook') !== false) {
             $ve->add('X-MICROSOFT-CDO-BUSYSTATUS', $event['free_busy'] == 'outofoffice' ? 'OOF' : strtoupper($event['free_busy']));
         }
     }
     if ($event['priority']) {
         $ve->add('PRIORITY', $event['priority']);
     }
     if ($event['cancelled']) {
         $ve->add('STATUS', 'CANCELLED');
     } else {
         if ($event['free_busy'] == 'tentative') {
             $ve->add('STATUS', 'TENTATIVE');
         } else {
             if ($event['complete'] == 100) {
                 $ve->add('STATUS', 'COMPLETED');
             } else {
                 if (!empty($event['status'])) {
                     $ve->add('STATUS', $event['status']);
                 }
             }
         }
     }
     if (!empty($event['sensitivity'])) {
         $ve->add('CLASS', strtoupper($event['sensitivity']));
     }
     if (!empty($event['complete'])) {
         $ve->add('PERCENT-COMPLETE', intval($event['complete']));
     }
     // Apple iCal and BusyCal required the COMPLETED date to be set in order to consider a task complete
     if ($event['status'] == 'COMPLETED' || $event['complete'] == 100) {
         $ve->add('COMPLETED', $event['changed'] ?: new DateTime('now - 1 hour'), true);
     }
     if ($event['valarms']) {
         foreach ($event['valarms'] as $alarm) {
             $va = $vcal_creator->createComponent('VALARM');
             $va->ACTION = $alarm['action'];
             if ($alarm['trigger'] instanceof DateTime) {
                 $va->add('TRIGGER', $alarm['trigger']);
             } else {
                 $va->add('TRIGGER', $alarm['trigger']);
                 if (strtoupper($alarm['related']) == 'END') {
                     $va->TRIGGER['RELATED'] = 'END';
                 }
             }
             if ($alarm['action'] == 'EMAIL') {
                 foreach ((array) $alarm['attendees'] as $attendee) {
                     $va->add('ATTENDEE', 'mailto:' . $attendee);
                 }
             }
             if ($alarm['description']) {
                 $va->add('DESCRIPTION', $alarm['description'] ?: $event['title']);
             }
             if ($alarm['summary']) {
                 $va->add('SUMMARY', $alarm['summary']);
             }
             if ($alarm['duration']) {
                 $va->add('DURATION', $alarm['duration']);
                 $va->add('REPEAT', intval($alarm['repeat']));
             }
             if ($alarm['uri']) {
                 $va->add('ATTACH', $alarm['uri'], array('VALUE' => 'URI'));
             }
             $ve->add($va);
         }
     } else {
         if ($event['alarms']) {
             $va = $vcal_creator->createComponent('VALARM');
             list($trigger, $va->action) = explode(':', $event['alarms']);
             $val = libcalendaring::parse_alarm_value($trigger);
             if ($val[3]) {
                 $va->add('TRIGGER', $val[3]);
             } else {
                 if ($val[0] instanceof DateTime) {
                     $va->add('TRIGGER', $val[0]);
                 }
             }
             $ve->add($va);
         }
     }
     foreach ((array) $event['attendees'] as $attendee) {
         if ($attendee['role'] == 'ORGANIZER') {
             if (empty($event['organizer'])) {
                 $event['organizer'] = $attendee;
             }
         } else {
             if (!empty($attendee['email'])) {
                 if (isset($attendee['rsvp'])) {
                     $attendee['rsvp'] = $attendee['rsvp'] ? 'TRUE' : null;
                 }
                 $ve->add('ATTENDEE', 'mailto:' . $attendee['email'], array_filter(self::map_keys($attendee, $this->attendee_keymap)));
             }
         }
     }
     if ($event['organizer']) {
         $ve->add('ORGANIZER', 'mailto:' . $event['organizer']['email'], self::map_keys($event['organizer'], array('name' => 'CN')));
     }
     foreach ((array) $event['url'] as $url) {
         if (!empty($url)) {
             $ve->add('URL', $url);
         }
     }
     if (!empty($event['parent_id'])) {
         $ve->add('RELATED-TO', $event['parent_id'], array('RELTYPE' => 'PARENT'));
     }
     if ($event['comment']) {
         $ve->add('COMMENT', $event['comment']);
     }
     $memory_limit = parse_bytes(ini_get('memory_limit'));
     // export attachments
     if (!empty($event['attachments'])) {
         foreach ((array) $event['attachments'] as $attach) {
             // check available memory and skip attachment export if we can't buffer it
             // @todo: use rcube_utils::mem_check()
             if (is_callable($get_attachment) && $memory_limit > 0 && ($memory_used = function_exists('memory_get_usage') ? memory_get_usage() : 16 * 1024 * 1024) && $attach['size'] && $memory_used + $attach['size'] * 3 > $memory_limit) {
                 continue;
             }
             // embed attachments using the given callback function
             if (is_callable($get_attachment) && ($data = call_user_func($get_attachment, $attach['id'], $event))) {
                 // embed attachments for iCal
                 $ve->add('ATTACH', base64_encode($data), array_filter(array('VALUE' => 'BINARY', 'ENCODING' => 'BASE64', 'FMTTYPE' => $attach['mimetype'], 'X-LABEL' => $attach['name'])));
                 unset($data);
                 // attempt to free memory
             } else {
                 if (!empty($this->attach_uri)) {
                     $ve->add('ATTACH', strtr($this->attach_uri, array('{{id}}' => urlencode($attach['id']), '{{name}}' => urlencode($attach['name']), '{{mimetype}}' => urlencode($attach['mimetype']))), array('FMTTYPE' => $attach['mimetype'], 'VALUE' => 'URI'));
                 }
             }
         }
     }
     foreach ((array) $event['links'] as $uri) {
         $ve->add('ATTACH', $uri);
     }
     // add custom properties
     foreach ((array) $event['x-custom'] as $prop) {
         $ve->add($prop[0], $prop[1]);
     }
     // append to vcalendar container
     if ($vcal) {
         $vcal->add($ve);
     } else {
         // serialize and send to stdout
         echo $ve->serialize();
     }
     // append recurrence exceptions
     if (is_array($event['recurrence']) && $event['recurrence']['EXCEPTIONS']) {
         foreach ($event['recurrence']['EXCEPTIONS'] as $ex) {
             $exdate = $ex['recurrence_date'] ?: $ex['start'];
             $recurrence_id = $vcal_crator->createProperty('RECURRENCE-ID');
             $recurrence_id->setDateTime($exdate);
             if ($event['allday']) {
                 $recurrence_id['VALUE'] = 'DATE';
             }
             if ($ex['thisandfuture']) {
                 $recurrence_id->add('RANGE', 'THISANDFUTURE');
             }
             $this->_to_ical($ex, $vcal, $get_attachment, $recurrence_id);
         }
     }
 }
예제 #5
0
 /**
  * @depends test_import
  */
 function test_apple_alarms()
 {
     $ical = new libvcalendar();
     $events = $ical->import_from_file(__DIR__ . '/resources/apple-alarms.ics', 'UTF-8');
     $event = $events[0];
     // alarms
     $this->assertEquals('-45M:AUDIO', $event['alarms'], "Relative alarm string");
     $alarm = libcalendaring::parse_alarm_value($event['alarms']);
     $this->assertEquals('45', $alarm[0], "Alarm value");
     $this->assertEquals('-M', $alarm[1], "Alarm unit");
     $this->assertEquals(1, count($event['valarms']), "Ignore invalid alarm blocks");
     $this->assertEquals('AUDIO', $event['valarms'][0]['action'], "Full alarm item (action)");
     $this->assertEquals('-PT45M', $event['valarms'][0]['trigger'], "Full alarm item (trigger)");
     $this->assertEquals('Basso', $event['valarms'][0]['uri'], "Full alarm item (attachment)");
 }
 /**
  * Helper method to decode a serialized list of alarms
  */
 private function unserialize_alarms($alarms)
 {
     // decode json serialized alarms
     if ($alarms && $alarms[0] == '[') {
         $valarms = json_decode($alarms, true);
         foreach ($valarms as $i => $alarm) {
             if ($alarm['trigger'][0] == '@') {
                 try {
                     $valarms[$i]['trigger'] = new DateTime(substr($alarm['trigger'], 1));
                 } catch (Exception $e) {
                     unset($valarms[$i]);
                 }
             }
         }
     } else {
         if (strlen($alarms)) {
             list($trigger, $action) = explode(':', $alarms, 2);
             if ($trigger = libcalendaring::parse_alarm_value($trigger)) {
                 $valarms = array(array('action' => $action, 'trigger' => $trigger[3] ?: $trigger[0]));
             }
         }
     }
     return $valarms;
 }