Browse Source

ical stuff (parse/build) added

euromark 14 years ago
parent
commit
396920a2be

+ 147 - 0
Lib/IcalLib.php

@@ -0,0 +1,147 @@
+<?php
+
+//$path = dirname(__FILE__);
+//require_once($path . DS . 'Vendor' . DS . 'ical'.DS.'ical.php');
+App::import('Vendor', 'Tools.ical', array('file'=>'ical/ical.php'));
+App::import('Vendor', 'Tools.icalobject', array('file'=>'ical/i_cal_object.php'));
+
+App::uses('View', 'View');
+App::uses('Time', 'View/Helper');
+
+/**
+ * A wrapper for the Ical/Ics calendar lib
+ * @see http://www.dereuromark.de/2011/11/21/serving-views-as-files-in-cake2 for details
+ * 
+ * @author Mark Scherer
+ * @license MIT
+ * @cakephp 2.0 
+ * 2010-09-14 ms
+ */
+class IcalLib {
+
+	public $Ical;
+	public $Time;
+
+	public function __construct() {
+		$this->ICalObject = new ICalObject();
+		$this->Time = new TimeHelper(new View(null));
+	}
+
+/** BUILDING **/
+
+	/**
+	 * 
+	 * some automagic
+	 * - array urls are transformed in (full) absolute urls
+	 * - id => uid with @host
+	 * - start/end/timestamp to atom
+	 * - class to upper
+	 * @return string $icalContent (single vevent)
+	 * 2011-10-10 ms
+	 */
+	public function build($data, $addStartAndEnd = true) {
+		if (isset($data['start'])) {
+			$data['dtstart'] = $this->Time->toAtom($data['start']);
+			unset($data['start']);
+		}
+		if (isset($data['end'])) {
+			$data['dtend'] = $this->Time->toAtom($data['end']);
+			unset($data['end']);
+		}
+		if (isset($data['timestamp'])) {
+			$data['dtstamp'] = $this->Time->toAtom($data['timestamp']);
+			unset($data['timestamp']);
+		}
+		if (isset($data['id'])) {
+			$data['uid'] = $data['id'].'@'.env('HTTP_HOST');
+			unset($data['id']);
+		}
+		if (isset($data['class'])) {
+			$data['class'] = strtoupper($data['class']);
+		}
+		if (isset($data['url']) && is_array($data['url'])) {
+			$data['url'] = Router::url($data['url'], true);
+		}
+		$res = $this->ICalObject->create($data);
+		if ($addStartAndEnd) {
+			$res = 'BEGIN:VEVENT'.PHP_EOL.trim($res).PHP_EOL.'END:VEVENT';
+		}
+		return $res;
+	}
+
+	public function createStart($data = array()) {
+		$defaults = array(
+			'version' => '2.0',
+			'prodid' => '-//'.env('HTTP_HOST'),
+			'method' => 'PUBLISH',
+		);
+		$data = am($defaults, $data);
+		
+		$res = array();
+		$res[] = 'BEGIN:VCALENDAR';
+		foreach ($data as $key => $val) {
+			$res[] = strtoupper($key).':'.$val;
+		}
+		return implode(PHP_EOL, $res);
+	}
+	
+	public function createEnd() {
+		return 'END:VCALENDAR';
+	}
+
+
+/** PARSING **/
+
+	public function parse($url) {
+		if (!file_exists($url) || !($res = file_get_contents($url))) {
+			return false;
+		}
+		$this->Ical = new ical($url);
+		if ($this->Ical->parse()) {
+			return true;
+		}
+		return false;
+	}
+	
+	/**
+	 * @return array
+	 * 2010-09-14 ms
+	 */
+	public function getCalenderInfos() {
+		return $this->Ical->get_calender_data();
+	}
+
+	/**
+	 * key => value with key as unixTimeStamp and value as summary
+	 * @return array
+	 * 2010-09-14 ms
+	 */
+	public function getEventsAsList() {
+		$res = array();
+		$events = $this->getEvents();
+		foreach ($events as $event) {
+			$res[$event['DTSTART']['unixtime']] = $event['SUMMARY'];
+		}
+		return $res;
+	}
+	
+	/**
+	 * @return array $events or false on failure
+	 * 2010-09-14 ms
+	 */
+	public function getEvents() {
+		return $this->Ical->get_sort_event_list();
+	}
+	
+	/**
+	 * @return array $todos or false on failure
+	 * 2010-09-14 ms
+	 */
+	public function getTodos() {
+		return $this->Ical->get_todo_list();
+	}
+
+
+}
+
+

+ 70 - 0
Test/Case/Helper/IcalHelperTest.php

