diff --git a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php index 359d8ada..d4b5c06a 100644 --- a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php +++ b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php @@ -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; } diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php index daef994f..b93615e9 100644 --- a/plugins/libkolab/lib/kolab_format_contact.php +++ b/plugins/libkolab/lib/kolab_format_contact.php @@ -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; + } + } + } + } } diff --git a/plugins/libkolab/lib/kolab_format_distributionlist.php b/plugins/libkolab/lib/kolab_format_distributionlist.php index 84771765..9fe28c19 100644 --- a/plugins/libkolab/lib/kolab_format_distributionlist.php +++ b/plugins/libkolab/lib/kolab_format_distributionlist.php @@ -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(), ); } diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index 2e50753a..0ac475c8 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -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]); + } } }