[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 <?php // $Id: iCalendar_components.php,v 1.8 2005/07/21 22:31:44 defacer Exp $ 2 require_once ('include/utils/utils.php'); 3 4 class iCalendar_component { 5 var $name = NULL; 6 var $properties = NULL; 7 var $components = NULL; 8 var $valid_properties = NULL; 9 var $valid_components = NULL; 10 11 function iCalendar_component() { 12 $this->construct(); 13 } 14 15 function construct() { 16 // Initialize the components array 17 if(empty($this->components)) { 18 $this->components = array(); 19 foreach($this->valid_components as $name) { 20 $this->components[$name] = array(); 21 } 22 } 23 } 24 25 function get_name() { 26 return $this->name; 27 } 28 29 function add_property($name, $value = NULL, $parameters = NULL) { 30 31 // Uppercase first of all 32 $name = strtoupper($name); 33 // Are we trying to add a valid property? 34 $xname = false; 35 if(!isset($this->valid_properties[$name])) { 36 // If not, is it an x-name as per RFC 2445? 37 if(!rfc2445_is_xname($name)) { 38 return false; 39 } 40 // Since this is an xname, all components are supposed to allow this property 41 $xname = true; 42 } 43 44 // Create a property object of the correct class 45 if($xname) { 46 $property = new iCalendar_property_x; 47 $property->set_name($name); 48 } 49 else { 50 $classname = 'iCalendar_property_'.strtolower(str_replace('-', '_', $name)); 51 $property = new $classname; 52 } 53 // If $value is NULL, then this property must define a default value. 54 if($value === NULL) { 55 $value = $property->default_value(); 56 if($value === NULL) { 57 return false; 58 } 59 } 60 61 // Set this property's parent component to ourselves, because some 62 // properties behave differently according to what component they apply to. 63 $property->set_parent_component($this->name); 64 65 // Set parameters before value; this helps with some properties which 66 // accept a VALUE parameter, and thus change their default value type. 67 68 // The parameters must be valid according to property specifications 69 if(!empty($parameters)) { 70 foreach($parameters as $paramname => $paramvalue) { 71 if(!$property->set_parameter($paramname, $paramvalue)) { 72 return false; 73 } 74 } 75 76 // Some parameters interact among themselves (e.g. ENCODING and VALUE) 77 // so make sure that after the dust settles, these invariants hold true 78 if(!$property->invariant_holds()) { 79 return false; 80 } 81 } 82 83 // $value MUST be valid according to the property data type 84 if(!$property->set_value($value)) { 85 return false; 86 } 87 88 // If this property is restricted to only once, blindly overwrite value 89 if(!$xname && $this->valid_properties[$name] & RFC2445_ONCE) { 90 $this->properties[$name] = array($property); 91 } 92 93 // Otherwise add it to the instance array for this property 94 else { 95 $this->properties[$name][] = $property; 96 } 97 98 // Finally: after all these, does the component invariant hold? 99 if(!$this->invariant_holds()) { 100 // If not, completely undo the property addition 101 array_pop($this->properties[$name]); 102 if(empty($this->properties[$name])) { 103 unset($this->properties[$name]); 104 } 105 return false; 106 } 107 108 return true; 109 110 } 111 112 function add_component($component) { 113 114 // With the detailed interface, you can add only components with this function 115 if(!is_object($component) || !is_subclass_of($component, 'iCalendar_component')) { 116 return false; 117 } 118 119 $name = $component->get_name(); 120 121 // Only valid components as specified by this component are allowed 122 if(!in_array($name, $this->valid_components)) { 123 return false; 124 } 125 126 // Add it 127 $this->components[$name][] = $component; 128 129 return true; 130 } 131 132 function get_property_list($name) { 133 } 134 135 function invariant_holds() { 136 return true; 137 } 138 139 function is_valid() { 140 // If we have any child components, check that they are all valid 141 if(!empty($this->components)) { 142 foreach($this->components as $component => $instances) { 143 foreach($instances as $number => $instance) { 144 if(!$instance->is_valid()) { 145 return false; 146 } 147 } 148 } 149 } 150 // Finally, check the valid property list for any mandatory properties 151 // that have not been set and do not have a default value 152 foreach($this->valid_properties as $property => $propdata) { 153 if(($propdata & RFC2445_REQUIRED) && empty($this->properties[$property])) { 154 $classname = 'iCalendar_property_'.strtolower(str_replace('-', '_', $property)); 155 $object = new $classname; 156 if($object->default_value() === NULL) { 157 return false; 158 } 159 unset($object); 160 } 161 } 162 163 return true; 164 } 165 166 function serialize() { 167 // Check for validity of the object 168 if(!$this->is_valid()) { 169 return false; 170 } 171 172 // Maybe the object is valid, but there are some required properties that 173 // have not been given explicit values. In that case, set them to defaults. 174 foreach($this->valid_properties as $property => $propdata) { 175 if(($propdata & RFC2445_REQUIRED) && empty($this->properties[$property])) { 176 $this->add_property($property); 177 } 178 } 179 180 // Start tag 181 $string = rfc2445_fold('BEGIN:'.$this->name) . RFC2445_CRLF; 182 // List of properties 183 if(!empty($this->properties)) { 184 foreach($this->properties as $name => $properties) { 185 foreach($properties as $property) { 186 $string .= $property->serialize(); 187 } 188 } 189 } 190 // List of components 191 if(!empty($this->components)) { 192 foreach($this->components as $name => $components) { 193 foreach($components as $component) { 194 $string .= $component->serialize(); 195 } 196 } 197 } 198 199 // End tag 200 $string .= rfc2445_fold('END:'.$this->name) . RFC2445_CRLF; 201 202 return $string; 203 } 204 205 function assign_values($activity) { 206 foreach($this->mapping_arr as $key=>$components){ 207 if(!is_array($components['component']) && empty($components['function'])){ 208 $this->add_property($key,$activity[$components['component']]); 209 } else if(is_array($components['component']) && empty($components['function'])){ 210 $component = ''; 211 foreach($components['component'] as $comp){ 212 if(!empty($component)) $component .= ','; 213 $component .= $activity[$comp]; 214 } 215 $this->add_property($key,$component); 216 } else if(!empty($components['function'])){ 217 $this->$components['function']($activity); 218 } 219 } 220 return true; 221 } 222 223 function generateArray($ical_activity){ 224 global $current_user; 225 $activity = array(); 226 $activitytype = $ical_activity['TYPE']; 227 if($activitytype=='VEVENT'){ 228 $modtype = 'Events'; 229 } else { 230 $modtype = 'Calendar'; 231 } 232 foreach($this->mapping_arr as $key=>$comp){ 233 $type = $comp['type']; 234 $component = $comp['component']; 235 if(!is_array($component)){ 236 if($type!='user'){ 237 if(isset($this->field_mapping_arr[$component])){ 238 if(getFieldVisibilityPermission($modtype,$current_user->id,$this->field_mapping_arr[$component])=='0') 239 $activity[$this->field_mapping_arr[$component]] = $ical_activity[$key]; 240 else 241 $activity[$this->field_mapping_arr[$component]] = ''; 242 } else { 243 if(getFieldVisibilityPermission($modtype,$current_user->id,$component)=='0') 244 $activity[$component] = $ical_activity[$key]; 245 else 246 $activity[$component] = ''; 247 } 248 } 249 } else { 250 $temp = $ical_activity[$key]; 251 $count = 0; 252 if($type == 'string'){ 253 $values = explode('\\,',$temp); 254 } else if($type == 'datetime' && !empty($temp)){ 255 $values = $this->strtodatetime($temp); 256 } 257 foreach($component as $index){ 258 if(!isset($activity[$index])){ 259 if(isset($this->field_mapping_arr[$index])){ 260 if(getFieldVisibilityPermission($modtype,$current_user->id,$this->field_mapping_arr[$index])=='0') 261 $activity[$this->field_mapping_arr[$index]] = $values[$count]; 262 else 263 $activity[$this->field_mapping_arr[$index]] = ''; 264 } else { 265 if(getFieldVisibilityPermission($modtype,$current_user->id,$index)=='0') 266 $activity[$index] = $values[$count]; 267 else 268 $activity[$index] = ''; 269 } 270 } 271 $count++; 272 } 273 unset($values); 274 } 275 } 276 if($activitytype=='VEVENT'){ 277 $activity['activitytype'] = 'Meeting'; 278 if(!empty($ical_activity['VALARM'])){ 279 $temp = str_replace("P",'',$ical_activity['VALARM']['TRIGGER']); 280 //if there is negative value then ignore it because in vtiger even though its negative or postiview we 281 //make reminder to be before the event 282 $temp = str_replace("-",'',$temp); 283 $durationTypeCharacters = array('W','D','T','H','M','S'); 284 $reminder_time = 0; 285 foreach($durationTypeCharacters as $durationType) { 286 if(strpos($temp,$durationType) == false){ 287 continue; 288 } 289 $parts = explode($durationType, $temp); 290 $durationValue = $parts[0]; 291 $temp = $parts[1]; 292 $duration_type = $durationType; 293 $duration = intval($durationValue); 294 switch($duration_type){ 295 case 'W' : 296 $reminder_time += 24*24*60*$durationValue; 297 break; 298 case 'D' : 299 $reminder_time += 24*60*$durationValue; 300 break; 301 case 'T' : 302 //Skip this symbol since its just indicates the start of time component 303 break; 304 case 'H' : 305 $reminder_time += $duration*60; 306 break; 307 case 'M' : 308 $reminder_time = $duration; 309 break; 310 } 311 } 312 $activity['reminder_time'] = $reminder_time; 313 } 314 } else { 315 $activity['activitytype'] = 'Task'; 316 } 317 return $activity; 318 } 319 320 function strtodatetime($date){ 321 $date = preg_replace('/[A-Za-z_]*/', '', $date); 322 $year = substr($date,0,4); 323 $month = substr($date,4,2); 324 $day = substr($date,6,2); 325 $hours = substr($date,8,2); 326 $minutes = substr($date,10,2); 327 $seconds = substr($date,12,2); 328 $datetime[] = $year."-".$month."-".$day; 329 $datetime[] = $hours.":".$minutes.":".$seconds; 330 return $datetime; 331 } 332 } 333 334 class iCalendar extends iCalendar_component { 335 var $name = 'VCALENDAR'; 336 337 function construct() { 338 $this->valid_properties = array( 339 'CALSCALE' => RFC2445_OPTIONAL | RFC2445_ONCE, 340 'METHOD' => RFC2445_OPTIONAL | RFC2445_ONCE, 341 'PRODID' => RFC2445_REQUIRED | RFC2445_ONCE, 342 'VERSION' => RFC2445_REQUIRED | RFC2445_ONCE, 343 RFC2445_XNAME => RFC2445_OPTIONAL 344 ); 345 346 $this->valid_components = array( 347 'VEVENT', 'VTODO', 'VTIMEZONE' 348 // TODO: add support for the other component types 349 //, 'VJOURNAL', 'VFREEBUSY', 'VALARM' 350 ); 351 parent::construct(); 352 } 353 354 } 355 356 class iCalendar_event extends iCalendar_component { 357 358 var $name = 'VEVENT'; 359 var $properties; 360 var $mapping_arr = array( 361 'CLASS' => array('component'=>'visibility','type'=>'string'), 362 'DESCRIPTION' => array('component'=>'description','type'=>'string'), 363 'DTSTART' => array('component'=>array('date_start','time_start'),'function'=>'iCalendar_event_dtstart','type'=>'datetime'), 364 'DTEND' => array('component'=>array('due_date','time_end'),'function'=>'iCalendar_event_dtend','type'=>'datetime'), 365 'DTSTAMP' => array('component'=>array('date_start','time_start'),'function'=>'iCalendar_event_dtstamp','type'=>'datetime'), 366 'LOCATION' => array('component'=>'location','type'=>'string'), 367 'STATUS' => array('component'=>'eventstatus','type'=>'string'), 368 'SUMMARY' => array('component'=>'subject','type'=>'string'), 369 'PRIORITY' => array('component'=>'priority','type'=>'string'), 370 'ATTENDEE' => array('component'=>'activityid','function'=>'iCalendar_event_attendee','type'=>'user'), 371 'RESOURCES' => array('component'=>array('location','eventstatus'),'type'=>'string'), 372 ); 373 var $field_mapping_arr = array( 374 'priority'=>'taskpriority' 375 ); 376 377 function construct() { 378 379 $this->valid_components = array('VALARM'); 380 381 $this->valid_properties = array( 382 'CLASS' => RFC2445_OPTIONAL | RFC2445_ONCE, 383 'CREATED' => RFC2445_OPTIONAL | RFC2445_ONCE, 384 'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 385 // Standard ambiguous here: in 4.6.1 it says that DTSTAMP in optional, 386 // while in 4.8.7.2 it says it's REQUIRED. Go with REQUIRED. 387 'DTSTAMP' => RFC2445_REQUIRED | RFC2445_ONCE, 388 // Standard ambiguous here: in 4.6.1 it says that DTSTART in optional, 389 // while in 4.8.2.4 it says it's REQUIRED. Go with REQUIRED. 390 'DTSTART' => RFC2445_REQUIRED | RFC2445_ONCE, 391 'GEO' => RFC2445_OPTIONAL | RFC2445_ONCE, 392 'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE, 393 'LOCATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 394 'ORGANIZER' => RFC2445_OPTIONAL | RFC2445_ONCE, 395 'PRIORITY' => RFC2445_OPTIONAL | RFC2445_ONCE, 396 'SEQUENCE' => RFC2445_OPTIONAL | RFC2445_ONCE, 397 'STATUS' => RFC2445_OPTIONAL | RFC2445_ONCE, 398 'SUMMARY' => RFC2445_OPTIONAL | RFC2445_ONCE, 399 'TRANSP' => RFC2445_OPTIONAL | RFC2445_ONCE, 400 // Standard ambiguous here: in 4.6.1 it says that UID in optional, 401 // while in 4.8.4.7 it says it's REQUIRED. Go with REQUIRED. 402 'UID' => RFC2445_REQUIRED | RFC2445_ONCE, 403 'URL' => RFC2445_OPTIONAL | RFC2445_ONCE, 404 'RECURRENCE-ID' => RFC2445_OPTIONAL | RFC2445_ONCE, 405 'DTEND' => RFC2445_OPTIONAL | RFC2445_ONCE, 406 'DURATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 407 'ATTACH' => RFC2445_OPTIONAL, 408 'ATTENDEE' => RFC2445_OPTIONAL, 409 'CATEGORIES' => RFC2445_OPTIONAL, 410 'COMMENT' => RFC2445_OPTIONAL, 411 'CONTACT' => RFC2445_OPTIONAL, 412 'EXDATE' => RFC2445_OPTIONAL, 413 'EXRULE' => RFC2445_OPTIONAL, 414 'REQUEST-STATUS' => RFC2445_OPTIONAL, 415 'RELATED-TO' => RFC2445_OPTIONAL, 416 'RESOURCES' => RFC2445_OPTIONAL, 417 'RDATE' => RFC2445_OPTIONAL, 418 'RRULE' => RFC2445_OPTIONAL, 419 RFC2445_XNAME => RFC2445_OPTIONAL 420 ); 421 422 parent::construct(); 423 } 424 425 function invariant_holds() { 426 // DTEND and DURATION must not appear together 427 if(isset($this->properties['DTEND']) && isset($this->properties['DURATION'])) { 428 return false; 429 } 430 431 432 if(isset($this->properties['DTEND']) && isset($this->properties['DTSTART'])) { 433 // DTEND must be later than DTSTART 434 // The standard is not clear on how to hande different value types though 435 // TODO: handle this correctly even if the value types are different 436 if($this->properties['DTEND'][0]->value <= $this->properties['DTSTART'][0]->value) { 437 return false; 438 } 439 440 // DTEND and DTSTART must have the same value type 441 if($this->properties['DTEND'][0]->val_type != $this->properties['DTSTART'][0]->val_type) { 442 return false; 443 } 444 445 } 446 return true; 447 } 448 449 function iCalendar_event_dtstamp($activity){ 450 $components = gmdate('Ymd', strtotime($activity['date_start']." ".$activity['time_start']))."T".gmdate('His', strtotime($activity['date_start']." ".$activity['time_start']))."Z"; 451 $this->add_property("DTSTAMP",$components); 452 return true; 453 } 454 455 function iCalendar_event_dtstart($activity){ 456 $time = str_replace(':','',$activity['time_start']); 457 if(strlen($time)<6){ 458 while((6-strlen($time)) > 0 ){ 459 $time .= '0'; 460 } 461 } 462 $components = str_replace('-', '', $activity['date_start']).'T'. $time . 'Z'; 463 $this->add_property("DTSTART",$components); 464 return true; 465 } 466 467 function iCalendar_event_dtend($activity){ 468 $time = str_replace(':','',$activity['time_end']); 469 if(strlen($time)<6){ 470 while((6-strlen($time)) > 0 ){ 471 $time .= '0'; 472 } 473 } 474 $components = str_replace('-', '', $activity['due_date']).'T'. $time . 'Z'; 475 $this->add_property("DTEND",$components); 476 return true; 477 } 478 479 function iCalendar_event_attendee($activity){ 480 global $adb; 481 $users_res = $adb->pquery("SELECT inviteeid FROM vtiger_invitees WHERE activityid=?", array($activity['id'])); 482 if($adb->num_rows($users_res)>0){ 483 for($i=0;$i<$adb->num_rows($users_res);$i++){ 484 $inviteeid = $adb->query_result($users_res,$i,'inviteeid'); 485 $username = getUserFullName($inviteeid); 486 $user_email = getUserEmail($inviteeid); 487 $attendee = 'mailto:'.$user_email; 488 $this->add_property('ATTENDEE',$attendee); 489 } 490 } 491 return true; 492 } 493 494 } 495 496 class iCalendar_todo extends iCalendar_component { 497 var $name = 'VTODO'; 498 var $properties; 499 var $mapping_arr = array( 500 'DESCRIPTION' => array('component'=>'description','type'=>'string'), 501 'DTSTAMP' => array('component'=>array('date_start','time_start'),'function'=>'iCalendar_event_dtstamp','type'=>'datetime'), 502 'DTSTART' => array('component'=>array('date_start','time_start'),'function'=>'iCalendar_event_dtstart','type'=>'datetime'), 503 'DUE' => array('component'=>array('due_date'),'function'=>'iCalendar_event_dtend','type'=>'datetime'), 504 'STATUS' => array('component'=>'status','type'=>'string'), 505 'SUMMARY' => array('component'=>'subject','type'=>'string'), 506 'PRIORITY' => array('component'=>'priority','type'=>'string'), 507 'RESOURCES' => array('component'=>array('status'),'type'=>'string'), 508 ); 509 var $field_mapping_arr = array( 510 'status'=>'taskstatus', 511 'priority'=>'taskpriority' 512 ); 513 514 function construct() { 515 516 $this->valid_components = array(); 517 $this->valid_properties = array( 518 'CLASS' => RFC2445_OPTIONAL | RFC2445_ONCE, 519 'COMPLETED' => RFC2445_OPTIONAL | RFC2445_ONCE, 520 'CREATED' => RFC2445_OPTIONAL | RFC2445_ONCE, 521 'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 522 'DTSTAMP' => RFC2445_OPTIONAL | RFC2445_ONCE, 523 'DTSTART' => RFC2445_OPTIONAL | RFC2445_ONCE, 524 'GEO' => RFC2445_OPTIONAL | RFC2445_ONCE, 525 'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE, 526 'LOCATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 527 'ORGANIZER' => RFC2445_OPTIONAL | RFC2445_ONCE, 528 'PERCENT' => RFC2445_OPTIONAL | RFC2445_ONCE, 529 'PRIORITY' => RFC2445_OPTIONAL | RFC2445_ONCE, 530 'RECURID' => RFC2445_OPTIONAL | RFC2445_ONCE, 531 'SEQUENCE' => RFC2445_OPTIONAL | RFC2445_ONCE, 532 'STATUS' => RFC2445_OPTIONAL | RFC2445_ONCE, 533 'SUMMARY' => RFC2445_OPTIONAL | RFC2445_ONCE, 534 'UID' => RFC2445_OPTIONAL | RFC2445_ONCE, 535 'URL' => RFC2445_OPTIONAL | RFC2445_ONCE, 536 'DUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 537 'DURATION' => RFC2445_OPTIONAL | RFC2445_ONCE, 538 'ATTACH' => RFC2445_OPTIONAL, 539 'ATTENDEE' => RFC2445_OPTIONAL, 540 'CATEGORIES' => RFC2445_OPTIONAL, 541 'COMMENT' => RFC2445_OPTIONAL, 542 'CONTACT' => RFC2445_OPTIONAL, 543 'EXDATE' => RFC2445_OPTIONAL, 544 'EXRULE' => RFC2445_OPTIONAL, 545 'RSTATUS' => RFC2445_OPTIONAL, 546 'RELATED' => RFC2445_OPTIONAL, 547 'RESOURCES' => RFC2445_OPTIONAL, 548 'RDATE' => RFC2445_OPTIONAL, 549 'RRULE' => RFC2445_OPTIONAL, 550 'XPROP' => RFC2445_OPTIONAL 551 ); 552 553 parent::construct(); 554 // TODO: 555 // either 'due' or 'duration' may appear in a 'eventprop', but 'due' 556 // and 'duration' MUST NOT occur in the same 'eventprop' 557 } 558 function iCalendar_event_dtstamp($activity){ 559 $components = gmdate('Ymd', strtotime($activity['date_start']." ".$activity['time_start']))."T".gmdate('His', strtotime($activity['date_start']." ".$activity['time_start']))."Z"; 560 $this->add_property("DTSTAMP",$components); 561 return true; 562 } 563 564 function iCalendar_event_dtstart($activity){ 565 $time = str_replace(':','',$activity['time_start']); 566 if(strlen($time)<6){ 567 while((6-strlen($time)) > 0 ){ 568 $time .= '0'; 569 } 570 } 571 $components = str_replace('-', '', $activity['date_start']).'T'. $time . 'Z'; 572 $this->add_property("DTSTART",$components); 573 return true; 574 } 575 576 function iCalendar_event_dtend($activity){ 577 $components = str_replace('-', '', $activity['due_date']).'T000000Z'; 578 $this->add_property("DUE",$components); 579 return true; 580 } 581 } 582 583 class iCalendar_journal extends iCalendar_component { 584 // TODO: implement 585 } 586 587 class iCalendar_freebusy extends iCalendar_component { 588 // TODO: implement 589 } 590 591 class iCalendar_alarm extends iCalendar_component { 592 var $name='VALARM'; 593 var $properties; 594 var $mapping_arr = array( 595 'TRIGGER' => array('component'=>'reminder_time', 'function'=>'iCalendar_event_trigger'), 596 ); 597 598 function construct() { 599 600 $this->valid_components = array(); 601 $this->valid_properties = array( 602 'TRIGGER' => RFC2445_OPTIONAL | RFC2445_ONCE, 603 'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 604 'ACTION' => RFC2445_OPTIONAL | RFC2445_ONCE, 605 'X-WR-ALARMUID' => RFC2445_OPTIONAL | RFC2445_ONCE, 606 RFC2445_XNAME => RFC2445_OPTIONAL 607 ); 608 609 parent::construct(); 610 } 611 612 function iCalendar_event_trigger($activity){ 613 $reminder_time = $activity['reminder_time']; 614 if($reminder_time>60){ 615 $reminder_time = round($reminder_time/60); 616 $reminder = $reminder_time.'H'; 617 }else { 618 $reminder = $reminder_time.'M'; 619 } 620 $this->add_property('ACTION', 'DISPLAY'); 621 $this->add_property('TRIGGER', 'PT'.$reminder); 622 $this->add_property('DESCRIPTION', 'Reminder'); 623 return true; 624 } 625 } 626 627 class iCalendar_timezone extends iCalendar_component { 628 var $name = 'VTIMEZONE'; 629 var $properties; 630 631 function construct() { 632 $this->valid_components = array(); 633 $this->valid_properties = array( 634 'TZID' => RFC2445_REQUIRED | RFC2445_ONCE, 635 'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE, 636 'TZURL' => RFC2445_OPTIONAL | RFC2445_ONCE, 637 // TODO: the next two are components of their own! 638 'STANDARDC' => RFC2445_OPTIONAL, 639 'DAYLIGHTC' => RFC2445_OPTIONAL, 640 'TZOFFSETFROM' => RFC2445_OPTIONAL | RFC2445_ONCE, 641 'TZOFFSETTO' => RFC2445_OPTIONAL | RFC2445_ONCE, 642 'X-PROP' => RFC2445_OPTIONAL 643 ); 644 645 parent::construct(); 646 } 647 648 } 649 650 // REMINDER: DTEND must be later than DTSTART for all components which support both 651 // REMINDER: DUE must be later than DTSTART for all components which support both 652 653 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |