|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00015 class iCalendar_component { 00016 var $name = NULL; 00017 var $properties = NULL; 00018 var $components = NULL; 00019 var $valid_properties = NULL; 00020 var $valid_components = NULL; 00025 var $parser_errors = NULL; 00026 00027 function __construct() { 00028 // Initialize the components array 00029 if(empty($this->components)) { 00030 $this->components = array(); 00031 foreach($this->valid_components as $name) { 00032 $this->components[$name] = array(); 00033 } 00034 } 00035 } 00036 00037 function get_name() { 00038 return $this->name; 00039 } 00040 00041 function add_property($name, $value = NULL, $parameters = NULL) { 00042 00043 // Uppercase first of all 00044 $name = strtoupper($name); 00045 00046 // Are we trying to add a valid property? 00047 $xname = false; 00048 if(!isset($this->valid_properties[$name])) { 00049 // If not, is it an x-name as per RFC 2445? 00050 if(!rfc2445_is_xname($name)) { 00051 return false; 00052 } 00053 // Since this is an xname, all components are supposed to allow this property 00054 $xname = true; 00055 } 00056 00057 // Create a property object of the correct class 00058 if($xname) { 00059 $property = new iCalendar_property_x; 00060 $property->set_name($name); 00061 } 00062 else { 00063 $classname = 'iCalendar_property_'.strtolower(str_replace('-', '_', $name)); 00064 $property = new $classname; 00065 } 00066 00067 // If $value is NULL, then this property must define a default value. 00068 if($value === NULL) { 00069 $value = $property->default_value(); 00070 if($value === NULL) { 00071 return false; 00072 } 00073 } 00074 00075 // Set this property's parent component to ourselves, because some 00076 // properties behave differently according to what component they apply to. 00077 $property->set_parent_component($this->name); 00078 00079 // Set parameters before value; this helps with some properties which 00080 // accept a VALUE parameter, and thus change their default value type. 00081 00082 // The parameters must be valid according to property specifications 00083 if(!empty($parameters)) { 00084 foreach($parameters as $paramname => $paramvalue) { 00085 if(!$property->set_parameter($paramname, $paramvalue)) { 00086 return false; 00087 } 00088 } 00089 00090 // Some parameters interact among themselves (e.g. ENCODING and VALUE) 00091 // so make sure that after the dust settles, these invariants hold true 00092 if(!$property->invariant_holds()) { 00093 return false; 00094 } 00095 } 00096 00097 // $value MUST be valid according to the property data type 00098 if(!$property->set_value($value)) { 00099 return false; 00100 } 00101 00102 // Check if the property already exists, and is limited to one occurrance, 00103 // DON'T overwrite the value - this can be done explicity with set_value() instead. 00104 if(!$xname && $this->valid_properties[$name] & RFC2445_ONCE && isset($this->properties[$name])) { 00105 return false; 00106 } 00107 else { 00108 // Otherwise add it to the instance array for this property 00109 $this->properties[$name][] = $property; 00110 } 00111 00112 // Finally: after all these, does the component invariant hold? 00113 if(!$this->invariant_holds()) { 00114 // If not, completely undo the property addition 00115 array_pop($this->properties[$name]); 00116 if(empty($this->properties[$name])) { 00117 unset($this->properties[$name]); 00118 } 00119 return false; 00120 } 00121 00122 return true; 00123 00124 } 00125 00126 function add_component($component) { 00127 00128 // With the detailed interface, you can add only components with this function 00129 if(!is_object($component) || !is_subclass_of($component, 'iCalendar_component')) { 00130 return false; 00131 } 00132 00133 $name = $component->get_name(); 00134 00135 // Only valid components as specified by this component are allowed 00136 if(!in_array($name, $this->valid_components)) { 00137 return false; 00138 } 00139 00140 // Add it 00141 $this->components[$name][] = $component; 00142 00143 return true; 00144 } 00145 00146 function get_property_list($name) { 00147 } 00148 00149 function invariant_holds() { 00150 return true; 00151 } 00152 00153 function is_valid() { 00154 // If we have any child components, check that they are all valid 00155 if(!empty($this->components)) { 00156 foreach($this->components as $component => $instances) { 00157 foreach($instances as $number => $instance) { 00158 if(!$instance->is_valid()) { 00159 return false; 00160 } 00161 } 00162 } 00163 } 00164 00165 // Finally, check the valid property list for any mandatory properties 00166 // that have not been set and do not have a default value 00167 foreach($this->valid_properties as $property => $propdata) { 00168 if(($propdata & RFC2445_REQUIRED) && empty($this->properties[$property])) { 00169 $classname = 'iCalendar_property_'.strtolower(str_replace('-', '_', $property)); 00170 $object = new $classname; 00171 if($object->default_value() === NULL) { 00172 return false; 00173 } 00174 unset($object); 00175 } 00176 } 00177 00178 return true; 00179 } 00180 00181 function serialize() { 00182 // Check for validity of the object 00183 if(!$this->is_valid()) { 00184 return false; 00185 } 00186 00187 // Maybe the object is valid, but there are some required properties that 00188 // have not been given explicit values. In that case, set them to defaults. 00189 foreach($this->valid_properties as $property => $propdata) { 00190 if(($propdata & RFC2445_REQUIRED) && empty($this->properties[$property])) { 00191 $this->add_property($property); 00192 } 00193 } 00194 00195 // Start tag 00196 $string = rfc2445_fold('BEGIN:'.$this->name) . RFC2445_CRLF; 00197 00198 // List of properties 00199 if(!empty($this->properties)) { 00200 foreach($this->properties as $name => $properties) { 00201 foreach($properties as $property) { 00202 $string .= $property->serialize(); 00203 } 00204 } 00205 } 00206 00207 // List of components 00208 if(!empty($this->components)) { 00209 foreach($this->components as $name => $components) { 00210 foreach($components as $component) { 00211 $string .= $component->serialize(); 00212 } 00213 } 00214 } 00215 00216 // End tag 00217 $string .= rfc2445_fold('END:'.$this->name) . RFC2445_CRLF; 00218 00219 return $string; 00220 } 00221 00233 function unserialize($string) { 00234 $string = rfc2445_unfold($string); // Unfold any long lines 00235 $lines = explode(RFC2445_CRLF, $string); // Create an array of lines 00236 00237 $components = array(); // Initialise a stack of components 00238 $this->clear_errors(); 00239 foreach ($lines as $key => $line) { 00240 // ignore empty lines 00241 if (trim($line) == '') { 00242 continue; 00243 } 00244 00245 // Divide the line up into label, parameters and data fields. 00246 if (!preg_match('#^(?P<label>[-[:alnum:]]+)(?P<params>(?:;(?:(?:[-[:alnum:]]+)=(?:[^[:cntrl:]";:,]+|"[^[:cntrl:]"]+")))*):(?P<data>.*)$#', $line, $match)) { 00247 $this->parser_error('Invalid line: '.$key.', ignoring'); 00248 continue; 00249 } 00250 00251 // parse parameters 00252 $params = array(); 00253 if (preg_match_all('#;(?P<param>[-[:alnum:]]+)=(?P<value>[^[:cntrl:]";:,]+|"[^[:cntrl:]"]+")#', $match['params'], $pmatch)) { 00254 $params = array_combine($pmatch['param'], $pmatch['value']); 00255 } 00256 $label = $match['label']; 00257 $data = $match['data']; 00258 unset($match, $pmatch); 00259 00260 if ($label == 'BEGIN') { 00261 // This is the start of a component. 00262 $current_component = array_pop($components); // Get the current component off the stack so we can check its valid components 00263 if ($current_component == null) { // If there's nothing on the stack 00264 $current_component = $this; // use the iCalendar 00265 } 00266 if (in_array($data, $current_component->valid_components)) { // Check that the new component is a valid subcomponent of the current one 00267 if($current_component != $this) { 00268 array_push($components, $current_component); // We're done with the current component, put it back on the stack. 00269 } 00270 if(strpos($data, 'V') === 0) { 00271 $data = substr($data, 1); 00272 } 00273 $cname = 'iCalendar_' . strtolower($data); 00274 $new_component = new $cname; 00275 array_push($components, $new_component); // Push a new component onto the stack 00276 } else { 00277 if($current_component != $this) { 00278 array_push($components, $current_component); 00279 $this->parser_error('Invalid component type on line '.$key); 00280 } 00281 } 00282 unset($current_component, $new_component); 00283 } else if ($label == 'END') { 00284 // It's the END of a component. 00285 $component = array_pop($components); // Pop the top component off the stack - we're now done with it 00286 $parent_component = array_pop($components); // Pop the component's conatining component off the stack so we can add this component to it. 00287 if($parent_component == null) { 00288 $parent_component = $this; // If there's no components on the stack, use the iCalendar object 00289 } 00290 if ($parent_component->add_component($component) === false) { 00291 $this->parser_error("Failed to add component on line $key"); 00292 } 00293 if ($parent_component != $this) { // If we're not using the iCalendar 00294 array_push($components, $parent_component); // Put the component back on the stack 00295 } 00296 unset($parent_component, $component); 00297 } else { 00298 00299 $component = array_pop($components); // Get the component off the stack so we can add properties to it 00300 if ($component == null) { // If there's nothing on the stack 00301 $component = $this; // use the iCalendar 00302 } 00303 00304 if ($component->add_property($label, $data, $params) === false) { 00305 $this->parser_error("Failed to add property '$label' on line $key"); 00306 } 00307 00308 if($component != $this) { // If we're not using the iCalendar 00309 array_push($components, $component); // Put the component back on the stack 00310 } 00311 unset($component); 00312 } 00313 00314 } 00315 00316 } 00317 00318 function clear_errors() { 00319 $this->parser_errors = array(); 00320 } 00321 00322 function parser_error($error) { 00323 $this->parser_errors[] = $error; 00324 } 00325 00326 } 00327 00328 class iCalendar extends iCalendar_component { 00329 var $name = 'VCALENDAR'; 00330 00331 function __construct() { 00332 $this->valid_properties = array( 00333 'CALSCALE' => RFC2445_OPTIONAL | RFC2445_ONCE, 00334 'METHOD' => RFC2445_OPTIONAL | RFC2445_ONCE, 00335 'PRODID' => RFC2445_REQUIRED | RFC2445_ONCE, 00336 'VERSION' => RFC2445_REQUIRED | RFC2445_ONCE, 00337 RFC2445_XNAME => RFC2445_OPTIONAL 00338 ); 00339 00340 $this->valid_components = array( 00341 'VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VTIMEZONE', 'VALARM' 00342 ); 00343 parent::__construct(); 00344 } 00345 00346 } 00347 00348 class iCalendar_event extends iCalendar_component { 00349 00350 var $name = 'VEVENT'; 00351 var $properties; 00352 00353 function __construct() { 00354 00355 $this->valid_components = array('VALARM'); 00356 00357 $this->valid_properties = array( 00358 'CLASS' => RFC2445_OPTIONAL | RFC2445_ONCE, 00359 'CREATED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00360 'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00361 // Standard ambiguous here: in 4.6.1 it says that DTSTAMP in optional, 00362 // while in 4.8.7.2 it says it's REQUIRED. Go with REQUIRED. 00363 'DTSTAMP' => RFC2445_REQUIRED | RFC2445_ONCE, 00364 // Standard ambiguous here: in 4.6.1 it says that DTSTART in optional, 00365 // while in 4.8.2.4 it says it's REQUIRED. Go with REQUIRED. 00366 'DTSTART' => RFC2445_REQUIRED | RFC2445_ONCE, 00367 'GEO' => RFC2445_OPTIONAL | RFC2445_ONCE, 00368 'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00369 'LOCATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00370 'ORGANIZER' => RFC2445_OPTIONAL | RFC2445_ONCE, 00371 'PRIORITY' => RFC2445_OPTIONAL | RFC2445_ONCE, 00372 'SEQUENCE' => RFC2445_OPTIONAL | RFC2445_ONCE, 00373 'STATUS' => RFC2445_OPTIONAL | RFC2445_ONCE, 00374 'SUMMARY' => RFC2445_OPTIONAL | RFC2445_ONCE, 00375 'TRANSP' => RFC2445_OPTIONAL | RFC2445_ONCE, 00376 // Standard ambiguous here: in 4.6.1 it says that UID in optional, 00377 // while in 4.8.4.7 it says it's REQUIRED. Go with REQUIRED. 00378 'UID' => RFC2445_REQUIRED | RFC2445_ONCE, 00379 'URL' => RFC2445_OPTIONAL | RFC2445_ONCE, 00380 'RECURRENCE-ID' => RFC2445_OPTIONAL | RFC2445_ONCE, 00381 'DTEND' => RFC2445_OPTIONAL | RFC2445_ONCE, 00382 'DURATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00383 'ATTACH' => RFC2445_OPTIONAL, 00384 'ATTENDEE' => RFC2445_OPTIONAL, 00385 'CATEGORIES' => RFC2445_OPTIONAL, 00386 'COMMENT' => RFC2445_OPTIONAL, 00387 'CONTACT' => RFC2445_OPTIONAL, 00388 'EXDATE' => RFC2445_OPTIONAL, 00389 'EXRULE' => RFC2445_OPTIONAL, 00390 'REQUEST-STATUS' => RFC2445_OPTIONAL, 00391 'RELATED-TO' => RFC2445_OPTIONAL, 00392 'RESOURCES' => RFC2445_OPTIONAL, 00393 'RDATE' => RFC2445_OPTIONAL, 00394 'RRULE' => RFC2445_OPTIONAL, 00395 RFC2445_XNAME => RFC2445_OPTIONAL 00396 ); 00397 00398 parent::__construct(); 00399 } 00400 00401 function invariant_holds() { 00402 // DTEND and DURATION must not appear together 00403 if(isset($this->properties['DTEND']) && isset($this->properties['DURATION'])) { 00404 return false; 00405 } 00406 00407 00408 if(isset($this->properties['DTEND']) && isset($this->properties['DTSTART'])) { 00409 // DTEND must be later than DTSTART 00410 // The standard is not clear on how to hande different value types though 00411 // TODO: handle this correctly even if the value types are different 00412 if($this->properties['DTEND'][0]->value <= $this->properties['DTSTART'][0]->value) { 00413 return false; 00414 } 00415 00416 // DTEND and DTSTART must have the same value type 00417 if($this->properties['DTEND'][0]->val_type != $this->properties['DTSTART'][0]->val_type) { 00418 return false; 00419 } 00420 00421 } 00422 return true; 00423 } 00424 00425 } 00426 00427 class iCalendar_todo extends iCalendar_component { 00428 var $name = 'VTODO'; 00429 var $properties; 00430 00431 function __construct() { 00432 00433 $this->valid_components = array('VALARM'); 00434 00435 $this->valid_properties = array( 00436 'CLASS' => RFC2445_OPTIONAL | RFC2445_ONCE, 00437 'COMPLETED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00438 'CREATED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00439 'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00440 'DTSTAMP' => RFC2445_OPTIONAL | RFC2445_ONCE, 00441 'DTSTAP' => RFC2445_OPTIONAL | RFC2445_ONCE, 00442 'GEO' => RFC2445_OPTIONAL | RFC2445_ONCE, 00443 'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00444 'LOCATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00445 'ORGANIZER' => RFC2445_OPTIONAL | RFC2445_ONCE, 00446 'PERCENT' => RFC2445_OPTIONAL | RFC2445_ONCE, 00447 'PRIORITY' => RFC2445_OPTIONAL | RFC2445_ONCE, 00448 'RECURID' => RFC2445_OPTIONAL | RFC2445_ONCE, 00449 'SEQUENCE' => RFC2445_OPTIONAL | RFC2445_ONCE, 00450 'STATUS' => RFC2445_OPTIONAL | RFC2445_ONCE, 00451 'SUMMARY' => RFC2445_OPTIONAL | RFC2445_ONCE, 00452 'UID' => RFC2445_OPTIONAL | RFC2445_ONCE, 00453 'URL' => RFC2445_OPTIONAL | RFC2445_ONCE, 00454 'DUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 00455 'DURATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00456 'ATTACH' => RFC2445_OPTIONAL, 00457 'ATTENDEE' => RFC2445_OPTIONAL, 00458 'CATEGORIES' => RFC2445_OPTIONAL, 00459 'COMMENT' => RFC2445_OPTIONAL, 00460 'CONTACT' => RFC2445_OPTIONAL, 00461 'EXDATE' => RFC2445_OPTIONAL, 00462 'EXRULE' => RFC2445_OPTIONAL, 00463 'RSTATUS' => RFC2445_OPTIONAL, 00464 'RELATED' => RFC2445_OPTIONAL, 00465 'RESOURCES' => RFC2445_OPTIONAL, 00466 'RDATE' => RFC2445_OPTIONAL, 00467 'RRULE' => RFC2445_OPTIONAL, 00468 RFC2445_XNAME => RFC2445_OPTIONAL 00469 ); 00470 00471 parent::__construct(); 00472 } 00473 00474 function invariant_holds() { 00475 // DTEND and DURATION must not appear together 00476 if(isset($this->properties['DTEND']) && isset($this->properties['DURATION'])) { 00477 return false; 00478 } 00479 00480 00481 if(isset($this->properties['DTEND']) && isset($this->properties['DTSTART'])) { 00482 // DTEND must be later than DTSTART 00483 // The standard is not clear on how to hande different value types though 00484 // TODO: handle this correctly even if the value types are different 00485 if($this->properties['DTEND'][0]->value <= $this->properties['DTSTART'][0]->value) { 00486 return false; 00487 } 00488 00489 // DTEND and DTSTART must have the same value type 00490 if($this->properties['DTEND'][0]->val_type != $this->properties['DTSTART'][0]->val_type) { 00491 return false; 00492 } 00493 00494 } 00495 00496 if(isset($this->properties['DUE']) && isset($this->properties['DTSTART'])) { 00497 if($this->properties['DUE'][0]->value <= $this->properties['DTSTART'][0]->value) { 00498 return false; 00499 } 00500 } 00501 00502 return true; 00503 } 00504 00505 } 00506 00507 class iCalendar_journal extends iCalendar_component { 00508 var $name = 'VJOURNAL'; 00509 var $properties; 00510 00511 function __construct() { 00512 00513 $this->valid_properties = array( 00514 'CLASS' => RFC2445_OPTIONAL | RFC2445_ONCE, 00515 'CREATED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00516 'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00517 'DTSTART' => RFC2445_OPTIONAL | RFC2445_ONCE, 00518 'DTSTAMP' => RFC2445_OPTIONAL | RFC2445_ONCE, 00519 'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00520 'ORGANIZER' => RFC2445_OPTIONAL | RFC2445_ONCE, 00521 'RECURRANCE-ID' => RFC2445_OPTIONAL | RFC2445_ONCE, 00522 'SEQUENCE' => RFC2445_OPTIONAL | RFC2445_ONCE, 00523 'STATUS' => RFC2445_OPTIONAL | RFC2445_ONCE, 00524 'SUMMARY' => RFC2445_OPTIONAL | RFC2445_ONCE, 00525 'UID' => RFC2445_OPTIONAL | RFC2445_ONCE, 00526 'URL' => RFC2445_OPTIONAL | RFC2445_ONCE, 00527 'ATTACH' => RFC2445_OPTIONAL, 00528 'ATTENDEE' => RFC2445_OPTIONAL, 00529 'CATEGORIES' => RFC2445_OPTIONAL, 00530 'COMMENT' => RFC2445_OPTIONAL, 00531 'CONTACT' => RFC2445_OPTIONAL, 00532 'EXDATE' => RFC2445_OPTIONAL, 00533 'EXRULE' => RFC2445_OPTIONAL, 00534 'RELATED-TO' => RFC2445_OPTIONAL, 00535 'RDATE' => RFC2445_OPTIONAL, 00536 'RRULE' => RFC2445_OPTIONAL, 00537 RFC2445_XNAME => RFC2445_OPTIONAL 00538 ); 00539 00540 parent::__construct(); 00541 00542 } 00543 } 00544 00545 class iCalendar_freebusy extends iCalendar_component { 00546 var $name = 'VFREEBUSY'; 00547 var $properties; 00548 00549 function __construct() { 00550 $this->valid_components = array(); 00551 $this->valid_properties = array( 00552 'CONTACT' => RFC2445_OPTIONAL | RFC2445_ONCE, 00553 'DTSTART' => RFC2445_OPTIONAL | RFC2445_ONCE, 00554 'DTEND' => RFC2445_OPTIONAL | RFC2445_ONCE, 00555 'DURATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00556 'DTSTAMP' => RFC2445_OPTIONAL | RFC2445_ONCE, 00557 'ORGANIZER' => RFC2445_OPTIONAL | RFC2445_ONCE, 00558 'UID' => RFC2445_OPTIONAL | RFC2445_ONCE, 00559 'URL' => RFC2445_OPTIONAL | RFC2445_ONCE, 00560 // TODO: the next two are components of their own! 00561 'ATTENDEE' => RFC2445_OPTIONAL, 00562 'COMMENT' => RFC2445_OPTIONAL, 00563 'FREEBUSY' => RFC2445_OPTIONAL, 00564 'RSTATUS' => RFC2445_OPTIONAL, 00565 RFC2445_XNAME => RFC2445_OPTIONAL 00566 ); 00567 00568 parent::__construct(); 00569 } 00570 00571 function invariant_holds() { 00572 // DTEND and DURATION must not appear together 00573 if(isset($this->properties['DTEND']) && isset($this->properties['DURATION'])) { 00574 return false; 00575 } 00576 00577 00578 if(isset($this->properties['DTEND']) && isset($this->properties['DTSTART'])) { 00579 // DTEND must be later than DTSTART 00580 // The standard is not clear on how to hande different value types though 00581 // TODO: handle this correctly even if the value types are different 00582 if($this->properties['DTEND'][0]->value <= $this->properties['DTSTART'][0]->value) { 00583 return false; 00584 } 00585 00586 // DTEND and DTSTART must have the same value type 00587 if($this->properties['DTEND'][0]->val_type != $this->properties['DTSTART'][0]->val_type) { 00588 return false; 00589 } 00590 00591 } 00592 return true; 00593 } 00594 } 00595 00596 class iCalendar_alarm extends iCalendar_component { 00597 var $name = 'VALARM'; 00598 var $properties; 00599 00600 function __construct() { 00601 $this->valid_components = array(); 00602 $this->valid_properties = array( 00603 'ACTION' => RFC2445_REQUIRED | RFC2445_ONCE, 00604 'TRIGGER' => RFC2445_REQUIRED | RFC2445_ONCE, 00605 // If one of these 2 occurs, so must the other. 00606 'DURATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00607 'REPEAT' => RFC2445_OPTIONAL | RFC2445_ONCE, 00608 // The following is required if action == "PROCEDURE" | "AUDIO" 00609 'ATTACH' => RFC2445_OPTIONAL, 00610 // The following is required if trigger == "EMAIL" | "DISPLAY" 00611 'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 00612 // The following are required if action == "EMAIL" 00613 'SUMMARY' => RFC2445_OPTIONAL | RFC2445_ONCE, 00614 'ATTENDEE' => RFC2445_OPTIONAL, 00615 RFC2445_XNAME => RFC2445_OPTIONAL 00616 ); 00617 00618 parent::__construct(); 00619 } 00620 00621 function invariant_holds() { 00622 // DTEND and DURATION must not appear together 00623 if(isset($this->properties['ACTION'])) { 00624 switch ($this->properties['ACTION'][0]->value) { 00625 case 'AUDIO': 00626 if (!isset($this->properties['ATTACH'])) { 00627 return false; 00628 } 00629 break; 00630 case 'DISPLAY': 00631 if (!isset($this->properties['DESCRIPTION'])) { 00632 return false; 00633 } 00634 break; 00635 case 'EMAIL': 00636 if (!isset($this->properties['DESCRIPTION']) || !isset($this->properties['SUMMARY']) || !isset($this->properties['ATTACH'])) { 00637 return false; 00638 } 00639 break; 00640 case 'PROCEDURE': 00641 if (!isset($this->properties['ATTACH']) || count($this->properties['ATTACH']) > 1) { 00642 return false; 00643 } 00644 break; 00645 } 00646 } 00647 return true; 00648 } 00649 00650 00651 } 00652 00653 class iCalendar_timezone extends iCalendar_component { 00654 var $name = 'VTIMEZONE'; 00655 var $properties; 00656 00657 function __construct() { 00658 00659 $this->valid_components = array('STANDARD', 'DAYLIGHT'); 00660 00661 $this->valid_properties = array( 00662 'TZID' => RFC2445_REQUIRED | RFC2445_ONCE, 00663 'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE, 00664 'TZURL' => RFC2445_OPTIONAL | RFC2445_ONCE, 00665 RFC2445_XNAME => RFC2445_OPTIONAL 00666 ); 00667 00668 parent::__construct(); 00669 } 00670 00671 } 00672 00673 class iCalendar_standard extends iCalendar_component { 00674 var $name = 'STANDARD'; 00675 var $properties; 00676 00677 function __construct() { 00678 $this->valid_components = array(); 00679 $this->valid_properties = array( 00680 'DTSTART' => RFC2445_REQUIRED | RFC2445_ONCE, 00681 'TZOFFSETTO' => RFC2445_REQUIRED | RFC2445_ONCE, 00682 'TZOFFSETFROM' => RFC2445_REQUIRED | RFC2445_ONCE, 00683 'COMMENT' => RFC2445_OPTIONAL, 00684 'RDATE' => RFC2445_OPTIONAL, 00685 'RRULE' => RFC2445_OPTIONAL, 00686 'TZNAME' => RFC2445_OPTIONAL, 00687 RFC2445_XNAME => RFC2445_OPTIONAL, 00688 ); 00689 parent::__construct(); 00690 } 00691 } 00692 00693 class iCalendar_daylight extends iCalendar_standard { 00694 var $name = 'DAYLIGHT'; 00695 } 00696 00697 // REMINDER: DTEND must be later than DTSTART for all components which support both 00698 // REMINDER: DUE must be later than DTSTART for all components which support both 00699