MDL-78165 mod_bigbluebuttonbn: Fetch cron status using API
[moodle.git] / lib / bennu / iCalendar_properties.php
blob653fdc7e6fc1bb23de6ff7b286a94ffa36803fa2
1 <?php
3 /**
4 * BENNU - PHP iCalendar library
5 * (c) 2005-2006 Ioannis Papaioannou (pj@moodle.org). All rights reserved.
7 * Released under the LGPL.
9 * See http://bennu.sourceforge.net/ for more information and downloads.
11 * @author Ioannis Papaioannou
12 * @version $Id$
13 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
16 class iCalendar_property {
17 // Properties can have parameters, but cannot have other properties or components
19 var $parent_component = NULL;
20 var $value = NULL;
21 var $parameters = NULL;
22 var $valid_parameters = NULL;
24 // These are common for 95% of properties, so define them here and override as necessary
25 var $val_multi = false;
26 var $val_default = NULL;
28 /** @var int|null RFC2445_TYPE value. */
29 protected $val_type;
31 /** @var string property name. */
32 protected $name;
34 function __construct() {
35 $this->parameters = array();
38 // If some property needs extra care with its parameters, override this
39 // IMPORTANT: the parameter name MUST BE CAPITALIZED!
40 function is_valid_parameter($parameter, $value) {
42 if(is_array($value)) {
43 if(!iCalendar_parameter::multiple_values_allowed($parameter)) {
44 return false;
46 foreach($value as $item) {
47 if(!iCalendar_parameter::is_valid_value($this, $parameter, $item)) {
48 return false;
51 return true;
54 return iCalendar_parameter::is_valid_value($this, $parameter, $value);
57 function invariant_holds() {
58 return true;
61 // If some property is very picky about its values, it should do the work itself
62 // Only data type validation is done here
63 function is_valid_value($value) {
64 if(is_array($value)) {
65 if(!$this->val_multi) {
66 return false;
68 else {
69 foreach($value as $oneval) {
70 if(!rfc2445_is_valid_value($oneval, $this->val_type)) {
71 return false;
75 return true;
77 return rfc2445_is_valid_value($value, $this->val_type);
80 function default_value() {
81 return $this->val_default;
84 function set_parent_component($componentname) {
85 if(class_exists('iCalendar_'.strtolower(substr($componentname, 1)))) {
86 $this->parent_component = strtoupper($componentname);
87 return true;
90 return false;
93 function set_value($value) {
94 if($this->is_valid_value($value)) {
95 // This transparently formats any value type according to the iCalendar specs
96 if(is_array($value)) {
97 foreach($value as $key => $item) {
98 $value[$key] = rfc2445_do_value_formatting($item, $this->val_type);
100 $this->value = implode(',', $value);
102 else {
103 $this->value = rfc2445_do_value_formatting($value, $this->val_type);
106 return true;
108 return false;
111 function get_value() {
112 // First of all, assume that we have multiple values
113 $valarray = explode('\\,', $this->value);
115 // Undo transparent formatting
116 $valtype = $this->val_type;
117 $replace_function = function($a) use ($valtype) {
118 return rfc2445_undo_value_formatting($a, $valtype);
120 $valarray = array_map($replace_function, $valarray);
122 // Now, if this property cannot have multiple values, don't return as an array
123 if(!$this->val_multi) {
124 return $valarray[0];
127 // Otherwise return an array even if it has one element, for uniformity
128 return $valarray;
132 function set_parameter($name, $value) {
134 // Uppercase
135 $name = strtoupper($name);
137 // Are we trying to add a valid parameter?
138 $xname = false;
139 if(!isset($this->valid_parameters[$name])) {
140 // If not, is it an x-name as per RFC 2445?
141 if(!rfc2445_is_xname($name)) {
142 return false;
144 // No more checks -- all components are supposed to allow x-name parameters
145 $xname = true;
148 if(!$this->is_valid_parameter($name, $value)) {
149 return false;
152 if(is_array($value)) {
153 foreach($value as $key => $element) {
154 $value[$key] = iCalendar_parameter::do_value_formatting($name, $element);
157 else {
158 $value = iCalendar_parameter::do_value_formatting($name, $value);
161 $this->parameters[$name] = $value;
163 // Special case: if we just changed the VALUE parameter, reflect this
164 // in the object's status so that it only accepts correct type values
165 if($name == 'VALUE') {
166 // TODO: what if this invalidates an already-set value?
167 $this->val_type = constant('RFC2445_TYPE_'.str_replace('-', '_', $value));
170 return true;
174 function get_parameter($name) {
176 // Uppercase
177 $name = strtoupper($name);
179 if(isset($this->parameters[$name])) {
180 // If there are any double quotes in the value, invisibly strip them
181 if(is_array($this->parameters[$name])) {
182 foreach($this->parameters[$name] as $key => $value) {
183 if(substr($value, 0, 1) == '"') {
184 $this->parameters[$name][$key] = substr($value, 1, strlen($value) - 2);
187 return $this->parameters[$name];
190 else {
191 if(substr($this->parameters[$name], 0, 1) == '"') {
192 return substr($this->parameters[$name], 1, strlen($this->parameters[$name]) - 2);
197 return NULL;
200 function serialize() {
201 $string = $this->name;
203 if(!empty($this->parameters)) {
204 foreach($this->parameters as $name => $value) {
205 $string .= ';'.$name.'=';
206 if(is_array($value)) {
207 $string .= implode(',', $value);
209 else {
210 $string .= $value;
215 $string .= ':'.$this->value;
217 return rfc2445_fold($string) . RFC2445_CRLF;
221 // 4.7 Calendar Properties
222 // -----------------------
224 class iCalendar_property_calscale extends iCalendar_property {
226 var $name = 'CALSCALE';
227 var $val_type = RFC2445_TYPE_TEXT;
229 function __construct() {
230 parent::__construct();
231 $this->valid_parameters = array(
232 RFC2445_XNAME => RFC2445_OPTIONAL
236 function is_valid_value($value) {
237 // This is case-sensitive
238 return ($value === 'GREGORIAN');
242 class iCalendar_property_method extends iCalendar_property {
244 var $name = 'METHOD';
245 var $val_type = RFC2445_TYPE_TEXT;
247 function __construct() {
248 parent::__construct();
249 $this->valid_parameters = array(
250 RFC2445_XNAME => RFC2445_OPTIONAL
254 function is_valid_value($value) {
255 // This is case-sensitive
256 // Methods from RFC 2446
257 $methods = array('PUBLISH', 'REQUEST', 'REPLY', 'ADD', 'CANCEL', 'REFRESH', 'COUNTER', 'DECLINECOUNTER');
258 return in_array($value, $methods);
262 class iCalendar_property_prodid extends iCalendar_property {
264 var $name = 'PRODID';
265 var $val_type = RFC2445_TYPE_TEXT;
266 var $val_default = NULL;
268 function __construct() {
269 parent::__construct();
270 $this->val_default = '-//John Papaioannou/NONSGML Bennu '._BENNU_VERSION.'//EN';
272 $this->valid_parameters = array(
273 RFC2445_XNAME => RFC2445_OPTIONAL
278 class iCalendar_property_version extends iCalendar_property {
280 var $name = 'VERSION';
281 var $val_type = RFC2445_TYPE_TEXT;
282 var $val_default = '2.0';
284 function __construct() {
285 parent::__construct();
286 $this->valid_parameters = array(
287 RFC2445_XNAME => RFC2445_OPTIONAL
291 function is_valid_value($value) {
292 return($value === '2.0' || $value === 2.0);
297 // 4.8.1 Descriptive Component Properties
298 // --------------------------------------
300 class iCalendar_property_attach extends iCalendar_property {
302 var $name = 'ATTACH';
303 var $val_type = RFC2445_TYPE_URI;
305 function __construct() {
306 parent::__construct();
307 $this->valid_parameters = array(
308 'FMTTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE,
309 'ENCODING' => RFC2445_OPTIONAL | RFC2445_ONCE,
310 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
311 RFC2445_XNAME => RFC2445_OPTIONAL
315 function invariant_holds() {
316 if(isset($this->parameters['ENCODING']) && !isset($this->parameters['VALUE'])) {
317 return false;
319 if(isset($this->parameters['VALUE']) && !isset($this->parameters['ENCODING'])) {
320 return false;
323 return true;
326 function is_valid_parameter($parameter, $value) {
328 $parameter = strtoupper($parameter);
330 if(!parent::is_valid_parameter($parameter, $value)) {
331 return false;
334 if($parameter === 'ENCODING' && strtoupper($value) != 'BASE64') {
335 return false;
338 if($parameter === 'VALUE' && strtoupper($value) != 'BINARY') {
339 return false;
342 return true;
346 class iCalendar_property_categories extends iCalendar_property {
348 var $name = 'CATEGORIES';
349 var $val_type = RFC2445_TYPE_TEXT;
350 var $val_multi = true;
352 function __construct() {
353 parent::__construct();
354 $this->valid_parameters = array(
355 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
356 RFC2445_XNAME => RFC2445_OPTIONAL
361 class iCalendar_property_class extends iCalendar_property {
363 var $name = 'CLASS';
364 var $val_type = RFC2445_TYPE_TEXT;
365 var $val_default = 'PUBLIC';
367 function __construct() {
368 parent::__construct();
369 $this->valid_parameters = array(
370 RFC2445_XNAME => RFC2445_OPTIONAL
374 function is_valid_value($value) {
375 // If this is not an xname, it is case-sensitive
376 return ($value === 'PUBLIC' || $value === 'PRIVATE' || $value === 'CONFIDENTIAL' || rfc2445_is_xname(strtoupper($value)));
380 class iCalendar_property_comment extends iCalendar_property {
382 var $name = 'COMMENT';
383 var $val_type = RFC2445_TYPE_TEXT;
385 function __construct() {
386 parent::__construct();
387 $this->valid_parameters = array(
388 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE,
389 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
390 RFC2445_XNAME => RFC2445_OPTIONAL
395 class iCalendar_property_description extends iCalendar_property {
397 var $name = 'DESCRIPTION';
398 var $val_type = RFC2445_TYPE_TEXT;
400 function __construct() {
401 parent::__construct();
402 $this->valid_parameters = array(
403 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE,
404 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
405 RFC2445_XNAME => RFC2445_OPTIONAL
410 class iCalendar_property_geo extends iCalendar_property {
412 var $name = 'GEO';
413 var $val_type = RFC2445_TYPE_TEXT;
415 function __construct() {
416 parent::__construct();
417 $this->valid_parameters = array(
418 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE,
419 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
420 RFC2445_XNAME => RFC2445_OPTIONAL
424 function is_valid_value($value) {
425 // This MUST be two floats separated by a semicolon
426 if(!is_string($value)) {
427 return false;
430 $floats = explode(';', $value);
431 if(count($floats) != 2) {
432 return false;
435 return rfc2445_is_valid_value($floats[0], RFC2445_TYPE_FLOAT) && rfc2445_is_valid_value($floats[1], RFC2445_TYPE_FLOAT);
438 function set_value($value) {
439 // Must override this, otherwise the semicolon separating
440 // the two floats would get auto-quoted, which is illegal
441 if($this->is_valid_value($value)) {
442 $this->value = $value;
443 return true;
446 return false;
451 class iCalendar_property_location extends iCalendar_property {
453 var $name = 'LOCATION';
454 var $val_type = RFC2445_TYPE_TEXT;
456 function __construct() {
457 parent::__construct();
458 $this->valid_parameters = array(
459 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE,
460 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
461 RFC2445_XNAME => RFC2445_OPTIONAL
466 class iCalendar_property_percent_complete extends iCalendar_property {
468 var $name = 'PERCENT-COMPLETE';
469 var $val_type = RFC2445_TYPE_INTEGER;
471 function __construct() {
472 parent::__construct();
473 $this->valid_parameters = array(
474 RFC2445_XNAME => RFC2445_OPTIONAL
478 function is_valid_value($value) {
479 // Only integers between 0 and 100 inclusive allowed
480 if(!parent::is_valid_value($value)) {
481 return false;
483 $value = intval($value);
484 return ($value >= 0 && $value <= 100);
489 class iCalendar_property_priority extends iCalendar_property {
491 var $name = 'PRIORITY';
492 var $val_type = RFC2445_TYPE_INTEGER;
494 function __construct() {
495 parent::__construct();
496 $this->valid_parameters = array(
497 RFC2445_XNAME => RFC2445_OPTIONAL
501 function is_valid_value($value) {
502 // Only integers between 0 and 9 inclusive allowed
503 if(!parent::is_valid_value($value)) {
504 return false;
507 $value = intval($value);
508 return ($value >= 0 && $value <= 9);
512 class iCalendar_property_resources extends iCalendar_property {
514 var $name = 'RESOURCES';
515 var $val_type = RFC2445_TYPE_TEXT;
516 var $val_multi = true;
518 function __construct() {
519 parent::__construct();
520 $this->valid_parameters = array(
521 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE,
522 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
523 RFC2445_XNAME => RFC2445_OPTIONAL
528 class iCalendar_property_status extends iCalendar_property {
530 var $name = 'STATUS';
531 var $val_type = RFC2445_TYPE_TEXT;
533 function __construct() {
534 parent::__construct();
535 $this->valid_parameters = array(
536 RFC2445_XNAME => RFC2445_OPTIONAL
540 function is_valid_value($value) {
541 // This is case-sensitive
542 switch ($this->parent_component) {
543 case 'VEVENT':
544 $allowed = array('TENTATIVE', 'CONFIRMED', 'CANCELLED');
545 break;
546 case 'VTODO':
547 $allowed = array('NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED');
548 break;
549 case 'VJOURNAL':
550 $allowed = array('DRAFT', 'FINAL', 'CANCELLED');
551 break;
553 return in_array($value, $allowed);
559 class iCalendar_property_summary extends iCalendar_property {
561 var $name = 'SUMMARY';
562 var $val_type = RFC2445_TYPE_TEXT;
564 function __construct() {
565 parent::__construct();
566 $this->valid_parameters = array(
567 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE,
568 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
569 RFC2445_XNAME => RFC2445_OPTIONAL
574 // 4.8.2 Date and Time Component Properties
575 // ----------------------------------------
577 class iCalendar_property_completed extends iCalendar_property {
579 var $name = 'COMPLETED';
580 var $val_type = RFC2445_TYPE_DATE_TIME;
582 function __construct() {
583 parent::__construct();
584 $this->valid_parameters = array(
585 RFC2445_XNAME => RFC2445_OPTIONAL
589 function is_valid_value($value) {
590 if(!parent::is_valid_value($value)) {
591 return false;
593 // Time MUST be in UTC format
594 return(substr($value, -1) == 'Z');
598 class iCalendar_property_dtend extends iCalendar_property {
600 var $name = 'DTEND';
601 var $val_type = RFC2445_TYPE_DATE_TIME;
603 function __construct() {
604 parent::__construct();
605 $this->valid_parameters = array(
606 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
607 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE,
608 RFC2445_XNAME => RFC2445_OPTIONAL
612 function is_valid_value($value) {
613 if(!parent::is_valid_value($value)) {
614 return false;
617 // If present in a FREEBUSY component, must be in UTC format
618 if($this->parent_component == 'VFREEBUSY' && substr($value, -1) != 'Z') {
619 return false;
622 return true;
626 function is_valid_parameter($parameter, $value) {
628 $parameter = strtoupper($parameter);
630 if(!parent::is_valid_parameter($parameter, $value)) {
631 return false;
633 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) {
634 return false;
637 return true;
641 class iCalendar_property_due extends iCalendar_property {
643 var $name = 'DUE';
644 var $val_type = RFC2445_TYPE_DATE_TIME;
646 function __construct() {
647 parent::__construct();
648 $this->valid_parameters = array(
649 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
650 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE,
651 RFC2445_XNAME => RFC2445_OPTIONAL
655 function is_valid_value($value) {
656 if(!parent::is_valid_value($value)) {
657 return false;
660 // If present in a FREEBUSY component, must be in UTC format
661 if($this->parent_component == 'VFREEBUSY' && substr($value, -1) != 'Z') {
662 return false;
665 return true;
669 function is_valid_parameter($parameter, $value) {
671 $parameter = strtoupper($parameter);
673 if(!parent::is_valid_parameter($parameter, $value)) {
674 return false;
676 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) {
677 return false;
680 return true;
684 class iCalendar_property_dtstart extends iCalendar_property {
686 var $name = 'DTSTART';
687 var $val_type = RFC2445_TYPE_DATE_TIME;
689 function __construct() {
690 parent::__construct();
691 $this->valid_parameters = array(
692 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
693 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE,
694 RFC2445_XNAME => RFC2445_OPTIONAL
698 // TODO: unimplemented stuff when parent is a VTIMEZONE component
700 function is_valid_value($value) {
701 if(!parent::is_valid_value($value)) {
702 return false;
705 // If present in a FREEBUSY component, must be in UTC format
706 if($this->parent_component == 'VFREEBUSY' && substr($value, -1) != 'Z') {
707 return false;
710 return true;
713 function is_valid_parameter($parameter, $value) {
715 $parameter = strtoupper($parameter);
717 if(!parent::is_valid_parameter($parameter, $value)) {
718 return false;
720 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) {
721 return false;
724 return true;
728 class iCalendar_property_duration extends iCalendar_property {
730 var $name = 'DURATION';
731 var $val_type = RFC2445_TYPE_DURATION;
733 function __construct() {
734 parent::__construct();
735 $this->valid_parameters = array(
736 RFC2445_XNAME => RFC2445_OPTIONAL
740 function is_valid_value($value) {
741 if(!parent::is_valid_value($value)) {
742 return false;
745 // Value must be positive
746 return ($value[0] != '-');
750 class iCalendar_property_freebusy extends iCalendar_property {
752 var $name = 'FREEBUSY';
753 var $val_type = RFC2445_TYPE_PERIOD;
754 var $val_multi = true;
756 function __construct() {
757 parent::__construct();
758 $this->valid_parameters = array(
759 'FBTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE,
760 RFC2445_XNAME => RFC2445_OPTIONAL
764 function is_valid_value($value) {
765 if(!parent::is_valid_value($value)) {
766 return false;
769 $pos = strpos($value, '/'); // We know there's only one / in there
770 if($value[$pos - 1] != 'Z') {
771 // Start time MUST be in UTC
772 return false;
774 if($value[$pos + 1] != 'P' && substr($value, -1) != 'Z') {
775 // If the second part is not a period, it MUST be in UTC
776 return false;
779 return true;
782 // TODO: these properties SHOULD be shorted in ascending order (by start time and end time as tiebreak)
785 class iCalendar_property_transp extends iCalendar_property {
787 var $name = 'TRANSP';
788 var $val_type = RFC2445_TYPE_TEXT;
789 var $val_default = 'OPAQUE';
791 function __construct() {
792 parent::__construct();
793 $this->valid_parameters = array(
794 RFC2445_XNAME => RFC2445_OPTIONAL
798 function is_valid_value($value) {
799 return ($value === 'TRANSPARENT' || $value === 'OPAQUE');
803 // TODO: 4.8.3 timezone component properties
806 // 4.8.4 Relationship Component Properties
807 // ---------------------------------------
809 class iCalendar_property_attendee extends iCalendar_property {
811 var $name = 'ATTENDEE';
812 var $val_type = RFC2445_TYPE_CAL_ADDRESS;
814 // TODO: MUST NOT be specified when the calendar object has METHOD=PUBLISH
815 // TODO: standard has lots of detail here, make triple sure that we eventually conform
817 function __construct() {
818 parent::__construct();
819 $this->valid_parameters = array(
820 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
821 'CN' => RFC2445_OPTIONAL | RFC2445_ONCE,
822 'ROLE' => RFC2445_OPTIONAL | RFC2445_ONCE,
823 'PARTSTAT' => RFC2445_OPTIONAL | RFC2445_ONCE,
824 'RSVP' => RFC2445_OPTIONAL | RFC2445_ONCE,
825 'CUTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE,
826 'MEMBER' => RFC2445_OPTIONAL | RFC2445_ONCE,
827 'DELEGATED-TO' => RFC2445_OPTIONAL | RFC2445_ONCE,
828 'DELEGATED-FROM' => RFC2445_OPTIONAL | RFC2445_ONCE,
829 'SENT-BY' => RFC2445_OPTIONAL | RFC2445_ONCE,
830 'DIR' => RFC2445_OPTIONAL | RFC2445_ONCE,
831 RFC2445_XNAME => RFC2445_OPTIONAL
835 function set_parent_component($componentname) {
836 if(!parent::set_parent_component($componentname)) {
837 return false;
840 if($this->parent_component == 'VFREEBUSY' || $this->parent_component == 'VALARM') {
841 // Most parameters become invalid in this case, the full allowed set is now:
842 $this->valid_parameters = array(
843 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
844 RFC2445_XNAME => RFC2445_OPTIONAL
848 return false;
853 class iCalendar_property_contact extends iCalendar_property {
855 var $name = 'CONTACT';
856 var $val_type = RFC2445_TYPE_TEXT;
858 function __construct() {
859 parent::__construct();
860 $this->valid_parameters = array(
861 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE,
862 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
863 RFC2445_XNAME => RFC2445_OPTIONAL
868 class iCalendar_property_organizer extends iCalendar_property {
870 var $name = 'ORGANIZER';
871 var $val_type = RFC2445_TYPE_CAL_ADDRESS;
873 function __construct() {
874 parent::__construct();
875 $this->valid_parameters = array(
876 'CN' => RFC2445_OPTIONAL | RFC2445_ONCE,
877 'DIR' => RFC2445_OPTIONAL | RFC2445_ONCE,
878 'SENT-BY' => RFC2445_OPTIONAL | RFC2445_ONCE,
879 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
880 RFC2445_XNAME => RFC2445_OPTIONAL
884 // TODO:
886 Conformance: This property MUST be specified in an iCalendar object
887 that specifies a group scheduled calendar entity. This property MUST
888 be specified in an iCalendar object that specifies the publication of
889 a calendar user's busy time. This property MUST NOT be specified in
890 an iCalendar object that specifies only a time zone definition or
891 that defines calendar entities that are not group scheduled entities,
892 but are entities only on a single user's calendar.
897 class iCalendar_property_recurrence_id extends iCalendar_property {
899 // TODO: can only be specified when defining recurring components in the calendar
901 Conformance: This property can be specified in an iCalendar object
902 containing a recurring calendar component.
904 Description: The full range of calendar components specified by a
905 recurrence set is referenced by referring to just the "UID" property
906 value corresponding to the calendar component. The "RECURRENCE-ID"
907 property allows the reference to an individual instance within the
908 recurrence set.
911 var $name = 'RECURRENCE-ID';
912 var $val_type = RFC2445_TYPE_DATE_TIME;
914 function __construct() {
915 parent::__construct();
916 $this->valid_parameters = array(
917 'RANGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
918 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE,
919 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
920 RFC2445_XNAME => RFC2445_OPTIONAL
924 function is_valid_parameter($parameter, $value) {
926 $parameter = strtoupper($parameter);
928 if(!parent::is_valid_parameter($parameter, $value)) {
929 return false;
931 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) {
932 return false;
935 return true;
940 class iCalendar_property_related_to extends iCalendar_property {
942 var $name = 'RELATED-TO';
943 var $val_type = RFC2445_TYPE_TEXT;
945 // TODO: the value of this property must reference another component's UID
947 function __construct() {
948 parent::__construct();
949 $this->valid_parameters = array(
950 'RELTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE,
951 RFC2445_XNAME => RFC2445_OPTIONAL
956 class iCalendar_property_url extends iCalendar_property {
958 var $name = 'URL';
959 var $val_type = RFC2445_TYPE_URI;
961 function __construct() {
962 parent::__construct();
963 $this->valid_parameters = array(
964 RFC2445_XNAME => RFC2445_OPTIONAL
969 class iCalendar_property_uid extends iCalendar_property {
971 var $name = 'UID';
972 var $val_type = RFC2445_TYPE_TEXT;
974 function __construct() {
975 parent::__construct();
976 $this->valid_parameters = array(
977 RFC2445_XNAME => RFC2445_OPTIONAL
980 // The exception to the rule: this is not a static value, so we
981 // generate it on-the-fly here. Guaranteed to be different for
982 // each instance of this property, too. Nice.
983 $this->val_default = Bennu::generate_guid();
987 // 4.8.5 Recurrence Component Properties
988 // -------------------------------------
990 class iCalendar_property_exdate extends iCalendar_property {
992 var $name = 'EXDATE';
993 var $val_type = RFC2445_TYPE_DATE_TIME;
994 var $val_multi = true;
996 function __construct() {
997 parent::__construct();
998 $this->valid_parameters = array(
999 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE,
1000 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
1001 RFC2445_XNAME => RFC2445_OPTIONAL
1005 function is_valid_parameter($parameter, $value) {
1007 $parameter = strtoupper($parameter);
1009 if(!parent::is_valid_parameter($parameter, $value)) {
1010 return false;
1012 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) {
1013 return false;
1016 return true;
1021 class iCalendar_property_exrule extends iCalendar_property {
1023 var $name = 'EXRULE';
1024 var $val_type = RFC2445_TYPE_RECUR;
1026 function __construct() {
1027 parent::__construct();
1028 $this->valid_parameters = array(
1029 RFC2445_XNAME => RFC2445_OPTIONAL
1034 class iCalendar_property_rdate extends iCalendar_property {
1036 var $name = 'RDATE';
1037 var $val_type = RFC2445_TYPE_DATE_TIME;
1038 var $val_multi = true;
1040 function __construct() {
1041 parent::__construct();
1042 $this->valid_parameters = array(
1043 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE,
1044 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
1045 RFC2445_XNAME => RFC2445_OPTIONAL
1049 function is_valid_parameter($parameter, $value) {
1051 $parameter = strtoupper($parameter);
1053 if(!parent::is_valid_parameter($parameter, $value)) {
1054 return false;
1056 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME' || $value == 'PERIOD')) {
1057 return false;
1060 return true;
1065 class iCalendar_property_rrule extends iCalendar_property {
1067 var $name = 'RRULE';
1068 var $val_type = RFC2445_TYPE_RECUR;
1070 function __construct() {
1071 parent::__construct();
1072 $this->valid_parameters = array(
1073 RFC2445_XNAME => RFC2445_OPTIONAL
1078 // 4.8.6 Alarm Component Properties
1079 // -------------------------------------------
1080 class iCalendar_property_action extends iCalendar_property {
1081 var $name = 'ACTION';
1082 var $val_type = RFC2445_TYPE_TEXT;
1084 function __construct() {
1085 parent::__construct();
1086 $this->valid_parameters = array(
1087 RFC2445_XNAME => RFC2445_OPTIONAL
1091 function is_valid_value($value) {
1092 if(!parent::is_valid_value($value)) {
1093 return false;
1096 // Value must be one of the following, or an x-name.
1097 $valid_values = array('ACTION', 'DISPLAY', 'EMAIL', 'PROCEDURE');
1098 return(in_array($value, $valid_values) || rfc2445_is_xname($value));
1103 class iCalendar_property_repeat extends iCalendar_property {
1104 var $name = 'REPEAT';
1105 var $val_type = RFC2445_TYPE_INTEGER;
1107 function __construct() {
1108 parent::__construct();
1109 $this->valid_parameters = array(
1110 RFC2445_XNAME => RFC2445_OPTIONAL
1115 class iCalendar_property_trigger extends iCalendar_property {
1116 var $name = 'TRIGGER';
1117 var $val_type = RFC2445_TYPE_TEXT;
1119 function __construct() {
1120 parent::__construct();
1121 $this->valid_parameters = array(
1122 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
1123 'RELATED' => RFC2445_OPTIONAL | RFC2445_ONCE,
1124 RFC2445_XNAME => RFC2445_OPTIONAL
1128 function is_valid_value($value) {
1129 if(!parent::is_valid_value($value)) {
1130 return false;
1132 // Must either be DURATION or DATE_TIME type
1133 return(rfc2445_is_valid_value($value, RFC2445_TYPE_DURATION)
1134 || rfc2445_is_valid_value($value, RFC2445_TYPE_DATE_TIME));
1140 // 4.8.7 Change Management Component Properties
1141 // --------------------------------------------
1143 class iCalendar_property_created extends iCalendar_property {
1145 var $name = 'CREATED';
1146 var $val_type = RFC2445_TYPE_DATE_TIME;
1148 function __construct() {
1149 parent::__construct();
1150 $this->valid_parameters = array(
1151 RFC2445_XNAME => RFC2445_OPTIONAL
1155 function is_valid_value($value) {
1156 if(!parent::is_valid_value($value)) {
1157 return false;
1159 // Time MUST be in UTC format
1160 return(substr($value, -1) == 'Z');
1164 class iCalendar_property_dtstamp extends iCalendar_property {
1166 var $name = 'DTSTAMP';
1167 var $val_type = RFC2445_TYPE_DATE_TIME;
1169 function __construct() {
1170 parent::__construct();
1171 $this->valid_parameters = array(
1172 RFC2445_XNAME => RFC2445_OPTIONAL
1176 function is_valid_value($value) {
1177 if(!parent::is_valid_value($value)) {
1178 return false;
1180 // Time MUST be in UTC format
1181 return(substr($value, -1) == 'Z');
1185 class iCalendar_property_last_modified extends iCalendar_property {
1187 var $name = 'LAST-MODIFIED';
1188 var $val_type = RFC2445_TYPE_DATE_TIME;
1190 function __construct() {
1191 parent::__construct();
1192 $this->valid_parameters = array(
1193 RFC2445_XNAME => RFC2445_OPTIONAL
1197 function is_valid_value($value) {
1198 if(!parent::is_valid_value($value)) {
1199 return false;
1201 // Time MUST be in UTC format
1202 return(substr($value, -1) == 'Z');
1206 class iCalendar_property_sequence extends iCalendar_property {
1208 var $name = 'SEQUENCE';
1209 var $val_type = RFC2445_TYPE_INTEGER;
1210 var $val_default = 0;
1212 function __construct() {
1213 parent::__construct();
1214 $this->valid_parameters = array(
1215 RFC2445_XNAME => RFC2445_OPTIONAL
1219 function is_valid_value($value) {
1220 if(!parent::is_valid_value($value)) {
1221 return false;
1223 $value = intval($value);
1224 return ($value >= 0);
1228 // 4.8.8 Miscellaneous Component Properties
1229 // ----------------------------------------
1231 class iCalendar_property_x extends iCalendar_property {
1233 var $name = RFC2445_XNAME;
1234 var $val_type = NULL;
1236 function __construct() {
1237 parent::__construct();
1238 $this->valid_parameters = array(
1239 // X-ALT-DESC (Description) can have FMTTYPE declaration of text/html is a property for HTML content.
1240 'FMTTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE,
1241 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
1242 RFC2445_XNAME => RFC2445_OPTIONAL
1246 function set_name($name) {
1248 $name = strtoupper($name);
1250 if(rfc2445_is_xname($name)) {
1251 $this->name = $name;
1252 return true;
1255 return false;
1259 class iCalendar_property_request_status extends iCalendar_property {
1261 // IMPORTANT NOTE: This property value includes TEXT fields
1262 // separated by semicolons. Unfortunately, auto-value-formatting
1263 // cannot be used in this case. As an exception, the value passed
1264 // to this property MUST be already escaped.
1266 var $name = 'REQUEST-STATUS';
1267 var $val_type = RFC2445_TYPE_TEXT;
1269 function __construct() {
1270 parent::__construct();
1271 $this->valid_parameters = array(
1272 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
1273 RFC2445_XNAME => RFC2445_OPTIONAL
1277 function is_valid_value($value) {
1278 if(!is_string($value) || empty($value)) {
1279 return false;
1282 $len = strlen($value);
1283 $parts = array();
1284 $from = 0;
1285 $escch = false;
1287 for($i = 0; $i < $len; ++$i) {
1288 if($value[$i] == ';' && !$escch) {
1289 // Token completed
1290 $parts[] = substr($value, $from, $i - $from);
1291 $from = $i + 1;
1292 continue;
1294 $escch = ($value[$i] == '\\');
1296 // Add one last token with the remaining text; if the value
1297 // ended with a ';' it was illegal, so check that this token
1298 // is not the empty string.
1299 $parts[] = substr($value, $from);
1301 $count = count($parts);
1303 // May have 2 or 3 tokens (last one is optional)
1304 if($count != 2 && $count != 3) {
1305 return false;
1308 // REMEMBER: if ANY part is empty, we have an illegal value
1310 // First token must be hierarchical numeric status (3 levels max)
1311 if(strlen($parts[0]) == 0) {
1312 return false;
1315 if($parts[0][0] < '1' || $parts[0][0] > '4') {
1316 return false;
1319 $len = strlen($parts[0]);
1321 // Max 3 levels, and can't end with a period
1322 if($len > 5 || $parts[0][$len - 1] == '.') {
1323 return false;
1326 for($i = 1; $i < $len; ++$i) {
1327 if(($i & 1) == 1 && $parts[0][$i] != '.') {
1328 // Even-indexed chars must be periods
1329 return false;
1331 else if(($i & 1) == 0 && ($parts[0][$i] < '0' || $parts[0][$i] > '9')) {
1332 // Odd-indexed chars must be numbers
1333 return false;
1337 // Second and third tokens must be TEXT, and already escaped, so
1338 // they are not allowed to have UNESCAPED semicolons, commas, slashes,
1339 // or any newlines at all
1341 for($i = 1; $i < $count; ++$i) {
1342 if(strpos($parts[$i], "\n") !== false) {
1343 return false;
1346 $len = strlen($parts[$i]);
1347 if($len == 0) {
1348 // Cannot be empty
1349 return false;
1352 $parts[$i] .= '#'; // This guard token saves some conditionals in the loop
1354 for($j = 0; $j < $len; ++$j) {
1355 $thischar = $parts[$i][$j];
1356 $nextchar = $parts[$i][$j + 1];
1357 if($thischar == '\\') {
1358 // Next char must now be one of ";,\nN"
1359 if($nextchar != ';' && $nextchar != ',' && $nextchar != '\\' &&
1360 $nextchar != 'n' && $nextchar != 'N') {
1361 return false;
1364 // OK, this escaped sequence is correct, bypass next char
1365 ++$j;
1366 continue;
1368 if($thischar == ';' || $thischar == ',' || $thischar == '\\') {
1369 // This wasn't escaped as it should
1370 return false;
1375 return true;
1378 function set_value($value) {
1379 // Must override this, otherwise the value would be quoted again
1380 if($this->is_valid_value($value)) {
1381 $this->value = $value;
1382 return true;
1385 return false;
1390 class iCalendar_property_tzid extends iCalendar_property {
1392 var $name = 'TZID';
1393 var $val_type = RFC2445_TYPE_TEXT;
1395 function __construct() {
1396 parent::__construct();
1397 $this->valid_parameters = array(
1398 RFC2445_XNAME => RFC2445_OPTIONAL
1402 function is_valid_value($value) {
1403 if(!parent::is_valid_value($value)) {
1404 return false;
1405 } else {
1406 return true;
1411 class iCalendar_property_tzname extends iCalendar_property {
1413 var $name = 'TZNAME';
1414 var $val_type = RFC2445_TYPE_TEXT;
1416 function __construct() {
1417 parent::__construct();
1418 $this->valid_parameters = array(
1419 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
1420 RFC2445_XNAME => RFC2445_OPTIONAL
1424 function is_valid_value($value) {
1425 if(!parent::is_valid_value($value)) {
1426 return false;
1427 } else {
1428 return true;
1433 class iCalendar_property_tzoffsetfrom extends iCalendar_property {
1435 var $name = 'TZOFFSETFROM';
1436 var $val_type = RFC2445_TYPE_UTC_OFFSET;
1438 function __construct() {
1439 parent::__construct();
1440 $this->valid_parameters = array(
1441 RFC2445_XNAME => RFC2445_OPTIONAL
1445 function is_valid_value($value) {
1446 if(!parent::is_valid_value($value)) {
1447 return false;
1448 } else {
1449 return true;
1454 class iCalendar_property_tzoffsetto extends iCalendar_property {
1456 var $name = 'TZOFFSETTO';
1457 var $val_type = RFC2445_TYPE_UTC_OFFSET;
1459 function __construct() {
1460 parent::__construct();
1461 $this->valid_parameters = array(
1462 RFC2445_XNAME => RFC2445_OPTIONAL
1466 function is_valid_value($value) {
1467 if(!parent::is_valid_value($value)) {
1468 return false;
1469 } else {
1470 return true;
1475 class iCalendar_property_tzurl extends iCalendar_property {
1477 var $name = 'TZURL';
1478 var $val_type = RFC2445_TYPE_URI;
1480 function __construct() {
1481 parent::__construct();
1482 $this->valid_parameters = array(
1483 RFC2445_XNAME => RFC2445_OPTIONAL
1488 #######################
1490 class iCalendar_property_class extends iCalendar_property {
1492 var $name = 'CLASS';
1493 var $val_type = RFC2445_TYPE_TEXT;
1495 function __construct() {
1496 parent::__construct();
1497 $this->valid_parameters = array(
1498 RFC2445_XNAME => RFC2445_OPTIONAL