@@ -0,0 +1,70 @@
+<?php
+
+App::import('Helper', 'Tools.Ical');
+App::uses('MyCakeTestCase', 'Tools.Lib');
+App::uses('String', 'Utility');
+App::uses('View', 'View');
+
+/**
+ * A wrapper for the Ical/Ics calendar lib
+ * @uses Tools.IcalLib
+ * @see http://www.dereuromark.de/2011/11/21/serving-views-as-files-in-cake2 for details
+ * 
+ * @author Mark Scherer
+ * @license MIT
+ * @cakephp 2.0 
+ * 2010-09-14 ms
+ */
+class IcalHelperTest extends MyCakeTestCase {
+	
+	public $Ical;
+	
+	public function setUp() {
+		$this->Ical = new IcalHelper(new View(null));
+	}
+	
+	public function tearDown() {
+		
+	}
+	
+	public function testObject() {
+		$this->assertTrue(is_a($this->Ical, 'IcalHelper'));
+	}
+		
+	public function testAdd() {
+		$data = array(
+			'url' => 'http://www.spiegel.de',
+			'start' => '2010-10-09 22:23:34',
+			'end' => '2010-10-09 23:23:34',
+			'summary' => 'xyz',
+			'description' => 'xyz hjdhfj dhfäöüp e',
+			'organizer' => 'CEO',
+			'class' => 'public',
+		);
+		$res = $this->Ical->add($data);
+		$this->assertTrue($res);
+		
+	}
+	
+	
+	public function testGenerate() {
+		$data = array(
+			'url' => 'http://www.spiegel.de',
+			'start' => '2010-10-09 22:23:34',
+			'end' => '2010-10-09 23:23:34',
+			'summary' => 'xyz',
+			'description' => 'xyz hjdhfj dhfäöüp e',
+			'organizer' => 'CEO',
+			'class' => 'public',
+			'timestamp' => '2010-10-08 22:23:34',
+			'id' => String::uuid(),
+			'location' => 'München'
+		);
+		$this->Ical->add($data);
+		$this->Ical->add($data);
+		$res = $this->Ical->generate();
+		pr($res);
+		ob_flush();
+	}
+	
+}

+ 76 - 0
Test/Case/Lib/IcalLibTest.php

@@ -0,0 +1,76 @@
+<?php
+
+App::uses('IcalLib', 'Tools.Lib');
+
+class IcalLibTest extends CakeTestCase {
+
+	public $file;
+	
+	public function setUp() {
+		$this->Ical = new IcalLib();
+		
+		$this->file = CakePlugin::path('Tools').'Test'.DS.'test_files'.DS.'ics'.DS.'basic.ics';
+	}
+	
+
+	public function tearDown() {
+		unset($this->Ical);
+	}
+	
+		
+	public function testObject() {
+		$this->assertTrue(is_object($this->Ical));
+		
+	}
+
+
+/** building **/
+	// see IcalHelper() for this
+
+
+/** parsing **/
+
+	public function testParse() {
+		
+		$is = $this->Ical->parse($this->file);
+		$this->assertTrue(!empty($is));
+	}
+
+	public function testCalenderInfos() {
+		
+		$is = $this->Ical->parse($this->file);
+		$is = $this->Ical->getCalenderInfos();
+		pr($is);
+		$this->assertTrue(!empty($is));
+	}		
+
+	public function testEvents() {
+		
+		$is = $this->Ical->parse($this->file);
+		$is = $this->Ical->getEvents();
+		pr($is);
+		$this->assertTrue(!empty($is));
+	}
+	
+	public function testTodos() {
+		
+		$is = $this->Ical->parse($this->file);
+		$is = $this->Ical->getTodos();
+		echo returns($is).BR;
+		$this->assertEmpty($is);
+	}	
+
+
+	public function testEventsAsList() {
+		
+		$is = $this->Ical->parse($this->file);
+		$is = $this->Ical->getEventsAsList();
+		foreach ($is as $i => $val) {
+			echo date(FORMAT_NICE_YMD, $i).': '.h($val).BR;
+		}
+		$this->assertTrue(!empty($is));
+		ob_flush();
+	}
+
+}
+

+ 135 - 0
Test/Fixture/CodeKeyFixture.php

