<?php /** * Handle the FREE-BUSY-QUERY variant of REPORT */ include_once "freebusy-functions.php"; $fbq_content = $xmltree->GetContent('urn:ietf:params:xml:ns:caldav:free-busy-query'); $fbq_start = $fbq_content[0]->GetAttribute('start'); $fbq_end = $fbq_content[0]->GetAttribute('end'); if (!(isset($fbq_start) || isset($fbq_end))) { $request->DoResponse(400, 'All valid freebusy requests MUST contain a time-range filter'); } $range_start = new RepeatRuleDateTime($fbq_start); $range_end = new RepeatRuleDateTime($fbq_end); /** We use the same code for the REPORT, the POST and the freebusy GET... */ $freebusy = get_freebusy('^' . $request->path . $request->DepthRegexTail(), $range_start, $range_end); $result = new iCalComponent(); $result->VCalendar(); $result->AddComponent($freebusy); $request->DoResponse(200, $result->Render(), 'text/calendar'); // Won't return from that
function ischedule_freebusy_request($ic, $attendees, $attendees_fail) { global $c, $session, $request; $reply = new XMLDocument(array("urn:ietf:params:xml:ns:ischedule" => "I")); $icalAttendees = $ic->GetAttendees(); $responses = array(); $ical = $ic->GetComponents('VFREEBUSY'); $ical = $ical[0]; $fbq_start = $ical->GetPValue('DTSTART'); $fbq_end = $ical->GetPValue('DTEND'); if (!(isset($fbq_start) || isset($fbq_end))) { $request->DoResponse(400, 'All valid freebusy requests MUST contain a DTSTART and a DTEND'); } $range_start = new RepeatRuleDateTime($fbq_start); $range_end = new RepeatRuleDateTime($fbq_end); foreach ($attendees as $k => $attendee) { $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule'); $fb = get_freebusy('^' . $attendee->dav_name, $range_start, $range_end); $fb->AddProperty('UID', $ical->GetPValue('UID')); $fb->SetProperties($ical->GetProperties('ORGANIZER'), 'ORGANIZER'); foreach ($ical->GetProperties('ATTENDEE') as $at) { if ($at->Value() == 'mailto:' . $attendee->email) { $fb->AddProperty($at); } } $vcal = new vCalendar(array('METHOD' => 'REPLY')); $vcal->AddComponent($fb); $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule'); $response->NewElement("recipient", 'mailto:' . $attendee->email, false, 'urn:ietf:params:xml:ns:ischedule'); $response->NewElement("request-status", "2.0;Success", false, 'urn:ietf:params:xml:ns:ischedule'); $response->NewElement("calendar-data", $vcal->Render(), false, 'urn:ietf:params:xml:ns:ischedule'); $responses[] = $response; } foreach ($attendees_fail as $k => $attendee) { $XMLresponse = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule'); $XMLresponse->NewElement("recipient", $reply->href('mailto:' . $attendee)); $XMLresponse->NewElement("request-status", '5.3;cannot schedule this user, unknown or access denied'); $responses[] = $XMLresponse; } $response = $reply->NewXMLElement("schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:ischedule'); $request->XMLResponse(200, $response); }
function handle_freebusy_request($ic) { global $c, $session, $request, $ical; $request->NeedPrivilege('CALDAV:schedule-send-freebusy'); $reply = new XMLDocument(array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C")); $responses = array(); $fbq_start = $ic->GetPValue('DTSTART'); $fbq_end = $ic->GetPValue('DTEND'); if (!(isset($fbq_start) || isset($fbq_end))) { $request->DoResponse(400, 'All valid freebusy requests MUST contain a DTSTART and a DTEND'); } $range_start = new RepeatRuleDateTime($fbq_start); $range_end = new RepeatRuleDateTime($fbq_end); $attendees = $ic->GetProperties('ATTENDEE'); if (preg_match('# iCal/\\d#', $_SERVER['HTTP_USER_AGENT'])) { dbg_error_log("POST", "Non-compliant iCal request. Using X-WR-ATTENDEE property"); $wr_attendees = $ic->GetProperties('X-WR-ATTENDEE'); foreach ($wr_attendees as $k => $v) { $attendees[] = $v; } } dbg_error_log("POST", "Responding with free/busy for %d attendees", count($attendees)); foreach ($attendees as $k => $attendee) { $attendee_email = preg_replace('/^mailto:/', '', $attendee->Value()); dbg_error_log("POST", "Calculating free/busy for %s", $attendee_email); /** @todo Refactor this so we only do one query here and loop through the results */ $params = array(':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth, ':email' => $attendee_email); $qry = new AwlQuery('SELECT pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS p, username FROM usr JOIN principal USING(user_no) WHERE lower(usr.email) = lower(:email)', $params); if (!$qry->Exec('POST', __LINE__, __FILE__)) { $request->DoResponse(501, 'Database error'); } if ($qry->rows() > 1) { // Unlikely, but if we get more than one result we'll do an exact match instead. if (!$qry->QDo('SELECT pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS p, username FROM usr JOIN principal USING(user_no) WHERE usr.email = :email', $params)) { $request->DoResponse(501, 'Database error'); } if ($qry->rows() == 0) { /** Sigh... Go back to the original case-insensitive match */ $qry->QDo('SELECT pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS p, username FROM usr JOIN principal USING(user_no) WHERE lower(usr.email) = lower(:email)', $params); } } $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:caldav'); $reply->CalDAVElement($response, "recipient", $reply->href($attendee->Value())); if ($qry->rows() == 0) { $remote = new iSchedule(); $answer = $remote->sendRequest($attendee->Value(), 'VFREEBUSY/REQUEST', $ical->Render()); if ($answer === false) { $reply->CalDAVElement($response, "request-status", "3.7;Invalid Calendar User"); $reply->CalDAVElement($response, "calendar-data"); $responses[] = $response; continue; } foreach ($answer as $a) { if ($a === false) { $reply->CalDAVElement($response, "request-status", "3.7;Invalid Calendar User"); $reply->CalDAVElement($response, "calendar-data"); } elseif (substr($a, 0, 1) >= 1) { $reply->CalDAVElement($response, "request-status", $a); $reply->CalDAVElement($response, "calendar-data"); } else { $reply->CalDAVElement($response, "request-status", "2.0;Success"); $reply->CalDAVElement($response, "calendar-data", $a); } $responses[] = $response; } continue; } if (!($attendee_usr = $qry->Fetch())) { $request->DoResponse(501, 'Database error'); } if ((privilege_to_bits('schedule-query-freebusy') & bindec($attendee_usr->p)) == 0) { $reply->CalDAVElement($response, "request-status", "3.8;No authority"); $reply->CalDAVElement($response, "calendar-data"); $responses[] = $response; continue; } $attendee_path_match = '^/' . $attendee_usr->username . '/'; $fb = get_freebusy($attendee_path_match, $range_start, $range_end, bindec($attendee_usr->p)); $fb->AddProperty('UID', $ic->GetPValue('UID')); $fb->SetProperties($ic->GetProperties('ORGANIZER'), 'ORGANIZER'); $fb->AddProperty($attendee); $vcal = new vCalendar(array('METHOD' => 'REPLY')); $vcal->AddComponent($fb); $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:caldav'); $reply->CalDAVElement($response, "recipient", $reply->href($attendee->Value())); $reply->CalDAVElement($response, "request-status", "2.0;Success"); // Cargo-cult setting $reply->CalDAVElement($response, "calendar-data", $vcal->Render()); $responses[] = $response; } $response = $reply->NewXMLElement("schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:caldav'); $request->XMLResponse(200, $response); }
if (preg_match('{^/(\\S+@[a-z0-9][a-z0-9-]*[.][a-z0-9.-]+)/?$}i', $request->path, $matches)) { $principal = new Principal('email', $matches[1]); $path_match = '^' . $principal->dav_name(); } if (isset($fb_format) && $fb_format != 'text/calendar') { $request->DoResponse(406, translate('This server only supports the text/calendar format for freebusy URLs')); } if (!$request->HavePrivilegeTo('read-free-busy')) { $request->DoResponse(404); } require_once "freebusy-functions.php"; switch ($_SERVER['REQUEST_METHOD']) { case 'GET': $range_start = new RepeatRuleDateTime($fb_start); if (!isset($fb_end)) { $range_end = clone $range_start; $range_end->modify($fb_period); } else { $range_end = new RepeatRuleDateTime($fb_end); } $freebusy = get_freebusy($path_match, $range_start, $range_end); $result = new vCalendar(); $result->AddComponent($freebusy); $request->DoResponse(200, $result->Render(), 'text/calendar'); break; default: dbg_error_log("freebusy", "Unhandled request method >>%s<<", $_SERVER['REQUEST_METHOD']); dbg_log_array("freebusy", 'HEADERS', $raw_headers); dbg_log_array("freebusy", '_SERVER', $_SERVER, true); @dbg_error_log("freebusy", "RAW: %s", str_replace("\n", "", str_replace("\r", "", $request->raw_post))); }