11dbg_error_log(
"POST",
"method handler");
13require_once(
"XMLDocument.php");
14include_once(
'caldav-PUT-functions.php');
15include_once(
'freebusy-functions.php');
16include_once(
'iSchedule.php');
18if ( ! ini_get(
'open_basedir') && (isset($c->dbg[
'ALL']) || isset($c->dbg[
'post'])) ) {
19 $fh = fopen(
'/var/log/davical/POST.debug',
'w');
21 fwrite($fh,$request->raw_post);
27function handle_freebusy_request( $ic ) {
28 global $c, $session, $request, $ical;
30 $request->NeedPrivilege(
'urn:ietf:params:xml:ns:caldav:schedule-send-freebusy');
31 $reply =
new XMLDocument( array(
"DAV:" =>
"",
"urn:ietf:params:xml:ns:caldav" =>
"C" ) );
34 $fbq_start = $ic->GetPValue(
'DTSTART');
35 $fbq_end = $ic->GetPValue(
'DTEND');
36 if ( ! ( isset($fbq_start) || isset($fbq_end) ) ) {
37 $request->DoResponse( 400,
'All valid freebusy requests MUST contain a DTSTART and a DTEND' );
43 $attendees = $ic->GetProperties(
'ATTENDEE');
44 if ( preg_match(
'# iCal/\d#', $_SERVER[
'HTTP_USER_AGENT']) ) {
45 dbg_error_log(
"POST",
"Non-compliant iCal request. Using X-WR-ATTENDEE property" );
46 $wr_attendees = $ic->GetProperties(
'X-WR-ATTENDEE');
47 foreach( $wr_attendees AS $k => $v ) {
51 dbg_error_log(
"POST",
"Responding with free/busy for %d attendees", count($attendees) );
53 if (isset($c->enable_attendee_group_resolution) && $c->enable_attendee_group_resolution) {
54 $new_attendees = array();
55 foreach( $attendees AS $attendee ) {
56 $v = $attendee->Value();
58 if ($v ==
"invalid:nomail") {
59 $localname = $attendee->GetParameterValue(
"CN");
60 }
else if ((preg_match(
'/^@/', $v) == 1) || (preg_match(
'/mailto:@/',$v) == 1)) {
61 $localname = preg_replace(
'/^.*@/',
'', $v);
62 }
else if (preg_match(
'/@/', $v) != 1) {
66 dbg_error_log(
'POST',
'try to resolve local attendee %s', $localname);
67 $qry =
new AwlQuery(
'SELECT fullname, email FROM usr WHERE user_no = (SELECT user_no FROM principal WHERE type_id = 1 AND user_no = (SELECT user_no FROM usr WHERE lower(username) = (text(:username)))) UNION SELECT fullname, email FROM usr WHERE user_no IN (SELECT user_no FROM principal WHERE principal_id IN (SELECT member_id FROM group_member WHERE group_id = (SELECT principal_id FROM principal WHERE type_id = 3 AND user_no = (SELECT user_no FROM usr WHERE lower(username) = (text(:username))))))', array(
':username' => strtolower($localname)));
68 if ( $qry->Exec(
'POST',__LINE__,__FILE__) && $qry->rows() >= 1 ) {
69 dbg_error_log(
'POST',
'resolved local name %s to %d individual attendees', $localname, $qry->rows());
70 while ($row = $qry->Fetch()) {
71 dbg_error_log(
'POST',
'adding individual attendee %s <%s>', $row->fullname, $row->email);
72 $new_attendees[] =
new vProperty(
"ATTENDEE:mailto:" . $row->email);
76 $new_attendees[] = clone($attendee);
79 $attendees = $new_attendees;
82 foreach( $attendees AS $k => $attendee ) {
83 $attendee_email = preg_replace(
'/^mailto:/',
'', $attendee->Value() );
84 dbg_error_log(
"POST",
"Calculating free/busy for %s", $attendee_email );
87 $params = array(
':session_principal' => $session->principal_id,
':scan_depth' => $c->permission_scan_depth,
':email' => $attendee_email );
88 $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 );
89 if ( !$qry->Exec(
'POST',__LINE__,__FILE__) ) $request->DoResponse( 501,
'Database error');
90 if ( $qry->rows() > 1 ) {
92 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 ) )
93 $request->DoResponse( 501,
'Database error');
94 if ( $qry->rows() == 0 ) {
96 $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 );
100 $response = $reply->NewXMLElement(
"response",
false,
false,
'urn:ietf:params:xml:ns:caldav');
101 $reply->CalDAVElement($response,
"recipient", $reply->href($attendee->Value()) );
103 if ( $qry->rows() == 0 ) {
105 $answer = $remote->sendRequest ( $attendee->Value(),
'VFREEBUSY/REQUEST', $ical->Render() );
106 if ( $answer ===
false ) {
107 $reply->CalDAVElement($response,
"request-status",
"3.7;Invalid Calendar User" );
108 $reply->CalDAVElement($response,
"calendar-data" );
109 $responses[] = $response;
113 foreach ( $answer as $a )
115 if ( $a ===
false ) {
116 $reply->CalDAVElement($response,
"request-status",
"3.7;Invalid Calendar User" );
117 $reply->CalDAVElement($response,
"calendar-data" );
119 elseif ( substr( $a, 0, 1 ) >= 1 ) {
120 $reply->CalDAVElement($response,
"request-status", $a );
121 $reply->CalDAVElement($response,
"calendar-data" );
124 $reply->CalDAVElement($response,
"request-status",
"2.0;Success" );
125 $reply->CalDAVElement($response,
"calendar-data", $a );
127 $responses[] = $response;
131 if ( ! $attendee_usr = $qry->Fetch() ) $request->DoResponse( 501,
'Database error');
132 if ( (privilege_to_bits(
'schedule-query-freebusy') & bindec($attendee_usr->p)) == 0 ) {
133 $reply->CalDAVElement($response,
"request-status",
"3.8;No authority" );
134 $reply->CalDAVElement($response,
"calendar-data" );
135 $responses[] = $response;
138 $attendee_path_match =
'^/'.$attendee_usr->username.
'/';
139 $fb = get_freebusy( $attendee_path_match, $range_start, $range_end, bindec($attendee_usr->p) );
141 $fb->AddProperty(
'UID', $ic->GetPValue(
'UID') );
142 $fb->SetProperties( $ic->GetProperties(
'ORGANIZER'),
'ORGANIZER');
143 $fb->AddProperty( $attendee );
145 $vcal =
new vCalendar( array(
'METHOD' =>
'REPLY') );
146 $vcal->AddComponent( $fb );
148 $response = $reply->NewXMLElement(
"response",
false,
false,
'urn:ietf:params:xml:ns:caldav' );
149 $reply->CalDAVElement($response,
"recipient", $reply->href($attendee->Value()) );
150 $reply->CalDAVElement($response,
"request-status",
"2.0;Success" );
151 $reply->CalDAVElement($response,
"calendar-data", $vcal->Render() );
152 $responses[] = $response;
155 $response = $reply->NewXMLElement(
"schedule-response", $responses, $reply->GetXmlNsArray(),
'urn:ietf:params:xml:ns:caldav' );
156 $request->XMLResponse( 200, $response );
160function handle_cancel_request( $ic ) {
161 global $c, $session, $request;
163 $request->NeedPrivilege(
'urn:ietf:params:xml:ns:caldav:schedule-send-reply');
165 $reply =
new XMLDocument( array(
"DAV:" =>
"",
"urn:ietf:params:xml:ns:caldav" =>
"C" ) );
167 $response = $reply->NewXMLElement(
"response",
false,
false,
'urn:ietf:params:xml:ns:caldav' );
168 $reply->CalDAVElement($response,
"request-status",
"2.0;Success" );
169 $response = $reply->NewXMLElement(
"schedule-response", $response, $reply->GetXmlNsArray() );
170 $request->XMLResponse( 200, $response );
174$ical =
new vCalendar( $request->raw_post );
175$method = $ical->GetPValue(
'METHOD');
177$resources = $ical->GetComponents(
'VTIMEZONE',
false);
178$first = $resources[0];
181 dbg_error_log(
'POST',
'Handling iTIP "REQUEST" method with "%s" component.', $method, $first->GetType() );
182 if ( $first->GetType() ==
'VFREEBUSY' )
183 handle_freebusy_request( $first );
184 elseif ( $first->GetType() ==
'VEVENT' ) {
185 $request->NeedPrivilege(
'urn:ietf:params:xml:ns:caldav:schedule-send-invite');
186 handle_schedule_request( $ical );
189 dbg_error_log(
'POST',
'Ignoring iTIP "REQUEST" with "%s" component.', $first->GetType() );
193 dbg_error_log(
'POST',
'Handling iTIP "REPLY" with "%s" component.', $first->GetType() );
194 $request->NeedPrivilege(
'urn:ietf:params:xml:ns:caldav:schedule-send-reply');
195 handle_schedule_reply ( $ical );
199 dbg_error_log(
"POST",
"Handling iTIP 'CANCEL' method.", $method );
200 handle_cancel_request( $first );
204 dbg_error_log(
"POST",
"Unhandled '%s' method in request.", $method );