calendar choosing, timezone fix, import all

this is version 1.0 =)
This commit is contained in:
Christoph Haas 2012-11-17 11:42:48 +00:00
parent af3fcfb457
commit e64d8415bc
4 changed files with 466 additions and 442 deletions

View File

@ -34,6 +34,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
this.initForm() this.initForm()
], ],
buttons: [ buttons: [
this.createSubmitAllButton(),
this.createSubmitButton(), this.createSubmitButton(),
this.createCancelButton() this.createCancelButton()
] ]
@ -81,7 +82,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
var parsedData = new Array(eventdata.events.length); var parsedData = new Array(eventdata.events.length);
for(var i=0; i < eventdata.events.length; i++) { for(var i=0; i < eventdata.events.length; i++) {
parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], parseInt(eventdata.events[i]["DTSTART"]), parseInt(eventdata.events[i]["DTEND"]), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"]); parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], new Date(parseInt(eventdata.events[i]["DTSTART"])), new Date(parseInt(eventdata.events[i]["DTEND"])), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"]);
} }
} }
@ -126,16 +127,16 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
createSelectBox: function() { createSelectBox: function() {
ctx = container.getContextByName('calendar'); ctx = container.getContextByName('calendar');
model = ctx.getModel(); model = ctx.getModel();
defaultFolder = model.getDefaultFolder(); defaultFolder = model.getDefaultFolder(); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
subFolders = defaultFolder.getChildren(); subFolders = defaultFolder.getChildren();
var myStore = new Ext.data.ArrayStore({ var myStore = new Ext.data.ArrayStore({
fields: ['calendar_id', 'calendar_displayname'], fields: ['calendar_id', 'calendar_displayname'],
idIndex: 0 // id for each record will be the first element idIndex: 0 // id for each record will be the first element
}); });
/* Calendar Record holds the name and real name of the calender */ /* Calendar Record holds the name and real name of the calender */
var CalendarRecord = Ext.data.Record.create([ var CalendarRecord = Ext.data.Record.create([
{name: 'realname', type: "string"}, {name: 'realname', type: "string"},
{name: 'displayname', type: "string"} {name: 'displayname', type: "string"}
@ -144,85 +145,103 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
/* Store the default folder */ /* Store the default folder */
var myNewRecord = new CalendarRecord({ var myNewRecord = new CalendarRecord({
realname: defaultFolder.getDefaultFolderKey(), realname: defaultFolder.getDefaultFolderKey(),
displayname: defaultFolder.getDisplayName() displayname: defaultFolder.getDisplayName()
}); });
myStore.add(myNewRecord); myStore.add(myNewRecord);
for(i=0;i<subFolders.length;i++) { for(i=0;i<subFolders.length;i++) {
/* Store all subfolders */ /* Store all subfolders */
myNewRecord = new CalendarRecord({ myNewRecord = new CalendarRecord({
realname: subFolders[i].getDisplayName(), // TODO: get the real path... realname: subFolders[i].getDisplayName(), // TODO: get the real path...
displayname: subFolders[i].getDisplayName() displayname: subFolders[i].getDisplayName()
}); });
myStore.add(myNewRecord); myStore.add(myNewRecord);
} }
/* commit the changes to the store */ /* commit the changes to the store */
myStore.commitChanges(); myStore.commitChanges();
return { return {
xtype: "selectbox", xtype: "selectbox",
editable: false, ref: 'calendarselector',
name: "choosen_calendar", id: 'calendarselector',
width: 100, editable: false,
fieldLabel: "Select a calender", name: "choosen_calendar",
store: myStore, width: 100,
valueField: 'realname', fieldLabel: "Select a calender",
displayField: 'displayname', store: myStore,
labelSeperator: ":", valueField: 'realname',
border: false, displayField: 'displayname',
anchor: "100%", labelSeperator: ":",
scope: this, border: false,
allowBlank: false anchor: "100%",
} scope: this,
allowBlank: false
}
}, },
createUploadField: function() { createUploadField: function() {
return { return {
xtype: "fileuploadfield", xtype: "fileuploadfield",
ref: 'fileuploadfield', ref: 'fileuploadfield',
columnWidth: 1.0, columnWidth: 1.0,
id: 'form-file', id: 'form-file',
name: 'icsdata', name: 'icsdata',
emptyText: 'Select an .ics calendar', emptyText: 'Select an .ics calendar',
border: false, border: false,
anchor: "100%", anchor: "100%",
scope: this, scope: this,
allowBlank: false, allowBlank: false,
listeners: { listeners: {
'fileselected': this.onFileSelected, 'fileselected': this.onFileSelected,
scope: this scope: this
} }
} }
}, },
createSubmitButton: function() { createSubmitButton: function() {
return { return {
xtype: "button", xtype: "button",
ref: "submitButton", ref: "submitButton",
id: "submitButton", id: "submitButton",
disabled: true, disabled: true,
width: 100, width: 100,
border: false, border: false,
text: _("Import"), text: _("Import"),
anchor: "100%", anchor: "100%",
handler: this.importAllEvents, handler: this.importCheckedEvents,
scope: this, scope: this,
allowBlank: false allowBlank: false
} }
},
createSubmitAllButton: function() {
return {
xtype: "button",
ref: "submitAllButton",
id: "submitAllButton",
disabled: true,
width: 100,
border: false,
text: _("Import All"),
anchor: "100%",
handler: this.importAllEvents,
scope: this,
allowBlank: false
}
}, },
createCancelButton: function() { createCancelButton: function() {
return { return {
xtype: "button", xtype: "button",
width: 100, width: 100,
border: false, border: false,
text: _("Cancel"), text: _("Cancel"),
anchor: "100%", anchor: "100%",
handler: this.close, handler: this.close,
scope: this, scope: this,
allowBlank: false allowBlank: false
} }
}, },
/** /**
@ -230,7 +249,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
* in the {@link Ext.ux.form.FileUploadField} and the dialog is closed * in the {@link Ext.ux.form.FileUploadField} and the dialog is closed
* @param {Ext.ux.form.FileUploadField} uploadField being added a file to * @param {Ext.ux.form.FileUploadField} uploadField being added a file to
*/ */
onFileSelected : function(uploadField) { onFileSelected : function(uploadField) {
var form = this.addFormPanel.getForm(); var form = this.addFormPanel.getForm();
if (form.isValid()) { if (form.isValid()) {
@ -238,7 +257,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
waitMsg: 'Uploading and parsing calendar...', waitMsg: 'Uploading and parsing calendar...',
url: 'plugins/calendarimporter/php/upload.php', url: 'plugins/calendarimporter/php/upload.php',
failure: function(file, action) { failure: function(file, action) {
Ext.getCmp('submitButton').disable(); // momstly called... Ext.getCmp('submitButton').disable();
Ext.getCmp('submitAllButton').disable();
Ext.MessageBox.show({ Ext.MessageBox.show({
title : _('Error'), title : _('Error'),
msg : _(action.result.errors[action.result.errors.type]), msg : _(action.result.errors[action.result.errors.type]),
@ -249,6 +269,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
success: function(file, action){ success: function(file, action){
uploadField.reset(); uploadField.reset();
Ext.getCmp('submitButton').enable(); Ext.getCmp('submitButton').enable();
Ext.getCmp('submitAllButton').enable();
this.timezone = action.result.response.calendar["X-WR-TIMEZONE"]; this.timezone = action.result.response.calendar["X-WR-TIMEZONE"];
this.insert(this.items.length,this.createGrid(action.result.response)); this.insert(this.items.length,this.createGrid(action.result.response));
this.doLayout(); this.doLayout();
@ -284,22 +305,94 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPa
return newRecord; return newRecord;
}, },
importAllEvents: function () { importAllEvents: function () {
//receive existing calendar store //receive existing calendar store
var calendarStore = new Zarafa.calendar.AppointmentStore(); var selIndex = this.calendarselector.selectedIndex;
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar'); var calValue = this.calendarselector.value;
//receive Records from grid rows if(selIndex == -1) { // no calendar choosen
var newRecords = this.eventgrid.selModel.getSelections(); Ext.MessageBox.show({
Ext.each(newRecords, function(newRecord) { title : _('Error'),
var record = this.convertToAppointmentRecord(calendarFolder,newRecord.data); msg : _('You have to choose a calendar!'),
console.log(record); icon : Ext.MessageBox.ERROR,
calendarStore.add(record); buttons : Ext.MessageBox.OK
}, this); });
calendarStore.save(); } else {
this.dialog.close();
var calendarStore = new Zarafa.calendar.AppointmentStore();
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
if(calValue != "calendar") {
var subFolders = calendarFolder.getChildren();
for(i=0;i<subFolders.length;i++) {
// loo up right folder
// TODO: improve!!
if(subFolders[i].getDisplayName() == calValue) {
calendarFolder = subFolders[i];
break;
}
}
}
//receive Records from grid rows
this.eventgrid.selModel.selectAll(); // select all entries
var newRecords = this.eventgrid.selModel.getSelections();
Ext.each(newRecords, function(newRecord) {
var record = this.convertToAppointmentRecord(calendarFolder,newRecord.data);
calendarStore.add(record);
}, this);
calendarStore.save();
this.dialog.close();
}
},
importCheckedEvents: function () {
//receive existing calendar store
var selIndex = this.calendarselector.selectedIndex;
var calValue = this.calendarselector.value;
if(selIndex == -1) { // no calendar choosen
Ext.MessageBox.show({
title : _('Error'),
msg : _('You have to choose a calendar!'),
icon : Ext.MessageBox.ERROR,
buttons : Ext.MessageBox.OK
});
} else {
if(this.eventgrid.selModel.getCount() < 1) {
Ext.MessageBox.show({
title : _('Error'),
msg : _('You have to choose at least one event to import!'),
icon : Ext.MessageBox.ERROR,
buttons : Ext.MessageBox.OK
});
} else {
var calendarStore = new Zarafa.calendar.AppointmentStore();
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
if(calValue != "calendar") {
var subFolders = calendarFolder.getChildren();
for(i=0;i<subFolders.length;i++) {
// loo up right folder
// TODO: improve!!
if(subFolders[i].getDisplayName() == calValue) {
calendarFolder = subFolders[i];
break;
}
}
}
//receive Records from grid rows
var newRecords = this.eventgrid.selModel.getSelections();
Ext.each(newRecords, function(newRecord) {
var record = this.convertToAppointmentRecord(calendarFolder,newRecord.data);
calendarStore.add(record);
}, this);
calendarStore.save();
this.dialog.close();
}
}
} }
}); });
Ext.reg('calendarimporter.importpanel', Zarafa.plugins.calendarimporter.dialogs.ImportPanel); Ext.reg('calendarimporter.importpanel', Zarafa.plugins.calendarimporter.dialogs.ImportPanel);

View File

@ -2,7 +2,7 @@
<!DOCTYPE plugin SYSTEM "manifest.dtd"> <!DOCTYPE plugin SYSTEM "manifest.dtd">
<plugin version="2"> <plugin version="2">
<info> <info>
<version>0.1</version> <version>1.0</version>
<name>calendarimporter</name> <name>calendarimporter</name>
<title>ICS Calendar Importer</title> <title>ICS Calendar Importer</title>
<author>Christoph Haas</author> <author>Christoph Haas</author>

View File

@ -5,10 +5,12 @@
* PHP Version 5 * PHP Version 5
* *
* @category Parser * @category Parser
* @author Martin Thoma
* @author Christoph Haas <mail@h44z.net> * @author Christoph Haas <mail@h44z.net>
* @modified 17.11.2012 by Christoph Haas (original at http://code.google.com/p/ics-parser/)
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
* @version SVN: 13 * @version SVN: 16
* @example $ical = new ical('MyCal.ics'); * @example $ical = new ical('calendar.ics');
* print_r( $ical->events() ); * print_r( $ical->events() );
*/ */
@ -18,393 +20,322 @@
* @param {string} filename The name of the file which should be parsed * @param {string} filename The name of the file which should be parsed
* @constructor * @constructor
*/ */
class ICal class ICal {
{ /* How many ToDos are in this ical? */
/* How many ToDos are in this ical? */ public /** @type {int} */ $todo_count = 0;
public /** @type {int} */ $todo_count = 0;
/* How many events are in this ical? */ /* How many events are in this ical? */
public /** @type {int} */ $event_count = 0; public /** @type {int} */ $event_count = 0;
/* The parsed calendar */ /* The parsed calendar */
public /** @type {Array} */ $cal; public /** @type {Array} */ $cal;
/* Error message store... null default */ /* Error message store... null default */
public /** @type {String} */ $errors; public /** @type {String} */ $errors;
/* Which keyword has been added to cal at last? */ /* Which keyword has been added to cal at last? */
private /** @type {string} */ $_lastKeyWord; private /** @type {string} */ $_lastKeyWord;
/** /* The default timezone, used to convert UTC Time */
* Creates the iCal-Object private /** @type {string} */ $default_timezone = "Europe/Vienna";
*
* @param {string} $filename The path to the iCal-file
*
* @return Object The iCal-Object
*/
public function __construct($filename)
{
if (!$filename) {
$this->errors = "No filename specified";
return false;
}
$lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) {
$this->errors = "Not a valid ical file";
return false;
} else {
// TODO: Fix multiline-description problem (see http://tools.ietf.org/html/rfc2445#section-4.8.1.5)
foreach ($lines as $line) {
$line = trim($line);
$add = $this->keyValueFromString($line);
if ($add === false) {
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
continue;
}
list($keyword, $value) = $add;
switch ($line) {
// http://www.kanzaki.com/docs/ical/vtodo.html
case "BEGIN:VTODO":
$this->todo_count++;
$type = "VTODO";
break;
// http://www.kanzaki.com/docs/ical/vevent.html
case "BEGIN:VEVENT":
//echo "vevent gematcht";
$this->event_count++;
$type = "VEVENT";
break;
//all other special strings
case "BEGIN:VCALENDAR":
case "BEGIN:DAYLIGHT":
// http://www.kanzaki.com/docs/ical/vtimezone.html
case "BEGIN:VTIMEZONE":
case "BEGIN:STANDARD":
$type = $value;
break;
case "END:VTODO": // end special text - goto VCALENDAR key
case "END:VEVENT":
case "END:VCALENDAR":
case "END:DAYLIGHT":
case "END:VTIMEZONE":
case "END:STANDARD":
$type = "VCALENDAR";
break;
default:
$this->addCalendarComponentWithKeyAndValue($type,
$keyword,
$value);
break;
}
}
return $this->cal;
}
}
/** /**
* Creates the iCal-Object * Creates the iCal-Object
* *
* @param {string} $filecontent The content of the iCal-file * @param {string} $filename The path to the iCal-file
* *
* @return Object The iCal-Object * @return Object The iCal-Object
*/ */
public function setContent($filecontent) public function __construct($filename) {
{ if (!$filename) {
if (!$filecontent) { $this->errors = "No filename specified";
$this->errors = "No filecontent"; return false;
return false; }
}
$lines = explode("\n", $filecontent); $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) { if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) {
$this->errors = "Not a valid ical file"; $this->errors = "Not a valid ical file";
return false; return false;
} else { } else {
// TODO: Fix multiline-description problem (see http://tools.ietf.org/html/rfc2445#section-4.8.1.5)
foreach ($lines as $line) {
$line = trim($line);
$add = $this->keyValueFromString($line);
if ($add === false) {
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
continue;
}
list($keyword, $value) = $add; foreach ($lines as $line) {
$line = trim($line);
$add = $this->keyValueFromString($line);
if ($add === false) {
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
continue;
}
switch ($line) { list($keyword, $value) = $add;
// http://www.kanzaki.com/docs/ical/vtodo.html
case "BEGIN:VTODO":
$this->todo_count++;
$type = "VTODO";
break;
// http://www.kanzaki.com/docs/ical/vevent.html switch ($line) {
case "BEGIN:VEVENT": // http://www.kanzaki.com/docs/ical/vtodo.html
//echo "vevent gematcht"; case "BEGIN:VTODO":
$this->event_count++; $this->todo_count++;
$type = "VEVENT"; $type = "VTODO";
break; break;
//all other special strings // http://www.kanzaki.com/docs/ical/vevent.html
case "BEGIN:VCALENDAR": case "BEGIN:VEVENT":
case "BEGIN:DAYLIGHT": //echo "vevent gematcht";
// http://www.kanzaki.com/docs/ical/vtimezone.html $this->event_count++;
case "BEGIN:VTIMEZONE": $type = "VEVENT";
case "BEGIN:STANDARD": break;
$type = $value;
break;
case "END:VTODO": // end special text - goto VCALENDAR key
case "END:VEVENT":
case "END:VCALENDAR":
case "END:DAYLIGHT":
case "END:VTIMEZONE":
case "END:STANDARD":
$type = "VCALENDAR";
break;
default:
$this->addCalendarComponentWithKeyAndValue($type,
$keyword,
$value);
break;
}
}
return $this->cal;
}
}
/** //all other special strings
* Add to $this->ical array one value and key. case "BEGIN:VCALENDAR":
* case "BEGIN:DAYLIGHT":
* @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ... // http://www.kanzaki.com/docs/ical/vtimezone.html
* @param {string} $keyword The keyword, for example DTSTART case "BEGIN:VTIMEZONE":
* @param {string} $value The value, for example 20110105T090000Z case "BEGIN:STANDARD":
* $type = $value;
* @return {None} break;
*/ case "END:VTODO": // end special text - goto VCALENDAR key
public function addCalendarComponentWithKeyAndValue($component, case "END:VEVENT":
$keyword, case "END:VCALENDAR":
$value) case "END:DAYLIGHT":
{ case "END:VTIMEZONE":
if ($keyword == false) { case "END:STANDARD":
$keyword = $this->last_keyword; $type = "VCALENDAR";
break;
default:
$this->addCalendarComponentWithKeyAndValue($type, $keyword, $value);
break;
}
}
return $this->cal;
}
}
switch ($component) { /**
case 'VEVENT': * Add to $this->ical array one value and key.
*
* @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ...
* @param {string} $keyword The keyword, for example DTSTART
* @param {string} $value The value, for example 20110105T090000Z
*
* @return {None}
*/
public function addCalendarComponentWithKeyAndValue($component, $keyword, $value) {
if ($keyword == false) {
$keyword = $this->last_keyword;
switch ($component) {
case 'VEVENT':
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
$ts = $this->iCalDateToUnixTimestamp($value); $ts = $this->iCalDateToUnixTimestamp($value);
$value = $ts * 1000; $value = $ts * 1000;
} }
$value = str_replace("\\n", "\n", $value); $value = str_replace("\\n", "\n", $value);
$value = $this->cal[$component][$this->event_count - 1] $value = $this->cal[$component][$this->event_count - 1]
[$keyword].$value; [$keyword].$value;
break; break;
case 'VTODO' : case 'VTODO' :
$value = $this->cal[$component][$this->todo_count - 1] $value = $this->cal[$component][$this->todo_count - 1]
[$keyword].$value; [$keyword].$value;
break; break;
} }
} }
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
$keyword = explode(";", $keyword); $keyword = explode(";", $keyword);
$keyword = $keyword[0]; // remove additional content like VALUE=DATE $keyword = $keyword[0]; // remove additional content like VALUE=DATE
} }
switch ($component) { if (stristr($keyword, "TIMEZONE")) {
case "VTODO": $this->default_timezone = $value; // store the calendertimezone
$this->cal[$component][$this->todo_count - 1][$keyword] = $value; }
//$this->cal[$component][$this->todo_count]['Unix'] = $unixtime;
break; switch ($component) {
case "VEVENT": case "VTODO":
$this->cal[$component][$this->todo_count - 1][$keyword] = $value;
//$this->cal[$component][$this->todo_count]['Unix'] = $unixtime;
break;
case "VEVENT":
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
$ts = $this->iCalDateToUnixTimestamp($value); $ts = $this->iCalDateToUnixTimestamp($value);
$value = $ts * 1000; $value = $ts * 1000;
} }
$value = str_replace("\\n", "\n", $value); $value = str_replace("\\n", "\n", $value);
$this->cal[$component][$this->event_count - 1][$keyword] = $value; $this->cal[$component][$this->event_count - 1][$keyword] = $value;
break; break;
default: default:
$this->cal[$component][$keyword] = $value; $this->cal[$component][$keyword] = $value;
break; break;
} }
$this->last_keyword = $keyword; $this->last_keyword = $keyword;
} }
/**
* Get a key-value pair of a string.
*
* @param {string} $text which is like "VCALENDAR:Begin" or "LOCATION:"
*
* @return {array} array("VCALENDAR", "Begin")
*/
public function keyValueFromString($text)
{
preg_match("/(^[^a-z:]+)[:]([\w\W]*)/", $text, $matches);
error_log("Matching: " . count($matches) . " " . $text);
if (count($matches) == 0) {
return false;
}
$matches = array_splice($matches, 1, 2);
return $matches;
}
/**
* Return Unix timestamp from ical date time format
*
* @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or
* YYYYMMDD[T]HHMMSS
*
* @return {int}
*/
public function iCalDateToUnixTimestamp($icalDate)
{
$icalDate = str_replace('T', '', $icalDate);
$icalDate = str_replace('Z', '', $icalDate);
$pattern = '/([0-9]{4})'; // 1: YYYY
$pattern .= '([0-9]{2})'; // 2: MM
$pattern .= '([0-9]{2})'; // 3: DD
$pattern .= '([0-9]{0,2})'; // 4: HH
$pattern .= '([0-9]{0,2})'; // 5: MM
$pattern .= '([0-9]{0,2})/'; // 6: SS
preg_match($pattern, $icalDate, $date);
// Unix timestamp can't represent dates before 1970
if ($date[1] <= 1970) {
return false;
}
// Unix timestamps after 03:14:07 UTC 2038-01-19 might cause an overflow
// if 32 bit integers are used.
$timestamp = mktime((int)$date[4],
(int)$date[5],
(int)$date[6],
(int)$date[2],
(int)$date[3],
(int)$date[1]);
return $timestamp;
}
/**
* Returns an array of arrays with all events. Every event is an associative
* array and each property is an element it.
*
* @return {array}
*/
public function events()
{
$array = $this->cal;
return $array['VEVENT'];
}
/** /**
* Returns an array of calendar types. * Get a key-value pair of a string.
* *
* @return {array} * @param {string} $text which is like "VCALENDAR:Begin" or "LOCATION:"
*/ *
public function calendar() * @return {array} array("VCALENDAR", "Begin")
{ */
$array = $this->cal; public function keyValueFromString($text) {
return $array['VCALENDAR']; preg_match("/(^[^a-z:]+)[:]([\w\W]*)/", $text, $matches);
} if (count($matches) == 0) {
return false;
}
$matches = array_splice($matches, 1, 2);
return $matches;
}
/** /**
* Returns a boolean value whether thr current calendar has events or not * Return Unix timestamp from ical date time format
* *
* @return {boolean} * @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or
*/ * YYYYMMDD[T]HHMMSS
public function hasEvents() *
{ * @return {int}
return ( count($this->events()) > 0 ? true : false ); */
} public function iCalDateToUnixTimestamp($icalDate) {
$icalDate = str_replace('T', '', $icalDate);
$icalDate = str_replace('Z', '', $icalDate);
/** $pattern = '/([0-9]{4})'; // 1: YYYY
* Returns false when the current calendar has no events in range, else the $pattern .= '([0-9]{2})'; // 2: MM
* events. $pattern .= '([0-9]{2})'; // 3: DD
* $pattern .= '([0-9]{0,2})'; // 4: HH
* Note that this function makes use of a UNIX timestamp. This might be a $pattern .= '([0-9]{0,2})'; // 5: MM
* problem on January the 29th, 2038. $pattern .= '([0-9]{0,2})/'; // 6: SS
* See http://en.wikipedia.org/wiki/Unix_time#Representing_the_number preg_match($pattern, $icalDate, $date);
*
* @param {boolean} $rangeStart Either true or false
* @param {boolean} $rangeEnd Either true or false
*
* @return {mixed}
*/
public function eventsFromRange($rangeStart = false, $rangeEnd = false)
{
$events = $this->sortEventsWithOrder($this->events(), SORT_ASC);
if (!$events) { // Unix timestamp can't represent dates before 1970
return false; if ($date[1] <= 1970) {
} return false;
}
// Unix timestamps after 03:14:07 UTC 2038-01-19 might cause an overflow
// if 32 bit integers are used.
$timestamp = mktime((int)$date[4],
(int)$date[5],
(int)$date[6],
(int)$date[2],
(int)$date[3],
(int)$date[1]);
$extendedEvents = array();
if ($rangeStart !== false) { $utcdate = new DateTime();
$rangeStart = new DateTime(); $utcdate->setTimestamp($timestamp);
} $utcdate->setTimezone(new DateTimeZone($this->default_timezone));
$utcoffset = $utcdate->getOffset();
if ($rangeEnd !== false or $rangeEnd <= 0) {
$rangeEnd = new DateTime('2038/01/18');
} else {
$rangeEnd = new DateTime($rangeEnd);
}
$rangeStart = $rangeStart->format('U'); return ($timestamp + $utcoffset);
$rangeEnd = $rangeEnd->format('U'); }
/**
* Returns an array of arrays with all events. Every event is an associative
* array and each property is an element it.
*
* @return {array}
*/
public function events() {
$array = $this->cal;
return $array['VEVENT'];
}
/**
* Returns an array of calendar types.
*
* @return {array}
*/
public function calendar() {
$array = $this->cal;
return $array['VCALENDAR'];
}
/**
* Returns a boolean value whether thr current calendar has events or not
*
* @return {boolean}
*/
public function hasEvents() {
return ( count($this->events()) > 0 ? true : false );
}
/**
* Returns false when the current calendar has no events in range, else the
* events.
*
* Note that this function makes use of a UNIX timestamp. This might be a
* problem on January the 29th, 2038.
* See http://en.wikipedia.org/wiki/Unix_time#Representing_the_number
*
* @param {boolean} $rangeStart Either true or false
* @param {boolean} $rangeEnd Either true or false
*
* @return {mixed}
*/
public function eventsFromRange($rangeStart = false, $rangeEnd = false) {
$events = $this->sortEventsWithOrder($this->events(), SORT_ASC);
if (!$events) {
return false;
}
$extendedEvents = array();
if ($rangeStart !== false) {
$rangeStart = new DateTime();
}
if ($rangeEnd !== false or $rangeEnd <= 0) {
$rangeEnd = new DateTime('2038/01/18');
} else {
$rangeEnd = new DateTime($rangeEnd);
}
$rangeStart = $rangeStart->format('U');
$rangeEnd = $rangeEnd->format('U');
// loop through all events by adding two new elements // loop through all events by adding two new elements
foreach ($events as $anEvent) { foreach ($events as $anEvent) {
$timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']); $timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
if ($timestamp >= $rangeStart && $timestamp <= $rangeEnd) { if ($timestamp >= $rangeStart && $timestamp <= $rangeEnd) {
$extendedEvents[] = $anEvent; $extendedEvents[] = $anEvent;
} }
} }
return $extendedEvents; return $extendedEvents;
} }
/** /**
* Returns sorted events * Returns sorted events
* *
* @param {array} $events An array with events. * @param {array} $events An array with events.
* @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR, * @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR,
* SORT_NUMERIC, SORT_STRING * SORT_NUMERIC, SORT_STRING
* *
* @return {array} * @return {array}
*/ */
public function sortEventsWithOrder($events, $sortOrder = SORT_ASC) public function sortEventsWithOrder($events, $sortOrder = SORT_ASC) {
{ $extendedEvents = array();
$extendedEvents = array();
// loop through all events by adding two new elements // loop through all events by adding two new elements
foreach ($events as $anEvent) { foreach ($events as $anEvent) {
if (!array_key_exists('UNIX_TIMESTAMP', $anEvent)) { if (!array_key_exists('UNIX_TIMESTAMP', $anEvent)) {
$anEvent['UNIX_TIMESTAMP'] = $anEvent['UNIX_TIMESTAMP'] =
$this->iCalDateToUnixTimestamp($anEvent['DTSTART']); $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
} }
if (!array_key_exists('REAL_DATETIME', $anEvent)) { if (!array_key_exists('REAL_DATETIME', $anEvent)) {
$anEvent['REAL_DATETIME'] = $anEvent['REAL_DATETIME'] =
date("d.m.Y", $anEvent['UNIX_TIMESTAMP']); date("d.m.Y", $anEvent['UNIX_TIMESTAMP']);
} }
$extendedEvents[] = $anEvent; $extendedEvents[] = $anEvent;
} }
foreach ($extendedEvents as $key => $value) { foreach ($extendedEvents as $key => $value) {
$timestamp[$key] = $value['UNIX_TIMESTAMP']; $timestamp[$key] = $value['UNIX_TIMESTAMP'];
} }
array_multisort($timestamp, $sortOrder, $extendedEvents); array_multisort($timestamp, $sortOrder, $extendedEvents);
return $extendedEvents; return $extendedEvents;
} }
} }
?> ?>

View File

@ -47,7 +47,7 @@ class Plugincalendarimporter extends Plugin {
'plugins' => Array( 'plugins' => Array(
'calendarimporter' => Array( 'calendarimporter' => Array(
'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE, 'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE,
'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT 'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT // currently not used, maybe in next release
) )
) )
) )