Andrew's Web Libraries (AWL)
vCalendar.php
1 <?php
21 require_once('vComponent.php');
22 
23 class vCalendar extends vComponent {
24 
34  private $contained_type;
35  private $primary_component;
36  private $timezones;
37  private $organizer;
38  private $attendees;
39  private $schedule_agent;
40 
51  function __construct($content=null) {
52  $this->contained_type = null;
53  $this->primary_component = null;
54  $this->timezones = array();
55  if ( empty($content) || is_array($content) ) {
56  parent::__construct();
57  $this->SetType('VCALENDAR');
58  $this->AddProperty('PRODID', '-//davical.org//NONSGML AWL Calendar//EN');
59  $this->AddProperty('VERSION', '2.0');
60  $this->AddProperty('CALSCALE', 'GREGORIAN');
61  if ( !empty($content) ) {
62  foreach( $content AS $k => $v ) {
63  $this->AddProperty($k,$v);
64  }
65  }
66  }
67  else {
68  parent::__construct($content);
69  $components = $this->GetComponents();
70  if(isset($components) && count($components) > 0){
71  foreach( $components AS $k => $comp ) {
72  if ( $comp->GetType() == 'VTIMEZONE' ) {
73  $this->AddTimeZone($comp, true);
74  }
75  else if ( empty($this->contained_type) ) {
76  $this->contained_type = $comp->GetType();
77  $this->primary_component = $comp;
78  }
79  }
80  }
81 
82  if ( !isset($this->contained_type) && !empty($this->timezones) ) {
83  $this->contained_type = 'VTIMEZONE';
84  $this->primary_component = reset($this->timezones);
85  }
86  }
87  }
88 
89 
93  function AddTimeZone(vComponent $vtz, $in_components=false) {
94  $tzid = $vtz->GetPValue('TZID');
95  if ( empty($tzid) ) {
96  dbg_error_log('ERROR','Ignoring invalid VTIMEZONE with no TZID parameter!');
97  dbg_log_array('LOG', 'vTimezone', $vtz, true);
98  return;
99  }
100  $this->timezones[$tzid] = $vtz;
101  if ( !$in_components ) $this->AddComponent($vtz);
102  }
103 
104 
110  function GetTimeZone( $tzid ) {
111  if ( empty($this->timezones[$tzid]) ) return null;
112  return $this->timezones[$tzid];
113  }
114 
115 
120  function GetOrganizer() {
121  if ( !isset($this->organizer) ) {
122  $organizers = $this->GetPropertiesByPath('/VCALENDAR/*/ORGANIZER');
123  $organizer = (count($organizers) > 0 ? $organizers[0] : false);
124  $this->organizer = (empty($organizer) ? false : $organizer );
125  if ( $this->organizer ) {
126  $this->schedule_agent = $organizer->GetParameterValue('SCHEDULE-AGENT');
127  if ( empty($schedule_agent) ) $this->schedule_agent = 'SERVER';
128  }
129  }
130  return $this->organizer;
131  }
132 
133 
138  function GetScheduleAgent() {
139  if ( !isset($this->schedule_agent) ) $this->GetOrganizer();
140  return $this->schedule_agent;
141  }
142 
143 
147  function GetAttendees() {
148  if ( !isset($this->attendees) ) {
149  $this->attendees = array();
150  $attendees = $this->GetPropertiesByPath('/VCALENDAR/*/ATTENDEE');
151  $wr_attendees = $this->GetPropertiesByPath('/VCALENDAR/*/X-WR-ATTENDEE');
152  if ( count ( $wr_attendees ) > 0 ) {
153  dbg_error_log( 'PUT', 'Non-compliant iCal request. Using X-WR-ATTENDEE property' );
154  foreach( $wr_attendees AS $k => $v ) {
155  $attendees[] = $v;
156  }
157  }
158  $this->attendees = $attendees;
159  }
160  return $this->attendees;
161  }
162 
163 
164 
170  function UpdateAttendeeStatus( $email, vProperty $statusProperty ) {
171  foreach($this->GetComponents() AS $ck => $v ) {
172  if ($v->GetType() == 'VEVENT' || $v->GetType() == 'VTODO' ) {
173  $new_attendees = array();
174  foreach( $v->GetProperties() AS $p ) {
175  if ( $p->Name() == 'ATTENDEE' ) {
176  if ( $p->Value() == $email || $p->Value() == 'mailto:'.$email ) {
177  $new_attendees[] = $statusProperty;
178  }
179  else {
180  $new_attendees[] = clone($p);
181  }
182  }
183  }
184  $v->SetProperties($new_attendees,'ATTENDEE');
185  $this->attendees = null;
186  $this->rendered = null;
187  }
188  }
189  }
190 
191 
192 
197  function UpdateOrganizerStatus( vProperty $statusProperty ) {
198  $this->rendered = null;
199  foreach($this->GetComponents() AS $ck => $v ) {
200  if ($v->GetType() == 'VEVENT' || $v->GetType() == 'VTODO' ) {
201  $v->SetProperties(array($statusProperty), 'ORGANIZER');
202  $this->organizer = null;
203  $this->rendered = null;
204  }
205  }
206  }
207 
208 
209 
219  function StartFilter( $filters ) {
220  dbg_error_log('vCalendar', ':StartFilter we have %d filters to test', count($filters) );
221 
222  if ( count($filters) != 1 ) return false;
223 
224  $tag = $filters[0]->GetNSTag();
225  $name = $filters[0]->GetAttribute("name");
226  if ( $tag != "urn:ietf:params:xml:ns:caldav:comp-filter" || $name != 'VCALENDAR' ) return false;
227  return $this->TestFilter($filters[0]->GetContent());
228  }
229 
230 
237  function GetOlsonName( vComponent $vtz ) {
238  $tzstring = $vtz->GetPValue('TZID');
239  $tzid = olson_from_tzstring($tzstring);
240  if ( !empty($tzid) ) return $tzid;
241 
242  $tzstring = $vtz->GetPValue('X-LIC-LOCATION');
243  $tzid = olson_from_tzstring($tzstring);
244  if ( !empty($tzid) ) return $tzid;
245 
246  $tzcdo = $vtz->GetPValue('X-MICROSOFT-CDO-TZID');
247  if ( empty($tzcdo) ) return null;
248  switch( $tzcdo ) {
253  case 0: return('UTC');
254  case 1: return('Europe/London');
255  case 2: return('Europe/Lisbon');
256  case 3: return('Europe/Paris');
257  case 4: return('Europe/Berlin');
258  case 5: return('Europe/Bucharest');
259  case 6: return('Europe/Prague');
260  case 7: return('Europe/Athens');
261  case 8: return('America/Brasilia');
262  case 9: return('America/Halifax');
263  case 10: return('America/New_York');
264  case 11: return('America/Chicago');
265  case 12: return('America/Denver');
266  case 13: return('America/Los_Angeles');
267  case 14: return('America/Anchorage');
268  case 15: return('Pacific/Honolulu');
269  case 16: return('Pacific/Apia');
270  case 17: return('Pacific/Auckland');
271  case 18: return('Australia/Brisbane');
272  case 19: return('Australia/Adelaide');
273  case 20: return('Asia/Tokyo');
274  case 21: return('Asia/Singapore');
275  case 22: return('Asia/Bangkok');
276  case 23: return('Asia/Kolkata');
277  case 24: return('Asia/Muscat');
278  case 25: return('Asia/Tehran');
279  case 26: return('Asia/Baghdad');
280  case 27: return('Asia/Jerusalem');
281  case 28: return('America/St_Johns');
282  case 29: return('Atlantic/Azores');
283  case 30: return('America/Noronha');
284  case 31: return('Africa/Casablanca');
285  case 32: return('America/Argentina/Buenos_Aires');
286  case 33: return('America/La_Paz');
287  case 34: return('America/Indiana/Indianapolis');
288  case 35: return('America/Bogota');
289  case 36: return('America/Regina');
290  case 37: return('America/Tegucigalpa');
291  case 38: return('America/Phoenix');
292  case 39: return('Pacific/Kwajalein');
293  case 40: return('Pacific/Fiji');
294  case 41: return('Asia/Magadan');
295  case 42: return('Australia/Hobart');
296  case 43: return('Pacific/Guam');
297  case 44: return('Australia/Darwin');
298  case 45: return('Asia/Shanghai');
299  case 46: return('Asia/Novosibirsk');
300  case 47: return('Asia/Karachi');
301  case 48: return('Asia/Kabul');
302  case 49: return('Africa/Cairo');
303  case 50: return('Africa/Harare');
304  case 51: return('Europe/Moscow');
305  case 53: return('Atlantic/Cape_Verde');
306  case 54: return('Asia/Yerevan');
307  case 55: return('America/Panama');
308  case 56: return('Africa/Nairobi');
309  case 58: return('Asia/Yekaterinburg');
310  case 59: return('Europe/Helsinki');
311  case 60: return('America/Godthab');
312  case 61: return('Asia/Rangoon');
313  case 62: return('Asia/Kathmandu');
314  case 63: return('Asia/Irkutsk');
315  case 64: return('Asia/Krasnoyarsk');
316  case 65: return('America/Santiago');
317  case 66: return('Asia/Colombo');
318  case 67: return('Pacific/Tongatapu');
319  case 68: return('Asia/Vladivostok');
320  case 69: return('Africa/Ndjamena');
321  case 70: return('Asia/Yakutsk');
322  case 71: return('Asia/Dhaka');
323  case 72: return('Asia/Seoul');
324  case 73: return('Australia/Perth');
325  case 74: return('Asia/Riyadh');
326  case 75: return('Asia/Taipei');
327  case 76: return('Australia/Sydney');
328 
329  case 57: // null
330  case 52: // null
331  default: // null
332  }
333  return null;
334  }
335 
336 
342  function Confidential() {
343  static $keep_properties = array( 'DTSTAMP'=>1, 'DTSTART'=>1, 'RRULE'=>1, 'DURATION'=>1, 'DTEND'=>1, 'DUE'=>1, 'UID'=>1, 'CLASS'=>1, 'TRANSP'=>1, 'CREATED'=>1, 'LAST-MODIFIED'=>1 );
344  static $resource_components = array( 'VEVENT'=>1, 'VTODO'=>1, 'VJOURNAL'=>1 );
345  $this->MaskComponents(array( 'VTIMEZONE'=>1, 'VEVENT'=>1, 'VTODO'=>1, 'VJOURNAL'=>1 ), false);
346  $this->MaskProperties($keep_properties, $resource_components );
347  if ( isset($this->rendered) ) unset($this->rendered);
348  foreach( $this->GetComponents() AS $comp ) {
349  if ( isset($resource_components[$comp->GetType()] ) ) {
350  if ( isset($comp->rendered) ) unset($comp->rendered);
351  $comp->AddProperty( 'SUMMARY', translate('Busy') );
352  }
353  }
354 
355  return $this;
356  }
357 
358 
362  function GetItip($method, $attendee_value ) {
363  $iTIP = clone($this);
364  static $keep_properties = array( 'DTSTART'=>1, 'DURATION'=>1, 'DTEND'=>1, 'DUE'=>1, 'UID'=>1,
365  'SEQUENCE'=>1, 'ORGANIZER'=>1, 'ATTENDEE'=>1 );
366  static $resource_components = array( 'VEVENT'=>1, 'VTODO'=>1, 'VJOURNAL'=>1 );
367  $iTIP->MaskComponents($resource_components, false);
368  $iTIP->MaskProperties($keep_properties, $resource_components );
369  $iTIP->AddProperty('METHOD',$method);
370  if ( isset($iTIP->rendered) ) unset($iTIP->rendered);
371  if ( !empty($attendee_value) ) {
372  $iTIP->attendees = array();
373  foreach( $iTIP->GetComponents() AS $comp ) {
374  if ( isset($resource_components[$comp->GetType()] ) ) {
375  foreach( $comp->GetProperties() AS $k=> $property ) {
376  switch( $property->Name() ) {
377  case 'ATTENDEE':
378  if ( $property->Value() == $attendee_value )
379  $iTIP->attendees[] = $property->ClearParameters(array('CUTYPE'=>true, 'SCHEDULE-STATUS'=>true));
380  else
381  $comp->clearPropertyAt($k);
382  break;
383  }
384  }
385  $comp->AddProperty('DTSTAMP', date('Ymd\THis\Z'));
386  }
387  }
388  }
389 
390  return $iTIP;
391  }
392 
393 
397  function GetUID() {
398  if ( empty($this->primary_component) ) return null;
399  return $this->primary_component->GetPValue('UID');
400 
401  }
402 
403 
408  function SetUID( $newUid ) {
409  if ( empty($this->primary_component) ) return;
410  $this->primary_component->SetProperties( array( new vProperty('UID', $newUid) ), 'UID');
411  }
412 
413 }
UpdateAttendeeStatus( $email, vProperty $statusProperty)
Definition: vCalendar.php:170
AddTimeZone(vComponent $vtz, $in_components=false)
Definition: vCalendar.php:93
__construct($content=null)
Definition: vCalendar.php:51
GetAttendees()
Definition: vCalendar.php:147
UpdateOrganizerStatus(vProperty $statusProperty)
Definition: vCalendar.php:197
GetOrganizer()
Definition: vCalendar.php:120
GetTimeZone( $tzid)
Definition: vCalendar.php:110
GetOlsonName(vComponent $vtz)
Definition: vCalendar.php:237
Confidential()
Definition: vCalendar.php:342
StartFilter( $filters)
Definition: vCalendar.php:219
SetUID( $newUid)
Definition: vCalendar.php:408
GetScheduleAgent()
Definition: vCalendar.php:138
GetItip($method, $attendee_value)
Definition: vCalendar.php:362
AddComponent( $new_component)
Definition: vComponent.php:666
AddProperty( $new_property, $value=null, $parameters=null)
Definition: vComponent.php:550
GetPValue( $type)
Definition: vComponent.php:399
MaskComponents( $keep, $recursive=true)
Definition: vComponent.php:699
GetPropertiesByPath( $path)
Definition: vComponent.php:457
MaskProperties( $keep, $component_list=null)
Definition: vComponent.php:723
GetComponents( $type=null, $normal_match=true)
Definition: vComponent.php:581
SetType( $type)
Definition: vComponent.php:343
TestFilter( $filters)
Definition: vComponent.php:928