* or the GNU Affero General Public License, version 3:
* iCalcreator is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* iCalcreator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public
* License along with this program.
* If not, see .
*/
namespace kigkonsult\iCalcreator;
use kigkonsult\iCalcreator\util\util;
/**
* Do NOT alter or remove the constant!!
*/
if( ! defined( 'ICALCREATOR_VERSION' ))
define( 'ICALCREATOR_VERSION', 'iCalcreator 2.24' );
/**
* iCalcreator base class
*
* Properties and methods shared by vcalendar and calendarComponents
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.22.20 - 2017-01-30
*/
abstract class iCalBase {
use traits\X_PROPtrait;
/**
* @var array container for sub-components
* @access protected
*/
protected $components = [];
/**
* @var array $unparsed calendar/components in 'raw' text...
* @access protected
*/
protected $unparsed = null;
/**
* @var array $config configuration
* @access protected
*/
protected $config = [];
/**
* @var int component index
* @access protected
*/
protected $compix = 0;
/**
* @var array get multi property index
* @access protected
*/
protected $propix = [];
/**
* @var array delete multi property index
* @access protected
*/
protected $propdelix = [];
/**
* __clone method
*
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.23.12 - 2017-04-20
*/
public function __clone() {
foreach( $this->components as $cix => $component )
$this->components[$cix] = clone $component;
if( isset( $this->compix ))
$this->compix = [];
if( isset( $this->propix ))
$this->propix = [];
if( isset( $this->propdelix ))
$this->propdelix = [];
}
/**
* Return config value or info about subcomponents, false on not found
*
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.22.23 - 2017-02-02
* @param mixed $config
* @return mixed
*/
public function getConfig( $config = false) {
static $LCORDNO = 'ordno';
static $LCTYPE = 'type';
static $LCUID = 'uid';
static $LCPROPS = 'props';
static $LCSUB = 'sub';
if( empty( $config )) {
$return = [];
$return[util::$ALLOWEMPTY] = $this->getConfig( util::$ALLOWEMPTY );
if( false !== ( $lang = $this->getConfig( util::$LANGUAGE )))
$return[util::$LANGUAGE] = $lang;
$return[util::$TZID] = $this->getConfig( util::$TZID );
$return[util::$UNIQUE_ID] = $this->getConfig( util::$UNIQUE_ID );
return $return;
}
switch( strtoupper( $config )) {
case util::$ALLOWEMPTY:
if( isset( $this->config[util::$ALLOWEMPTY] ))
return $this->config[util::$ALLOWEMPTY];
break;
case util::$COMPSINFO:
unset( $this->compix );
$info = [];
if( ! empty( $this->components )) {
foreach( $this->components as $cix => $component ) {
if( empty( $component ))
continue;
$info[$cix][$LCORDNO] = $cix + 1;
$info[$cix][$LCTYPE] = $component->objName;
$info[$cix][$LCUID] = $component->getProperty( util::$UID );
$info[$cix][$LCPROPS] = $component->getConfig( util::$PROPINFO );
$info[$cix][$LCSUB] = $component->getConfig( util::$COMPSINFO );
}
}
return $info;
break;
case util::$LANGUAGE: // get language for calendar component as defined in [RFC 1766]
if( isset( $this->config[util::$LANGUAGE] ))
return $this->config[util::$LANGUAGE];
break;
case util::$PROPINFO:
$output = [];
if( ! in_array( $this->objName, util::$LCSUBCOMPS )) {
if( empty( $this->uid ))
$this->uid = util::makeUid( $this->getConfig( util::$UNIQUE_ID ));
$output[util::$UID] = 1;
if( empty( $this->dtstamp ))
$this->dtstamp = util::makeDtstamp();
$output[util::$DTSTAMP] = 1;
}
if( ! empty( $this->summary )) $output[util::$SUMMARY] = 1;
if( ! empty( $this->description )) $output[util::$DESCRIPTION] = count( $this->description );
if( ! empty( $this->dtstart )) $output[util::$DTSTART] = 1;
if( ! empty( $this->dtend )) $output[util::$DTEND] = 1;
if( ! empty( $this->due )) $output[util::$DUE] = 1;
if( ! empty( $this->duration )) $output[util::$DURATION] = 1;
if( ! empty( $this->rrule )) $output[util::$RRULE] = count( $this->rrule );
if( ! empty( $this->rdate )) $output[util::$RDATE] = count( $this->rdate );
if( ! empty( $this->exdate )) $output[util::$EXDATE] = count( $this->exdate );
if( ! empty( $this->exrule )) $output[util::$EXRULE] = count( $this->exrule );
if( ! empty( $this->action )) $output[util::$ACTION] = 1;
if( ! empty( $this->attach )) $output[util::$ATTACH] = count( $this->attach );
if( ! empty( $this->attendee )) $output[util::$ATTENDEE] = count( $this->attendee );
if( ! empty( $this->categories )) $output[util::$CATEGORIES] = count( $this->categories );
if( ! empty( $this->class )) $output[util::$CLASS] = 1;
if( ! empty( $this->comment )) $output[util::$COMMENT] = count( $this->comment );
if( ! empty( $this->completed )) $output[util::$COMPLETED] = 1;
if( ! empty( $this->contact )) $output[util::$CONTACT] = count( $this->contact );
if( ! empty( $this->created )) $output[util::$CREATED] = 1;
if( ! empty( $this->freebusy )) $output[util::$FREEBUSY] = count( $this->freebusy );
if( ! empty( $this->geo )) $output[util::$GEO] = 1;
if( ! empty( $this->lastmodified )) $output[util::$LAST_MODIFIED] = 1;
if( ! empty( $this->location )) $output[util::$LOCATION] = 1;
if( ! empty( $this->organizer )) $output[util::$ORGANIZER] = 1;
if( ! empty( $this->percentcomplete )) $output[util::$PERCENT_COMPLETE] = 1;
if( ! empty( $this->priority )) $output[util::$PRIORITY] = 1;
if( ! empty( $this->recurrenceid )) $output[util::$RECURRENCE_ID] = 1;
if( ! empty( $this->relatedto )) $output[util::$RELATED_TO] = count( $this->relatedto );
if( ! empty( $this->repeat )) $output[util::$REPEAT] = 1;
if( ! empty( $this->requeststatus )) $output[util::$REQUEST_STATUS] = count( $this->requeststatus );
if( ! empty( $this->resources )) $output[util::$RESOURCES] = count( $this->resources );
if( ! empty( $this->sequence )) $output[util::$SEQUENCE] = 1;
if( ! empty( $this->status )) $output[util::$STATUS] = 1;
if( ! empty( $this->transp )) $output[util::$TRANSP] = 1;
if( ! empty( $this->trigger )) $output[util::$TRIGGER] = 1;
if( ! empty( $this->tzid )) $output[util::$TZID] = 1;
if( ! empty( $this->tzname )) $output[util::$TZNAME] = count( $this->tzname );
if( ! empty( $this->tzoffsetfrom )) $output[util::$TZOFFSETFROM] = 1;
if( ! empty( $this->tzoffsetto )) $output[util::$TZOFFSETTO] = 1;
if( ! empty( $this->tzurl )) $output[util::$TZURL] = 1;
if( ! empty( $this->url )) $output[util::$URL] = 1;
if( ! empty( $this->xprop )) $output[util::$X_PROP] = count( $this->xprop );
return $output;
break;
case util::$SETPROPERTYNAMES:
return array_keys( $this->getConfig( util::$PROPINFO ));
break;
case util::$TZID:
if( isset( $this->config[util::$TZID] ))
return $this->config[util::$TZID];
break;
case util::$UNIQUE_ID:
if( empty( $this->config[util::$UNIQUE_ID] ))
$this->config[util::$UNIQUE_ID] = ( isset( $_SERVER[util::$SERVER_NAME] ))
? gethostbyname( $_SERVER[util::$SERVER_NAME] )
: util::$LOCALHOST;
return $this->config[util::$UNIQUE_ID];
break;
}
return false;
}
/**
* General component config setting
*
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.23.12 - 2017-04-22
* @param mixed $config
* @param string $value
* @param bool $softUpdate
* @return bool true on success
*/
public function setConfig( $config, $value=null, $softUpdate=null ) {
if( is_null( $softUpdate ))
$softUpdate = false;
if( is_array( $config )) {
$config = array_change_key_case( $config, CASE_UPPER );
foreach( $config as $cKey => $cValue ) {
if( false === $this->setConfig( $cKey, $cValue, $softUpdate ))
return false;
}
return true;
}
$res = false;
switch( strtoupper( $config )) {
case util::$ALLOWEMPTY:
$this->config[util::$ALLOWEMPTY] = $value;
$subcfg = [util::$ALLOWEMPTY => $value];
$res = true;
break;
case util::$LANGUAGE: // set language for component as defined in [RFC 1766]
$value = trim( $value );
if( empty( $this->config[util::$LANGUAGE] ) || ! $softUpdate )
$this->config[util::$LANGUAGE] = $value;
$subcfg = [util::$LANGUAGE => $value];
$res = true;
break;
case util::$TZID:
$this->config[util::$TZID] = trim( $value );
$subcfg = [util::$TZID => trim( $value )];
$res = true;
break;
case util::$UNIQUE_ID:
$value = trim( $value );
$this->config[util::$UNIQUE_ID] = $value;
$subcfg = [util::$UNIQUE_ID => $value];
$res = true;
break;
default: // any unvalid config key.. .
return true;
}
if( ! $res )
return false;
if( isset( $subcfg ) && ! empty( $this->components )) {
foreach( $subcfg as $cfgkey => $cfgvalue ) {
foreach( $this->components as $cix => $component ) {
$res = $this->components[$cix]->setConfig( $cfgkey, $cfgvalue, $softUpdate );
if( ! $res )
break 2;
}
}
}
return $res;
}
/**
* Return number of components
*
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.23.5 - 2017-04-13
* @return int
*/
public function countComponents() {
return ( empty( $this->components )) ? 0 : count( $this->components );
}
/**
* Return new calendar component, included in calendar or component
*
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.22.20 - 2017-04-13
* @param string $compType component type
* @return calendarComponent
*/
public function newComponent( $compType ) {
$config = $this->getConfig();
$ix = ( empty( $this->components ))
? 0
: key( array_slice( $this->components, -1, 1, TRUE )) + 1;
switch( strtolower( $compType )) {
case util::$LCVALARM :
$this->components[$ix] = new valarm( $config );
break;
case util::$LCVEVENT :
$this->components[$ix] = new vevent( $config );
break;
case util::$LCVTODO :
$this->components[$ix] = new vtodo( $config );
break;
case util::$LCVJOURNAL :
$this->components[$ix] = new vjournal( $config );
break;
case util::$LCVFREEBUSY :
$this->components[$ix] = new vfreebusy( $config );
break;
case util::$LCVTIMEZONE :
array_unshift( $this->components, new vtimezone( $config ));
$ix = 0;
break;
case util::$LCSTANDARD :
array_unshift( $this->components, new vtimezone( util::$LCSTANDARD, $config ));
$ix = 0;
break;
case util::$LCDAYLIGHT :
$this->components[$ix] = new vtimezone( util::$LCDAYLIGHT, $config );
break;
default:
return false;
}
return $this->components[$ix];
}
/**
* Delete calendar subcomponent from component container
*
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.23.12 - 2017-05-06
* @param mixed $arg1 ordno / component type / component uid
* @param mixed $arg2 ordno if arg1 = component type
* @return bool true on success
*/
public function deleteComponent( $arg1, $arg2=false ) {
static $INDEX = 'INDEX';
if( ! isset( $this->components ))
return false;
$argType = $index = null;
if ( ctype_digit( (string) $arg1 )) {
$argType = $INDEX;
$index = (int) $arg1 - 1;
}
elseif( in_array( strtolower( $arg1 ), util::$ALLCOMPS )) {
$argType = strtolower( $arg1 );
$index = ( ! empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
}
$cix2dC = 0;
$remove = false;
foreach( $this->components as $cix => $component ) {
if(( $INDEX == $argType ) && ( $index == $cix )) {
unset( $this->components[$cix] );
$remove = true;
break;
}
elseif( $argType == $component->objName ) {
if( $index == $cix2dC ) {
unset( $this->components[$cix] );
$remove = true;
break;
}
$cix2dC++;
}
elseif( ! $argType &&
( $arg1 == $component->getProperty( util::$UID ))) {
unset( $this->components[$cix] );
$remove = true;
break;
}
} // end foreach( $this->components as $cix => $component )
if( $remove ) {
$this->components = array_filter( $this->components );
return true;
}
return false;
}
/**
* Add calendar component as subcomponent to container for subcomponents
*
* @author Kjell-Inge Gustafsson, kigkonsult
* @since 2.23.2 - 2015-03-18
* @param object $component calendarComponent
* @param mixed $arg1 ordno/component type/ component uid
* @param mixed $arg2 ordno if arg1 = component type
* @return bool
*/
public function setComponent( $component, $arg1=false, $arg2=false ) {
static $INDEX = 'INDEX';
if( ! isset( $this->components ))
return false;
$component->setConfig( $this->getConfig(), false, true );
if( ! in_array( strtolower( $component->objName ), util::$LCSUBCOMPS )) {
/* make sure dtstamp and uid is set */
$component->getProperty( util::$DTSTAMP );
$component->getProperty( util::$UID );
}
if( ! $arg1 ) { // plain insert, last in chain
$this->components[] = clone $component;
return true;
}
$argType = $index = null;
if ( ctype_digit( (string) $arg1 )) { // index insert/replace
$argType = $INDEX;
$index = (int) $arg1 - 1;
}
elseif( in_array( strtolower( $arg1 ), util::$MCOMPS )) {
$argType = strtolower( $arg1 );
$index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
}
// else if arg1 is set, arg1 must be an UID
$cix2sC = 0;
foreach( $this->components as $cix => $component2 ) {
if( empty( $component2 ))
continue;
if(( $INDEX == $argType ) && ( $index == $cix )) { // index insert/replace
$this->components[$cix] = clone $component;
return true;
}
elseif( $argType == $component2->objName ) { // component Type index insert/replace
if( $index == $cix2sC ) {
$this->components[$cix] = clone $component;
return true;
}
$cix2sC++;
}
elseif( ! $argType && ( $arg1 == $component2->getProperty( util::$UID ))) {
$this->components[$cix] = clone $component; // UID insert/replace
return true;
}
}
/* arg1=index and not found.. . insert at index .. .*/
if( $INDEX == $argType ) {
$this->components[$index] = clone $component;
ksort( $this->components, SORT_NUMERIC );
}
else /* not found.. . insert last in chain anyway .. .*/
$this->components[] = clone $component;
return true;
}
}