1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11:
12: require_once('iSchedule.php');
13: require_once('vComponent.php');
14: require_once('vCalendar.php');
15: require_once('WritableCollection.php');
16: include_once('freebusy-functions.php');
17:
18:
19: class FakeSession {
20: function __construct($principal) {
21:
22: foreach( $principal AS $k => $v ) {
23: $this->{$k} = $v;
24: }
25: $this->username = $principal->username();
26: $this->user_no = $principal->user_no();
27: $this->principal_id = $principal->principal_id();
28: $this->email = $principal->email();
29: $this->dav_name = $principal->dav_name();
30: $this->principal = $principal;
31:
32: $this->logged_in = true;
33:
34: }
35:
36: function AllowedTo($do_something) {
37: return true;
38: }
39: }
40:
41: $d = new iSchedule ();
42: if ( $d->validateRequest ( ) ) {
43: $ical = new vCalendar( $request->raw_post );
44: $attendee = Array ();
45: $addresses = Array ();
46: $attendees = $ical->GetAttendees();
47: foreach( $attendees AS $v ) {
48: $email = preg_replace( '/^mailto:/i', '', $v->Value() );
49: $addresses[] = $email;
50: }
51: $organizer = $ical->GetOrganizer();
52: $addresses[] = preg_replace( '/^mailto:/i', '', $organizer->Value() );
53: $recipients = Array ();
54: $attendees_ok = Array ();
55: $attendees_fail = Array ();
56: if ( strpos ( $_SERVER['HTTP_RECIPIENT'], ',' ) === false ) {
57: $recipients[] = $_SERVER['HTTP_RECIPIENT'];
58: }
59: else {
60: $rcpt = explode ( ',', $_SERVER['HTTP_RECIPIENT'] );
61: foreach ( $rcpt as $k => $v ) {
62: $recipients[$k] = preg_replace( '/^mailto:/i', '', trim ( $v ) );
63: }
64: }
65: if ( ! in_array ( preg_replace( '/^mailto:/i', '', $_SERVER['HTTP_ORIGINATOR'] ), $addresses ) ) {
66: $request->DoResponse( 412, translate('sender must be organizer or attendee of event') );
67: }
68: foreach ( $recipients as $v ) {
69: if ( ! in_array ( preg_replace( '/^mailto:/i', '', $v ), $addresses ) ) {
70: dbg_error_log('ischedule','recipient missing from event ' . $v );
71: $reply->XMLResponse( 403, translate('recipient must be organizer or attendee of event') . $v );
72: continue;
73: }
74: $email = preg_replace( '/^mailto:/', '', $v );
75: dbg_error_log('ischedule','recipient ' . $v );
76: $schedule_target = new Principal('email',$email);
77: if ( $schedule_target == false ){
78: array_push ( $attendees_fail, $schedule_target );
79: continue;
80: }
81: array_push ( $attendees_ok, $schedule_target );
82:
83: }
84: $method = $ical->GetPValue('METHOD');
85: $content_type = explode ( ';', $_SERVER['CONTENT_TYPE'] );
86: if ( $content_type[0] != 'text/calendar' )
87: $reply->XMLResponse( 406, 'content must be text/calendar' );
88: $content_parts = Array ();
89: foreach ( $content_type as $v ) {
90: list ( $a, $b ) = explode ( '=', trim ( $v ), 2 );
91: $content_parts[strtolower($a)] = strtoupper($b);
92: }
93: if ( isset ( $content_parts['method'] ) )
94: $method = $content_parts['method'];
95: switch ( $method )
96: {
97: case 'REQUEST':
98: if ( $content_parts['component'] == 'VFREEBUSY' ) {
99: ischedule_freebusy_request ( $ical, $attendees_ok, $attendees_fail );
100: }
101: if ( $content_parts['component'] == 'VEVENT' ) {
102: ischedule_request ( $ical, $attendees_ok, $attendees_fail );
103:
104: }
105: if ( $content_parts['component'] == 'VTODO' ) {
106: ischedule_request ( $ical, $attendees_ok, $attendees_fail );
107:
108: }
109: if ( $content_parts['component'] == 'VJOURNAL' ) {
110:
111: }
112: break;
113: case 'REPLY':
114: ischedule_request ( $ical, $attendees_ok, $attendees_fail );
115: break;
116: case 'ADD':
117: ischedule_request ( $ical, $attendees_ok, $attendees_fail );
118: break;
119: case 'CANCEL':
120: ischedule_request ( $ical, $attendees_ok, $attendees_fail );
121: break;
122: case 'PUBLISH':
123: break;
124: case 'REFRESH':
125: break;
126: case 'COUNTER':
127: break;
128: case 'DECLINECOUNTER':
129: break;
130: default:
131: dbg_error_log('ischedule','invalid request' );
132: $request->DoResponse( 400, translate('invalid request') );
133: }
134: }
135: else {
136: dbg_error_log('ischedule','invalid request' );
137: $request->DoResponse( 400, translate('invalid request') );
138: }
139:
140: function ischedule_freebusy_request( $ic, $attendees, $attendees_fail) {
141: global $c, $session, $request;
142: $reply = new XMLDocument( array( "urn:ietf:params:xml:ns:ischedule" => "I" ) );
143: $icalAttendees = $ic->GetAttendees();
144: $responses = array();
145: $ical = $ic->GetComponents('VFREEBUSY');
146: $ical = $ical[0];
147: $fbq_start = $ical->GetPValue('DTSTART');
148: $fbq_end = $ical->GetPValue('DTEND');
149: if ( ! ( isset($fbq_start) || isset($fbq_end) ) ) {
150: $request->DoResponse( 400, 'All valid freebusy requests MUST contain a DTSTART and a DTEND' );
151: }
152:
153: $range_start = new RepeatRuleDateTime($fbq_start);
154: $range_end = new RepeatRuleDateTime($fbq_end);
155:
156: foreach( $attendees AS $k => $attendee ) {
157: $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
158: $fb = get_freebusy( '^'.$attendee->dav_name, $range_start, $range_end );
159:
160: $fb->AddProperty( 'UID', $ical->GetPValue('UID') );
161: $fb->SetProperties( $ical->GetProperties('ORGANIZER'), 'ORGANIZER');
162: foreach ( $ical->GetProperties('ATTENDEE') as $at ) {
163: if ( $at->Value() == 'mailto:' . $attendee->email )
164: $fb->AddProperty( $at );
165: }
166:
167: $vcal = new vCalendar( array('METHOD' => 'REPLY') );
168: $vcal->AddComponent( $fb );
169:
170: $response = $reply->NewXMLElement( "response", false, false, 'urn:ietf:params:xml:ns:ischedule' );
171: $response->NewElement( "recipient", 'mailto:'.$attendee->email, false, 'urn:ietf:params:xml:ns:ischedule' );
172: $response->NewElement( "request-status", "2.0;Success", false, 'urn:ietf:params:xml:ns:ischedule' );
173: $response->NewElement( "calendar-data", $vcal->Render(), false, 'urn:ietf:params:xml:ns:ischedule' );
174:
175: $responses[] = $response;
176: }
177:
178: foreach ( $attendees_fail AS $k => $attendee ) {
179: $XMLresponse = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
180: $XMLresponse->NewElement( "recipient", $reply->href('mailto:'.$attendee));
181: $XMLresponse->NewElement( "request-status",'5.3;cannot schedule this user, unknown or access denied');
182: $responses[] = $XMLresponse;
183: }
184: $response = $reply->NewXMLElement( "schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:ischedule' );
185: $request->XMLResponse( 200, $response );
186: }
187:
188: function ischedule_request( $ic, $attendees, $attendees_fail ) {
189: global $c, $session, $request;
190: $oldSession = $session;
191: $reply = new XMLDocument( array( "urn:ietf:params:xml:ns:ischedule" => "I" ) );
192: $responses = array();
193: $ical = $ic->GetComponents('VEVENT');
194: $ical = $ical[0];
195:
196: foreach ( $attendees AS $k => $attendee ) {
197: $XMLresponse = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
198: dbg_error_log('ischedule','scheduling event for ' .$attendee->email);
199: $schedule_target = new Principal('email',$attendee->email);
200: $response = '3.7';
201: if ( $schedule_target->Exists() ) {
202: $session = new FakeSession($schedule_target);
203: $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar')));
204: if ( !$attendee_calendar->Exists() ) {
205: dbg_error_log('ERROR','Default calendar at "%s" does not exist for user "%s"',
206: $attendee_calendar->dav_name(), $schedule_target->username());
207: $response = '5.3;cannot schedule this user, unknown or access denied';
208: }
209: else {
210: $attendee_inbox = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-inbox')));
211: if ( ! $attendee_inbox->HavePrivilegeTo('schedule-deliver-invite') ) {
212: $response = '3.8;denied';
213: }
214: else if ( $attendee_inbox->WriteCalendarMember($ic, false) !== false ) {
215: $response = '2.0;delivered';
216: }
217: }
218: $session = $oldSession;
219: }
220: dbg_error_log( 'ischedule', 'Status for attendee <%s> set to "%s"', $attendee->email, $response );
221: $XMLresponse->NewElement("recipient", 'mailto:'.$attendee->email, false, 'urn:ietf:params:xml:ns:ischedule' );
222: $XMLresponse->NewElement("request-status", $response, false, 'urn:ietf:params:xml:ns:ischedule' );
223: $responses[] = $XMLresponse;
224: }
225:
226: foreach ( $attendees_fail AS $k => $attendee ) {
227: $XMLresponse = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
228: $XMLresponse->NewElement("recipient", 'mailto:'.$attendee->email, false, 'urn:ietf:params:xml:ns:ischedule' );
229: $XMLresponse->NewElement("request-status", '5.3;cannot schedule this user, unknown or access denied', false, 'urn:ietf:params:xml:ns:ischedule' );
230: $responses[] = $XMLresponse;
231: }
232:
233: $response = $reply->NewXMLElement( "schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:ischedule' );
234: $request->XMLResponse( 200, $response );
235: }
236:
237: function ischedule_cancel( $ic, $attendees, $attendees_fail ) {
238: global $c, $session, $request;
239: $reply = new XMLDocument( array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C", "urn:ietf:params:xml:ns:ischedule" => "I" ) );
240: $responses = array();
241: $ical = $ic->GetComponents('VEVENT');
242: $ical = $ical[0];
243:
244: foreach ( $attendees AS $k => $attendee ) {
245: $XMLresponse = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
246: dbg_error_log('ischedule','scheduling event for ' .$attendee->email);
247: $schedule_target = new Principal('email',$attendee->email);
248: $response = '3.7';
249: if ( $schedule_target->Exists() ) {
250: $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar')));
251: if ( !$attendee_calendar->Exists() ) {
252: dbg_error_log('ERROR','Default calendar at "%s" does not exist for user "%s"',
253: $attendee_calendar->dav_name(), $schedule_target->username());
254: $response = '5.3;cannot schedule this user, unknown or access denied';
255: }
256: else {
257: $attendee_inbox = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-inbox')));
258: if ( ! $attendee_inbox->HavePrivilegeTo('schedule-deliver-invite') ) {
259: $response = '3.8;denied';
260: }
261: else if ( $attendee_inbox->WriteCalendarMember($ic, false) !== false ) {
262: $response = '2.0;delivered';
263: }
264: }
265: }
266: dbg_error_log( 'PUT', 'Status for attendee <%s> set to "%s"', $attendee->email, $response );
267: $XMLresponse->NewElement("recipient", $reply->href('mailto:'.$attendee->email), false, 'urn:ietf:params:xml:ns:ischedule' );
268: $XMLresponse->NewElement("request-status", $response, false, 'urn:ietf:params:xml:ns:ischedule' );
269: $responses[] = $XMLresponse;
270: }
271:
272: foreach ( $attendees_fail AS $k => $attendee ) {
273: $XMLresponse = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:ischedule');
274: $XMLresponse->NewElement("recipient", $reply->href('mailto:'.$attendee->email), false, 'urn:ietf:params:xml:ns:ischedule' );
275: $XMLresponse->NewElement("request-status", '5.3;cannot schedule this user, unknown or access denied', false, 'urn:ietf:params:xml:ns:ischedule' );
276: $responses[] = $XMLresponse;
277: }
278:
279: $response = $reply->NewXMLElement( "schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:ischedule' );
280: $request->XMLResponse( 200, $response );
281: }
282:
283: