From 39cafac3f5e9cff676b379c1ecb1c847eec558e2 Mon Sep 17 00:00:00 2001 From: thomascube Date: Fri, 7 Oct 2011 11:07:23 +0000 Subject: Autocomplete LDAP records when adding contacts from mail (#1488073) --- CHANGELOG | 1 + program/include/rcube_addressbook.php | 7 +-- program/include/rcube_contacts.php | 7 +-- program/include/rcube_ldap.php | 84 +++++++++++++++++++++++++---------- program/steps/mail/addcontact.inc | 10 +++++ 5 files changed, 80 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 748d9300f..f9c1ff036 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Autocomplete LDAP records when adding contacts from mail (#1488073) - Plugin API: added 'ready' hook (#1488063) - Ignore DSN request when it isn't supported by SMTP server (#1487800) - Make sure LDAP name fields aren't arrays (#1488108) diff --git a/program/include/rcube_addressbook.php b/program/include/rcube_addressbook.php index 94a715bae..88f0aa900 100644 --- a/program/include/rcube_addressbook.php +++ b/program/include/rcube_addressbook.php @@ -30,7 +30,7 @@ abstract class rcube_addressbook /** constants for error reporting **/ const ERROR_READ_ONLY = 1; const ERROR_NO_CONNECTION = 2; - const ERROR_INCOMPLETE = 3; + const ERROR_VALIDATE = 3; const ERROR_SAVING = 4; const ERROR_SEARCH = 5; @@ -182,15 +182,16 @@ abstract class rcube_addressbook * If input isn't valid, the message to display can be fetched using get_error() * * @param array Assoziative array with data to save + * @param boolean Attempt to fix/complete record automatically * @return boolean True if input is valid, False if not. */ - public function validate($save_data) + public function validate(&$save_data, $autofix = false) { // check validity of email addresses foreach ($this->get_col_values('email', $save_data, true) as $email) { if (strlen($email)) { if (!check_email(rcube_idn_to_ascii($email))) { - $this->set_error('warning', rcube_label(array('name' => 'emailformaterror', 'vars' => array('email' => $email)))); + $this->set_error(self::ERROR_VALIDATE, rcube_label(array('name' => 'emailformaterror', 'vars' => array('email' => $email)))); return false; } } diff --git a/program/include/rcube_contacts.php b/program/include/rcube_contacts.php index 3ad53a6db..c810ce60e 100644 --- a/program/include/rcube_contacts.php +++ b/program/include/rcube_contacts.php @@ -500,16 +500,17 @@ class rcube_contacts extends rcube_addressbook * If input not valid, the message to display can be fetched using get_error() * * @param array Assoziative array with data to save + * @param boolean Try to fix/complete record automatically * @return boolean True if input is valid, False if not. */ - public function validate($save_data) + public function validate(&$save_data, $autofix = false) { // validate e-mail addresses - $valid = parent::validate($save_data); + $valid = parent::validate($save_data, $autofix); // require at least one e-mail address (syntax check is already done) if ($valid && !array_filter($this->get_col_values('email', $save_data, true))) { - $this->set_error('warning', 'noemailwarning'); + $this->set_error(self::ERROR_VALIDATE, 'noemailwarning'); $valid = false; } diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index a3f6dc56d..3af343f2d 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -448,13 +448,6 @@ class rcube_ldap extends rcube_addressbook return $this->result; } - // add general filter to query - if (!empty($this->prop['filter']) && empty($this->filter)) - { - $filter = $this->prop['filter']; - $this->set_search_set($filter); - } - // query URL is given by the selected group if ($this->group_id && $this->group_url) { @@ -463,10 +456,14 @@ class rcube_ldap extends rcube_addressbook { $this->base_dn = $m[1]; $this->prop['scope'] = $m[2]; - $this->filter = $m[3]; + $this->filter = $this->filter ? '(&(' . $m[3] . ')(' . $this->filter . '))' : $m[3]; } } + // add general filter to query + if (!empty($this->prop['filter']) && empty($this->filter)) + $this->set_search_set($this->prop['filter']); + // exec LDAP search if no result resource is stored if ($this->conn && !$this->ldap_result) $this->_exec_search(); @@ -689,19 +686,49 @@ class rcube_ldap extends rcube_addressbook * If input not valid, the message to display can be fetched using get_error() * * @param array Assoziative array with data to save - * + * @param boolean Try to fix/complete record automatically * @return boolean True if input is valid, False if not. */ - public function validate($save_data) + public function validate(&$save_data, $autofix = false) { // check for name input if (empty($save_data['name'])) { - $this->set_error('warning', 'nonamewarning'); + $this->set_error(self::ERROR_VALIDATE, 'nonamewarning'); + return false; + } + + // Verify that the required fields are set. + $missing = null; + $ldap_data = $this->_map_data($save_data); + foreach ($this->prop['required_fields'] as $fld) { + if (!isset($ldap_data[$fld])) { + $missing[$fld] = 1; + } + } + + if ($missing) { + // try to complete record automatically + if ($autofix) { + $reverse_map = array_flip($this->fieldmap); + $name_parts = preg_split('/[\s,.]+/', $save_data['name']); + if ($missing['sn']) { + $sn_field = $reverse_map['sn']; + $save_data[$sn_field] = array_pop ($name_parts); + } + if ($missing[($fn_field = $this->fieldmap['firstname'])]) { + $save_data['firstname'] = array_shift($name_parts); + } + + return $this->validate($save_data, false); + } + + // TODO: generate message saying which fields are missing + $this->set_error(self::ERROR_VALIDATE, 'formincomplete'); return false; } // validate e-mail addresses - return parent::validate($save_data); + return parent::validate($save_data, $autofix); } @@ -715,17 +742,8 @@ class rcube_ldap extends rcube_addressbook function insert($save_cols) { // Map out the column names to their LDAP ones to build the new entry. - $newentry = array(); + $newentry = $this->_map_data($save_cols); $newentry['objectClass'] = $this->prop['LDAP_Object_Classes']; - foreach ($this->fieldmap as $col => $fld) { - $val = $save_cols[$col]; - if (is_array($val)) - $val = array_filter($val); // remove empty entries - if ($fld && $val) { - // The field does exist, add it to the entry. - $newentry[$fld] = $val; - } // end if - } // end foreach // Verify that the required fields are set. $missing = null; @@ -738,7 +756,7 @@ class rcube_ldap extends rcube_addressbook // abort process if requiered fields are missing // TODO: generate message saying which fields are missing if ($missing) { - $this->set_error(self::ERROR_INCOMPLETE, 'formincomplete'); + $this->set_error(self::ERROR_VALIDATE, 'formincomplete'); return false; } @@ -1051,6 +1069,26 @@ class rcube_ldap extends rcube_addressbook } + /** + * Convert a record data set into LDAP field attributes + */ + private function _map_data($save_cols) + { + $ldap_data = array(); + foreach ($this->fieldmap as $col => $fld) { + $val = $save_cols[$col]; + if (is_array($val)) + $val = array_filter($val); // remove empty entries + if ($fld && $val) { + // The field does exist, add it to the entry. + $ldap_data[$fld] = $val; + } + } + + return $ldap_data; + } + + /** * Returns unified attribute name (resolving aliases) */ diff --git a/program/steps/mail/addcontact.inc b/program/steps/mail/addcontact.inc index b74d95faa..dafb2763c 100644 --- a/program/steps/mail/addcontact.inc +++ b/program/steps/mail/addcontact.inc @@ -60,6 +60,16 @@ if (!empty($_POST['_address']) && is_object($CONTACTS)) $contact['email'] = rcube_idn_to_utf8($contact['email']); $contact['name'] = rcube_addressbook::compose_display_name($contact); + // validate contact record + if (!$CONTACTS->validate($contact, true)) { + $error = $CONTACTS->get_error(); + // TODO: show dialog to complete record + // if ($error['type'] == rcube_addressbook::ERROR_VALIDATE) { } + + $OUTPUT->show_message($error['message'] ? $error['message'] : 'errorsavingcontact', 'error'); + $OUTPUT->send(); + } + // check for existing contacts $existing = $CONTACTS->search('email', $contact['email'], true, false); -- cgit v1.2.3