49 require_once(
'XMLElement.php');
50 require_once(
'AwlQuery.php');
103 $this->parameters = array();
104 unset($this->rendered);
105 if ( $propstring != null && gettype($propstring) ==
'string' ) {
120 $this->rendered = (strlen($propstring) < 72 ? $propstring : null);
123 $unescaped = preg_replace(
'{\\\\[nN]}',
"\n", $propstring);
135 if (count($split) != 2) {
137 dbg_error_log(
'ERROR',
"iCalendar::ParseFrom(): Couldn't parse property from string: `%s`, skipping", $unescaped);
140 list($prop, $value) = $split;
143 $this->content = preg_replace(
"/\\\\([,;:\"\\\\])/",
'$1', $value);
147 $this->name = array_shift($parameters);
148 $this->parameters = array();
149 foreach ($parameters AS $k => $v) {
150 $pos = strpos($v,
'=');
151 $name = substr($v, 0, $pos);
152 $value = substr($v, $pos + 1);
153 $this->parameters[$name] = preg_replace(
'/^"(.+)"$/',
'$1', $value);
171 for($i = 0, $len = strlen($str); $i < $len; ++$i) {
174 $inquote = !$inquote;
176 if (!$inquote && $ch == $sep) {
180 if ($limit > 0 && $num == $limit) {
181 $result[] = substr($str, $cursor);
184 $result[] = substr($str, $cursor, $i - $cursor);
188 if ($i + 1 == $len) {
190 $result[] = substr($str, $cursor);
204 function Name( $newname = null ) {
205 if ( $newname != null ) {
206 $this->name = $newname;
207 if ( isset($this->rendered) ) unset($this->rendered);
221 function Value( $newvalue = null ) {
222 if ( $newvalue != null ) {
223 $this->content = $newvalue;
224 if ( isset($this->rendered) ) unset($this->rendered);
226 return $this->content;
238 if ( $newparams != null ) {
239 $this->parameters = $newparams;
240 if ( isset($this->rendered) ) unset($this->rendered);
242 return $this->parameters;
254 if ( isset($this->content) ) {
255 return (stristr( $this->content, $search ) !==
false);
269 if ( isset($this->parameters[$name]) )
return $this->parameters[$name];
280 if ( isset($this->rendered) ) unset($this->rendered);
281 $this->parameters[$name] = $value;
290 foreach( $this->parameters AS $k => $v ) {
291 $escaped = preg_replace(
"/([;:])/",
'\\\\$1', $v);
292 $rendered .= sprintf(
";%s=%s", $k, $escaped );
304 if ( isset($this->rendered) )
return $this->rendered;
306 $property = preg_replace(
'/[;].*$/',
'', $this->name );
307 $escaped = $this->content;
308 switch( $property ) {
310 case 'ATTACH':
case 'GEO':
case 'PERCENT-COMPLETE':
case 'PRIORITY':
311 case 'DURATION':
case 'FREEBUSY':
case 'TZOFFSETFROM':
case 'TZOFFSETTO':
312 case 'TZURL':
case 'ATTENDEE':
case 'ORGANIZER':
case 'RECURRENCE-ID':
313 case 'URL':
case 'EXRULE':
case 'SEQUENCE':
case 'CREATED':
314 case 'RRULE':
case 'REPEAT':
case 'TRIGGER':
317 case 'COMPLETED':
case 'DTEND':
318 case 'DUE':
case 'DTSTART':
319 case 'DTSTAMP':
case 'LAST-MODIFIED':
320 case 'CREATED':
case 'EXDATE':
322 if ( isset($this->parameters[
'VALUE']) && $this->parameters[
'VALUE'] ==
'DATE' ) {
323 $escaped = substr( $escaped, 0, 8);
329 $escaped = str_replace(
'\\',
'\\\\', $escaped);
330 $escaped = preg_replace(
'/\r?\n/',
'\\n', $escaped);
331 $escaped = preg_replace(
"/([,;])/",
'\\\\$1', $escaped);
334 if ( (strlen($property) + strlen($escaped)) <= 72 ) {
335 $this->rendered = $property . $escaped;
337 else if ( (strlen($property) + strlen($escaped)) > 72 && (strlen($property) < 72) && (strlen($escaped) < 72) ) {
338 $this->rendered = $property .
"\r\n " . $escaped;
341 $this->rendered = preg_replace(
'/(.{72})/u',
'$1'.
"\r\n ", $property . $escaped );
343 return $this->rendered;
394 $this->properties = array();
395 $this->components = array();
396 $this->rendered =
"";
397 if ( $content != null && (gettype($content) ==
'string' || gettype($content) ==
'array') ) {
408 $this->SetType(
'VCALENDAR');
409 $this->AddProperty(
'PRODID',
'-//davical.org//NONSGML AWL Calendar//EN');
410 $this->AddProperty(
'VERSION',
'2.0');
411 $this->AddProperty(
'CALSCALE',
'GREGORIAN');
412 if ( is_array($extra_properties) ) {
413 foreach( $extra_properties AS $k => $v ) {
414 $this->AddProperty($k,$v);
425 foreach( $this->components AS $k => $v ) {
426 $also = $v->CollectParameterValues($parameter_name);
427 $values = array_merge( $values, $also );
429 foreach( $this->properties AS $k => $v ) {
430 $also = $v->GetParameterValue($parameter_name);
431 if ( isset($also) && $also !=
"" ) {
445 $this->rendered = $content;
446 $content = $this->UnwrapComponent($content);
453 $length = strlen($content);
455 while( $linefrom < $length ) {
456 $lineto = strpos( $content,
"\n", $linefrom );
457 if ( $lineto ===
false ) {
458 $lineto = strpos( $content,
"\r", $linefrom );
461 $line = substr( $content, $linefrom, $lineto - $linefrom);
462 $linefrom = $lineto + 1;
465 $line = substr( $content, $linefrom );
468 if ( preg_match(
'/^\s*$/', $line ) )
continue;
469 $line = rtrim( $line,
"\r\n" );
472 if ( $type ===
false ) {
473 if ( preg_match(
'/^BEGIN:(.+)$/', $line, $matches ) ) {
476 $finish =
"END:$type";
478 dbg_error_log(
'iCalendar',
"::ParseFrom: Start component of type '%s'", $type);
481 dbg_error_log(
'iCalendar',
"::ParseFrom: Ignoring crap before start of component: $line");
483 if ( $line !=
"" ) $this->rendered = null;
486 else if ( $type == null ) {
487 dbg_error_log(
'iCalendar',
"::ParseFrom: Ignoring crap after end of component");
488 if ( $line !=
"" ) $this->rendered = null;
490 else if ( $line == $finish ) {
491 dbg_error_log(
'iCalendar',
"::ParseFrom: End of component");
495 if ( $subtype ===
false && preg_match(
'/^BEGIN:(.+)$/', $line, $matches ) ) {
497 $subtype = $matches[1];
498 $subfinish =
"END:$subtype";
499 $subcomponent = $line .
"\r\n";
500 dbg_error_log(
'iCalendar',
"::ParseFrom: Found a subcomponent '%s'", $subtype);
502 else if ( $subtype ) {
504 $subcomponent .= $this->WrapComponent($line);
505 if ( $line == $subfinish ) {
506 dbg_error_log(
'iCalendar',
"::ParseFrom: End of subcomponent '%s'", $subtype);
517 $this->properties[] =
new iCalProp($line);
530 return preg_replace(
'/\r?\n[ \t]/',
'', $content );
542 $strs = preg_split(
"/\r?\n/", $content );
544 foreach ($strs as $str) {
545 $wrapped .= preg_replace(
'/(.{72})/u',
'$1'.
"\r\n ", $str ) .
"\r\n";
562 if ( isset($this->rendered) ) unset($this->rendered);
572 $properties = array();
573 foreach( $this->properties AS $k => $v ) {
574 if ( $type == null || $v->Name() == $type ) {
575 $properties[$k] = $v;
590 foreach( $this->properties AS $k => $v ) {
591 if ( $v->Name() == $type )
return $v->Value();
606 foreach( $this->properties AS $k => $v ) {
607 if ( $v->Name() == $type )
return $v->GetParameterValue($parameter_name);
618 if ( $type != null ) {
620 foreach( $this->properties AS $k => $v ) {
621 if ( $v->Name() == $type ) {
622 unset($this->properties[$k]);
623 if ( isset($this->rendered) ) unset($this->rendered);
626 $this->properties = array_values($this->properties);
629 if ( isset($this->rendered) ) unset($this->rendered);
630 $this->properties = array();
639 if ( isset($this->rendered) && count($new_properties) > 0 ) unset($this->rendered);
640 $this->ClearProperties($type);
641 foreach( $new_properties AS $k => $v ) {
642 $this->AddProperty($v);
654 function AddProperty( $new_property, $value = null, $parameters = null ) {
655 if ( isset($this->rendered) ) unset($this->rendered);
656 if ( isset($value) && gettype($new_property) ==
'string' ) {
658 $new_prop->Name($new_property);
659 $new_prop->Value($value);
660 if ( $parameters != null ) $new_prop->Parameters($parameters);
661 dbg_error_log(
'iCalendar',
" Adding new property '%s'", $new_prop->Render() );
662 $this->properties[] = $new_prop;
664 else if ( gettype($new_property) ) {
665 $this->properties[] = $new_property;
675 foreach( $this->components AS $k => $v ) {
676 if ( $v->GetType() !=
'VTIMEZONE' )
return $this->components[$k];
690 if ( !preg_match(
'#^mailto:#', $email ) ) $email =
'mailto:'.$email;
691 $props = $this->GetPropertiesByPath(
'!VTIMEZONE/ORGANIZER');
692 foreach( $props AS $k => $prop ) {
693 if ( $prop->Value() == $email )
return true;
706 if ( !preg_match(
'#^mailto:#', $email ) ) $email =
'mailto:'.$email;
707 if ( $this->IsOrganizer($email) )
return true;
708 $props = $this->GetPropertiesByPath(
'!VTIMEZONE/ATTENDEE');
709 foreach( $props AS $k => $prop ) {
710 if ( $prop->Value() == $email )
return true;
725 $components = $this->components;
726 if ( $type != null ) {
727 foreach( $components AS $k => $v ) {
728 if ( ($v->GetType() != $type) === $normal_match ) {
729 unset($components[$k]);
732 $components = array_values($components);
743 if ( $type != null ) {
745 foreach( $this->components AS $k => $v ) {
746 if ( $v->GetType() == $type ) {
747 unset($this->components[$k]);
748 if ( isset($this->rendered) ) unset($this->rendered);
751 if ( ! $this->components[$k]->ClearComponents($type) ) {
752 if ( isset($this->rendered) ) unset($this->rendered);
756 return isset($this->rendered);
759 if ( isset($this->rendered) ) unset($this->rendered);
760 $this->components = array();
772 if ( isset($this->rendered) ) unset($this->rendered);
773 if ( count($new_component) > 0 ) $this->ClearComponents($type);
774 foreach( $new_component AS $k => $v ) {
775 $this->components[] = $v;
786 if ( is_array($new_component) && count($new_component) == 0 )
return;
787 if ( isset($this->rendered) ) unset($this->rendered);
788 if ( is_array($new_component) ) {
789 foreach( $new_component AS $k => $v ) {
790 $this->components[] = $v;
794 $this->components[] = $new_component;
804 foreach( $this->components AS $k => $v ) {
805 if ( ! in_array( $v->GetType(), $keep ) ) {
806 unset($this->components[$k]);
807 if ( isset($this->rendered) ) unset($this->rendered);
810 $v->MaskComponents($keep);
822 foreach( $this->components AS $k => $v ) {
823 $v->MaskProperties($keep, $component_list);
826 if ( !isset($component_list) || in_array($this->GetType(), $component_list) ) {
827 foreach( $this->properties AS $k => $v ) {
828 if ( ! in_array( $v->name, $keep ) ) {
829 unset($this->properties[$k]);
830 if ( isset($this->rendered) ) unset($this->rendered);
843 $confidential = clone($this);
844 $keep_properties = array(
'DTSTAMP',
'DTSTART',
'RRULE',
'DURATION',
'DTEND',
'DUE',
'UID',
'CLASS',
'TRANSP',
'CREATED',
'LAST-MODIFIED' );
845 $resource_components = array(
'VEVENT',
'VTODO',
'VJOURNAL' );
846 $confidential->MaskComponents(array(
'VTIMEZONE',
'STANDARD',
'DAYLIGHT',
'VEVENT',
'VTODO',
'VJOURNAL' ));
847 $confidential->MaskProperties($keep_properties, $resource_components );
849 if ( isset($confidential->rendered) )
850 unset($confidential->rendered);
852 if ( in_array( $confidential->GetType(), $resource_components ) ) {
853 $confidential->AddProperty(
'SUMMARY', translate(
'Busy') );
855 foreach( $confidential->components AS $k => $v ) {
856 if ( in_array( $v->GetType(), $resource_components ) ) {
857 $v->AddProperty(
'SUMMARY', translate(
'Busy') );
861 return $confidential;
875 return substr($this->
Render($restricted_properties), 0 , -2);
882 function Render( $restricted_properties = null) {
884 $unrestricted = (!isset($restricted_properties) || count($restricted_properties) == 0);
886 if ( isset($this->rendered) && $unrestricted )
887 return $this->rendered;
889 $rendered =
"BEGIN:$this->type\r\n";
890 foreach( $this->properties AS $k => $v ) {
891 if ( method_exists($v,
'Render') ) {
892 if ( $unrestricted || isset($restricted_properties[$v]) ) $rendered .= $v->Render() .
"\r\n";
895 foreach( $this->components AS $v ) { $rendered .= $v->Render(); }
896 $rendered .=
"END:$this->type\r\n";
898 $rendered = preg_replace(
'{(?<!\r)\n}',
"\r\n", $rendered);
899 if ( $unrestricted ) $this->rendered = $rendered;
915 $properties = array();
916 dbg_error_log(
'iCalendar',
"GetPropertiesByPath: Querying within '%s' for path '%s'", $this->type, $path );
917 if ( !preg_match(
'#(/?)(!?)([^/]+)(/?.*)$#', $path, $matches ) )
return $properties;
919 $adrift = ($matches[1] ==
'');
920 $normal = ($matches[2] ==
'');
921 $ourtest = $matches[3];
922 $therest = $matches[4];
923 dbg_error_log(
'iCalendar',
"GetPropertiesByPath: Matches: %s -- %s -- %s -- %s\n", $matches[1], $matches[2], $matches[3], $matches[4] );
924 if ( $ourtest ==
'*' || (($ourtest == $this->type) === $normal) && $therest !=
'' ) {
925 if ( preg_match(
'#^/(!?)([^/]+)$#', $therest, $matches ) ) {
926 $normmatch = ($matches[1] ==
'');
927 $proptest = $matches[2];
928 foreach( $this->properties AS $k => $v ) {
929 if ( $proptest ==
'*' || (($v->Name() == $proptest) === $normmatch ) ) {
938 foreach( $this->components AS $k => $v ) {
939 $properties = array_merge( $properties, $v->GetPropertiesByPath($therest) );
948 foreach( $this->components AS $k => $v ) {
949 $properties = array_merge( $properties, $v->GetPropertiesByPath($path) );
952 dbg_error_log(
'iCalendar',
"GetPropertiesByPath: Found %d within '%s' for path '%s'\n", count($properties), $this->type, $path );
MaskProperties( $keep, $component_list=null)
__construct( $propstring=null)
SetParameterValue( $name, $value)
ClearProperties( $type=null)
RenderWithoutWrap($restricted_properties=null)
UnwrapComponent( $content)
SetComponents( $new_component, $type=null)
AddComponent( $new_component)
__construct( $content=null)
CollectParameterValues( $parameter_name)
SetProperties( $new_properties, $type=null)
SplitQuoted($str, $sep=',', $limit=0)
Parameters( $newparams=null)
GetPropertiesByPath( $path)
& FirstNonTimezone( $type=null)
VCalendar( $extra_properties=null)
Render( $restricted_properties=null)
GetComponents( $type=null, $normal_match=true)
AddProperty( $new_property, $value=null, $parameters=null)
GetPParamValue( $type, $parameter_name)
ClearComponents( $type=null)
GetProperties( $type=null)
GetParameterValue( $name)