Exemple #1
0
 /**
  * Creates or modifies an existing event
  * TODO: detect if we are defining a new recurrence-id
  */
 function modify()
 {
     // Important data to be filled later
     $etag = '';
     $href = '';
     $calendar = '';
     $resource = null;
     // Default new properties. To be cleaned
     // on Icshelper library
     $p = $this->input->post(null, TRUE);
     // XSS
     $this->load->library('form_validation');
     $this->form_validation->set_rules('calendar', $this->i18n->_('labels', 'calendar'), 'required');
     $this->form_validation->set_rules('summary', $this->i18n->_('labels', 'summary'), 'required');
     $this->form_validation->set_rules('start_date', $this->i18n->_('labels', 'startdate'), 'required|callback__valid_date');
     $this->form_validation->set_rules('end_date', $this->i18n->_('labels', 'enddate'), 'required|callback__valid_date');
     $this->form_validation->set_rules('recurrence_count', $this->i18n->_('labels', 'repeatcount'), 'callback__empty_or_natural_no_zero');
     $this->form_validation->set_rules('recurrence_until', $this->i18n->_('labels', 'repeatuntil'), 'callback__empty_or_valid_date');
     if ($this->form_validation->run() === FALSE) {
         $this->_throw_exception(validation_errors());
     }
     $this->load->library('caldav');
     // DateTime objects
     $start = null;
     $end = null;
     $tz = isset($p['timezone']) ? $this->timezonemanager->getTz($p['timezone']) : $this->timezonemanager->getTz($this->config->item('default_timezone'));
     // Additional validations
     // 1. All day? If all day, require start_time, end_date and end_time
     // If not, generate our own values
     if (isset($p['allday']) && $p['allday'] == 'true') {
         // Start and end days, 00:00
         $start = $this->dates->frontend2datetime($p['start_date'] . ' ' . date($this->time_format, mktime(0, 0)), $this->tz_utc);
         $end = $this->dates->frontend2datetime($p['end_date'] . ' ' . date($this->time_format, mktime(0, 0)), $this->tz_utc);
         // Add 1 day (iCalendar needs this)
         $end->add(new DateInterval('P1D'));
     } else {
         // Create new form validation rules
         $this->form_validation->set_rules('start_time', $this->i18n->_('labels', 'starttime'), 'required|callback__valid_time');
         $this->form_validation->set_rules('end_time', $this->i18n->_('labels', 'endtime'), 'required|callback__valid_time');
         if ($this->form_validation->run() === FALSE) {
             $this->_throw_exception(validation_errors());
         }
         // 2. Check if start date <= end date
         $start = $this->dates->frontend2datetime($p['start_date'] . ' ' . $p['start_time'], $tz);
         $end = $this->dates->frontend2datetime($p['end_date'] . ' ' . $p['end_time'], $tz);
         if ($end->getTimestamp() < $start->getTimestamp()) {
             $this->_throw_exception($this->i18n->_('messages', 'error_startgreaterend'));
         }
     }
     $p['dtstart'] = $start;
     $p['dtend'] = $end;
     // Recurrence checks
     unset($p['rrule']);
     if (isset($p['recurrence_type'])) {
         if ($p['recurrence_type'] != 'none') {
             if (isset($p['recurrence_until']) && !empty($p['recurrence_until'])) {
                 $p['recurrence_until'] .= date($this->time_format, mktime(0, 0));
                 // Tricky
             }
             $rrule = $this->recurrence->build($p, $rrule_err);
             if (FALSE === $rrule) {
                 // Couldn't build rrule
                 $this->extended_logs->message('ERROR', 'Error building RRULE (' . $rrule_err . ')');
                 $this->_throw_exception($this->i18n->_('messages', 'error_bogusrepeatrule') . ': ' . $rrule_err);
             }
         } else {
             // Deleted RRULE
             // TODO in the future, consider recurrence-id and so
             $rrule = '';
         }
         $p['rrule'] = $rrule;
     }
     // Reminders
     $reminders = array();
     // Contains a list of old parseable (visible on UI) reminders.
     // Used to remove reminders that were deleted by user
     $visible_reminders = isset($p['visible_reminders']) ? $p['visible_reminders'] : array();
     if (isset($p['reminders']) && is_array($p['reminders'])) {
         $data_reminders = $p['reminders'];
         $num_reminders = count($data_reminders['is_absolute']);
         for ($i = 0; $i < $num_reminders; $i++) {
             $this_reminder = null;
             $data_reminders['is_absolute'][$i] = $data_reminders['is_absolute'][$i] == 'true' ? TRUE : FALSE;
             if ($data_reminders['is_absolute'][$i]) {
                 $when = $this->dates->frontend2datetime($data_reminders['tdate'][$i] . ' ' . $data_reminders['ttime'][$i], $this->tz);
                 $when->setTimezone($this->tz_utc);
                 $this_reminder = Reminder::createFrom($when);
             } else {
                 $when = array('before' => $data_reminders['before'][$i] == 'true', 'relatedStart' => $data_reminders['relatedStart'][$i] == 'true');
                 $interval = $data_reminders['interval'][$i];
                 $when[$interval] = $data_reminders['qty'][$i];
                 $this_reminder = Reminder::createFrom($when);
             }
             if (!empty($data_reminders['order'][$i])) {
                 $this_reminder->order = $data_reminders['order'][$i];
             }
             log_message('INTERNALS', 'Adding reminder ' . $this_reminder);
             $reminders[] = $this_reminder;
         }
     }
     // Is this a new event or a modification?
     // Valid destination calendar?
     if (!$this->caldav->is_valid_calendar($this->auth->get_user(), $this->auth->get_passwd(), $p['calendar'])) {
         $this->_throw_exception($this->i18n->_('messages', 'error_calendarnotfound', array('%calendar' => $p['calendar'])));
     } else {
         $calendar = $p['calendar'];
     }
     if (!isset($p['modification'])) {
         // New event (resource)
         $new_uid = $this->icshelper->new_resource($p, $resource, $this->tz, $reminders);
         $href = $new_uid . '.ics';
         $etag = '*';
     } else {
         // Load existing resource
         // Valid original calendar?
         if (!isset($p['original_calendar'])) {
             $this->_throw_exception($this->i18n->_('messages', 'error_interfacefailure'));
         } else {
             $original_calendar = $p['original_calendar'];
         }
         if (!$this->caldav->is_valid_calendar($this->auth->get_user(), $this->auth->get_passwd(), $original_calendar)) {
             $this->_throw_exception($this->i18n->_('messages', 'error_calendarnotfound', array('%calendar' => $original_calendar)));
         }
         $uid = $p['uid'];
         $href = $p['href'];
         $etag = $p['etag'];
         $res = $this->caldav->fetch_resource_by_uid($this->auth->get_user(), $this->auth->get_passwd(), $uid, $original_calendar);
         if (is_null($res)) {
             $this->_throw_error($this->i18n->_('messages', 'error_eventnotfound'));
         }
         if ($etag != $res['etag']) {
             $this->_throw_error($this->i18n->_('messages', 'error_eventchanged'));
         }
         $resource = $this->icshelper->parse_icalendar($res['data']);
         $timezones = $this->icshelper->get_timezones($resource);
         $vevent = null;
         // TODO: recurrence-id?
         $modify_pos = $this->icshelper->find_component_position($resource, 'VEVENT', array(), $vevent);
         if (is_null($vevent)) {
             $this->_throw_error($this->i18n->_('messages', 'error_eventnofound'));
         }
         $tz = $this->icshelper->detect_tz($vevent, $timezones);
         // Change every property
         $force_new_value = isset($p['allday']) && $p['allday'] == 'true' ? 'DATE' : 'DATE-TIME';
         $vevent = $this->icshelper->make_start($vevent, $tz, $start, null, $force_new_value);
         $vevent = $this->icshelper->make_end($vevent, $tz, $end, null, $force_new_value);
         $properties = array('summary' => $p['summary'], 'location' => $p['location'], 'description' => $p['description']);
         // Only change RRULE when we are able to
         if (isset($p['rrule'])) {
             $properties['rrule'] = $p['rrule'];
         }
         // CLASS and TRANSP
         if (isset($p['class'])) {
             $properties['class'] = $p['class'];
         }
         if (isset($p['transp'])) {
             $properties['transp'] = strtoupper($p['transp']);
         }
         $vevent = $this->icshelper->change_properties($vevent, $properties);
         // Add/change/remove reminders
         $vevent = $this->icshelper->set_valarms($vevent, $reminders, $visible_reminders);
         $vevent = $this->icshelper->set_last_modified($vevent);
         $resource = $this->icshelper->replace_component($resource, 'vevent', $modify_pos, $vevent);
         if ($resource === FALSE) {
             $this->_throw_error($this->i18n->_('messages', 'error_internalgen'));
         }
         // Moving event between calendars
         if ($original_calendar != $calendar) {
             // We will need this etag later
             $original_etag = $etag;
             $etag = '*';
         }
     }
     // PUT on server
     $new_etag = $this->caldav->put_resource($this->auth->get_user(), $this->auth->get_passwd(), $href, $calendar, $resource, $etag);
     if (FALSE === $new_etag) {
         $code = $this->caldav->get_last_response();
         switch ($code[0]) {
             case '412':
                 // TODO new events + already used UIDs!
                 if (isset($p['modification'])) {
                     $this->_throw_exception($this->i18n->_('messages', 'error_eventchanged'));
                 } else {
                     // Already used UID on new event. What a bad luck!
                     // TODO propose a solution
                     $this->_throw_error('Bad luck' . ' Repeated UID');
                 }
                 break;
             case '403':
                 $this->_throw_error($this->i18n->_('messages', 'error_denied'));
                 break;
             default:
                 $this->_throw_error($this->i18n->_('messages', 'error_unknownhttpcode', array('%res' => $code[0])));
                 break;
         }
     } else {
         // Remove original event
         if (isset($p['modification']) && $original_calendar != $calendar) {
             $res = $this->caldav->delete_resource($this->auth->get_user(), $this->auth->get_passwd(), $href, $original_calendar, $original_etag);
             if ($res === TRUE) {
                 $this->extended_logs->message('INTERNALS', 'Deleted event (moved) with uid=' . $uid . ' from calendar ' . $original_calendar);
             } else {
                 // There was an error
                 $this->extended_logs->message('INTERNALS', 'Error deleting event (moved) with uid=' . $uid . ' from calendar ' . $original_calendar . ': ' . $res);
                 $this->_throw_exception($res);
             }
         }
         // Return a list of affected calendars (original_calendar, new
         // calendar)
         $affected_calendars = array($calendar);
         if (isset($original_calendar) && $original_calendar != $calendar) {
             $affected_calendars[] = $original_calendar;
         }
         $this->_throw_success($affected_calendars);
     }
 }
Exemple #2
0
 /**
  * Parses a VEVENT resource VALARM definitions
  * 
  * Returns an associative array ('n1#' => new Reminder, 'n2#' => new
  * Reminder...), where 'n#' is the order where this VALARM was found
  */
 function parse_valarms($vevent, $timezones = array())
 {
     $parsed_reminders = array();
     $order = 0;
     while ($valarm = $vevent->getComponent('valarm')) {
         $order++;
         // TODO parse more actions
         $action = $valarm->getProperty('action');
         if ($action == 'DISPLAY') {
             $trigger = $valarm->getProperty('trigger');
             $reminder = null;
             if (isset($trigger['before'])) {
                 // Related to event start/end
                 $reminder = Reminder::createFrom($trigger);
             } else {
                 // Absolute date-time trigger
                 $tz = $this->detect_tz($valarm, $timezones, 'trigger');
                 $datetime = $this->CI->dates->idt2datetime($trigger, $tz);
                 // Use default timezone
                 $datetime->setTimezone($this->tz);
                 $reminder = Reminder::createFrom($datetime);
                 $reminder->tdate = $datetime->format($this->date_frontend_format);
                 $reminder->ttime = $datetime->format($this->time_frontend_format);
             }
             if ($reminder !== null) {
                 $reminder->order = $order;
                 $parsed_reminders[$order] = $reminder;
             }
         }
     }
     return $parsed_reminders;
 }