* * This file is part of AgenDAV. * * AgenDAV is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * AgenDAV is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with AgenDAV. If not, see . */ class Calendar extends CI_Controller { private $calendar_colors; private $prefs; function __construct() { parent::__construct(); if (!$this->auth->is_authenticated()) { $this->extended_logs->message('INFO', 'Anonymous access attempt to ' . uri_string()); $this->output->set_status_header('401'); $this->output->_display(); die(); } $this->calendar_colors = $this->config->item('calendar_colors'); $this->prefs = Preferences::singleton($this->session->userdata('prefs')); $this->load->library('caldav'); $this->output->set_content_type('application/json'); } function index() { } /** * Retrieve a list of calendars (owned by current user or shared by * other users with the current one) */ function all() { $arr_calendars = $this->caldav->all_user_calendars( $this->auth->get_user(), $this->auth->get_passwd()); // Hide calendars user doesn't want to be shown $hidden_calendars = $this->prefs->hidden_calendars; if ($hidden_calendars !== null) { foreach ($arr_calendars as $c => $data) { if (isset($hidden_calendars[$c])) { unset($arr_calendars[$c]); } } } // Default calendar $default_calendar = $this->prefs->default_calendar; if ($default_calendar !== null && isset($arr_calendars[$default_calendar])) { $arr_calendars[$default_calendar]->default_calendar = TRUE; } elseif (count($arr_calendars) > 0) { $first = array_shift(array_keys($arr_calendars)); $arr_calendars[$first]->default_calendar = TRUE; } // Add public URL if ($this->config->item('show_public_caldav_url')) { foreach ($arr_calendars as $calendar) { $calendar->public_url = $this->caldav->build_calendar_url( $this->auth->get_user(), $calendar->calendar); } } // Save calendars into session (avoid multiple CalDAV queries when // editing/adding events) $this->session->set_userdata('available_calendars', $arr_calendars); $this->output->set_output(json_encode($arr_calendars)); } /** * Creates a calendar */ function create() { $displayname = $this->input->post('displayname', TRUE); $calendar_color = $this->input->post('calendar_color', TRUE); // Display name if (empty($displayname)) { $this->_throw_exception($this->i18n->_('messages', 'error_calname_missing')); } // Default color if (empty($calendar_color)) { $calendar_color = '#' . $this->calendar_color[0]; } // Get current own calendars $current_calendars = $this->caldav->get_own_calendars( $this->auth->get_user(), $this->auth->get_passwd() ); // Generate internal calendar name do { $calendar = $this->icshelper->generate_guid(); } while (isset($current_calendars[$calendar])); // Add transparency to color $calendar_color = $this->caldav->_rgb2rgba($calendar_color); // Calendar properties $props = array( 'displayname' => $displayname, 'color' => $calendar_color, ); $res = $this->caldav->mkcalendar( $this->auth->get_user(), $this->auth->get_passwd(), $calendar, $props); if ($res !== TRUE) { $this->_throw_error($this->i18n->_('messages', $res[0], $res[1])); } else { $this->_throw_success(); } } /** * Deletes a calendar */ function delete() { $calendar = $this->input->post('calendar'); if ($calendar === FALSE) { $this->extended_logs->message('ERROR', 'Call to delete_calendar() without calendar'); $this->_throw_error($this->i18n->_('messages', 'error_interfacefailure')); } // Get current own calendars and check if this one exists $current_calendars = $this->caldav->get_own_calendars( $this->auth->get_user(), $this->auth->get_passwd() ); if (!isset($current_calendars[$calendar])) { $this->extended_logs->message('INTERNALS', 'Call to delete_calendar() with non-existent calendar (' .$calendar.')'); $this->_throw_exception( $this->i18n->_('messages', 'error_calendarnotfound', array('%calendar' => $p['calendar']))); } // Delete calendar shares (if any), even if calendar sharing is not // enabled $shares = $this->shared_calendars->get_shared_from($this->auth->get_user()); if (isset($shares[$calendar])) { $this_calendar_shares = array_values($shares[$calendar]); foreach ($this_calendar_shares as $k => $data) { $this->shared_calendars->remove($data['sid']); } } $replace_pattern = '/^' . $this->auth->get_user() . ':/'; $internal_calendar = preg_replace($replace_pattern, '', $calendar); // Proceed to remove calendar from CalDAV server $res = $this->caldav->delete_resource( $this->auth->get_user(), $this->auth->get_passwd(), '', $internal_calendar, null); if ($res === TRUE) { $this->_throw_success($calendar); } else { // There was an error $this->_throw_exception($this->i18n->_('messages', $res[0], $res[1])); } } /** * Modifies a calendar */ function modify() { $is_sharing_enabled = $this->config->item('enable_calendar_sharing'); $calendar = $this->input->post('calendar'); $displayname = $this->input->post('displayname'); $calendar_color = $this->input->post('calendar_color'); $is_shared_calendar = $this->input->post('is_shared_calendar'); // Will be only used for shared calendars $sid = null; // In case this calendar is owned by current user, this will contain // a list of users he/she wants to share the calendar with $share_with = $this->input->post('share_with'); if ($calendar === FALSE || $displayname === FALSE || $calendar_color === FALSE || ($is_sharing_enabled && $is_shared_calendar === FALSE)) { $this->extended_logs->message('ERROR', 'Call to modify_calendar() with incomplete parameters'); $this->_throw_error($this->i18n->_('messages', 'error_interfacefailure')); } // Calculate boolean value for is_shared_calendar $is_shared_calendar = ($is_shared_calendar === FALSE ? FALSE : ($is_shared_calendar == 'true')); // Check if calendar is valid if (!$this->caldav->is_valid_calendar( $this->auth->get_user(), $this->auth->get_passwd(), $calendar)) { $this->extended_logs->message('INTERNALS', 'Call to modify_calendar() with non-existent calendar ' .' or with access forbidden (' .$calendar.')'); $this->_throw_exception( $this->i18n->_('messages', 'error_calendarnotfound', array('%calendar' => $calendar))); } // Retrieve ID on shared calendars table if ($is_sharing_enabled && $is_shared_calendar) { $current_calendar_shares = $this->shared_calendars->users_with_access_to($calendar); $current_user = $this->auth->get_user(); foreach ($current_calendar_shares as $sh) { if ($sh['username'] == $current_user) { $sid = $sh['sid']; break; } } if ($sid === null) { $this->extended_logs->message('ERROR', 'Call to modify_calendar() with shared calendar, ' .'but no sid was found'); $this->_throw_error($this->i18n->_('messages', 'error_interfacefailure')); } } // Add transparency to color $calendar_color = $this->caldav->_rgb2rgba($calendar_color); // Calendar properties $props = array( 'displayname' => $displayname, 'color' => $calendar_color, ); // Proceed to modify calendar if (!$is_shared_calendar) { $replace_pattern = '/^' . $this->auth->get_user() . ':/'; $internal_calendar = preg_replace($replace_pattern, '', $calendar); $res = $this->caldav->proppatch( $this->auth->get_user(), $this->auth->get_passwd(), $internal_calendar, $props); } else if ($is_sharing_enabled) { // If this a shared calendar, store settings locally $success = $this->shared_calendars->store($sid, null, $calendar, $this->auth->get_user(), $props); if ($success === FALSE) { $this->_throw_exception($this->i18n->_('messages', 'error_internal')); } else { $res = TRUE; } } else { // Tried to modify a shared calendar when sharing is disabled $this->extended_logs->message('ERROR', 'Tried to modify the shared calendar ' . $calendar .' when calendar sharing is disabled'); $this->_throw_exception($this->i18n->_('messages', 'error_interfacefailure')); } // Set ACLs if ($is_sharing_enabled && $res === TRUE && !$is_shared_calendar) { $set_shares = array(); if (is_array($share_with) && isset($share_with['sid']) && isset($share_with['username']) && isset($share_with['write_access'])) { $num_shares = count($share_with['sid']); for ($i=0;$i<$num_shares;$i++) { $exists_username = isset($share_with['username'][$i]); $exists_write_access = isset($share_with['write_access'][$i]); if (!$exists_username || !$exists_write_access) { $this->extended_logs->message('ERROR', 'Ignoring incomplete share row ('.$i.') attributes' .' on calendar modification: ' . serialize($share_with)); } else { $new_share = array( 'username' => $share_with['username'][$i], 'write_access' => $share_with['write_access'][$i], ); if (!empty($share_with['sid'][$i])) { $new_share['sid'] = $share_with['sid'][$i]; } $set_shares[] = $new_share; } } } $res = $this->caldav->setacl( $this->auth->get_user(), $this->auth->get_passwd(), $internal_calendar, $set_shares); // Update shares on database if ($res === TRUE) { $current_shares = $this->shared_calendars->users_with_access_to($calendar); $orig_sids = array(); foreach ($current_shares as $db_share_row) { $orig_sids[$db_share_row['sid']] = TRUE; } $updated_sids = array(); foreach ($set_shares as $share) { $this_sid = isset($share['sid']) ? $share['sid'] : null; $this->shared_calendars->store( $this_sid, $this->auth->get_user(), $internal_calendar, $share['username'], null, // Preserve options $share['write_access']); if (!is_null($this_sid)) { $updated_sids[$this_sid] = true; } } // Removed shares foreach (array_keys($orig_sids) as $sid) { if (!isset($updated_sids[$sid])) { $this->shared_calendars->remove($sid); } } } } if ($res === TRUE) { $this->_throw_success(); } else { // There was an error $this->_throw_exception($this->i18n->_('messages', $res[0], $res[1])); } } /** * Throws an exception message */ function _throw_exception($message) { $this->output->set_output(json_encode(array( 'result' => 'EXCEPTION', 'message' => $message))); $this->output->_display(); die(); } /** * Throws an error message */ function _throw_error($message) { $this->output->set_output(json_encode(array( 'result' => 'ERROR', 'message' => $message))); $this->output->_display(); die(); } /** * Throws a success message */ function _throw_success($message = '') { $this->output->set_output(json_encode(array( 'result' => 'SUCCESS', 'message' => $message))); $this->output->_display(); die(); } }