Merge branch 'MDL-22308_20' of git://git.catalyst.net.nz/moodle-r2
authorPetr Skoda <commits@skodak.org>
Sun, 17 Apr 2011 14:30:41 +0000 (16:30 +0200)
committerPetr Skoda <commits@skodak.org>
Sun, 17 Apr 2011 14:30:41 +0000 (16:30 +0200)
lib/bennu/iCalendar_components.php
lib/bennu/iCalendar_properties.php
lib/bennu/iCalendar_rfc2445.php

index 5a4127d..9235098 100644 (file)
@@ -9,7 +9,6 @@
  *  See http://bennu.sourceforge.net/ for more information and downloads.
  *
  * @author Ioannis Papaioannou 
- * @version $Id$
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 
@@ -19,12 +18,13 @@ class iCalendar_component {
     var $components       = NULL;
     var $valid_properties = NULL;
     var $valid_components = NULL;
+    /**
+     * Added to hold errors from last run of unserialize
+     * @var $parser_errors array
+     */
+    var $parser_errors = NULL;
 
-    function iCalendar_component() {
-        $this->construct();
-    }
-
-    function construct() {
+    function __construct() {
         // Initialize the components array
         if(empty($this->components)) {
             $this->components = array();
@@ -99,13 +99,13 @@ class iCalendar_component {
             return false;
         }
 
-        // If this property is restricted to only once, blindly overwrite value
-        if(!$xname && $this->valid_properties[$name] & RFC2445_ONCE) {
-            $this->properties[$name] = array($property);
-        }
-
-        // Otherwise add it to the instance array for this property
-        else {
+        // Check if the property already exists, and is limited to one occurrance,
+        // DON'T overwrite the value - this can be done explicity with set_value() instead.
+        if(!$xname && $this->valid_properties[$name] & RFC2445_ONCE && isset($this->properties[$name])) {
+            return false;
+        } 
+               else {
+             // Otherwise add it to the instance array for this property
             $this->properties[$name][] = $property;
         }
 
@@ -218,13 +218,112 @@ class iCalendar_component {
 
         return $string;
     }
+    
+    /**
+    * unserialize()
+    *
+    * I needed a way to convert an iCalendar component back to a Bennu object so I could
+    * easily access and modify it after it had been stored; if this functionality is already
+    * present somewhere in the library, I apologize for adding it here unnecessarily; however,
+    * I couldn't find it so I added it myself.
+    * @param string $string the iCalendar object to load in to this iCalendar_component
+    * @return bool true if the file parsed with no errors. False if there were errors.
+    */
+    
+    function unserialize($string) {
+        $string = rfc2445_unfold($string); // Unfold any long lines
+        $lines = explode(RFC2445_CRLF, $string); // Create an array of lines
+        
+        $components = array(); // Initialise a stack of components
+        $this->clear_errors();
+        foreach ($lines as $key => $line) {
+            // Divide the line up into label, parameters and data fields.
+            if (!preg_match('#^(?P<label>[-[:alnum:]]+)(?P<params>(?:;(?:(?:[-[:alnum:]]+)=(?:[^[:cntrl:]";:,]+|"[^[:cntrl:]"]+")))*):(?P<data>.*)$#', $line, $match)) {
+                $this->parser_error('Invalid line: '.$key.', ignoring');
+                continue;
+            }
+
+            // parse parameters
+            $params = array();
+            if (preg_match_all('#;(?P<param>[-[:alnum:]]+)=(?P<value>[^[:cntrl:]";:,]+|"[^[:cntrl:]"]+")#', $match['params'], $pmatch)) {
+                $params = array_combine($pmatch['param'], $pmatch['value']);
+            } 
+            $label = $match['label'];
+            $data  = $match['data'];
+            unset($match, $pmatch);
+
+            if ($label == 'BEGIN') {
+                // This is the start of a component.
+                $current_component = array_pop($components); // Get the current component off the stack so we can check its valid components
+                if ($current_component == null) { // If there's nothing on the stack
+                    $current_component = $this; // use the iCalendar
+                }
+                if (in_array($data, $current_component->valid_components)) { // Check that the new component is a valid subcomponent of the current one
+                    if($current_component != $this) {
+                        array_push($components, $current_component); // We're done with the current component, put it back on the stack.
+                    }
+                    if(strpos($data, 'V') === 0) {
+                        $data = substr($data, 1);
+                    }
+                    $cname = 'iCalendar_' . strtolower($data);
+                    $new_component = new $cname;
+                    array_push($components, $new_component); // Push a new component onto the stack
+                } else {
+                    if($current_component != $this) {
+                        array_push($components, $current_component);
+                        $this->parser_error('Invalid component type on line '.$key);
+                    }                        
+                }
+                unset($current_component, $new_component);
+            } else if ($label == 'END') {
+                // It's the END of a component.
+                $component = array_pop($components); // Pop the top component off the stack - we're now done with it
+                $parent_component = array_pop($components); // Pop the component's conatining component off the stack so we can add this component to it.
+                if($parent_component == null) {
+                    $parent_component = $this; // If there's no components on the stack, use the iCalendar object
+                }
+                if ($parent_component->add_component($component) === false) {
+                    $this->parser_error("Failed to add component on line $key");
+                }
+                if ($parent_component != $this) { // If we're not using the iCalendar
+                        array_push($components, $parent_component); // Put the component back on the stack
+                }
+                unset($parent_component, $component);
+            } else {
+                
+                $component = array_pop($components); // Get the component off the stack so we can add properties to it
+                if ($component == null) { // If there's nothing on the stack
+                    $component = $this; // use the iCalendar
+                }
+
+                if ($component->add_property($label, $data, $params) === false) {
+                    $this->parser_error("Failed to add property '$label' on line $key");
+                }
+
+                if($component != $this) { // If we're not using the iCalendar
+                    array_push($components, $component); // Put the component back on the stack
+                }
+                unset($component);
+            }
+
+        }
+        
+    }
+
+    function clear_errors() {
+        $this->parser_errors = array();
+    }
+
+    function parser_error($error) {
+        $this->parser_errors[] = $error;
+    }
 
 }
 
 class iCalendar extends iCalendar_component {
     var $name = 'VCALENDAR';
 
-    function construct() {
+    function __construct() {
         $this->valid_properties = array(
             'CALSCALE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
             'METHOD'      => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -234,11 +333,9 @@ class iCalendar extends iCalendar_component {
         );
 
         $this->valid_components = array(
-            'VEVENT'
-            // TODO: add support for the other component types
-            //, 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VTIMEZONE', 'VALARM'
+            'VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VTIMEZONE', 'VALARM'
         );
-        parent::construct();
+        parent::__construct();
     }
 
 }
@@ -248,7 +345,7 @@ class iCalendar_event extends iCalendar_component {
     var $name       = 'VEVENT';
     var $properties;
     
-    function construct() {
+    function __construct() {
         
         $this->valid_components = array('VALARM');
 
@@ -293,7 +390,7 @@ class iCalendar_event extends iCalendar_component {
             RFC2445_XNAME    => RFC2445_OPTIONAL
         );
 
-        parent::construct();
+        parent::__construct();
     }
 
     function invariant_holds() {
@@ -326,84 +423,272 @@ class iCalendar_todo extends iCalendar_component {
     var $name       = 'VTODO';
     var $properties;
 
-    function construct() {
-
-        $this->properties = array(
-            'class'       => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'completed'   => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'created'     => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'description' => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'dtstamp'     => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'dtstart'     => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'geo'         => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'last-modified'    => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'location'    => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'organizer'   => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'percent'     => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'priority'    => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'recurid'     => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'sequence'    => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'status'      => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'summary'     => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'uid'         => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'url'         => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'due'         => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'duration'    => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'attach'      => RFC2445_OPTIONAL,
-            'attendee'    => RFC2445_OPTIONAL,
-            'categories'  => RFC2445_OPTIONAL,
-            'comment'     => RFC2445_OPTIONAL,
-            'contact'     => RFC2445_OPTIONAL,
-            'exdate'      => RFC2445_OPTIONAL,
-            'exrule'      => RFC2445_OPTIONAL,
-            'rstatus'     => RFC2445_OPTIONAL,
-            'related'     => RFC2445_OPTIONAL,
-            'resources'   => RFC2445_OPTIONAL,
-            'rdate'       => RFC2445_OPTIONAL,
-            'rrule'       => RFC2445_OPTIONAL,
-            'xprop'       => RFC2445_OPTIONAL
+    function __construct() {
+        
+        $this->valid_components = array('VALARM');
+
+        $this->valid_properties = array(
+            'CLASS'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'COMPLETED'   => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'CREATED'     => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DESCRIPTION' => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DTSTAMP'     => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DTSTAP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'GEO'         => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'LOCATION'    => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'ORGANIZER'   => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'PERCENT'     => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'PRIORITY'    => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'RECURID'     => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'SEQUENCE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'STATUS'      => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'SUMMARY'     => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'UID'         => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'URL'         => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DUE'         => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DURATION'    => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'ATTACH'      => RFC2445_OPTIONAL,
+            'ATTENDEE'    => RFC2445_OPTIONAL,
+            'CATEGORIES'  => RFC2445_OPTIONAL,
+            'COMMENT'     => RFC2445_OPTIONAL,
+            'CONTACT'     => RFC2445_OPTIONAL,
+            'EXDATE'      => RFC2445_OPTIONAL,
+            'EXRULE'      => RFC2445_OPTIONAL,
+            'RSTATUS'     => RFC2445_OPTIONAL,
+            'RELATED'     => RFC2445_OPTIONAL,
+            'RESOURCES'   => RFC2445_OPTIONAL,
+            'RDATE'       => RFC2445_OPTIONAL,
+            'RRULE'       => RFC2445_OPTIONAL,
+            RFC2445_XNAME => RFC2445_OPTIONAL
         );
 
-        parent::construct();
-        // TODO:
-        // either 'due' or 'duration' may appear in  a 'eventprop', but 'due'
-        // and 'duration' MUST NOT occur in the same 'eventprop'
+        parent::__construct();
     }
+    
+    function invariant_holds() {
+        // DTEND and DURATION must not appear together
+        if(isset($this->properties['DTEND']) && isset($this->properties['DURATION'])) {
+            return false;
+        }
+
+        
+        if(isset($this->properties['DTEND']) && isset($this->properties['DTSTART'])) {
+            // DTEND must be later than DTSTART
+            // The standard is not clear on how to hande different value types though
+            // TODO: handle this correctly even if the value types are different
+            if($this->properties['DTEND'][0]->value <= $this->properties['DTSTART'][0]->value) {
+                return false;
+            }
+
+            // DTEND and DTSTART must have the same value type
+            if($this->properties['DTEND'][0]->val_type != $this->properties['DTSTART'][0]->val_type) {
+                return false;
+            }
+
+        }
+        
+        if(isset($this->properties['DUE']) && isset($this->properties['DTSTART'])) {
+            if($this->properties['DUE'][0]->value <= $this->properties['DTSTART'][0]->value) {
+                return false;
+            }   
+        }
+        
+        return true;
+    }
+    
 }
 
 class iCalendar_journal extends iCalendar_component {
-    // TODO: implement
+    var $name = 'VJOURNAL';
+    var $properties;
+    
+    function __construct() {
+       
+        $this->valid_properties = array(
+            'CLASS'         => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'CREATED'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DESCRIPTION'   => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DTSTART'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DTSTAMP'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'LAST-MODIFIED' => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'ORGANIZER'     => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'RECURRANCE-ID' => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'SEQUENCE'      => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'STATUS'        => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'SUMMARY'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'UID'           => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'URL'           => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'ATTACH'        => RFC2445_OPTIONAL,
+            'ATTENDEE'      => RFC2445_OPTIONAL,
+            'CATEGORIES'    => RFC2445_OPTIONAL,
+            'COMMENT'       => RFC2445_OPTIONAL,
+            'CONTACT'       => RFC2445_OPTIONAL,
+            'EXDATE'        => RFC2445_OPTIONAL,
+            'EXRULE'        => RFC2445_OPTIONAL,
+            'RELATED-TO'    => RFC2445_OPTIONAL,
+            'RDATE'         => RFC2445_OPTIONAL,
+            'RRULE'         => RFC2445_OPTIONAL,
+            RFC2445_XNAME   => RFC2445_OPTIONAL            
+        );
+        
+         parent::__construct();
+        
+    }
 }
 
 class iCalendar_freebusy extends iCalendar_component {
-    // TODO: implement
+    var $name       = 'VFREEBUSY';
+    var $properties;
+
+    function __construct() {
+        $this->valid_components = array();
+        $this->valid_properties = array(
+            'CONTACT'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DTSTART'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DTEND'         => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DURATION'      => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'DTSTAMP'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'ORGANIZER'     => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'UID'           => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'URL'           => RFC2445_OPTIONAL | RFC2445_ONCE,
+            // TODO: the next two are components of their own!
+            'ATTENDEE'      => RFC2445_OPTIONAL,
+            'COMMENT'       => RFC2445_OPTIONAL,
+            'FREEBUSY'      => RFC2445_OPTIONAL,
+            'RSTATUS'       => RFC2445_OPTIONAL,
+            RFC2445_XNAME   => RFC2445_OPTIONAL
+        );
+        
+        parent::__construct();
+    }
+    
+    function invariant_holds() {
+        // DTEND and DURATION must not appear together
+        if(isset($this->properties['DTEND']) && isset($this->properties['DURATION'])) {
+            return false;
+        }
+
+        
+        if(isset($this->properties['DTEND']) && isset($this->properties['DTSTART'])) {
+            // DTEND must be later than DTSTART
+            // The standard is not clear on how to hande different value types though
+            // TODO: handle this correctly even if the value types are different
+            if($this->properties['DTEND'][0]->value <= $this->properties['DTSTART'][0]->value) {
+                return false;
+            }
+
+            // DTEND and DTSTART must have the same value type
+            if($this->properties['DTEND'][0]->val_type != $this->properties['DTSTART'][0]->val_type) {
+                return false;
+            }
+
+        }
+        return true;
+    }
 }
 
 class iCalendar_alarm extends iCalendar_component {
-    // TODO: implement
+    var $name       = 'VALARM';
+    var $properties;
+
+    function __construct() {
+        $this->valid_components = array();
+        $this->valid_properties = array(
+            'ACTION'    => RFC2445_REQUIRED | RFC2445_ONCE,
+            'TRIGGER'   => RFC2445_REQUIRED | RFC2445_ONCE,
+            // If one of these 2 occurs, so must the other.
+            'DURATION'  => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'REPEAT'    => RFC2445_OPTIONAL | RFC2445_ONCE, 
+            // The following is required if action == "PROCEDURE" | "AUDIO"           
+            'ATTACH'    => RFC2445_OPTIONAL,
+            // The following is required if trigger == "EMAIL" | "DISPLAY" 
+            'DESCRIPTION'  => RFC2445_OPTIONAL | RFC2445_ONCE,
+            // The following are required if action == "EMAIL"
+            'SUMMARY'   => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'ATTENDEE'  => RFC2445_OPTIONAL,
+            RFC2445_XNAME   => RFC2445_OPTIONAL
+        );
+     
+        parent::__construct();
+    }
+        
+    function invariant_holds() {
+        // DTEND and DURATION must not appear together
+        if(isset($this->properties['ACTION'])) {
+            switch ($this->properties['ACTION'][0]->value) {
+               case 'AUDIO':
+                    if (!isset($this->properties['ATTACH'])) {
+                       return false;
+                    }
+                    break;
+                case 'DISPLAY':
+                    if (!isset($this->properties['DESCRIPTION'])) {
+                       return false;
+                    }
+                    break;
+                case 'EMAIL':
+                    if (!isset($this->properties['DESCRIPTION']) || !isset($this->properties['SUMMARY']) || !isset($this->properties['ATTACH'])) {
+                        return false;
+                    }
+                    break;
+                case 'PROCEDURE':
+                    if (!isset($this->properties['ATTACH']) || count($this->properties['ATTACH']) > 1) {
+                       return false;
+                    }
+                    break;
+            }
+        }
+        return true;
+    }
+        
+        
 }
 
 class iCalendar_timezone extends iCalendar_component {
     var $name       = 'VTIMEZONE';
     var $properties;
 
-    function construct() {
+    function __construct() {
 
-        $this->properties = array(
-            'tzid'        => RFC2445_REQUIRED | RFC2445_ONCE,
-            'last-modified'    => RFC2445_OPTIONAL | RFC2445_ONCE,
-            'tzurl'       => RFC2445_OPTIONAL | RFC2445_ONCE,
-            // TODO: the next two are components of their own!
-            'standardc'   => RFC2445_REQUIRED,
-            'daylightc'   => RFC2445_REQUIRED,
-            'x-prop'      => RFC2445_OPTIONAL
+        $this->valid_components = array('STANDARD', 'DAYLIGHT');
+
+        $this->valid_properties = array(
+            'TZID'        => RFC2445_REQUIRED | RFC2445_ONCE,
+            'LAST-MODIFIED'    => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'TZURL'       => RFC2445_OPTIONAL | RFC2445_ONCE,
+            RFC2445_XNAME => RFC2445_OPTIONAL
         );
         
-        parent::construct();
+        parent::__construct();
     }
 
 }
 
+class iCalendar_standard extends iCalendar_component {
+    var $name       = 'STANDARD';
+    var $properties;
+    
+    function __construct() {
+        $this->valid_components = array();
+        $this->valid_properties = array(
+            'DTSTART'   =>  RFC2445_REQUIRED | RFC2445_ONCE,
+            'TZOFFSETTO'    =>  RFC2445_REQUIRED | RFC2445_ONCE,
+            'TZOFFSETFROM'  =>  RFC2445_REQUIRED | RFC2445_ONCE,
+            'COMMENT'   =>  RFC2445_OPTIONAL,
+            'RDATE'   =>  RFC2445_OPTIONAL,
+            'RRULE'   =>  RFC2445_OPTIONAL,
+            'TZNAME'   =>  RFC2445_OPTIONAL,
+            RFC2445_XNAME   =>  RFC2445_OPTIONAL,
+        ); 
+        parent::__construct();
+    }
+}
+
+class iCalendar_daylight extends iCalendar_standard {
+    var $name   =   'DAYLIGHT';
+}
+
 // REMINDER: DTEND must be later than DTSTART for all components which support both
 // REMINDER: DUE must be later than DTSTART for all components which support both
 
index 9da0dc0..bb621ce 100644 (file)
@@ -25,11 +25,7 @@ class iCalendar_property {
     var $val_multi        = false;
     var $val_default      = NULL;
 
-    function iCalendar_property() {
-        $this->construct();
-    }
-
-    function construct() {
+    function __construct() {
         $this->parameters = array();
     }
 
@@ -221,7 +217,7 @@ class iCalendar_property_calscale extends iCalendar_property {
     var $name        = 'CALSCALE';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -238,7 +234,7 @@ class iCalendar_property_method extends iCalendar_property {
     var $name        = 'METHOD';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -258,7 +254,7 @@ class iCalendar_property_prodid extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_TEXT;
     var $val_default = NULL;
 
-    function construct() {
+    function __construct() {
         $this->val_default = '-//John Papaioannou/NONSGML Bennu '._BENNU_VERSION.'//EN';
 
         $this->valid_parameters = array(
@@ -273,7 +269,7 @@ class iCalendar_property_version extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_TEXT;
     var $val_default = '2.0';
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -293,7 +289,7 @@ class iCalendar_property_attach extends iCalendar_property {
     var $name        = 'ATTACH';
     var $val_type    = RFC2445_TYPE_URI;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'FMTTYPE'     => RFC2445_OPTIONAL | RFC2445_ONCE,
             'ENCODING'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -339,7 +335,7 @@ class iCalendar_property_categories extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_TEXT;
     var $val_multi   = true;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
             RFC2445_XNAME => RFC2445_OPTIONAL
@@ -353,7 +349,7 @@ class iCalendar_property_class extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_TEXT;
     var $val_default = 'PUBLIC';
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -370,7 +366,7 @@ class iCalendar_property_comment extends iCalendar_property {
     var $name        = 'COMMENT';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'ALTREP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -384,7 +380,7 @@ class iCalendar_property_description extends iCalendar_property {
     var $name        = 'DESCRIPTION';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'ALTREP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -398,7 +394,7 @@ class iCalendar_property_geo extends iCalendar_property {
     var $name        = 'GEO';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'ALTREP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -438,7 +434,7 @@ class iCalendar_property_location extends iCalendar_property {
     var $name        = 'LOCATION';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'ALTREP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -452,7 +448,7 @@ class iCalendar_property_percent_complete extends iCalendar_property {
     var $name        = 'PERCENT-COMPLETE';
     var $val_type    = RFC2445_TYPE_INTEGER;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -474,7 +470,7 @@ class iCalendar_property_priority extends iCalendar_property {
     var $name        = 'PRIORITY';
     var $val_type    = RFC2445_TYPE_INTEGER;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -497,7 +493,7 @@ class iCalendar_property_resources extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_TEXT;
     var $val_multi   = true;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'ALTREP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -511,7 +507,7 @@ class iCalendar_property_status extends iCalendar_property {
     var $name        = 'STATUS';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -541,7 +537,7 @@ class iCalendar_property_summary extends iCalendar_property {
     var $name        = 'SUMMARY';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'ALTREP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -558,7 +554,7 @@ class iCalendar_property_completed extends iCalendar_property {
     var $name        = 'COMPLETED';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -578,7 +574,7 @@ class iCalendar_property_dtend extends iCalendar_property {
     var $name        = 'DTEND';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'VALUE'       => RFC2445_OPTIONAL | RFC2445_ONCE,
             'TZID'        => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -620,7 +616,7 @@ class iCalendar_property_due extends iCalendar_property {
     var $name        = 'DUE';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'VALUE'       => RFC2445_OPTIONAL | RFC2445_ONCE,
             'TZID'        => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -662,7 +658,7 @@ class iCalendar_property_dtstart extends iCalendar_property {
     var $name        = 'DTSTART';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'VALUE'       => RFC2445_OPTIONAL | RFC2445_ONCE,
             'TZID'        => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -705,7 +701,7 @@ class iCalendar_property_duration extends iCalendar_property {
     var $name        = 'DURATION';
     var $val_type    = RFC2445_TYPE_DURATION;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -727,7 +723,7 @@ class iCalendar_property_freebusy extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_PERIOD;
     var $val_multi   = true;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'FBTYPE'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             RFC2445_XNAME => RFC2445_OPTIONAL
@@ -744,7 +740,7 @@ class iCalendar_property_freebusy extends iCalendar_property {
             // Start time MUST be in UTC
             return false;
         }
-        if($value{$pos + 1} != 'P' && $substr($value, -1) != 'Z') {
+        if($value{$pos + 1} != 'P' && substr($value, -1) != 'Z') {
             // If the second part is not a period, it MUST be in UTC
             return false;
         }
@@ -761,7 +757,7 @@ class iCalendar_property_transp extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_TEXT;
     var $val_default = 'OPAQUE';
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -786,7 +782,7 @@ class iCalendar_property_attendee extends iCalendar_property {
     // TODO: MUST NOT be specified when the calendar object has METHOD=PUBLISH
     // TODO: standard has lots of detail here, make triple sure that we eventually conform
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'LANGUAGE'       => RFC2445_OPTIONAL | RFC2445_ONCE,
             'CN'             => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -826,7 +822,7 @@ class iCalendar_property_contact extends iCalendar_property {
     var $name        = 'CONTACT';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'ALTREP'      => RFC2445_OPTIONAL | RFC2445_ONCE,
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -840,7 +836,7 @@ class iCalendar_property_organizer extends iCalendar_property {
     var $name        = 'ORGANIZER';
     var $val_type    = RFC2445_TYPE_CAL_ADDRESS;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'CN'          => RFC2445_OPTIONAL | RFC2445_ONCE,
             'DIR'         => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -880,7 +876,7 @@ class iCalendar_property_recurrence_id extends iCalendar_property {
     var $name        = 'RECURRENCE-ID';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'RANGE'       => RFC2445_OPTIONAL | RFC2445_ONCE,
             'TZID'        => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -912,7 +908,7 @@ class iCalendar_property_related_to extends iCalendar_property {
 
     // TODO: the value of this property must reference another component's UID
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'RELTYPE'     => RFC2445_OPTIONAL | RFC2445_ONCE,
             RFC2445_XNAME => RFC2445_OPTIONAL
@@ -925,7 +921,7 @@ class iCalendar_property_url extends iCalendar_property {
     var $name        = 'URL';
     var $val_type    = RFC2445_TYPE_URI;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -937,7 +933,7 @@ class iCalendar_property_uid extends iCalendar_property {
     var $name        = 'UID';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -958,7 +954,7 @@ class iCalendar_property_exdate extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_DATE_TIME;
     var $val_multi   = true;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'TZID'        => RFC2445_OPTIONAL | RFC2445_ONCE,
             'VALUE'       => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -987,7 +983,7 @@ class iCalendar_property_exrule extends iCalendar_property {
     var $name        = 'EXRULE';
     var $val_type    = RFC2445_TYPE_RECUR;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -1000,7 +996,7 @@ class iCalendar_property_rdate extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_DATE_TIME;
     var $val_multi   = true;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'TZID'        => RFC2445_OPTIONAL | RFC2445_ONCE,
             'VALUE'       => RFC2445_OPTIONAL | RFC2445_ONCE,
@@ -1029,14 +1025,71 @@ class iCalendar_property_rrule extends iCalendar_property {
     var $name        = 'RRULE';
     var $val_type    = RFC2445_TYPE_RECUR;
 
-    function construct() {
+    function __construct() {
+        $this->valid_parameters = array(
+            RFC2445_XNAME => RFC2445_OPTIONAL
+        );
+    }
+}
+
+// 4.8.6 Alarm Component Properties
+// -------------------------------------------
+class iCalendar_property_action extends iCalendar_property {
+       var $name      = 'ACTION';
+    var $val_type   = RFC2445_TYPE_TEXT;
+    
+    function __construct() {
+        $this->valid_parameters = array(
+            RFC2445_XNAME => RFC2445_OPTIONAL
+        );
+    }
+    
+    function is_valid_value($value) {
+        if(!parent::is_valid_value($value)) {
+            return false;
+        }
+        
+        // Value must be one of the following, or an x-name.
+        $valid_values = array('ACTION', 'DISPLAY', 'EMAIL', 'PROCEDURE');
+        return(in_array($value, $valid_values) || rfc2445_is_xname($value));        
+        
+    }
+}
+
+class iCalendar_property_repeat extends iCalendar_property {
+    var $name      = 'REPEAT';
+    var $val_type   = RFC2445_TYPE_INTEGER;
+    
+    function __construct() {
+        $this->valid_parameters = array(
+            RFC2445_XNAME => RFC2445_OPTIONAL
+        );
+    }   
+}
+
+class iCalendar_property_trigger extends iCalendar_property {
+    var $name      = 'TRIGGER';
+    var $val_type   = RFC2445_TYPE_TEXT;
+    
+    function __construct() {
         $this->valid_parameters = array(
+            'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE,
+            'RELATED' => RFC2445_OPTIONAL | RFC2445_ONCE,
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
     }
+    
+    function is_valid_value($value) {        
+       if(!parent::is_valid_value($value)) {
+            return false;
+        }
+        // Must either be DURATION or DATE_TIME type
+        return(rfc2445_is_valid_value($value, RFC2445_TYPE_DURATION) 
+            || rfc2445_is_valid_value($value, RFC2445_TYPE_DATE_TIME));
+    }
 }
 
-// TODO: 4.8.6 Alarm Component Properties
+
 
 // 4.8.7 Change Management Component Properties
 // --------------------------------------------
@@ -1046,7 +1099,7 @@ class iCalendar_property_created extends iCalendar_property {
     var $name        = 'CREATED';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -1066,7 +1119,7 @@ class iCalendar_property_dtstamp extends iCalendar_property {
     var $name        = 'DTSTAMP';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -1086,7 +1139,7 @@ class iCalendar_property_last_modified extends iCalendar_property {
     var $name        = 'LAST-MODIFIED';
     var $val_type    = RFC2445_TYPE_DATE_TIME;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -1107,7 +1160,7 @@ class iCalendar_property_sequence extends iCalendar_property {
     var $val_type    = RFC2445_TYPE_INTEGER;
     var $val_default = 0;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
@@ -1130,7 +1183,7 @@ class iCalendar_property_x extends iCalendar_property {
     var $name        = RFC2445_XNAME;
     var $val_type    = NULL;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
             RFC2445_XNAME => RFC2445_OPTIONAL
@@ -1160,7 +1213,7 @@ class iCalendar_property_request_status extends iCalendar_property {
     var $name        = 'REQUEST-STATUS';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             'LANGUAGE'    => RFC2445_OPTIONAL | RFC2445_ONCE,
             RFC2445_XNAME => RFC2445_OPTIONAL
@@ -1280,6 +1333,88 @@ class iCalendar_property_request_status extends iCalendar_property {
 
 }
 
+class iCalendar_property_tzid extends iCalendar_property {
+
+    var $name        = 'TZID';
+    var $val_type    = RFC2445_TYPE_TEXT;
+
+    function __construct() {
+        $this->valid_parameters = array(
+            RFC2445_XNAME => RFC2445_OPTIONAL
+        );
+    }
+
+    function is_valid_value($value) {
+        if(!parent::is_valid_value($value)) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+}
+
+class iCalendar_property_tzname extends iCalendar_property {
+
+    var $name        = 'TZNAME';
+    var $val_type    = RFC2445_TYPE_TEXT;
+
+    function __construct() {
+        $this->valid_parameters = array(
+            'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE,
+            RFC2445_XNAME => RFC2445_OPTIONAL
+        );
+    }
+
+    function is_valid_value($value) {
+        if(!parent::is_valid_value($value)) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+}
+
+class iCalendar_property_tzoffsetfrom extends iCalendar_property {
+
+    var $name        = 'TZOFFSETFROM';
+    var $val_type    = RFC2445_TYPE_UTC_OFFSET;
+
+    function __construct() {
+        $this->valid_parameters = array(
+            RFC2445_XNAME => RFC2445_OPTIONAL
+        );
+    }
+
+    function is_valid_value($value) {
+        if(!parent::is_valid_value($value)) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+}
+
+class iCalendar_property_tzoffsetto extends iCalendar_property {
+
+    var $name        = 'TZOFFSETTO';
+    var $val_type    = RFC2445_TYPE_UTC_OFFSET;
+
+    function __construct() {
+        $this->valid_parameters = array(
+            RFC2445_XNAME => RFC2445_OPTIONAL
+        );
+    }
+
+    function is_valid_value($value) {
+        if(!parent::is_valid_value($value)) {
+            return false;
+        } else {
+               return true;
+        }
+    }
+}
+
+
 
 #######################
 /*
@@ -1288,10 +1423,11 @@ class iCalendar_property_class extends iCalendar_property {
     var $name        = 'CLASS';
     var $val_type    = RFC2445_TYPE_TEXT;
 
-    function construct() {
+    function __construct() {
         $this->valid_parameters = array(
             RFC2445_XNAME => RFC2445_OPTIONAL
         );
     }
 }
 */
+
index bdba8b2..f6376dd 100644 (file)
@@ -26,6 +26,9 @@ define('RFC2445_WSP',                "\t ");
 define('RFC2445_WEEKDAYS',           'MO,TU,WE,TH,FR,SA,SU');
 define('RFC2445_FOLDED_LINE_LENGTH', 75);
 
+define('RFC2445_PARAMETER_SEPARATOR',  ';');
+define('RFC2445_VALUE_SEPARATOR',      ':');
+
 define('RFC2445_REQUIRED', 0x01);
 define('RFC2445_OPTIONAL', 0x02);
 define('RFC2445_ONCE',     0x04);
@@ -740,6 +743,7 @@ function rfc2445_is_valid_value($value, $type) {
                 return false;
             }
 
+            $s = 0;
             if(strlen($value) == 7) {
                 $s = intval(substr($value, 5, 2));
                 $value = substr($value, 0, 5);