1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177:
<?php
dbg_error_log("POST", "method handler");
require_once("XMLDocument.php");
include_once('caldav-PUT-functions.php');
include_once('freebusy-functions.php');
include_once('iSchedule.php');
if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || isset($c->dbg['post'])) ) {
$fh = fopen('/var/log/davical/POST.debug','w');
if ( $fh ) {
fwrite($fh,$request->raw_post);
fclose($fh);
}
}
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 );
$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 ) {
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 ) {
$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" );
$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 );
}
function handle_cancel_request( $ic ) {
global $c, $session, $request;
$request->NeedPrivilege('CALDAV:schedule-send-reply');
$reply = new XMLDocument( array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C" ) );
$response = $reply->NewXMLElement( "response", false, false, 'urn:ietf:params:xml:ns:caldav' );
$reply->CalDAVElement($response, "request-status", "2.0;Success" );
$response = $reply->NewXMLElement( "schedule-response", $response, $reply->GetXmlNsArray() );
$request->XMLResponse( 200, $response );
}
$ical = new vCalendar( $request->raw_post );
$method = $ical->GetPValue('METHOD');
$resources = $ical->GetComponents('VTIMEZONE',false);
$first = $resources[0];
switch ( $method ) {
case 'REQUEST':
dbg_error_log('POST', 'Handling iTIP "REQUEST" method with "%s" component.', $method, $first->GetType() );
if ( $first->GetType() == 'VFREEBUSY' )
handle_freebusy_request( $first );
elseif ( $first->GetType() == 'VEVENT' ) {
$request->NeedPrivilege('CALDAV:schedule-send-invite');
handle_schedule_request( $ical );
}
else {
dbg_error_log('POST', 'Ignoring iTIP "REQUEST" with "%s" component.', $first->GetType() );
}
break;
case 'REPLY':
dbg_error_log('POST', 'Handling iTIP "REPLY" with "%s" component.', $first->GetType() );
$request->NeedPrivilege('CALDAV:schedule-send-reply');
handle_schedule_reply ( $ical );
break;
case 'CANCEL':
dbg_error_log("POST", "Handling iTIP 'CANCEL' method.", $method );
handle_cancel_request( $first );
break;
default:
dbg_error_log("POST", "Unhandled '%s' method in request.", $method );
}