diff options
author | Thomas Bruederli <bruederli@kolabsys.com> | 2012-11-13 11:04:34 (GMT) |
---|---|---|
committer | Thomas Bruederli <bruederli@kolabsys.com> | 2012-11-13 11:04:34 (GMT) |
commit | c1fce33bc37a72ef13dffed046aa5dd5f0f6fae7 (patch) | |
tree | f602ac503e6607b941ce706d668d7f86b8509509 | |
parent | d9cd404227f62656fab48620336397cdc351a605 (diff) | |
download | roundcubemail-plugins-kolab-c1fce33bc37a72ef13dffed046aa5dd5f0f6fae7.tar.gz |
Implement writing of contacts and distribution-lists using Horde classes
-rw-r--r-- | plugins/libkolab/lib/kolab_format.php | 95 | ||||
-rw-r--r-- | plugins/libkolab/lib/kolab_format_configuration.php | 2 | ||||
-rw-r--r-- | plugins/libkolab/lib/kolab_format_contact.php | 135 | ||||
-rw-r--r-- | plugins/libkolab/lib/kolab_format_distributionlist.php | 17 | ||||
-rw-r--r-- | plugins/libkolab/lib/kolab_storage.php | 3 | ||||
-rw-r--r-- | plugins/libkolab/lib/kolab_storage_folder.php | 21 |
6 files changed, 194 insertions, 79 deletions
diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index 622b411..d976328 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -37,6 +37,7 @@ abstract class kolab_format protected $handler; protected $data; protected $xmldata; + protected $kolab_object; protected $loaded = false; protected $version = 2.0; @@ -165,36 +166,6 @@ abstract class kolab_format } /** - * Convert a libkolabxml vector to a PHP array - * - * @param object vector Object - * @return array Indexed array contaning vector elements - */ - public static function vector2array($vec, $max = PHP_INT_MAX) - { - $arr = array(); - for ($i=0; $i < $vec->size() && $i < $max; $i++) - $arr[] = $vec->get($i); - return $arr; - } - - /** - * Build a libkolabxml vector (string) from a PHP array - * - * @param array Array with vector elements - * @return object vectors - */ - public static function array2vector($arr) - { - $vec = new vectors; - foreach ((array)$arr as $val) { - if (strlen($val)) - $vec->push($val); - } - return $vec; - } - - /** * Parse the X-Kolab-Type header from MIME messages and return the object type in short form * * @param string X-Kolab-Type header value @@ -215,7 +186,7 @@ abstract class kolab_format $handler = Horde_Kolab_Format::factory('XML', $this->xmltype, array('subtype' => $this->subtype)); if (!is_object($handler) || is_a($handler, 'PEAR_Error')) { - return false; + return; } $this->handler = $handler; @@ -227,45 +198,32 @@ abstract class kolab_format * * @return boolean True if there were errors, False if OK */ - protected function format_errors() + protected function format_errors($p) { - $ret = $log = false; - switch (kolabformat::error()) { - case kolabformat::NoError: - $ret = false; - break; - case kolabformat::Warning: - $ret = false; - $log = "Warning"; - break; - default: - $ret = true; - $log = "Error"; - } + $ret = false; - if ($log) { + if (is_object($p) && is_a($p, 'PEAR_Error')) { rcube::raise_error(array( 'code' => 660, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, - 'message' => "kolabformat $log: " . kolabformat::errorMessage(), + 'message' => "Horde_Kolab_Format error: " . $p->getMessage(), ), true); + + $ret = true; } return $ret; } /** - * Save the last generated UID to the object properties. - * Should be called after kolabformat::writeXXXX(); + * Generate a unique identifier for a Kolab object */ - protected function update_uid() + protected function generate_uid() { - // get generated UID - if (!$this->data['uid']) { - $this->data['uid'] = 'TODO'; - } + $rc = rcube::get_instance(); + return strtoupper(md5(time() . uniqid(rand())) . '-' . substr(md5($rc->user ? $rc->user->get_username() : rand()), 0, 16)); } /** @@ -298,11 +256,15 @@ abstract class kolab_format */ public function load($xml) { + $this->loaded = false; + // XML-to-array $object = $this->handler->load($xml); - $this->fromkolab2($object); - - $this->loaded = !$this->format_errors(); + if (!$this->format_errors($object)) { + $this->kolab_object = $object; + $this->fromkolab2($object); + $this->loaded = true; + } } /** @@ -315,12 +277,23 @@ abstract class kolab_format { $this->init(); - // TODO: implement his + if ($version && !self::supports($version)) + return false; + + // generate UID if not set + if (!$this->kolab_object['uid']) { + $this->kolab_object['uid'] = $this->generate_uid(); + } + + $xml = $this->handler->save($this->kolab_object); - if (!$this->format_errors()) - $this->update_uid(); - else + if (!$this->format_errors($xml) && strlen($xml)) { + $this->xmldata = $xml; + $this->data['uid'] = $this->kolab_object['uid']; + } + else { $this->xmldata = null; + } return $this->xmldata; } diff --git a/plugins/libkolab/lib/kolab_format_configuration.php b/plugins/libkolab/lib/kolab_format_configuration.php index 2970b10..edf22f7 100644 --- a/plugins/libkolab/lib/kolab_format_configuration.php +++ b/plugins/libkolab/lib/kolab_format_configuration.php @@ -63,7 +63,7 @@ class kolab_format_configuration extends kolab_format $this->CTYPE = 'application/x-vnd.kolab.configuration.' . $this->subtype; // cache this data - $this->data = $object; + $this->data = $this->kolab_object = $object; unset($this->data['_formatobj']); } diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php index fb033e3..cab7ded 100644 --- a/plugins/libkolab/lib/kolab_format_contact.php +++ b/plugins/libkolab/lib/kolab_format_contact.php @@ -94,6 +94,13 @@ class kolab_format_contact extends kolab_format private $kolab2_addresstypes = array( 'business' => 'work' ); + private $kolab2_arrays = array( + 'web-page' => 'url', + 'im-address' => true, + 'manager-name' => true, + 'assistant' => true, + 'children' => true, + ); private $kolab2_gender = array(0 => 'male', 1 => 'female'); @@ -114,7 +121,112 @@ class kolab_format_contact extends kolab_format { $this->init(); - // TODO: implement this + if ($object['uid']) + $this->kolab_object['uid'] = $object['uid']; + + $this->kolab_object['last-modification-date'] = time(); + + // map fields rcube => $kolab + foreach ($this->kolab2_fieldmap as $kolab => $rcube) { + $this->kolab_object[$kolab] = $object[$rcube]; + } + + // map gener values + if (isset($object['gender'])) { + $gender_map = array_flip($this->kolab2_gender); + $this->kolab_object['gender'] = $gender_map[$object['gender']]; + } + + // format dates + if ($object['birthday'] && ($date = @strtotime($object['birthday']))) + $this->kolab_object['birthday'] = date('Y-m-d', $date); + if ($object['anniversary'] && ($date = @strtotime($object['anniversary']))) + $this->kolab_object['anniversary'] = date('Y-m-d', $date); + + // make sure these attributes are single string values + foreach ($this->kolab2_arrays as $col => $field) { + if (!is_array($this->kolab_object[$col])) + continue; + if ($field === true) { + $values = $this->kolab_object[$col]; + } + else { + $values = array(); + foreach ($this->kolab_object[$col] as $v) + $values[] = $v[$field]; + } + $this->kolab_object[$col] = join('; ', $values); + } + + // save email addresses to field 'emails' + $emails = array(); + foreach ((array)$object['email'] as $email) + $emails[] = $email; + $this->kolab_object['emails'] = join(', ', array_filter($emails)); + unset($this->kolab_object['email']); + + // map phone types + foreach ((array)$this->kolab_object['phone'] as $i => $phone) { + if ($type = $this->phonetypes[$phone['type']]) + $this->kolab_object['phone'][$i]['type'] = $type; + } + + // save addresses (how weird is that?!) + $this->kolab_object['address'] = array(); + $seen_types = array(); + foreach ((array)$object['address'] as $adr) { + if ($type = $this->addresstypes[$adr['type']]) { + $updated = false; + $basekey = 'addr-' . $type . '-'; + + $this->kolab_object[$basekey . 'type'] = $type; + $this->kolab_object[$basekey . 'street'] = $adr['street']; + $this->kolab_object[$basekey . 'locality'] = $adr['locality']; + $this->kolab_object[$basekey . 'postal-code'] = $adr['zipcode']; + $this->kolab_object[$basekey . 'region'] = $adr['region']; + $this->kolab_object[$basekey . 'country'] = $adr['country']; + + // check if we updates an existing address entry of this type... + foreach($this->kolab_object['address'] as $index => $address) { + if ($this->kolab_object['type'] == $type) { + $this->kolab_object['address'][$index] = $new_address; + $updated = true; + } + } + + // ... add as new if not + if (!$updated) { + $this->kolab_object['address'][] = array( + 'type' => $type, + 'street' => $adr['street'], + 'locality' => $adr['locality'], + 'postal-code' => $adr['code'], + 'region' => $adr['region'], + 'country' => $adr['country'], + ); + } + + $seen_types[$type] = true; + } + else if ($adr['type'] == 'office') { + $this->kolab_object['office-location'] = $adr['locality']; + } + } + + // unset removed address properties + foreach ($this->addresstypes as $type) { + if (!$seen_types[$type]) { + $basekey = 'addr-' . $type . '-'; + unset( + $this->kolab_object[$basekey . 'type'], + $this->kolab_object[$basekey . 'street'], + $this->kolab_object[$basekey . 'locality'], + $this->kolab_object[$basekey . 'postal-code'], + $this->kolab_object[$basekey . 'region'], + $this->kolab_object[$basekey . 'country'] + ); + } + } // cache this data $this->data = $object; @@ -126,7 +238,7 @@ class kolab_format_contact extends kolab_format */ public function is_valid() { - return $this->data; + return strlen($this->data['uid']); } /** @@ -155,13 +267,28 @@ class kolab_format_contact extends kolab_format { $object = array( 'uid' => $record['uid'], + 'changed' => $record['last-modification-date'], 'email' => array(), 'phone' => array(), ); foreach ($this->kolab2_fieldmap as $kolab => $rcube) { - if (is_array($record[$kolab]) || strlen($record[$kolab])) - $object[$rcube] = $record[$kolab]; + if (is_array($record[$kolab]) || strlen($record[$kolab])) { + $object[$rcube] = $record[$kolab]; + + // split pseudo-arry values + if ($field = $this->kolab2_arrays[$kolab]) { + if ($field === true) { + $object[$rcube] = explode('; ', $record[$kolab]); + } + else { + $values = array(); + foreach (explode('; ', $record[$kolab]) as $v) + $values[] = array($field => $v); + $object[$rcube] = $values; + } + } + } } if (isset($record['gender'])) diff --git a/plugins/libkolab/lib/kolab_format_distributionlist.php b/plugins/libkolab/lib/kolab_format_distributionlist.php index ce44f38..b6fc566 100644 --- a/plugins/libkolab/lib/kolab_format_distributionlist.php +++ b/plugins/libkolab/lib/kolab_format_distributionlist.php @@ -38,7 +38,20 @@ class kolab_format_distributionlist extends kolab_format { $this->init(); - // TODO: implement this + if ($object['uid']) + $this->kolab_object['uid'] = $object['uid']; + + $this->kolab_object['last-modification-date'] = time(); + $this->kolab_object['last-name'] = $object['name']; + $this->kolab_object['member'] = array(); + + foreach ($object['member'] as $member) { + $this->kolab_object['member'][] = array( + 'uid' => $member['uid'], + 'smtp-address' => $member['email'], + 'display-name' => $member['name'], + ); + } // set type property for proper caching $object['_type'] = 'distribution-list'; @@ -50,7 +63,7 @@ class kolab_format_distributionlist extends kolab_format public function is_valid() { - return $this->data; + return !empty($this->data['uid']); } /** diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php index 79f949a..5b8eca7 100644 --- a/plugins/libkolab/lib/kolab_storage.php +++ b/plugins/libkolab/lib/kolab_storage.php @@ -31,7 +31,7 @@ class kolab_storage const SERVERSIDE_SUBSCRIPTION = 0; const CLIENTSIDE_SUBSCRIPTION = 1; - public static $version = 3.0; + public static $version = 2.0; public static $last_error; private static $ready = false; @@ -50,7 +50,6 @@ class kolab_storage $rcmail = rcube::get_instance(); self::$config = $rcmail->config; - self::$version = $rcmail->config->get('kolab_format_version', self::$version); self::$imap = $rcmail->get_storage(); self::$ready = class_exists('Horde_Kolab_Format') && (self::$imap->get_capability('METADATA') || self::$imap->get_capability('ANNOTATEMORE') || self::$imap->get_capability('ANNOTATEMORE2')); diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index 5ba5fa4..23bb3a6 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -543,22 +543,25 @@ class kolab_storage_folder if ($object['_attachments'][$key] == false) { unset($object['_attachments'][$key]); } - // load photo.attachment from old Kolab2 format to be directly embedded in xcard block + // load photo.attachment from old Kolab2 format else if ($type == 'contact' && ($key == 'photo.attachment' || $key == 'kolab-picture.png') && $att['id']) { - if (!isset($object['photo'])) - $object['photo'] = $this->get_attachment($object['_msguid'], $att['id'], $object['_mailbox']); - unset($object['_attachments'][$key]); + $existing_photo = true; + if (isset($object['photo'])) + unset($object['_attachments'][$key]); + else + $object['photo'] = $key; } } } - // save contact photo to attachment for Kolab2 format - if (kolab_storage::$version == 2.0 && $object['photo'] && !$existing_photo) { - $attkey = 'kolab-picture.png'; // this file name is hard-coded in libkolab/kolabformatV2/contact.cpp + // save new contact photo to attachment for Kolab2 format + if ($object['photo'] && !$existing_photo) { + $attkey = 'photo.attachment'; // this file name is hard-coded in libkolab/kolabformatV2/contact.cpp $object['_attachments'][$attkey] = array( 'mimetype'=> rc_image_content_type($object['photo']), 'content' => preg_match('![^a-z0-9/=+-]!i', $object['photo']) ? $object['photo'] : base64_decode($object['photo']), ); + $object['photo'] = $attkey; } // process attachments @@ -716,11 +719,11 @@ class kolab_storage_folder return false; $format->set($object); - $xml = $format->write(kolab_storage::$version); + $xml = $format->write(); $object['uid'] = $format->uid; // read UID from format $object['_formatobj'] = $format; - if (!$format->is_valid() || empty($object['uid'])) { + if (empty($xml) || !$format->is_valid() || empty($object['uid'])) { return false; } |