/** * The constructor, which just calls the actual type configured */ function PublicSession() { global $c; $principal = new Principal('username', 'unauthenticated'); // Assign each field in the selected record to the object foreach ($principal as $k => $v) { $this->{$k} = $v; } $this->username = $principal->username(); $this->user_no = $principal->user_no(); $this->principal_id = $principal->principal_id(); $this->email = $principal->email(); $this->dav_name = $principal->dav_name(); $this->principal = $principal; if (function_exists("awl_set_locale") && isset($this->locale) && $this->locale != "") { awl_set_locale($this->locale); } $this->groups = isset($c->public_groups) ? $c->public_groups : array(); $this->roles = array('Public' => true); $this->logged_in = false; }
/** * Creates some default home collections for the user. * @param string $username The username of the user we are creating relationships for. */ function CreateHomeCollections($username, $defult_timezone = null) { global $session, $c; if (!isset($c->default_collections)) { $c->default_collections = array(); if (!empty($c->home_calendar_name)) { $c->default_collections[] = array('type' => 'calendar', 'name' => $c->home_calendar_name); } if (!empty($c->home_addressbook_name)) { $c->default_collections[] = array('type' => 'addressbook', 'name' => $c->home_addressbook_name); } } if (!is_array($c->default_collections) || !count($c->default_collections)) { return true; } $principal = new Principal('username', $username); $user_fullname = $principal->fullname; // user fullname $user_rfullname = implode(' ', array_reverse(explode(' ', $principal->fullname))); // user fullname in reverse order $sql = 'INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, is_addressbook, default_privileges, created, modified, resourcetypes) '; $sql .= 'VALUES( :user_no, :parent_container, :collection_path, :dav_etag, :displayname, :is_calendar, :is_addressbook, :privileges::BIT(24), current_timestamp, current_timestamp, :resourcetypes );'; foreach ($c->default_collections as $v) { if ($v['type'] == 'calendar' || $v['type'] == 'addressbook') { if (!empty($v['name'])) { $qry = new AwlQuery('SELECT 1 FROM collection WHERE dav_name = :dav_name', array(':dav_name' => $principal->dav_name() . $v['name'] . '/')); if (!$qry->Exec()) { $c->messages[] = i18n('There was an error reading from the database.'); return false; } if ($qry->rows() > 0) { $c->messages[] = i18n('Home ' . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . ' already exists.'); return true; } else { $params[':user_no'] = $principal->user_no(); $params[':parent_container'] = $principal->dav_name(); $params[':dav_etag'] = '-1'; $params[':collection_path'] = $principal->dav_name() . $v['name'] . '/'; $params[':displayname'] = !isset($v['displayname']) || empty($v['displayname']) ? $user_fullname . ($v['type'] == 'calendar' ? ' calendar' : ' addressbook') : str_replace(array('%fn', '%rfn'), array($user_fullname, $user_rfullname), $v['displayname']); $params[':resourcetypes'] = $v['type'] == 'calendar' ? '<DAV::collection/><urn:ietf:params:xml:ns:caldav:calendar/>' : '<DAV::collection/><urn:ietf:params:xml:ns:carddav:addressbook/>'; $params[':is_calendar'] = $v['type'] == 'calendar' ? true : false; $params[':is_addressbook'] = $v['type'] == 'addressbook' ? true : false; $params[':privileges'] = !isset($v['privileges']) || $v['privileges'] === null ? null : privilege_to_bits($v['privileges']); $qry = new AwlQuery($sql, $params); if ($qry->Exec()) { $c->messages[] = i18n('Home ' . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . ' added.'); dbg_error_log("User", ":Write: Created user's home " . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . " at '%s'", $params[':collection_path']); // create value for urn:ietf:params:xml:ns:caldav:supported-calendar-component-set property if ($v['type'] == 'calendar' && isset($v['calendar_components']) && $v['calendar_components'] != null && is_array($v['calendar_components']) && count($v['calendar_components'])) { // convert the array to uppercase and allow only real calendar compontents $components_clean = array_intersect(array_map("strtoupper", $v['calendar_components']), array('VEVENT', 'VTODO', 'VJOURNAL', 'VTIMEZONE', 'VFREEBUSY', 'VPOLL', 'VAVAILABILITY')); // convert the $components_clean array to XML string $result_xml = ''; foreach ($components_clean as $curr) { $result_xml .= sprintf('<comp name="%s" xmlns="urn:ietf:params:xml:ns:caldav"/>', $curr); } // handle the components XML string as user defined property (see below) if ($result_xml != '') { $v['default_properties']['urn:ietf:params:xml:ns:caldav:supported-calendar-component-set'] = $result_xml; } } // store all user defined properties (note: it also handles 'calendar_components' - see above) if (isset($v['default_properties']) && $v['default_properties'] != null && is_array($v['default_properties']) && count($v['default_properties'])) { $sql2 = 'INSERT INTO property (dav_name, property_name, property_value, changed_on, changed_by) '; $sql2 .= 'VALUES (:collection_path, :property_name, :property_value, current_timestamp, :user_no);'; $params2[':user_no'] = $principal->user_no(); $params2[':collection_path'] = $principal->dav_name() . $v['name'] . '/'; foreach ($v['default_properties'] as $key => $val) { $params2[':property_name'] = $key; $params2[':property_value'] = $val; $qry2 = new AwlQuery($sql2, $params2); if ($qry2->Exec()) { dbg_error_log("User", ":Write: Created property '%s' for " . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . " at '%s'", $params2[':property_name'], $params2[':collection_path']); } else { $c->messages[] = i18n("There was an error writing to the database."); return false; } } } } else { $c->messages[] = i18n("There was an error writing to the database."); return false; } } } } } return true; }
/** * Create/Update the scheduling requests for this resource. This includes updating * the scheduled user's default calendar. * @param vComponent $resource The VEVENT/VTODO/... resource we are scheduling * @param boolean $create true if the scheduling requests are being created. * @return true If there was any scheduling action */ function do_scheduling_requests(vCalendar $resource, $create, $old_data = null, $remoteAttendee = false) { global $request, $c; if (!isset($request) || isset($c->enable_auto_schedule) && !$c->enable_auto_schedule) { return false; } if (!is_object($resource)) { trace_bug('do_scheduling_requests called with non-object parameter (%s)', gettype($resource)); return false; } $organizer = $resource->GetOrganizer(); if ($organizer === false || empty($organizer)) { dbg_error_log('PUT', 'Event has no organizer - no scheduling required.'); return false; } $organizer_email = preg_replace('/^mailto:/i', '', $organizer->Value()); if ($request->principal->email() != $organizer_email) { return do_scheduling_reply($resource, $organizer); } $schedule_request = clone $resource; $schedule_request->AddProperty('METHOD', 'REQUEST'); $old_attendees = array(); if (!empty($old_data)) { $old_resource = new vCalendar($old_data); $old_attendees = $old_resource->GetAttendees(); } $attendees = $resource->GetAttendees(); if (count($attendees) == 0 && count($old_attendees) == 0) { dbg_error_log('PUT', 'Event has no attendees - no scheduling required.', count($attendees)); return false; } $removed_attendees = array(); foreach ($old_attendees as $attendee) { $email = preg_replace('/^mailto:/i', '', $attendee->Value()); if ($email == $request->principal->email()) { continue; } $removed_attendees[$email] = $attendee; } $uids = $resource->GetPropertiesByPath('/VCALENDAR/*/UID'); if (count($uids) == 0) { dbg_error_log('PUT', 'No UID in VCALENDAR - giving up on REPLY.'); return false; } $uid = $uids[0]->Value(); dbg_error_log('PUT', 'Writing scheduling resources for %d attendees', count($attendees)); $scheduling_actions = false; foreach ($attendees as $attendee) { $email = preg_replace('/^mailto:/i', '', $attendee->Value()); if ($email == $request->principal->email()) { dbg_error_log("PUT", "not delivering to owner '%s'", $request->principal->email()); continue; } if ($create) { $attendee_is_new = true; } else { $attendee_is_new = !isset($removed_attendees[$email]); if (!$attendee_is_new) { unset($removed_attendees[$email]); } } $agent = $attendee->GetParameterValue('SCHEDULE-AGENT'); if ($agent && $agent != 'SERVER') { dbg_error_log("PUT", "not delivering to %s, schedule agent set to value other than server", $email); continue; } $schedule_target = new Principal('email', $email); $response = '3.7'; // Attendee was not found on server. dbg_error_log('PUT', 'Handling scheduling resources for %s on %s which is %s', $email, $create ? 'create' : 'update', $attendee_is_new ? 'new' : 'an update'); if ($schedule_target->Exists()) { // Instead of always writing to schedule-default-calendar, we first try to // find a calendar with an existing instance of the event. $sql = 'SELECT caldav_data.dav_name, caldav_data.caldav_data, caldav_data.collection_id FROM caldav_data JOIN calendar_item USING(dav_id) '; $sql .= 'WHERE caldav_data.collection_id IN (SELECT collection_id FROM collection WHERE is_calendar AND user_no =?) '; $sql .= 'AND uid=? LIMIT 1'; $qry = new AwlQuery($sql, $schedule_target->user_no(), $uid); if (!$qry->Exec('PUT', __LINE__, __FILE__) || $qry->rows() < 1) { dbg_error_log('PUT', "Could not find event in attendee's calendars"); $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar'))); } else { $row = $qry->Fetch(); $r = new DAVResource($row); $attendee_calendar = new WritableCollection(array('path' => $r->parent_path())); if ($attendee_calendar->IsCalendar()) { dbg_error_log('XXX', "found the event in attendee's calendar %s", $attendee_calendar->dav_name()); } else { dbg_error_log('XXX', 'could not find the event in any calendar, using schedule-default-calendar'); $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar'))); } } if (!$attendee_calendar->Exists()) { dbg_error_log('ERROR', 'Default calendar at "%s" does not exist for user "%s"', $attendee_calendar->dav_name(), $schedule_target->username()); $response = '5.2'; // No scheduling support for user } else { $attendee_inbox = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-inbox'))); if (!$attendee_inbox->HavePrivilegeTo('schedule-deliver-invite')) { $response = '3.8'; // No authority to deliver invitations to user. } else { if ($attendee_inbox->WriteCalendarMember($schedule_request, $attendee_is_new) !== false) { $response = '1.2'; // Scheduling invitation delivered successfully if ($attendee_calendar->WriteCalendarMember($resource, $attendee_is_new) === false) { dbg_error_log('ERROR', 'Could not write %s calendar member to %s', $attendee_is_new ? 'new' : 'updated', $attendee_calendar->dav_name(), $attendee_calendar->dav_name(), $schedule_target->username()); trace_bug('Failed to write scheduling resource.'); } } } } } else { if ($remoteAttendee) { $attendee->is_remote = true; $remote = new iSchedule(); $answer = $remote->sendRequest($email, 'VEVENT/REQUEST', $schedule_request->Render()); } else { $remote = new iSchedule(); $answer = $remote->sendRequest($email, 'VEVENT/REQUEST', $schedule_request->Render()); if ($answer === false) { $response = "3.7;Invalid Calendar User"; } else { foreach ($answer as $a) { if ($a === false) { $response = "3.7;Invalid Calendar User"; } elseif (substr($a, 0, 1) >= 1) { $response = $a; } else { $response = "2.0;Success"; } } } } } dbg_error_log('PUT', 'Status for attendee <%s> set to "%s"', $attendee->Value(), $response); $attendee->SetParameterValue('SCHEDULE-STATUS', $response); $scheduling_actions = true; } if (!$create) { foreach ($removed_attendees as $attendee) { $schedule_target = new Principal('email', $email); if ($schedule_target->Exists()) { $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar'))); } } } return $scheduling_actions; }
static function importFromDirectory() { global $c; if (empty($_POST["calendar_path"])) { dbg_error_log("importFromDirectory", "calendar path not given"); return; } $path_ics = $_POST["calendar_path"]; if (substr($path_ics, -1, 1) != '/') { $path_ics .= '/'; } // ensure that we target a collection if (substr($path_ics, 0, 1) != '/') { $path_ics = '/' . $path_ics; } // ensure that we target a collection if (empty($_POST["directory_path"])) { dbg_error_log("importFromDirectory", "directory path not given"); return; } $dir = $_POST["directory_path"]; if (!is_readable($dir)) { $c->messages[] = sprintf(i18n('directory %s is not readable'), htmlspecialchars($dir)); dbg_error_log("importFromDirectory", "directory is not readable"); return; } if ($handle = opendir($dir)) { $c->readonly_webdav_collections = false; // Override this setting so we can create collections/events on import. while (false !== ($file = readdir($handle))) { if ($file == "." || $file == ".." || substr($file, -4) != '.ics') { continue; } if (!is_readable($dir . '/' . $file)) { dbg_error_log("importFromDirectory", "ics file '%s' is not readable", $dir . '/' . $file); continue; } $ics = file_get_contents($dir . '/' . $file); $ics = trim($ics); if ($ics != '') { if (!check_string($ics)) { $c->messages[] = sprintf(translate('The file "%s" is not UTF-8 encoded, please check error for more details'), $dir . '/' . $file); continue; } $username = substr($file, 0, -4); $principal = new Principal('username', $username); if (!$principal->Exists()) { $c->messages[] = sprintf(translate('The principal "%s" does not exist'), $username); continue; } $path = "/" . $username . $path_ics; $user_no = $principal->user_no(); if (controlRequestContainer($username, $user_no, $path, false) === -1) { continue; } dbg_error_log("importFromDirectory", "importing to {$path}"); import_collection($ics, $user_no, $path, 1); $c->messages[] = sprintf(translate('All events of user "%s" were deleted and replaced by those from file %s'), substr($file, 0, -4), $dir . '/' . $file); } } closedir($handle); } }
/** * Does the actual processing of the iTIP CANCEL message on behalf of an ATTENDEE, * which generally means writing it into the ATTENDEE's default calendar. * * @param vCalendar $vcal The message. * @param vProperty $attendee * @param WritableCollection $attendee_calendar */ function processItipCancel(vCalendar $vcal, vProperty $attendee, WritableCollection $attendee_calendar, Principal $attendee_principal) { global $request; dbg_error_log('schedule', 'Processing iTIP CANCEL to %s', $attendee->Value()); header("Debug: Could maybe do the iMIP message dance for attendee " . $attendee->Value()); if (!$attendee_calendar->Exists()) { if (doImipMessage('CANCEL', $attendee_principal->email(), $vcal)) { return '1.1'; // Scheduling whoosit 'Sent' } else { dbg_error_log('ERROR', 'Default calendar at "%s" does not exist for attendee "%s"', $attendee_calendar->dav_name(), $attendee->Value()); return '5.2'; // No scheduling support for user } } $sql = 'SELECT caldav_data.dav_name FROM caldav_data JOIN calendar_item USING(dav_id) '; $sql .= 'WHERE caldav_data.collection_id IN (SELECT collection_id FROM collection WHERE is_calendar AND user_no =?) '; $sql .= 'AND uid=? LIMIT 1'; $uids = $vcal->GetPropertiesByPath('/VCALENDAR/*/UID'); if (count($uids) == 0) { dbg_error_log('schedule', 'No UID in VCALENDAR - giving up on CANCEL processing.'); return '3.8'; } $uid = $uids[0]->Value(); $qry = new AwlQuery($sql, $attendee_principal->user_no(), $uid); if (!$qry->Exec('schedule', __LINE__, __FILE__) || $qry->rows() < 1) { dbg_error_log('schedule', 'Could not find ATTENDEE copy of original event - not trying to DELETE it!'); return '1.2'; } $row = $qry->Fetch(); if ($attendee_calendar->actualDeleteCalendarMember($row->dav_name) === false) { dbg_error_log('ERROR', 'Could not delete calendar member %s for %s', $row->dav_name(), $attendee->Value()); trace_bug('Failed to write scheduling resource.'); return '5.2'; } return '1.2'; // Scheduling invitation delivered successfully }