1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11: dbg_error_log("POST", "method handler");
12:
13: require_once("XMLDocument.php");
14: include_once('caldav-PUT-functions.php');
15: include_once('freebusy-functions.php');
16: include_once('iSchedule.php');
17:
18: if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || isset($c->dbg['post'])) ) {
19: $fh = fopen('/var/log/davical/POST.debug','w');
20: if ( $fh ) {
21: fwrite($fh,$request->raw_post);
22: fclose($fh);
23: }
24: }
25:
26:
27: function handle_freebusy_request( $ic ) {
28: global $c, $session, $request, $ical;
29:
30: $request->NeedPrivilege('CALDAV:schedule-send-freebusy');
31: $reply = new XMLDocument( array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C" ) );
32: $responses = array();
33:
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' );
38: }
39:
40: $range_start = new RepeatRuleDateTime($fbq_start);
41: $range_end = new RepeatRuleDateTime($fbq_end);
42:
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 ) {
48: $attendees[] = $v;
49: }
50: }
51: dbg_error_log( "POST", "Responding with free/busy for %d attendees", count($attendees) );
52:
53: foreach( $attendees AS $k => $attendee ) {
54: $attendee_email = preg_replace( '/^mailto:/', '', $attendee->Value() );
55: dbg_error_log( "POST", "Calculating free/busy for %s", $attendee_email );
56:
57:
58: $params = array( ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth, ':email' => $attendee_email );
59: $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 );
60: if ( !$qry->Exec('POST',__LINE__,__FILE__) ) $request->DoResponse( 501, 'Database error');
61: if ( $qry->rows() > 1 ) {
62:
63: 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 ) )
64: $request->DoResponse( 501, 'Database error');
65: if ( $qry->rows() == 0 ) {
66:
67: $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 );
68: }
69: }
70:
71: $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:caldav');
72: $reply->CalDAVElement($response, "recipient", $reply->href($attendee->Value()) );
73:
74: if ( $qry->rows() == 0 ) {
75: $remote = new iSchedule ();
76: $answer = $remote->sendRequest ( $attendee->Value(), 'VFREEBUSY/REQUEST', $ical->Render() );
77: if ( $answer === false ) {
78: $reply->CalDAVElement($response, "request-status", "3.7;Invalid Calendar User" );
79: $reply->CalDAVElement($response, "calendar-data" );
80: $responses[] = $response;
81: continue;
82: }
83:
84: foreach ( $answer as $a )
85: {
86: if ( $a === false ) {
87: $reply->CalDAVElement($response, "request-status", "3.7;Invalid Calendar User" );
88: $reply->CalDAVElement($response, "calendar-data" );
89: }
90: elseif ( substr( $a, 0, 1 ) >= 1 ) {
91: $reply->CalDAVElement($response, "request-status", $a );
92: $reply->CalDAVElement($response, "calendar-data" );
93: }
94: else {
95: $reply->CalDAVElement($response, "request-status", "2.0;Success" );
96: $reply->CalDAVElement($response, "calendar-data", $a );
97: }
98: $responses[] = $response;
99: }
100: continue;
101: }
102: if ( ! $attendee_usr = $qry->Fetch() ) $request->DoResponse( 501, 'Database error');
103: if ( (privilege_to_bits('schedule-query-freebusy') & bindec($attendee_usr->p)) == 0 ) {
104: $reply->CalDAVElement($response, "request-status", "3.8;No authority" );
105: $reply->CalDAVElement($response, "calendar-data" );
106: $responses[] = $response;
107: continue;
108: }
109: $attendee_path_match = '^/'.$attendee_usr->username.'/';
110: $fb = get_freebusy( $attendee_path_match, $range_start, $range_end, bindec($attendee_usr->p) );
111:
112: $fb->AddProperty( 'UID', $ic->GetPValue('UID') );
113: $fb->SetProperties( $ic->GetProperties('ORGANIZER'), 'ORGANIZER');
114: $fb->AddProperty( $attendee );
115:
116: $vcal = new vCalendar( array('METHOD' => 'REPLY') );
117: $vcal->AddComponent( $fb );
118:
119: $response = $reply->NewXMLElement( "response", false, false, 'urn:ietf:params:xml:ns:caldav' );
120: $reply->CalDAVElement($response, "recipient", $reply->href($attendee->Value()) );
121: $reply->CalDAVElement($response, "request-status", "2.0;Success" );
122: $reply->CalDAVElement($response, "calendar-data", $vcal->Render() );
123: $responses[] = $response;
124: }
125:
126: $response = $reply->NewXMLElement( "schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:caldav' );
127: $request->XMLResponse( 200, $response );
128: }
129:
130:
131: function handle_cancel_request( $ic ) {
132: global $c, $session, $request;
133:
134: $request->NeedPrivilege('CALDAV:schedule-send-reply');
135:
136: $reply = new XMLDocument( array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C" ) );
137:
138: $response = $reply->NewXMLElement( "response", false, false, 'urn:ietf:params:xml:ns:caldav' );
139: $reply->CalDAVElement($response, "request-status", "2.0;Success" );
140: $response = $reply->NewXMLElement( "schedule-response", $response, $reply->GetXmlNsArray() );
141: $request->XMLResponse( 200, $response );
142: }
143:
144:
145: $ical = new vCalendar( $request->raw_post );
146: $method = $ical->GetPValue('METHOD');
147:
148: $resources = $ical->GetComponents('VTIMEZONE',false);
149: $first = $resources[0];
150: switch ( $method ) {
151: case 'REQUEST':
152: dbg_error_log('POST', 'Handling iTIP "REQUEST" method with "%s" component.', $method, $first->GetType() );
153: if ( $first->GetType() == 'VFREEBUSY' )
154: handle_freebusy_request( $first );
155: elseif ( $first->GetType() == 'VEVENT' ) {
156: $request->NeedPrivilege('CALDAV:schedule-send-invite');
157: handle_schedule_request( $ical );
158: }
159: else {
160: dbg_error_log('POST', 'Ignoring iTIP "REQUEST" with "%s" component.', $first->GetType() );
161: }
162: break;
163: case 'REPLY':
164: dbg_error_log('POST', 'Handling iTIP "REPLY" with "%s" component.', $first->GetType() );
165: $request->NeedPrivilege('CALDAV:schedule-send-reply');
166: handle_schedule_reply ( $ical );
167: break;
168:
169: case 'CANCEL':
170: dbg_error_log("POST", "Handling iTIP 'CANCEL' method.", $method );
171: handle_cancel_request( $first );
172: break;
173:
174: default:
175: dbg_error_log("POST", "Unhandled '%s' method in request.", $method );
176: }
177: