Overview

Packages

  • awl
    • caldav-client-v2
    • RRule
  • davical
    • authentication
      • drivers
    • caldav
    • DAViCalSession
    • DAVTicket
    • external-bind
    • feed
    • HTTPAuthSession
    • iSchedule
    • iSchedule-POST
    • logging
    • metrics
    • Principal
    • propfind
    • PublicSession
    • Request
    • Resource
    • tzservice
  • None
  • PHP

Functions

  • add_failure
  • check_for_expansion
  • component_to_xml
  • controlRequestContainer
  • delete_collection
  • deliverItipCancel
  • display_status
  • do_scheduling_for_delete
  • do_scheduling_reply
  • do_scheduling_requests
  • doImipMessage
  • doItipAttendeeReply
  • doItipOrganizerCancel
  • export_iCalendar
  • GetItip
  • GetTZID
  • handle_cancel_request
  • handle_freebusy_request
  • handle_schedule_reply
  • handle_schedule_request
  • import_addressbook_collection
  • import_calendar_collection
  • import_collection
  • late_catch_fatal_error
  • logRequestHeaders
  • obfuscated_event
  • process_ace
  • processItipCancel
  • property_response
  • public_events_only
  • rollback
  • rollback_on_error
  • send_dav_header
  • simple_write_resource
  • write_alarms
  • write_attendees
  • write_resource
  • Overview
  • Package
  • Function
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: /**
  3: * CalDAV Server - handle PUT method
  4: *
  5: * @package   davical
  6: * @subpackage   caldav
  7: * @author    Andrew McMillan <andrew@morphoss.com>
  8: * @copyright Morphoss Ltd - http://www.morphoss.com/
  9: * @license   http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
 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:     /** @todo Refactor this so we only do one query here and loop through the results */
 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:       // Unlikely, but if we get more than one result we'll do an exact match instead.
 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:         /** Sigh... Go back to the original case-insensitive match */
 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" );  // Cargo-cult setting
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" );  // Cargo-cult setting
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: 
DAViCal API documentation generated by ApiGen 2.8.0