@@ -0,0 +1,135 @@
+<?php
+/* CodeKey Fixture generated on: 2011-11-20 21:58:47 : 1321822727 */
+
+/**
+ * CodeKeyFixture
+ *
+ */
+class CodeKeyFixture extends CakeTestFixture {
+
+/**
+ * Fields
+ *
+ * @var array
+ */
+	public $fields = array(
+		'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary', 'collate' => NULL, 'comment' => ''),
+		'user_id' => array('type' => 'string', 'null' => false, 'length' => 36, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'),
+		'type' => array('type' => 'string', 'null' => false, 'length' => 10, 'collate' => 'utf8_unicode_ci', 'comment' => 'e.g.:activate,reactivate', 'charset' => 'utf8'),
+		'key' => array('type' => 'string', 'null' => false, 'length' => 60, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'),
+		'content' => array('type' => 'string', 'null' => false, 'collate' => 'utf8_unicode_ci', 'comment' => 'can transport some information', 'charset' => 'utf8'),
+		'used' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'collate' => NULL, 'comment' => ''),
+		'created' => array('type' => 'datetime', 'null' => false, 'default' => NULL, 'collate' => NULL, 'comment' => ''),
+		'modified' => array('type' => 'datetime', 'null' => false, 'default' => NULL, 'collate' => NULL, 'comment' => ''),
+		'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
+		'tableParameters' => array()
+	);
+
+/**
+ * Records
+ *
+ * @var array
+ */
+	public $records = array(
+		array(
+			'id' => '77',
+			'user_id' => '1',
+			'type' => 'qlogin',
+			'key' => '7k8qdcizigtudvxn2v9zep',
+			'content' => 'i:1;',
+			'used' => 0,
+			'created' => '2011-08-02 18:00:41',
+			'modified' => '2011-08-02 18:00:41'
+		),
+		array(
+			'id' => '78',
+			'user_id' => '2',
+			'type' => 'qlogin',
+			'key' => '23e32tpkcmdn8x9j8n0n00',
+			'content' => 'i:2;',
+			'used' => 0,
+			'created' => '2011-08-02 18:00:41',
+			'modified' => '2011-08-02 18:00:41'
+		),
+		array(
+			'id' => '79',
+			'user_id' => '1',
+			'type' => 'qlogin',
+			'key' => '3mpzed7eoewsjvyvg4vy35',
+			'content' => 'a:3:{s:10:"controller";s:4:"test";s:6:"action";s:3:"foo";i:0;s:3:"bar";}',
+			'used' => 1,
+			'created' => '2011-08-02 18:00:41',
+			'modified' => '2011-08-02 18:00:41'
+		),
+		array(
+			'id' => '80',
+			'user_id' => '2',
+			'type' => 'qlogin',
+			'key' => 'af8ww4y7jxzq5n6npmjpxx',
+			'content' => 's:13:"/test/foo/bar";',
+			'used' => 1,
+			'created' => '2011-08-02 18:00:41',
+			'modified' => '2011-08-02 18:00:41'
+		),
+		array(
+			'id' => '81',
+			'user_id' => '1',
+			'type' => 'qlogin',
+			'key' => '2s7i3zjw0rn009j4no552b',
+			'content' => 'i:1;',
+			'used' => 0,
+			'created' => '2011-08-02 18:01:16',
+			'modified' => '2011-08-02 18:01:16'
+		),
+		array(
+			'id' => '82',
+			'user_id' => '2',
+			'type' => 'qlogin',
+			'key' => 'tro596dig63cay0ps09vre',
+			'content' => 'i:2;',
+			'used' => 0,
+			'created' => '2011-08-02 18:01:16',
+			'modified' => '2011-08-02 18:01:16'
+		),
+		array(
+			'id' => '83',
+			'user_id' => '1',
+			'type' => 'qlogin',
+			'key' => 'penfangwc40x550wwvgfmu',
+			'content' => 'a:3:{s:10:"controller";s:4:"test";s:6:"action";s:3:"foo";i:0;s:3:"bar";}',
+			'used' => 1,
+			'created' => '2011-08-02 18:01:16',
+			'modified' => '2011-08-02 18:01:16'
+		),
+		array(
+			'id' => '84',
+			'user_id' => '2',
+			'type' => 'qlogin',
+			'key' => '2y7m5srasm3ozej0izxbhe',
+			'content' => 's:13:"/test/foo/bar";',
+			'used' => 1,
+			'created' => '2011-08-02 18:01:16',
+			'modified' => '2011-08-02 18:01:16'
+		),
+		array(
+			'id' => '85',
+			'user_id' => '1',
+			'type' => 'qlogin',
+			'key' => '5c6dp2w54ynxii2xo3c50m',
+			'content' => 'i:1;',
+			'used' => 0,
+			'created' => '2011-08-02 18:01:54',
+			'modified' => '2011-08-02 18:01:54'
+		),
+		array(
+			'id' => '86',
+			'user_id' => '2',
+			'type' => 'qlogin',
+			'key' => 'fr6a0d4waue2v6hmqeyek5',
+			'content' => 'i:2;',
+			'used' => 0,
+			'created' => '2011-08-02 18:01:54',
+			'modified' => '2011-08-02 18:01:54'
+		),
+	);
+}

+ 344 - 0
Test/test_files/ics/basic.ics

