Start implementation of libkolabxml event reading/writing + convert from Kolab 2 format

This commit is contained in:
Thomas B 2012-03-30 19:09:58 +02:00
parent 3ba191ed68
commit ed3c88a47c

View file

@ -26,16 +26,66 @@ class kolab_format_event extends kolab_format
{
public $CTYPE = 'application/calendar+xml';
private $sensitivity_map = array(
'public' => kolabformat::ClassPublic,
'private' => kolabformat::ClassPrivate,
'confidential' => kolabformat::ClassConfidential,
);
private $role_map = array(
'REQ-PARTICIPANT' => kolabformat::Required,
'OPT-PARTICIPANT' => kolabformat::Optional,
'NON-PARTICIPANT' => kolabformat::NonParticipant,
'CHAIR' => kolabformat::Chair,
);
private $status_map = array(
'UNKNOWN' => kolabformat::PartNeedsAction,
'NEEDS-ACTION' => kolabformat::PartNeedsAction,
'TENTATIVE' => kolabformat::PartTentative,
'ACCEPTED' => kolabformat::PartAccepted,
'DECLINED' => kolabformat::PartDeclined,
'DELEGATED' => kolabformat::PartDelegated,
);
private $kolab2_rolemap = array(
'required' => 'REQ-PARTICIPANT',
'optional' => 'OPT-PARTICIPANT',
'resource' => 'CHAIR',
);
private $kolab2_statusmap = array(
'none' => 'NEEDS-ACTION',
'tentative' => 'TENTATIVE',
'accepted' => 'CONFIRMED',
'accepted' => 'ACCEPTED',
'declined' => 'DECLINED',
);
private $kolab2_monthmap = array('', 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december');
/**
* Default constructor
*/
function __construct()
{
$obj = new Event;
$this->obj = new Event;
}
/**
* Load Contact object data from the given XML block
*
* @param string XML data
*/
public function load($xml)
{
$this->obj = kolabformat::readEvent($xml, false);
}
/**
* Write Contact object data to XML format
*
* @return string XML data
*/
public function write()
{
$xml = kolabformat::writeEvent($this->obj);
@ -43,24 +93,276 @@ class kolab_format_event extends kolab_format
return $xml;
}
/**
* Set contact properties to the kolabformat object
*
* @param array Contact data as hash array
*/
public function set(&$object)
{
// TODO: do the hard work of setting object values
// set some automatic values if missing
if (!$this->obj->created()) {
if (!empty($object['created']))
$object['created'] = new DateTime('now', self::$timezone);
$this->obj->setCreated(self::get_datetime($object['created']));
}
public function is_valid()
{
return is_object($this->obj) && $this->obj->isValid();
}
if (!empty($object['uid']))
$this->obj->setUid($object['uid']);
public function fromkolab2($object)
{
// TODO: increase sequence
// $this->obj->setSequence($this->obj->sequence()+1);
// do the hard work of setting object values
$this->obj->setStart(self::get_datetime($object['start'], null, $object['allday']));
$this->obj->setEnd(self::get_datetime($object['end'], null, $object['allday']));
$this->obj->setSummary($object['title']);
$this->obj->setLocation($object['location']);
$this->obj->setDescription($object['description']);
$this->obj->setPriority($object['priority']);
$this->obj->setClassification($this->sensitivity_map[$object['sensitivity']]);
$this->obj->setCategories(self::array2vector($object['categories']));
$this->obj->setTransparency($object['free_busy'] == 'free');
$status = kolabformat::StatusUndefined;
if ($object['free_busy'] == 'tentative')
$status = kolabformat::StatusTentative;
if ($object['cancelled'])
$status = kolabformat::StatusCancelled;
$this->obj->setStatus($status);
// process event attendees
$organizer = new ContactReference;
$attendees = new vectorattendee;
foreach ((array)$object['attendees'] as $attendee) {
$cr = new ContactReference(ContactReference::EmailReference, $attendee['email']);
$cr->setName($attendee['name']);
if ($attendee['role'] == 'ORGANIZER') {
$organizer = $cr;
}
else {
$att = new Attendee;
$att->setContact($cr);
$att->setPartStat($this->status_map[$attendee['status']]);
$att->setRole($this->role_map[$attendee['role']] ? $this->role_map[$attendee['role']] : kolabformat::Required);
$att->setRSVP((bool)$attendee['rsvp']);
if ($att->isValid())
$attendees->push($att);
}
}
$this->obj->setOrganizer($organizer);
$this->obj->setAttendees($attendees);
// TODO: save recurrence rule
// TODO: save alarm
$valarms = new vectoralarm;
if ($object['alarms']) {
$alarm = new Alarm;
list($duration, $type) = explode(":", $object['alarms']);
$valarms->push($alarm);
}
$this->obj->setAlarms($valarms);
// TODO: save attachments
// cache this data
unset($object['_formatobj']);
$this->data = $object;
}
/**
*
*/
public function is_valid()
{
return $this->data || (is_object($this->obj) && $this->obj->isValid());
}
/**
* Convert the Contact object into a hash array data structure
*
* @return array Contact data as hash array
*/
public function to_array()
{
// TODO: read object properties
// return cached result
if (!empty($this->data))
return $this->data;
$sensitivity_map = array_flip($this->sensitivity_map);
// read object properties
$object = array(
'uid' => $this->obj->uid(),
'changed' => self::php_datetime($this->obj->lastModified()),
'title' => $this->obj->summary(),
'location' => $this->obj->location(),
'description' => $this->obj->description(),
'allday' => $this->obj->start()->isDateOnly(),
'start' => self::php_datetime($this->obj->start()),
'end' => self::php_datetime($this->obj->end()),
'categories' => self::vector2array($this->obj->categories()),
'free_busy' => $this->obj->transparency() ? 'free' : 'busy', // TODO: transparency is only boolean
'sensitivity' => $sensitivity_map[$this->obj->classification()],
'priority' => $this->obj->priority(),
);
// status defines different event properties...
$status = $this->obj->status();
if ($status == kolabformat::StatusTentative)
$object['free_busy'] = 'tentative';
else if ($status == kolabformat::StatusCancelled)
$objec['cancelled'] = true;
// read organizer and attendees
if ($organizer = $this->obj->organizer()) {
$object['attendees'][] = array(
'role' => 'ORGANIZER',
'email' => $organizer->email(),
'name' => $organizer->name(),
);
}
$role_map = array_flip($this->role_map);
$status_map = array_flip($this->status_map);
$attvec = $this->obj->attendees();
for ($i=0; $i < $attvec->size(); $i++) {
$attendee = $attvec->get($i);
$cr = $attendee->contact();
$object['attendees'][] = array(
'role' => $role_map[$attendee->role()],
'status' => $status_map[$attendee->partStat()],
'rsvp' => $attendee->rsvp(),
'email' => $cr->email(),
'name' => $cr->name(),
);
}
// TODO: hanlde recurrence rules, alarms and attachments
$this->data = $object;
return $this->data;
}
/**
* Load data from old Kolab2 format
*/
public function fromkolab2($rec)
{
if (PEAR::isError($rec))
return;
$start_time = date('H:i:s', $rec['start-date']);
$allday = $rec['_is_all_day'] || ($start_time == '00:00:00' && $start_time == date('H:i:s', $rec['end-date']));
if ($allday) { // in Roundcube all-day events go from 12:00 to 13:00
$now = new DateTime('now', self::$timezone);
$gmt_offset = $now->getOffset();
$rec['start-date'] += 12 * 3600;
$rec['end-date'] -= 11 * 3600;
$rec['end-date'] -= $gmt_offset - date('Z', $rec['end-date']); // shift times from server's timezone to user's timezone
$rec['start-date'] -= $gmt_offset - date('Z', $rec['start-date']); // because generated with mktime() in Horde_Kolab_Format_Date::decodeDate()
// sanity check
if ($rec['end-date'] <= $rec['start-date'])
$rec['end-date'] += 86400;
}
// convert alarm time into internal format
if ($rec['alarm']) {
$alarm_value = $rec['alarm'];
$alarm_unit = 'M';
if ($rec['alarm'] % 1440 == 0) {
$alarm_value /= 1440;
$alarm_unit = 'D';
}
else if ($rec['alarm'] % 60 == 0) {
$alarm_value /= 60;
$alarm_unit = 'H';
}
$alarm_value *= -1;
}
// convert recurrence rules into internal pseudo-vcalendar format
if ($recurrence = $rec['recurrence']) {
$rrule = array(
'FREQ' => strtoupper($recurrence['cycle']),
'INTERVAL' => intval($recurrence['interval']),
);
if ($recurrence['range-type'] == 'number')
$rrule['COUNT'] = intval($recurrence['range']);
else if ($recurrence['range-type'] == 'date')
$rrule['UNTIL'] = $recurrence['range'];
if ($recurrence['day']) {
$byday = array();
$prefix = ($rrule['FREQ'] == 'MONTHLY' || $rrule['FREQ'] == 'YEARLY') ? intval($recurrence['daynumber'] ? $recurrence['daynumber'] : 1) : '';
foreach ($recurrence['day'] as $day)
$byday[] = $prefix . substr(strtoupper($day), 0, 2);
$rrule['BYDAY'] = join(',', $byday);
}
if ($recurrence['daynumber']) {
if ($recurrence['type'] == 'monthday' || $recurrence['type'] == 'daynumber')
$rrule['BYMONTHDAY'] = $recurrence['daynumber'];
else if ($recurrence['type'] == 'yearday')
$rrule['BYYEARDAY'] = $recurrence['daynumber'];
}
if ($recurrence['month']) {
$monthmap = array_flip($this->kolab2_monthmap);
$rrule['BYMONTH'] = strtolower($monthmap[$recurrence['month']]);
}
if ($recurrence['exclusion']) {
foreach ((array)$recurrence['exclusion'] as $excl)
$rrule['EXDATE'][] = strtotime($excl . date(' H:i:s', $rec['start-date'])); // use time of event start
}
}
$attendees = array();
if ($rec['organizer']) {
$attendees[] = array(
'role' => 'ORGANIZER',
'name' => $rec['organizer']['display-name'],
'email' => $rec['organizer']['smtp-address'],
'status' => 'ACCEPTED',
);
$_attendees .= $rec['organizer']['display-name'] . ' ' . $rec['organizer']['smtp-address'] . ' ';
}
foreach ((array)$rec['attendee'] as $attendee) {
$attendees[] = array(
'role' => $this->kolab2_rolemap[$attendee['role']],
'name' => $attendee['display-name'],
'email' => $attendee['smtp-address'],
'status' => $this->kolab2_statusmap[$attendee['status']],
'rsvp' => $attendee['request-response'],
);
$_attendees .= $rec['organizer']['display-name'] . ' ' . $rec['organizer']['smtp-address'] . ' ';
}
$this->data = array(
'uid' => $rec['uid'],
'title' => $rec['summary'],
'location' => $rec['location'],
'description' => $rec['body'],
'start' => $rec['start-date'],
'end' => $rec['end-date'],
'allday' => $allday,
'recurrence' => $rrule,
'alarms' => $alarm_value . $alarm_unit,
'categories' => explode(',', $rec['categories']),
'attachments' => $attachments,
'attendees' => $attendees,
'free_busy' => $rec['show-time-as'],
'priority' => $rec['priority'],
'sensitivity' => $rec['sensitivity'],
'changed' => $rec['last-modification-date'],
);
}
}