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:
Christoph Haas 2012-12-09 21:39:49 +00:00
parent d7ea948372
commit c0e51e294b
4 changed files with 10466 additions and 74 deletions

10
changelog.txt Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,7 @@ class ICal {
foreach ($lines as $line) {
$line = trim($line);
$add = $this->keyValueFromString($line);
error_log("line: " . $line);
if ($add === false) {
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
continue;
@ -121,47 +122,48 @@ class ICal {
$keyword = $this->last_keyword;
switch ($component) {
case 'VEVENT':
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
$ts = $this->iCalDateToUnixTimestamp($value);
$value = $ts * 1000;
}
$value = str_replace("\\n", "\n", $value);
$value = $this->cal[$component][$this->event_count - 1]
[$keyword].$value;
break;
case 'VTODO' :
$value = $this->cal[$component][$this->todo_count - 1]
[$keyword].$value;
break;
case 'VEVENT':
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
$ts = $this->iCalDateToUnixTimestamp($value);
$value = $ts * 1000;
}
$value = str_replace("\\n", "\n", $value);
$value = $this->cal[$component][$this->event_count - 1]
[$keyword].$value;
break;
case 'VTODO' :
$value = $this->cal[$component][$this->todo_count - 1]
[$keyword].$value;
break;
}
}
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
$keyword = explode(";", $keyword);
$keyword = $keyword[0]; // remove additional content like VALUE=DATE
}
//always strip additional content....
//if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
$keyword = explode(";", $keyword);
$keyword = $keyword[0]; // remove additional content like VALUE=DATE
//}
if (stristr($keyword, "TIMEZONE")) {
$this->default_timezone = $value; // store the calendertimezone
}
switch ($component) {
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")) {
$ts = $this->iCalDateToUnixTimestamp($value);
$value = $ts * 1000;
}
$value = str_replace("\\n", "\n", $value);
$this->cal[$component][$this->event_count - 1][$keyword] = $value;
break;
default:
$this->cal[$component][$keyword] = $value;
break;
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")) {
$ts = $this->iCalDateToUnixTimestamp($value);
$value = $ts * 1000;
}
$value = str_replace("\\n", "\n", $value);
$this->cal[$component][$this->event_count - 1][$keyword] = $value;
break;
default:
$this->cal[$component][$keyword] = $value;
break;
}
$this->last_keyword = $keyword;
}
@ -174,10 +176,13 @@ class ICal {
* @return {array} array("VCALENDAR", "Begin")
*/
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) {
return false;
}
$matches = array_splice($matches, 1, 2);
return $matches;
}

View File

@ -28,6 +28,7 @@
*/
include_once('mapi/class.recurrence.php');
include_once('plugins/calendarimporter/php/ical/class.icalcreator.php');
class CalendarexporterModule extends Module {
@ -102,53 +103,46 @@ class CalendarexporterModule extends Module {
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) {
return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time);
}
private function writeEvent($fh, $event) {
$head = "BEGIN:VEVENT\n";
$end = "END:VEVENT\n";
private function addEvent(&$vevent, $event) {
$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(
"UID" => $this->randomstring(10) . "-" . $this->randomstring(5) . "-ics@zarafa-export-plugin", // generate uid
"DTSTART" => $this->getIcalDate($event["commonstart"]) . "Z", // this times are utc!
"DTEND" => $this->getIcalDate($event["commonend"]) . "Z",
"DTSTAMP" => $this->getIcalDate($event["creation_time"]) . "Z",
"CREATED" => $this->getIcalDate($event["creation_time"]) . "Z",
"X-MICROSOFT-CDO-BUSYSTATUS" => $busystate[$event["busystatus"]],
"LAST-MODIFIED" => $this->getIcalDate($event["last_modification_time"]),
"DESCRIPTION" => str_replace("\n", "\\n",$event["description"]),
"LOCATION" => $event["location"],
"SUMMARY" => $event["subject"],
// some static content...
"TRANSP" => "OPAQUE",
"SEQUENCE" => "0"
);
$vevent->setProperty("LOCATION", $event["location"]); // property name - case independent
$vevent->setProperty("SUMMARY", $event["subject"]);
$vevent->setProperty("DESCRIPTION", str_replace("\n", "\\n",$event["description"]));
$vevent->setProperty("COMMENT", "Exported from Zarafa" );
$vevent->setProperty("ORGANIZER", $event["sent_representing_email_address"]);
$vevent->setProperty("DTSTART", $this->getIcalDate($event["commonstart"]) . "Z");
$vevent->setProperty("DTEND", $this->getIcalDate($event["commonend"]) . "Z");
$vevent->setProperty("DTSTAMP", $this->getIcalDate($event["creation_time"]) . "Z");
$vevent->setProperty("CREATED", $this->getIcalDate($event["creation_time"]) . "Z");
$vevent->setProperty("LAST-MODIFIED", $this->getIcalDate($event["last_modification_time"]) . "Z");
$vevent->setProperty("X-MICROSOFT-CDO-BUSYSTATUS", $busystate[$event["busystatus"]]);
$vevent->setProperty("X-ZARAFA-LABEL", $zlabel[$event["label"]]);
$vevent->setProperty("PRIORITY", $event["importance"]);
$vevent->setProperty("CLASS", $event["private"] ? "PRIVATE" : "PUBLIC");
fwrite($fh, $head);
// ATTENDEES
if(count($event["attendees"]) > 0) {
foreach($event["attendees"] as $attendee) {
$vevent->setProperty("ATTENDEE", $attendee["props"]["smtp_address"]);
}
}
// event fields:
foreach ($fields as $key => $value) {
fwrite($fh, $key . ":" . $value . "\n");
// REMINDERS
if($event["reminder"]) {
$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) {
@ -276,23 +270,68 @@ class CalendarexporterModule extends Module {
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) {
$secid = $this->randomstring();
$this->createSecIDFile($secid);
$tmpname = stripslashes($actionData["calendar"] . ".ics." . $this->randomstring(8));
$filename = TMP_PATH . "/" . $tmpname . "." . $secid;
// create ics file....
$fh = fopen($filename, 'w') or die("can't open ics file");
$this->writeICSHead($fh, $actionData["calendar"]);
$tz = date("e"); // use php timezone (maybe set up in php.ini, date.timezone)
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) {
$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);
fclose($fh);
$v->saveCalendar();
$response['status'] = true;
$response['fileid'] = $tmpname; // number of entries that will be exported