@@ -0,0 +1,344 @@
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:PUBLISH
+X-WR-TIMEZONE:UTC
+X-WR-CALDESC:Deutsche Feiertage
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20101003
+DTEND;VALUE=DATE:20101004
+DTSTAMP:20100912T135114Z
+UID:h@e49f1bd4767fae22857c86d82566096ce34af4f4@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Tag der deutschen Einheit
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20091003
+DTEND;VALUE=DATE:20091004
+DTSTAMP:20100912T135114Z
+UID:h@2a497ffb189275030300f3e10fd82b49f9056a05@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Tag der deutschen Einheit
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20100501
+DTEND;VALUE=DATE:20100502
+DTSTAMP:20100912T135114Z
+UID:h@dfbec0691326573f5aa3377e1037ff6c35c1f29b@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Tag der Arbeit
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20090501
+DTEND;VALUE=DATE:20090502
+DTSTAMP:20100912T135114Z
+UID:h@d9b49b273208d9e307fe147a35da9f590bfefaa9@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Tag der Arbeit
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20091226
+DTEND;VALUE=DATE:20091227
+DTSTAMP:20100912T135114Z
+UID:h@b115fde70367d64546344c551f728a050651f586@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Stefanstag/2. Weihnachtsfeiertag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20101226
+DTEND;VALUE=DATE:20101227
+DTSTAMP:20100912T135114Z
+UID:h@68a48d83d6bdbb538647d7c5b26335f4a6ad0d94@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Stefanstag/2. Weihnachtsfeiertag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20101231
+DTEND;VALUE=DATE:20110101
+DTSTAMP:20100912T135114Z
+UID:h@723b984910b70035691b2e8413c023f0f08f05a6@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Silvester
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20091231
+DTEND;VALUE=DATE:20100101
+DTSTAMP:20100912T135114Z
+UID:h@70f5ecf5402310dd6eb796db36cc60331d1823b1@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Silvester
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20091031
+DTEND;VALUE=DATE:20091101
+DTSTAMP:20100912T135114Z
+UID:h@a5ffb7b4e6ffd80236561e75348893432e5e28fd@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Reformationstag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20101031
+DTEND;VALUE=DATE:20101101
+DTSTAMP:20100912T135114Z
+UID:h@48a2e4789c07bf6c65be623a3c1ac184f74e2396@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Reformationstag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20100101
+DTEND;VALUE=DATE:20100102
+DTSTAMP:20100912T135114Z
+UID:h@5927ed72a35f849dca675f460090199d3299c7d7@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Neujahrstag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20090101
+DTEND;VALUE=DATE:20090102
+DTSTAMP:20100912T135114Z
+UID:h@391711b4e01ea684be9122bd83dd211b00401211@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Neujahrstag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20100815
+DTEND;VALUE=DATE:20100816
+DTSTAMP:20100912T135114Z
+UID:h@bd586b11ad3d16e63de7121cd5f46eb35ca06a7a@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Mariä Himmelfahrt
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20090815
+DTEND;VALUE=DATE:20090816
+DTSTAMP:20100912T135114Z
+UID:h@6e812365098241ac2b4e9478b655bfe6a6eac380@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Mariä Himmelfahrt
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20100106
+DTEND;VALUE=DATE:20100107
+DTSTAMP:20100912T135114Z
+UID:h@d7859ad3c249ed12257de2957651748278d2dedb@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Heilige Drei Könige
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20090106
+DTEND;VALUE=DATE:20090107
+DTSTAMP:20100912T135114Z
+UID:h@207ae331d32806efea06208c6f564910dc8499d5@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Heilige Drei Könige
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20091225
+DTEND;VALUE=DATE:20091226
+DTSTAMP:20100912T135114Z
+UID:h@cf0b85e5f0f8113be8f0ed8a7af0f6f4ba538366@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Erster Weihnachtsfeiertag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20101225
+DTEND;VALUE=DATE:20101226
+DTSTAMP:20100912T135114Z
+UID:h@0bd4464aab22129e87ee76a2f6c729d2c38e6e93@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Erster Weihnachtsfeiertag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20101117
+DTEND;VALUE=DATE:20101118
+DTSTAMP:20100912T135114Z
+UID:h@52d7ed6a3dbe4bd9e7dc6aabc66b9a667f92dc1f@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Buß- und Bettag
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20091101
+DTEND;VALUE=DATE:20091102
+DTSTAMP:20100912T135114Z
+UID:h@6ef86c13f4d595214f8f983874ab177c528f1e9c@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Allerheiligen
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20101101
+DTEND;VALUE=DATE:20101102
+DTSTAMP:20100912T135114Z
+UID:h@3205edfac1551c78ed36808481dae51be28441f1@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Deutsc
+ he Feiertage;X-NUM-GUESTS=0:mailto:de.german#holiday@group.v.calendar.googl
+ e.com
+CLASS:PUBLIC
+CREATED:20100912T122338Z
+LAST-MODIFIED:20100912T122338Z
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Allerheiligen
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR

+ 421 - 0
Vendor/ical/i_cal_object.php

@@ -0,0 +1,421 @@
+<?php
+
+//TODO: make a helper
+class ICalObject {
+
+	var $config = array('database' => '');
+	var $__count = 0;
+	var $__lastInsertId = null;
+	var $__data = null;
+
+	var $__timezones = array('US-Eastern');
+	var $columns = array('primary_key' => array('name' => 'uid'),
+						'string' => array('name' => 'string'),
+						'timestamp' => array('name' => 'timestamp', 'format' => 'Ymd/T/His'),
+						'datetime' => array('name' => 'timestamp', 'format' => 'Ymd/T/His')//,
+	);
+	var $__keyMap = array(
+			'id'			=> 'uid',
+			'end_date'		=> 'dtend',
+			'start_date'	=> 'dtstart',
+			'date_stamp'	=> 'dtstamp'
+	);
+	var $__textMap = array(
+			'"'		=> 'DQUOTE',
+			','		=> '\,',
+			//':'		=> '":"', // Not sure about this one
+			';'		=> '\;',
+			'\\'	=> '\\\\',
+			'\n'	=> '\\n'
+	);
+
+	function listSources() {
+		return array('calendars', 'events', 'todos', 'alarms', 'journals');
+	}
+
+	function create($data) {
+		return $this->__output($data);
+	}
+	
+
+	function read($filename = null) {
+
+		if ($filename != null) {
+			$this->__count = 0;
+			$this->config['database'] = $filename;
+		}
+
+		if ($this->__data == null) {
+			$this->__data = $this->__parse(file_get_contents($this->config['database']));
+		}
+		return $this->__data;
+	}
+
+	function update($data) { }
+
+	function delete($data) { }
+
+	function __output($data) {
+		$out = '';
+		foreach($data as $key => $val) {
+
+			$keyAppend = '';
+			if (in_array($key, array('Calendar', 'Event', 'Timezone', 'Todo', 'Alarm', 'Journals'))) {
+				$key = 'v' . $key;
+			}
+
+			if (is_array($val) && strtolower($key) != $key) {
+				if (countdim($val) > 1) {
+					foreach ($val as $val2) {
+						$out .= strtoupper("begin:{$key}\n");
+						$out .= $this->__output($val2);
+						$out .= strtoupper("end:{$key}\n");
+					}
+				} else {
+					$out .= strtoupper("begin:{$key}\n");
+					$out .= $this->__output($val);
+					$out .= strtoupper("end:{$key}\n");
+				}
+			} else {
+				if (is_array($val)) {
+					$tmp = array();
+					foreach ($val as $key2 => $val2) {
+						if ($key2 !== 0) {
+							$tmp[] = strtoupper($key2) . '=' . $val2;
+						}
+					}
+
+					if (!empty($tmp)) {
+						$keyAppend = ';' . join(';', $tmp);
+					}
+
+					$_val = $val[0];
+				} else {
+					$_val = $val;
+				}
+
+				switch ($key) {
+					case 'end_date':
+					case 'start_date':
+					case 'date_stamp':
+					case 'last_modified':
+					case 'trigger':
+						if (strpos($_val, ' weeks') === false && strpos($_val, ' days') === false && strpos($_val, ' hours') === false && strpos($_val, ' minutes') === false && strpos($_val, ' seconds') === false) {
+							$utc = false;
+							if (strpos($_val, 'UTC')) {
+								$utc = true;
+							}
+							
+							if (strpos($_val, ' ') === false && strpos($_val, ':') === false) {
+								$val = date('Ymd', strtotime($_val));
+							} else {
+								$_val = trim(r('UTC', '', $_val));
+								$tmp = date('Ymd', strtotime($_val)).'T'.date('His', strtotime($_val));
+								if ($utc) {
+									$tmp .= 'Z';
+								}
+								$val = $tmp;
+							}
+						} else {
+							$val = $this->__putDuration($val);
+						}
+					break;
+					case 'duration':
+						$val = $this->__putDuration($val);
+					break;
+					case 'contact':
+					case 'comment':
+					case 'description':
+					case 'location':
+					case 'prodid':
+					case 'resources':
+					case 'status':
+					case 'summary':
+						$s = array_keys($this->__textMap);
+						$r = array_values($this->__textMap);
+						$val = str_replace($s, $r, $val);
+						$val = str_replace('\\\\', '\\', $val);
+					break;
+					default:
+						if ($val === true) {
+							$val = 'TRUE';
+						} elseif ($val === false) {
+							$val = 'FALSE';
+						}
+					break;
+				}
+
+				if (in_array($key, array_keys($this->__keyMap))) {
+					$key = $this->__keyMap[$key];
+				}
+				if (is_array($val) && isset($val[0])) {
+					$val = $val[0];
+				}
+
+				$out .= strtoupper(str_replace('_', '-', $key)) . $keyAppend . ':' . $val . "\n";
+			}
+		}
+		return $out;
+	}
+
+	function __parse(&$lines) {
+
+		if (is_string($lines)) {
+			$lines = str_replace("\r", '', $lines);
+			$lines = explode("\n", $lines);
+
+			$lines1 = ($lines);
+
+			for ($i = 0; $i < count($lines); $i++) {
+				if (substr($lines[$i], 0, 1) == ' ') {
+					$lines[$i - 1] .= substr($lines[$i], 1);
+					array_splice($lines, $i, 1);
+				} elseif ($lines[$i] == '') {
+					array_splice($lines, $i, 1);
+				}
+			}
+		}
+
+		$data = array();
+		for ($i = $this->__count; $i < count($lines); $i++) {
+
+			$idx = strpos($lines[$i], ':');
+			$key = str_replace('-', '_', substr($lines[$i], 0, $idx));
+			$value = substr($lines[$i], $idx + 1);
+
+			if (strtolower($key) == 'end') {
+				$this->__count = $i++;
+				return $data;
+			} elseif (strtolower($key) == 'begin') {
+				$key = ucwords(strtolower($value));
+				if ($key{0} == 'V') {
+					$key = ucwords(substr($key, 1));
+				}
+				
+				$this->__count = ++$i;
+				$value = $this->__parse($lines);
+				$i = $this->__count;
+			} else {
+				if (strpos($key, ';')) {
+					$key = explode(';', $key);
+					$props = $key;
+					$key = $key[0];
+					array_shift($props);
+	
+					$value = array($value);
+					foreach ($props as $v) {
+						$tmp = explode('=', $v);
+						if (isset($tmp[1])) {
+							$value[strtolower($tmp[0])] = $tmp[1];
+						}
+					}
+				}
+				$key = strtolower($key);
+			}
+
+			if (in_array($key, $this->__keyMap)) {
+				$reverse = array_combine(array_values($this->__keyMap), array_keys($this->__keyMap));
+				$key = $reverse[$key];
+			}
+
+			// Format the data types
+			switch ($key) {
+				case 'end_date':
+				case 'start_date':
+				case 'date_stamp':
+				case 'last_modified':
+				case 'trigger':
+
+					if (is_array($value)) {
+						$value[0] = $this->__timestamp($value[0]);
+					} elseif (strpos(strtolower($value), '-p') !== false || strpos(strtolower($value), 'p') !== false) {
+						$value = $this->__duration($value);
+					} else {
+						$value = $this->__timestamp($value);
+					}
+				break;
+				case 'duration':
+					$value = $this->__duration($value);
+				break;
+				case 'contact':
+				case 'comment':
+				case 'description':
+				case 'location':
+				case 'prodid':
+				case 'resources':
+				case 'status':
+				case 'summary':
+					$r = array_keys($this->__textMap);
+					$s = array_values($this->__textMap);
+					$value = str_replace($s, $r, $value);
+				break;
+				default:
+					if ($value == 'TRUE') {
+						$value = true;
+					} elseif ($value == 'FALSE') {
+						$value = false;
+					}
+				break;
+			}
+
+			if (isset($data[$key])) {
+				if (!isset($data[$key][0])) {
+					$data[$key] = array($data[$key]);
+					$data[$key][] = $value;
+				} elseif (isset($data[$key][0]) && is_array($data[$key])) {
+					$data[$key][] = $value;
+				}
+			} else {
+				$data[$key] = $value;
+			}
+		}
+
+		return $data;
+	}
+
+	// Event UID generator
+	function __insertID() {
+		$chunk = array();
+		$hash = strtoupper(md5(intval(str_replace('.', '', env('SERVER_ADDR'))).''.intval(rand() * 1000).time()));
+		$chunk[] = substr($hash, 0, 8);
+		$chunk[] = substr($hash, 8, 4);
+		$chunk[] = substr($hash, 12, 4);
+		$chunk[] = substr($hash, 16, 4);
+		$chunk[] = substr($hash, 20);
+		$this->__lastInsertId = join('-', $chunk);
+		return $this->__lastInsertId;
+	}
+
+	function lastInsertId() {
+		return $this->__lastInsertId;
+	}
+
+	function __timestamp($time) {
+		if (strpos(strtolower($time), 'p') === 0 || strpos(strtolower($time), 'p') === 1) {
+			return $this->__duration($time);
+		}
+		$utc = false;
+		if (strpos(strtolower($time), 'z')) {
+			$utc = true;
+		}
+
+		if (strpos(strtolower($time), 't') === false) {
+			return date('Y-m-d', strtotime($time));
+		}
+		$time = explode('t', str_replace('z', '', strtolower($time)));
+		$time[1] = substr($time[1], 0, 2).':'.substr($time[1], 2, 2).':'.substr($time[1], 4, 2);
+		return date('Y-m-d', strtotime($time[0])).' '.$time[1] . ($utc ? ' UTC' : '');
+	}
+
+	function __putDuration($time, $date = null) {
+
+		$negative = false;
+		if (is_string($time)) {
+			if (strpos($time, '-') === 0) {
+				$time = substr($time, 1);
+				$negative = true;
+			}
+			$time = strtotime('+' . $time) - strtotime('now');;
+		}
+
+		if ($time < 0) {
+			$time = abs($time);
+			$negative = true;
+		}
+
+		$out = 'P';
+		$t = false;
+		$offset = array('W' => 604800, 'D' => 86400, 'H' => 3600, 'M' => 60, 'S' => 1);
+
+		if ($date != null) {
+			$time = strtotime($date) - strtotime($time);
+		}
+
+		foreach ($offset as $key => $val) {
+			$tmp = 0;
+			if ($time >= $val) {
+				$tmp = $time / $val;
+			}
+			
+			if ($tmp >= 1) {
+				if (in_array($key, array('H', 'M', 'S')) && $t == false) {
+					$t = true;
+					$out .= 'T';
+				}
+
+				$out .= $tmp.$key;
+				$time -= $tmp * $val;
+			}
+		}
+		return ($negative ? '-' : '') . $out;
+	}
+
+	function __duration($dur) {
+
+		$tmp = '';
+		$out = '';
+
+		for ($i = 0; $i < strlen($dur); $i++) {
+			switch(strtolower($dur{$i})) {
+				case 't':
+				case 'p':
+					// do nothing
+				break;
+				case 'w':
+					$out .= $tmp . ' week' . (intval($tmp) != 1 ? 's' : '') . ' ';
+					$tmp = '';
+				break;
+				case 'd':
+					$out .= $tmp . ' day' . (intval($tmp) != 1 ? 's' : '') . ' ';
+					$tmp = '';
+				break;
+				case 'h':
+					$out .= $tmp . ' hour' . (intval($tmp) != 1 ? 's' : '') . ' ';
+					$tmp = '';
+				break;
+				case 'm':
+					$out .= $tmp . ' minute' . (intval($tmp) != 1 ? 's' : '') . ' ';
+					$tmp = '';
+				break;
+				case 's':
+					$out .= $tmp . ' second' . (intval($tmp) != 1 ? 's' : '') . ' ';
+					$tmp = '';
+				break;
+				default:
+					$tmp .= $dur{$i};
+				break;
+			}
+		}
+		return trim($out);
+	}
+
+	function debug_compare($lines1) {
+
+		$data = $this->__parse($lines1);
+		pr($data);
+
+		$diff = 0;
+		$lines2 = explode("\n", $this->__output($data));
+		pr($lines2);
+		e('<table border=1>');
+
+		foreach ($lines1 as $i => $val) {
+
+			e('<tr><td>');
+			pr($i . ' : ' . $val);
+			e('</td><td>');
+
+			if ($lines2[$i] != $val) {
+				pr($lines2[$i]);
+				$diff++;
+			}
+			e('</td></tr>');
+		}
+		e('</table>');
+		pr('Diffs : '.$diff);
+
+		die();
+	}
+}
+
+

