calendarimporter 1.1 final:
- ics exporter - improved ics fileparser - fixed ExtJS Problem in chrome KNOWN PROBLEMS: - importer ignores some fields (priority, status...) - attechments are ignored - timezone handling is not perfect - recurrent events are not handled properly (im/export)
This commit is contained in:
parent
d7ea948372
commit
c0e51e294b
10
changelog.txt
Normal file
10
changelog.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
calendarimporter 1.1 final:
|
||||||
|
- ics exporter
|
||||||
|
- improved ics fileparser
|
||||||
|
- fixed ExtJS Problem in chrome
|
||||||
|
|
||||||
|
KNOWN PROBLEMS:
|
||||||
|
- importer ignores some fields (priority, status...)
|
||||||
|
- attechments are ignored
|
||||||
|
- timezone handling is not perfect
|
||||||
|
- recurrent events are not handled properly (im/export)
|
10338
php/ical/class.icalcreator.php
Normal file
10338
php/ical/class.icalcreator.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -61,6 +61,7 @@ class ICal {
|
|||||||
foreach ($lines as $line) {
|
foreach ($lines as $line) {
|
||||||
$line = trim($line);
|
$line = trim($line);
|
||||||
$add = $this->keyValueFromString($line);
|
$add = $this->keyValueFromString($line);
|
||||||
|
error_log("line: " . $line);
|
||||||
if ($add === false) {
|
if ($add === false) {
|
||||||
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
|
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
|
||||||
continue;
|
continue;
|
||||||
@ -121,47 +122,48 @@ class ICal {
|
|||||||
$keyword = $this->last_keyword;
|
$keyword = $this->last_keyword;
|
||||||
|
|
||||||
switch ($component) {
|
switch ($component) {
|
||||||
case 'VEVENT':
|
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")) {
|
//always strip additional content....
|
||||||
$keyword = explode(";", $keyword);
|
//if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
|
||||||
$keyword = $keyword[0]; // remove additional content like VALUE=DATE
|
$keyword = explode(";", $keyword);
|
||||||
}
|
$keyword = $keyword[0]; // remove additional content like VALUE=DATE
|
||||||
|
//}
|
||||||
|
|
||||||
if (stristr($keyword, "TIMEZONE")) {
|
if (stristr($keyword, "TIMEZONE")) {
|
||||||
$this->default_timezone = $value; // store the calendertimezone
|
$this->default_timezone = $value; // store the calendertimezone
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($component) {
|
switch ($component) {
|
||||||
case "VTODO":
|
case "VTODO":
|
||||||
$this->cal[$component][$this->todo_count - 1][$keyword] = $value;
|
$this->cal[$component][$this->todo_count - 1][$keyword] = $value;
|
||||||
//$this->cal[$component][$this->todo_count]['Unix'] = $unixtime;
|
//$this->cal[$component][$this->todo_count]['Unix'] = $unixtime;
|
||||||
break;
|
break;
|
||||||
case "VEVENT":
|
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;
|
||||||
}
|
}
|
||||||
@ -174,10 +176,13 @@ class ICal {
|
|||||||
* @return {array} array("VCALENDAR", "Begin")
|
* @return {array} array("VCALENDAR", "Begin")
|
||||||
*/
|
*/
|
||||||
public function keyValueFromString($text) {
|
public function keyValueFromString($text) {
|
||||||
preg_match("/(^[^a-z:]+)[:]([\w\W]*)/", $text, $matches);
|
preg_match("/(^[^a-z:]+[;a-zA-Z=\/]*)[:]([\w\W]*)/", $text, $matches);
|
||||||
|
|
||||||
|
error_log("macthes: " . count($matches). " " . $text);
|
||||||
if (count($matches) == 0) {
|
if (count($matches) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$matches = array_splice($matches, 1, 2);
|
$matches = array_splice($matches, 1, 2);
|
||||||
return $matches;
|
return $matches;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
include_once('mapi/class.recurrence.php');
|
include_once('mapi/class.recurrence.php');
|
||||||
|
include_once('plugins/calendarimporter/php/ical/class.icalcreator.php');
|
||||||
|
|
||||||
class CalendarexporterModule extends Module {
|
class CalendarexporterModule extends Module {
|
||||||
|
|
||||||
@ -102,53 +103,46 @@ class CalendarexporterModule extends Module {
|
|||||||
fclose($fh);
|
fclose($fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function writeICSHead($fh, $calname) {
|
|
||||||
$icshead = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Zarafa Webapp//Zarafa Calendar Exporter//DE\nMETHOD:PUBLISH\nX-WR-CALNAME:" . $calname. "\nX-WR-TIMEZONE:" . date("e") . "\n";
|
|
||||||
fwrite($fh, $icshead);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function writeICSEnd($fh) {
|
|
||||||
$icsend = "END:VCALENDAR";
|
|
||||||
fwrite($fh, $icsend);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getIcalDate($time, $incl_time = true) {
|
private function getIcalDate($time, $incl_time = true) {
|
||||||
return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time);
|
return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function writeEvent($fh, $event) {
|
private function addEvent(&$vevent, $event) {
|
||||||
$head = "BEGIN:VEVENT\n";
|
|
||||||
$end = "END:VEVENT\n";
|
|
||||||
|
|
||||||
$busystate = array("FREE", "TENTATIVE", "BUSY", "OOF");
|
$busystate = array("FREE", "TENTATIVE", "BUSY", "OOF");
|
||||||
|
$zlabel = array("NONE", "IMPORTANT", "WORK", "PERSONAL", "HOLIDAY", "REQUIRED", "TRAVEL REQUIRED", "PREPARATION REQUIERED", "BIRTHDAY", "SPECIAL DATE", "PHONE INTERVIEW");
|
||||||
|
|
||||||
$fields = array(
|
$vevent->setProperty("LOCATION", $event["location"]); // property name - case independent
|
||||||
"UID" => $this->randomstring(10) . "-" . $this->randomstring(5) . "-ics@zarafa-export-plugin", // generate uid
|
$vevent->setProperty("SUMMARY", $event["subject"]);
|
||||||
"DTSTART" => $this->getIcalDate($event["commonstart"]) . "Z", // this times are utc!
|
$vevent->setProperty("DESCRIPTION", str_replace("\n", "\\n",$event["description"]));
|
||||||
"DTEND" => $this->getIcalDate($event["commonend"]) . "Z",
|
$vevent->setProperty("COMMENT", "Exported from Zarafa" );
|
||||||
"DTSTAMP" => $this->getIcalDate($event["creation_time"]) . "Z",
|
$vevent->setProperty("ORGANIZER", $event["sent_representing_email_address"]);
|
||||||
"CREATED" => $this->getIcalDate($event["creation_time"]) . "Z",
|
$vevent->setProperty("DTSTART", $this->getIcalDate($event["commonstart"]) . "Z");
|
||||||
"X-MICROSOFT-CDO-BUSYSTATUS" => $busystate[$event["busystatus"]],
|
$vevent->setProperty("DTEND", $this->getIcalDate($event["commonend"]) . "Z");
|
||||||
"LAST-MODIFIED" => $this->getIcalDate($event["last_modification_time"]),
|
$vevent->setProperty("DTSTAMP", $this->getIcalDate($event["creation_time"]) . "Z");
|
||||||
"DESCRIPTION" => str_replace("\n", "\\n",$event["description"]),
|
$vevent->setProperty("CREATED", $this->getIcalDate($event["creation_time"]) . "Z");
|
||||||
"LOCATION" => $event["location"],
|
$vevent->setProperty("LAST-MODIFIED", $this->getIcalDate($event["last_modification_time"]) . "Z");
|
||||||
"SUMMARY" => $event["subject"],
|
$vevent->setProperty("X-MICROSOFT-CDO-BUSYSTATUS", $busystate[$event["busystatus"]]);
|
||||||
|
$vevent->setProperty("X-ZARAFA-LABEL", $zlabel[$event["label"]]);
|
||||||
// some static content...
|
$vevent->setProperty("PRIORITY", $event["importance"]);
|
||||||
"TRANSP" => "OPAQUE",
|
$vevent->setProperty("CLASS", $event["private"] ? "PRIVATE" : "PUBLIC");
|
||||||
"SEQUENCE" => "0"
|
|
||||||
);
|
|
||||||
|
|
||||||
fwrite($fh, $head);
|
// ATTENDEES
|
||||||
|
if(count($event["attendees"]) > 0) {
|
||||||
|
foreach($event["attendees"] as $attendee) {
|
||||||
|
$vevent->setProperty("ATTENDEE", $attendee["props"]["smtp_address"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// event fields:
|
// REMINDERS
|
||||||
foreach ($fields as $key => $value) {
|
if($event["reminder"]) {
|
||||||
fwrite($fh, $key . ":" . $value . "\n");
|
$valarm = & $vevent->newComponent("valarm"); // create an event alarm
|
||||||
|
$valarm->setProperty("action", "DISPLAY" );
|
||||||
|
$valarm->setProperty("description", $vevent->getProperty("SUMMARY")); // reuse the event summary
|
||||||
|
$valarm->setProperty("trigger", $this->getIcalDate($event["reminder_time"]) . "Z"); // create alarm trigger (in UTC datetime)
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($fields);
|
|
||||||
|
|
||||||
fwrite($fh, $end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function loadEventDescription($event) {
|
private function loadEventDescription($event) {
|
||||||
@ -276,23 +270,68 @@ class CalendarexporterModule extends Module {
|
|||||||
return $data['item']['props']['body'];
|
return $data['item']['props']['body'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function loadAttendees($event) {
|
||||||
|
$entryid = $this->getActionEntryID($event);
|
||||||
|
$store = $this->getActionStore($event);
|
||||||
|
|
||||||
|
$basedate = null;
|
||||||
|
|
||||||
|
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
||||||
|
$plaintext = true;
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
|
||||||
|
if($store && $entryid) {
|
||||||
|
$message = $GLOBALS['operations']->openMessage($store, $entryid);
|
||||||
|
|
||||||
|
|
||||||
|
// add all standard properties from the series/normal message
|
||||||
|
$data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $properties, (isset($plaintext) && $plaintext));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data['item']['recipients']['item'];
|
||||||
|
}
|
||||||
|
|
||||||
private function exportCalendar($actionType, $actionData) {
|
private function exportCalendar($actionType, $actionData) {
|
||||||
$secid = $this->randomstring();
|
$secid = $this->randomstring();
|
||||||
$this->createSecIDFile($secid);
|
$this->createSecIDFile($secid);
|
||||||
$tmpname = stripslashes($actionData["calendar"] . ".ics." . $this->randomstring(8));
|
$tmpname = stripslashes($actionData["calendar"] . ".ics." . $this->randomstring(8));
|
||||||
$filename = TMP_PATH . "/" . $tmpname . "." . $secid;
|
$filename = TMP_PATH . "/" . $tmpname . "." . $secid;
|
||||||
|
|
||||||
// create ics file....
|
$tz = date("e"); // use php timezone (maybe set up in php.ini, date.timezone)
|
||||||
$fh = fopen($filename, 'w') or die("can't open ics file");
|
|
||||||
$this->writeICSHead($fh, $actionData["calendar"]);
|
if($this->DEBUG) {
|
||||||
|
error_log("PHP Timezone: " . $tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array(
|
||||||
|
"language" => substr($GLOBALS["settings"]->get("zarafa/v1/main/language"),0,2),
|
||||||
|
"directory" => TMP_PATH . "/",
|
||||||
|
"filename" => $tmpname . "." . $secid,
|
||||||
|
"unique_id" => "zarafa-export-plugin",
|
||||||
|
"TZID" => $tz
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new vcalendar($config);
|
||||||
|
$v->setProperty("method", "PUBLISH"); // required of some calendar software
|
||||||
|
$v->setProperty("x-wr-calname", $actionData["calendar"]); // required of some calendar software
|
||||||
|
$v->setProperty("X-WR-CALDESC", "Exported Zarafa Calendar"); // required of some calendar software
|
||||||
|
$v->setProperty("X-WR-TIMEZONE", $tz);
|
||||||
|
|
||||||
|
$xprops = array("X-LIC-LOCATION" => $tz); // required of some calendar software
|
||||||
|
iCalUtilityFunctions::createTimezone($v, $tz, $xprops); // create timezone object in calendar
|
||||||
|
|
||||||
|
|
||||||
foreach($actionData["data"]["item"] as $event) {
|
foreach($actionData["data"]["item"] as $event) {
|
||||||
$event["props"]["description"] = $this->loadEventDescription($event);
|
$event["props"]["description"] = $this->loadEventDescription($event);
|
||||||
$this->writeEvent($fh, $event["props"]);
|
$event["props"]["attendees"] = $this->loadAttendees($event);
|
||||||
|
|
||||||
|
$vevent = & $v->newComponent("vevent"); // create a new event object
|
||||||
|
$this->addEvent($vevent, $event["props"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->writeICSEnd($fh);
|
$v->saveCalendar();
|
||||||
fclose($fh);
|
|
||||||
|
|
||||||
$response['status'] = true;
|
$response['status'] = true;
|
||||||
$response['fileid'] = $tmpname; // number of entries that will be exported
|
$response['fileid'] = $tmpname; // number of entries that will be exported
|
||||||
|
Loading…
Reference in New Issue
Block a user