Let libkolabxml generate UIDs; preserve object properties Roundcube doens't understand by loading old XML object before updating
This commit is contained in:
parent
edaad9b47c
commit
3f78d8f7b5
6 changed files with 95 additions and 54 deletions
|
@ -518,8 +518,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
if (!$existing) {
|
||||
// generate new Kolab contact item
|
||||
$object = $this->_from_rcube_contact($save_data);
|
||||
$object['uid'] = kolab_format::generate_uid();
|
||||
|
||||
$saved = $this->storagefolder->save($object, 'contact');
|
||||
|
||||
if (!$saved) {
|
||||
|
@ -554,7 +552,7 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
{
|
||||
$updated = false;
|
||||
if ($old = $this->storagefolder->get_object($this->_id2uid($id))) {
|
||||
$object = array_merge($old, $this->_from_rcube_contact($save_data));
|
||||
$object = $this->_from_rcube_contact($save_data, $old);
|
||||
|
||||
$saved = $this->storagefolder->save($object, 'contact', $uid);
|
||||
if (!$saved) {
|
||||
|
@ -1030,9 +1028,9 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
}
|
||||
|
||||
/**
|
||||
* Map fields from Roundcube format to internal Kolab_Format
|
||||
* Map fields from Roundcube format to internal kolab_format_contact properties
|
||||
*/
|
||||
private function _from_rcube_contact($contact)
|
||||
private function _from_rcube_contact($contact, $old = array())
|
||||
{
|
||||
if (!$contact['uid'] && $contact['ID'])
|
||||
$contact['uid'] = $this->_id2uid($contact['ID']);
|
||||
|
@ -1085,7 +1083,14 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
$contact['_attachments']['photo.attachment'] = false;
|
||||
}
|
||||
|
||||
return $contact;
|
||||
// copy meta data (starting with _) from old object
|
||||
foreach ((array)$old as $key => $val) {
|
||||
if (!isset($contact[$key]) && $key[0] == '_')
|
||||
$contact[$key] = $val;
|
||||
}
|
||||
|
||||
// add empty values for some fields which can be removed in the UI
|
||||
return $contact + array('nickname' => '', 'birthday' => '', 'anniversary' => '', 'freebusyurl' => '');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ abstract class kolab_format
|
|||
{
|
||||
public static $timezone;
|
||||
|
||||
protected $obj;
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Factory method to instantiate a kolab_format object of the given type
|
||||
*/
|
||||
|
@ -42,28 +45,18 @@ abstract class kolab_format
|
|||
return PEAR::raiseError(sprintf("Failed to load Kolab Format wrapper for type %s", $type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random UID for Kolab objects
|
||||
*
|
||||
* @return string UUID with a unique MD5 value
|
||||
*/
|
||||
public static function generate_uid()
|
||||
{
|
||||
return 'urn:uuid:' . md5(uniqid(mt_rand(), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given date/time value into a cDateTime object
|
||||
*
|
||||
* @param mixed Date/Time value either as unix timestamp, date string or PHP DateTime object
|
||||
* @param DateTimeZone The timezone the date/time is in. Use global default if empty
|
||||
* @param boolean True of the given date has no time component
|
||||
* @return object The libkolabxml date/time object or null on error
|
||||
* @return object The libkolabxml date/time object
|
||||
*/
|
||||
public static function get_datetime($datetime, $tz = null, $dateonly = false)
|
||||
{
|
||||
if (!$tz) $tz = self::$timezone;
|
||||
$result = null;
|
||||
$result = new cDateTime();
|
||||
|
||||
if (is_numeric($datetime))
|
||||
$datetime = new DateTime('@'.$datetime, $tz);
|
||||
|
@ -71,7 +64,6 @@ abstract class kolab_format
|
|||
$datetime = new DateTime($datetime, $tz);
|
||||
|
||||
if (is_a($datetime, 'DateTime')) {
|
||||
$result = new cDateTime();
|
||||
$result->setDate($datetime->format('Y'), $datetime->format('n'), $datetime->format('j'));
|
||||
|
||||
if (!$dateonly)
|
||||
|
@ -141,11 +133,34 @@ abstract class kolab_format
|
|||
public static function array2vector($arr)
|
||||
{
|
||||
$vec = new vectors;
|
||||
foreach ((array)$arr as $val)
|
||||
$vec->push($val);
|
||||
foreach ((array)$arr as $val) {
|
||||
if (strlen($val))
|
||||
$vec->push($val);
|
||||
}
|
||||
return $vec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the last generated UID to the object properties.
|
||||
* Should be called after kolabformat::writeXXXX();
|
||||
*/
|
||||
protected function update_uid()
|
||||
{
|
||||
// get generated UID
|
||||
if (!$this->data['uid']) {
|
||||
$this->data['uid'] = kolabformat::getSerializedUID();
|
||||
$this->obj->setUid($this->data['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct getter for object properties
|
||||
*/
|
||||
function __get($var)
|
||||
{
|
||||
return $this->data[$var];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Kolab object data from the given XML block
|
||||
*
|
||||
|
|
|
@ -24,8 +24,10 @@ class kolab_format_contact extends kolab_format
|
|||
'work' => Address::Work,
|
||||
);
|
||||
|
||||
private $data;
|
||||
private $obj;
|
||||
private $gendermap = array(
|
||||
'female' => Contact::Female,
|
||||
'male' => Contact::Male,
|
||||
);
|
||||
|
||||
// old Kolab 2 format field map
|
||||
private $kolab2_fieldmap = array(
|
||||
|
@ -98,7 +100,9 @@ class kolab_format_contact extends kolab_format
|
|||
*/
|
||||
public function write()
|
||||
{
|
||||
return kolabformat::writeContact($this->obj);
|
||||
$xml = kolabformat::writeContact($this->obj);
|
||||
parent::update_uid();
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,18 +113,16 @@ class kolab_format_contact extends kolab_format
|
|||
public function set(&$object)
|
||||
{
|
||||
// set some automatic values if missing
|
||||
if (empty($object['uid']))
|
||||
$object['uid'] = self::generate_uid();
|
||||
|
||||
if (false && !$this->obj->created()) {
|
||||
if (!empty($object['created']))
|
||||
$object['created'] = new DateTime('now', self::$timezone);
|
||||
$this->obj->setCreated(self::get_datetime($object['created']));
|
||||
}
|
||||
|
||||
// do the hard work of setting object values
|
||||
$this->obj->setUid($object['uid']);
|
||||
if (!empty($object['uid']))
|
||||
$this->obj->setUid($object['uid']);
|
||||
|
||||
// do the hard work of setting object values
|
||||
$nc = new NameComponents;
|
||||
$nc->setSurnames(self::array2vector($object['surname']));
|
||||
$nc->setGiven(self::array2vector($object['firstname']));
|
||||
|
@ -130,7 +132,7 @@ class kolab_format_contact extends kolab_format
|
|||
$this->obj->setNameComponents($nc);
|
||||
$this->obj->setName($object['name']);
|
||||
|
||||
if ($object['nickname'])
|
||||
if (isset($object['nickname']))
|
||||
$this->obj->setNickNames(self::array2vector($object['nickname']));
|
||||
|
||||
// organisation related properties (affiliation)
|
||||
|
@ -191,15 +193,15 @@ class kolab_format_contact extends kolab_format
|
|||
}
|
||||
$this->obj->setTelephones($tels);
|
||||
|
||||
if ($object['gender'])
|
||||
$this->obj->setGender($object['gender'] == 'female' ? Contact::Female : Contact::Male);
|
||||
if ($object['notes'])
|
||||
if (isset($object['gender']))
|
||||
$this->obj->setGender($this->gendermap[$object['gender']] ? $this->gendermap[$object['gender']] : Contact::NotSet);
|
||||
if (isset($object['notes']))
|
||||
$this->obj->setNote($object['notes']);
|
||||
if ($object['freebusyurl'])
|
||||
if (isset($object['freebusyurl']))
|
||||
$this->obj->setFreeBusyUrl($object['freebusyurl']);
|
||||
if ($object['birthday'])
|
||||
if (isset($object['birthday']))
|
||||
$this->obj->setBDay(self::get_datetime($object['birthday'], null, true));
|
||||
if ($object['anniversary'])
|
||||
if (isset($object['anniversary']))
|
||||
$this->obj->setAnniversary(self::get_datetime($object['anniversary'], null, true));
|
||||
|
||||
if (!empty($object['photo'])) {
|
||||
|
@ -304,8 +306,9 @@ class kolab_format_contact extends kolab_format
|
|||
if ($anniversary = self::php_datetime($this->obj->anniversary()))
|
||||
$object['anniversary'] = $anniversary->format('c');
|
||||
|
||||
if ($g = $this->obj->gender())
|
||||
$object['gender'] = $g == Contact::Female ? 'female' : 'male';
|
||||
$gendermap = array_flip($this->gendermap);
|
||||
if (($g = $this->obj->gender()) && $gendermap[$g])
|
||||
$object['gender'] = $gendermap[$g];
|
||||
|
||||
if ($this->obj->photoMimetype())
|
||||
$object['photo'] = $this->obj->photo();
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
class kolab_format_distributionlist extends kolab_format
|
||||
{
|
||||
public $CTYPE = 'application/vcard+xml';
|
||||
|
||||
private $data;
|
||||
private $obj;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
|
@ -30,17 +27,17 @@ class kolab_format_distributionlist extends kolab_format
|
|||
*/
|
||||
public function write()
|
||||
{
|
||||
return kolabformat::writeDistlist($this->obj);
|
||||
$xml = kolabformat::writeDistlist($this->obj);
|
||||
parent::update_uid();
|
||||
return $xml;
|
||||
}
|
||||
|
||||
public function set(&$object)
|
||||
{
|
||||
// set some automatic values if missing
|
||||
if (empty($object['uid']))
|
||||
$object['uid'] = self::generate_uid();
|
||||
if (!empty($object['uid']))
|
||||
$this->obj->setUid($object['uid']);
|
||||
|
||||
// do the hard work of setting object values
|
||||
$this->obj->setUid($object['uid']);
|
||||
$this->obj->setName($object['name']);
|
||||
|
||||
$members = new vectormember;
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
class kolab_format_event extends kolab_format
|
||||
{
|
||||
public $CTYPE = 'application/calendar+xml';
|
||||
|
||||
private $data;
|
||||
private $obj;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
|
@ -20,7 +17,9 @@ class kolab_format_event extends kolab_format
|
|||
|
||||
public function write()
|
||||
{
|
||||
return kolabformat::writeEvent($this->obj);
|
||||
$xml = kolabformat::writeEvent($this->obj);
|
||||
parent::update_uid();
|
||||
return $xml;
|
||||
}
|
||||
|
||||
public function set(&$object)
|
||||
|
|
|
@ -44,6 +44,7 @@ class kolab_storage_folder
|
|||
private $imap;
|
||||
private $info;
|
||||
private $owner;
|
||||
private $objcache = array();
|
||||
private $uid2msg = array();
|
||||
|
||||
|
||||
|
@ -239,7 +240,8 @@ class kolab_storage_folder
|
|||
*
|
||||
* @param string The IMAP message UID to fetch
|
||||
* @param string The object type expected
|
||||
* @return array Hash array representing the Kolab object
|
||||
* @param string The folder name where the message is stored
|
||||
* @return mixed Hash array representing the Kolab object, a kolab_format instance or false if not found
|
||||
*/
|
||||
private function read_object($msguid, $type = null, $folder = null)
|
||||
{
|
||||
|
@ -247,6 +249,10 @@ class kolab_storage_folder
|
|||
if (!$folder) $folder = $this->name;
|
||||
$ctype= self::KTYPE_PREFIX . $type;
|
||||
|
||||
// requested message not in local cache
|
||||
if ($this->objcache[$msguid])
|
||||
return $this->objcache[$msguid];
|
||||
|
||||
$this->imap->set_folder($folder);
|
||||
$message = new rcube_message($msguid);
|
||||
$attachments = array();
|
||||
|
@ -296,10 +302,16 @@ class kolab_storage_folder
|
|||
}
|
||||
|
||||
if ($format->is_valid()) {
|
||||
if ($formatobj)
|
||||
return $format;
|
||||
|
||||
$object = $format->to_array();
|
||||
$object['_msguid'] = $msguid;
|
||||
$object['_mailbox'] = $this->name;
|
||||
$object['_attachments'] = $attachments;
|
||||
$object['_formatobj'] = $format;
|
||||
|
||||
$this->objcache[$msguid] = $object;
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
@ -425,11 +437,21 @@ class kolab_storage_folder
|
|||
*/
|
||||
private function build_message(&$object, $type)
|
||||
{
|
||||
$format = kolab_format::factory($type);
|
||||
// load old object to preserve data we don't understand/process
|
||||
if (is_object($object['_formatobj']))
|
||||
$format = $object['_formatobj'];
|
||||
else if ($object['_msguid'] && ($old = $this->read_object($object['_msguid'], $type, $object['_mailbox'])))
|
||||
$format = $old['_formatobj'];
|
||||
|
||||
// create new kolab_format instance
|
||||
if (!$format)
|
||||
$format = kolab_format::factory($type);
|
||||
|
||||
$format->set($object);
|
||||
$xml = $format->write();
|
||||
$object['uid'] = $format->uid; // get read UID from format
|
||||
|
||||
if (!$format->is_valid()) {
|
||||
if (!$format->is_valid() || empty($object['uid'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -450,7 +472,7 @@ class kolab_storage_folder
|
|||
$mime->headers($headers);
|
||||
$mime->setTXTBody('This is a Kolab Groupware object. '
|
||||
. 'To view this object you will need an email client that understands the Kolab Groupware format. '
|
||||
. "For a list of such email clients please visit http://www.kolab.org/kolab2-clients.html\n\n");
|
||||
. "For a list of such email clients please visit http://www.kolab.org/\n\n");
|
||||
|
||||
$mime->addAttachment($xml,
|
||||
$format->CTYPE,
|
||||
|
|
Loading…
Add table
Reference in a new issue