+ 364 - 0
Vendor/ical/ical.php

@@ -0,0 +1,364 @@
+<?php
+/*
+	Copyright (c) 2010, Roman Ožana
+
+	Permission is hereby granted, free of charge, to any person
+	obtaining a copy of this software and associated documentation
+	files (the "Software"), to deal in the Software without
+	restriction, including without limitation the rights to use,
+	copy, modify, merge, publish, distribute, sublicense, and/or sell
+	copies of the Software, and to permit persons to whom the
+	Software is furnished to do so, subject to the following
+	conditions:
+
+	The above copyright notice and this permission notice shall be
+	included in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+	OTHER DEALINGS IN THE SOFTWARE.
+ */
+/**
+ * This class Parse iCal standard. Is prepare to iCal feature version. Now is testing with apple iCal standard 2.0.
+ *
+ * @name iCal parser
+ * @copyright Roman Ožana, 2011
+ * @author Roman Ožana 2006-2011
+
+ * @link www.nabito.net
+ * @link www.omdesign.cz
+ * @version 2.0
+ * @license MIT
+ *
+ * <code>
+ * 	$ical = new ical('./calendar.ics');
+ * 	$ical->parse();
+ *  echo '<pre>'.print_r($ical->get_all_data(), true).'</pre>';
+ * </code>
+ *
+ */
+
+//namespace Helpers\Calendar;
+
+class ical
+{
+
+	/** @var string content of file */
+	private $plain_content = null;
+	/** @var array save iCalendar parse data */
+	private $cal = array ();
+	/** @var string Help variable save last key (multiline string) */
+	private $last_key = '';
+	/** @var array buffer */
+	private $buffer = array ();
+	/** @var string nesting or open tag */
+	private $nesting = 'VCALENDAR';
+
+
+	/**
+	 * Constructr iCal parser object
+	 * @param string $filename
+	 */
+	public function __construct($filename = null)
+	{
+	if (!is_null($filename)) $this->read_file($filename);
+	}
+
+
+	/**
+	 * Read iCal file
+	 * @param string $filename
+	 */
+	public function read_file($filename)
+	{
+	// FIXME load file content and replace wrong way formated lines
+	$this->plain_content = preg_replace("/[\r\n]{1,} ([:;])/", "\\1", file_get_contents($filename));
+
+	// because Mozilla Calendar save values wrong, like this -->
+	#SUMMARY
+	# :Text of sumary
+	// good way is, for example in SunnyBird. SunnyBird save iCal like this example -->
+	#SUMMARY:Text of sumary
+	}
+
+
+	/**
+	 * Prekladac kalendare
+	 *
+	 * @param string|url $filename
+	 * @return unknown
+	 */
+	public function parse()
+	{
+	$this->plain_content = preg_split("/[\n]/", $this->plain_content); // split by lines
+	// is this text vcalendar standart text ? on line 1 is BEGIN:VCALENDAR
+	if (strpos($this->plain_content[0], 'BEGIN:VCALENDAR') === false)
+	{
+		throw new Exception('Not a VCALENDAR file');
+	}
+
+	foreach ($this->plain_content as $text)
+	{
+		$text = trim($text); // trim one line
+		if (!empty($text))
+		{
+		// get Key and Value VCALENDAR:Begin --> Key = VCALENDAR, Value = begin
+		list($key, $value) = $this->retun_key_value($text);
+
+
+		if ($key === false)
+		{
+			$key = $this->last_key; // in case key is empty
+		}
+
+		// process simple dates
+		if (($key == "DTSTAMP") || ($key == "LAST-MODIFIED") || ($key == "CREATED"))
+		{
+			$value = $this->ical_date_to_unix($value);
+		}
+
+		// process RRULE
+		if ($key == "RRULE")
+		{
+			$value = $this->ical_rrule($value);
+		}
+
+		//
+		// process ical date values like
+		//
+		// [DTSTART;VALUE=DATE] => 20121224
+		// [DTEND;VALUE=DATE] => 20121225
+		if (strpos($key, 'DTSTART') !== false || strpos($key, 'DTEND') !== false)
+		{
+			list($key, $value) = $this->ical_dt_date($key, $value);
+		}
+
+		switch ($text) // search special string
+		{
+			case "BEGIN:VCALENDAR":
+			case "BEGIN:DAYLIGHT":
+			case "BEGIN:VTIMEZONE":
+			case "BEGIN:STANDARD":
+			case "BEGIN:VTODO":
+			case "BEGIN:VEVENT":
+			$this->nesting = substr($text, 6);
+			$this->buffer[$this->nesting] = array (); // null buffer
+			break;
+
+
+			case "END:VCALENDAR":
+			$this->cal['VCALENDAR'] = $this->buffer['VCALENDAR']; // save buffer
+			break;
+
+			case "END:DAYLIGHT":
+			case "END:VTIMEZONE":
+			case "END:STANDARD":
+			case "END:VEVENT":
+			case "END:VTODO":
+			$this->cal[substr($text, 4)][] = $this->buffer[$this->nesting]; // save buffer
+			break;
+
+			default: // no special string
+			$this->buffer[$this->nesting][$key] = $value;
+			$this->last_key = $key; // save last key
+			break;
+		}
+		}
+	}
+	return $this->cal;
+	}
+
+
+	/* --------------------------------------------------------------------------
+	 * Private parser functions
+	 * -------------------------------------------------------------------------- */
+
+
+	/**
+	 * Parse text "XXXX:value text some with : " and return array($key = "XXXX", $value="value");
+	 *
+	 * @param unknown_type $text
+	 * @return unknown
+	 */
+	private function retun_key_value($text)
+	{
+	preg_match("/([^:]+)[:]([\w\W]+)/", $text, $matches);
+
+	if (empty($matches))
+	{
+		return array (false, $text);
+	}
+	else
+	{
+		$matches = array_splice($matches, 1, 2);
+		return $matches;
+	}
+	}
+
+
+	/**
+	 * Parse RRULE  return array
+	 *
+	 * @param unknown_type $value
+	 * @return unknown
+	 */
+	private function ical_rrule($value)
+	{
+	$rrule = explode(';', $value);
+	foreach ($rrule as $line)
+	{
+		$rcontent = explode('=', $line);
+		$result[$rcontent[0]] = $rcontent[1];
+	}
+	return $result;
+	}
+
+
+	/**
+	 * Return Unix time from ical date time fomrat (YYYYMMDD[T]HHMMSS[Z] or YYYYMMDD[T]HHMMSS)
+	 *
+	 * @param unknown_type $ical_date
+	 * @return unknown
+	 */
+	private function ical_date_to_unix($ical_date)
+	{
+	$ical_date = preg_replace(array ('/T/', '/Z/'), '', $ical_date); // remove T and Z from strig
+
+	if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})([0-9]{0,2})/', $ical_date, $date))
+	{
+
+		if ($date[1] <= 1970)
+		{
+		$date[1] = 1971; // FIXME UNIX timestamps can't deal with pre 1970 dates
+		}
+
+		return mktime((int) $date[4], (int) $date[5], (int) $date[6], (int) $date[2], (int) $date[3], (int) $date[1]);
+	}
+	else
+	{
+		return null;
+	}
+	}
+
+
+	/**
+	 * Return unix date from iCal date format
+	 *
+	 * @param string $key
+	 * @param string $value
+	 * @return array
+	 */
+	private function ical_dt_date($key, $value)
+	{
+	$value = $this->ical_date_to_unix($value);
+
+	// zjisteni TZID
+	$temp = explode(";", $key);
+
+	if (empty($temp[1])) // neni TZID
+	{
+			# 2011-06-02 ms fix
+		$value = str_replace('T', '', $value);
+		return array ($key, $value);
+	}
+	// pridani $value a $tzid do pole
+	$key = $temp[0];
+	$temp = explode("=", $temp[1]);
+	$return_value[$temp[0]] = $temp[1];
+	$return_value['unixtime'] = $value;
+
+	return array ($key, $return_value);
+	}
+
+
+	/* --------------------------------------------------------------------------
+	 * List of public getters
+	 * -------------------------------------------------------------------------- */
+
+
+	/**
+	 * Return sorted eventlist as array or false if calenar is empty
+	 *
+	 * @return array|boolean
+	 */
+	public function get_sort_event_list()
+	{
+	$temp = $this->get_event_list();
+	if (!empty($temp))
+	{
+		usort($temp, array (&$this, "ical_dtstart_compare"));
+		return $temp;
+	}
+	else
+	{
+		return false;
+	}
+	}
+
+
+	/**
+	 * Compare two unix timestamp
+	 *
+	 * @param array $a
+	 * @param array $b
+	 * @return integer
+	 */
+	private function ical_dtstart_compare($a, $b)
+	{
+	return strnatcasecmp($a['DTSTART']['unixtime'], $b['DTSTART']['unixtime']);
+	}
+
+
+	/**
+	 * Return eventlist array (not sort eventlist array)
+	 *
+	 * @return array
+	 */
+	public function get_event_list()
+	{
+	return $this->cal['VEVENT'];
+	}
+
+
+	/**
+	 * Return todo arry (not sort todo array)
+	 *
+	 * @return array
+	 */
+	public function get_todo_list()
+	{
+	if (empty($this->cal['VTODO'])) {
+		return array();
+	}
+	return $this->cal['VTODO'];
+	}
+
+
+	/**
+	 * Return base calendar data
+	 *
+	 * @return array
+	 */
+	public function get_calender_data()
+	{
+	return $this->cal['VCALENDAR'];
+	}
+
+
+	/**
+	 * Return array with all data
+	 *
+	 * @return array
+	 */
+	public function get_all_data()
+	{
+	return $this->cal;
+	}
+
+
+}