Adapt to recent changes in libkolabxml:

- store manager, assistant, spouse and children in Related objects
- add support for both uid and mailto distlist members
- fix contact photo transition from old Kolab2 format
This commit is contained in:
Thomas B 2012-03-20 23:51:43 +01:00
parent 824c89b326
commit 88d6ce9500
4 changed files with 140 additions and 58 deletions

View file

@ -47,8 +47,8 @@ class rcube_kolab_contacts extends rcube_addressbook
'email' => array('subtypes' => null),
'phone' => array(),
'address' => array('subtypes' => array('home','work')),
'officelocation' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1,
'label' => 'kolab_addressbook.officelocation', 'category' => 'main'),
// 'officelocation' => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1,
// 'label' => 'kolab_addressbook.officelocation', 'category' => 'main'),
'website' => array('subtypes' => null),
'im' => array('subtypes' => null),
'gender' => array('limit' => 1),
@ -58,10 +58,10 @@ class rcube_kolab_contacts extends rcube_addressbook
'anniversary' => array('limit' => 1),
'profession' => array('type' => 'text', 'size' => 40, 'maxlength' => 80, 'limit' => 1,
'label' => 'kolab_addressbook.profession', 'category' => 'personal'),
'manager' => array('limit' => 1),
'assistant' => array('limit' => 1),
'manager' => array('limit' => null),
'assistant' => array('limit' => null),
'spouse' => array('limit' => 1),
'children' => array('type' => 'text', 'size' => 40, 'maxlength' => 80, 'limit' => 1,
'children' => array('type' => 'text', 'size' => 40, 'maxlength' => 80, 'limit' => null,
'label' => 'kolab_addressbook.children', 'category' => 'personal'),
'pgppublickey' => array('type' => 'text', 'size' => 40, 'limit' => 1,
'label' => 'kolab_addressbook.pgppublickey'),
@ -69,7 +69,7 @@ class rcube_kolab_contacts extends rcube_addressbook
'label' => 'kolab_addressbook.freebusyurl'),
'notes' => array(),
'photo' => array(),
// TODO: define more Kolab-specific fields such as: role, language, latitude, longitude
// TODO: define more Kolab-specific fields such as: language, latitude, longitude
);
/**
@ -257,11 +257,14 @@ class rcube_kolab_contacts extends rcube_addressbook
if (is_array($this->filter['ids']) && array_search($member['ID'], $this->filter['ids']) === false)
continue;
$contact = $this->storagefolder->get_object($member['uid']);
if ($contact && !$seen[$member['ID']]++) {
if ($member['uid'] && ($contact = $this->storagefolder->get_object($member['uid'])) && !$seen[$member['ID']]++) {
$this->contacts[$member['ID']] = $this->_to_rcube_contact($contact);
$this->result->count++;
}
else if ($member['email'] && !$seen[$member['ID']]++) {
$this->contacts[$member['ID']] = $member;
$this->result->count++;
}
}
$ids = array_keys($seen);
}
@ -458,8 +461,18 @@ class rcube_kolab_contacts extends rcube_addressbook
*/
public function get_record($id, $assoc=false)
{
if ($object = $this->storagefolder->get_object($this->_id2uid($id))) {
$rec = null;
$uid = $this->_id2uid($id);
if (strpos($uid, 'mailto:') === 0) {
$this->_fetch_groups(true);
$rec = $this->contacts[$id];
$this->readonly = true; // set source to read-only
}
else if ($object = $this->storagefolder->get_object($uid)) {
$rec = $this->_to_rcube_contact($object);
}
if ($rec) {
$this->result = new rcube_result_set(1);
$this->result->add($rec);
return $assoc ? $rec : $this->result;
@ -592,19 +605,22 @@ class rcube_kolab_contacts extends rcube_addressbook
$count = 0;
foreach ($ids as $id) {
if ($uid = $this->_id2uid($id)) {
$deleted = $this->storagefolder->delete($uid, $force);
$is_mailto = strpos($uid, 'mailto:') === 0;
$deleted = $is_mailto || $this->storagefolder->delete($uid, $force);
if (!$deleted) {
raise_error(array(
'code' => 600, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Error deleting a contact object from the Kolab server"),
'message' => "Error deleting a contact object $uid from the Kolab server"),
true, false);
}
else {
// remove from distribution lists
foreach ((array)$this->groupmembers[$id] as $gid)
$this->remove_from_group($gid, $id);
foreach ((array)$this->groupmembers[$id] as $gid) {
if (!$is_mailto || $gid == $this->gid)
$this->remove_from_group($gid, $id);
}
// clear internal cache
unset($this->contacts[$id], $this->groupmembers[$id]);
@ -776,7 +792,7 @@ class rcube_kolab_contacts extends rcube_addressbook
$added = 0;
$exists = array();
$this->_fetch_groups();
$this->_fetch_groups(true);
$list = $this->distlists[$gid];
foreach ((array)$list['member'] as $i => $member)
@ -786,16 +802,24 @@ class rcube_kolab_contacts extends rcube_addressbook
$ids = array_diff($ids, $exists);
foreach ($ids as $contact_id) {
if ($uid = $this->_id2uid($contact_id)) {
$contact = $this->storagefolder->get_object($uid);
foreach ($this->get_col_values('email', $contact, true) as $email) {
$list['member'][] = array(
'uid' => $uid,
'mailto' => $email,
'name' => $contact['name'],
);
$uid = $this->_id2uid($contact_id);
if ($contact = $this->storagefolder->get_object($uid)) {
foreach ($this->get_col_values('email', $contact, true) as $email)
break;
}
$list['member'][] = array(
'uid' => $uid,
'email' => $email,
'name' => $contact['name'],
);
$this->groupmembers[$contact_id][] = $gid;
$added++;
}
else if (strpos($uid, 'mailto:') === 0 && ($contact = $this->contacts[$contact_id])) {
$list['member'][] = array(
'email' => $contact['email'],
'name' => $contact['name'],
);
$this->groupmembers[$contact_id][] = $gid;
$added++;
}
@ -953,16 +977,20 @@ class rcube_kolab_contacts extends rcube_addressbook
/**
* Read distribution-lists AKA groups from server
*/
private function _fetch_groups()
private function _fetch_groups($with_contacts = false)
{
if (!isset($this->distlists)) {
$this->distlists = $this->groupmembers = array();
foreach ((array)$this->storagefolder->get_objects('distribution-list') as $record) {
$record['ID'] = $this->_uid2id($record['uid']);
foreach ((array)$record['member'] as $i => $member) {
$mid = $this->_uid2id($member['uid']);
$mid = $this->_uid2id($member['uid'] ? $member['uid'] : 'mailto:' . $member['email']);
$record['member'][$i]['ID'] = $mid;
$record['member'][$i]['readonly'] = empty($member['uid']);
$this->groupmembers[$mid][] = $record['ID'];
if ($with_contacts && empty($member['uid']))
$this->contacts[$mid] = $record['member'][$i];
}
$this->distlists[$record['ID']] = $record;
}

View file

@ -47,7 +47,14 @@ class kolab_format_contact extends kolab_format
private $gendermap = array(
'female' => Contact::Female,
'male' => Contact::Male,
'male' => Contact::Male,
);
private $relatedmap = array(
'manager' => Related::Manager,
'assistant' => Related::Assistant,
'spouse' => Related::Spouse,
'children' => Related::Child,
);
// old Kolab 2 format field map
@ -160,15 +167,23 @@ class kolab_format_contact extends kolab_format
$org = new Affiliation;
if ($object['organization'])
$org->setOrganisation($object['organization']);
if ($object['department'])
$org->setOrganisationalUnits(self::array2vector($object['department']));
if ($object['jobtitle'])
$org->setTitles(self::array2vector($object['jobtitle']));
if ($object['officelocation'])
$org->setOffices(self::array2vector($object['officelocation']));
if ($object['manager'])
$org->setManagers(self::array2vector($object['manager']));
if ($object['assistant'])
$org->setAssistants(self::array2vector($object['assistant']));
// department ?
$org->setRoles(self::array2vector($object['jobtitle']));
// if ($object['officelocation'])
// $org->setOffices(self::array2vector($object['officelocation']));
$rels = new vectorrelated;
if ($object['manager']) {
foreach ((array)$object['manager'] as $manager)
$rels->push(new Related(Related::Text, $manager, Related::Manager));
}
if ($object['assistant']) {
foreach ((array)$object['assistant'] as $assistant)
$rels->push(new Related(Related::Text, $assistant, Related::Assistant));
}
$org->setRelateds($rels);
$orgs = new vectoraffiliation;
$orgs->push($org);
@ -226,21 +241,26 @@ class kolab_format_contact extends kolab_format
$this->obj->setAnniversary(self::get_datetime($object['anniversary'], null, true));
if (!empty($object['photo'])) {
if (strlen($object['photo']) < 255 && ($att = $object['_attachments'][$object['photo']])) {
if ($att['content'])
$this->obj->setPhoto($att['content'], $att['type']);
$object['_attachments'][$object['photo']] = false;
}
else if ($type = rc_image_content_type($object['photo'])) {
if ($type = rc_image_content_type($object['photo']))
$this->obj->setPhoto($object['photo'], $type);
$object['_attachments']['photo.attachment'] = false;
}
}
else if (isset($object['photo'])) {
$this->obj->setPhoto('','');
}
// TODO: handle spouse, children, profession, initials, pgppublickey, etc.
// spouse and children are relateds
$rels = new vectorrelated;
if ($object['spouse']) {
$rels->push(new Related(Related::Text, $object['spouse'], Related::Spouse));
}
if ($object['children']) {
foreach ((array)$object['children'] as $child)
$rels->push(new Related(Related::Text, $child, Related::Child));
}
$this->obj->setRelateds($rels);
// TODO: handle profession, language, pgppublickey, etc.
// cache this data
$this->data = $object;
@ -285,10 +305,10 @@ class kolab_format_contact extends kolab_format
if ($orgs->size()) {
$org = $orgs->get(0);
$object['organization'] = $org->organisation();
$object['jobtitle'] = join(' ', self::vector2array($org->titles()));
$object['manager'] = join(' ', self::vector2array($org->managers()));
$object['assistant'] = join(' ', self::vector2array($org->assistants()));
$object['officelocation'] = join(' ', self::vector2array($org->offices()));
$object['jobtitle'] = join(' ', self::vector2array($org->roles()));
// $object['officelocation'] = join(' ', self::vector2array($org->offices()));
$object['department'] = join(' ', self::vector2array($org->organisationalUnits()));
$this->read_relateds($org->relateds(), $object);
}
$object['email'] = self::vector2array($this->obj->emailAddresses());
@ -334,6 +354,9 @@ class kolab_format_contact extends kolab_format
if ($this->obj->photoMimetype())
$object['photo'] = $this->obj->photo();
// relateds -> spouse, children
$this->read_relateds($this->obj->relateds(), $object);
$this->data = $object;
return $this->data;
}
@ -381,4 +404,26 @@ class kolab_format_contact extends kolab_format
// remove empty fields
$this->data = array_filter($object);
}
/**
* Helper method to map contents of a Related vector to the contact data object
*/
private function read_relateds($rels, &$object)
{
$typemap = array_flip($this->relatedmap);
for ($i=0; $i < $rels->size(); $i++) {
$rel = $rels->get($i);
if ($rel->type() != Related::Text) // we can't handle UID relations yet
continue;
$types = $rel->relationTypes();
foreach ($typemap as $t => $field) {
if ($types & $t) {
$object[$field][] = $rel->text();
break;
}
}
}
}
}

View file

@ -61,14 +61,21 @@ class kolab_format_distributionlist extends kolab_format
$this->obj->setName($object['name']);
$members = new vectormember;
$seen = array();
$members = new vectorcontactref;
foreach ($object['member'] as $member) {
$m = new Member;
if ($member['uid'])
$m = new ContactReference(ContactReference::UidReference, $member['uid']);
else if ($member['email'])
$m = new ContactReference(ContactReference::EmailReference, $member['email']);
else
continue;
$m->setName($member['name']);
$m->setEmail($member['mailto']);
$m->setUid($member['uid']);
$members->push($m);
$seen[$member['email']]++;
}
$this->obj->setMembers($members);
}
@ -91,7 +98,7 @@ class kolab_format_distributionlist extends kolab_format
foreach ($record['member'] as $member) {
$object['member'][] = array(
'mailto' => $member['smtp-address'],
'email' => $member['smtp-address'],
'name' => $member['display-name'],
'uid' => $member['uid'],
);
@ -122,11 +129,11 @@ class kolab_format_distributionlist extends kolab_format
$members = $this->obj->members();
for ($i=0; $i < $members->size(); $i++) {
$member = $members->get($i);
if ($mailto = $member->email())
# if ($member->type() == ContactReference::UidReference && ($uid = $member->uid()))
$object['member'][] = array(
'mailto' => $mailto,
'name' => $member->name(),
'uid' => $member->uid(),
'email' => $member->email(),
'name' => $member->name(),
);
}

View file

@ -338,9 +338,11 @@ class kolab_storage_folder
if (!isset($object['_attachments'][$name])) {
$object['_attachments'][$name] = $old['_attachments'][$name];
}
// load photo.attachment contents to be directly embedded in xcard block
if ($name == 'photo.attachment' && !$object['_attachments'][$name]['content'] && $att['key'])
$object['_attachments'][$name]['content'] = $this->get_attachment($object['_msguid'], $att['key'], $object['_mailbox']);
// load photo.attachment from old Kolab2 format to be directly embedded in xcard block
if ($name == 'photo.attachment' && !isset($object['photo']) && !$object['_attachments'][$name]['content'] && $att['key']) {
$object['photo'] = $this->get_attachment($object['_msguid'], $att['key'], $object['_mailbox']);
unset($object['_attachments'][$name]);
}
}
}