From 40b72003fe3abd8c327476fa58dbb2a84c271281 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 16 Aug 2012 06:02:52 -0400 Subject: [PATCH] Force at least one subtype of address to be specified. Fixes issue where contact address wasn't displayed at all. --- program/include/rcube_ldap.php | 114 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 88 insertions(+), 26 deletions(-) diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index f42abf1..babd34b 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -103,32 +103,60 @@ } // use fieldmap to advertise supported coltypes to the application - foreach ($this->fieldmap as $col => $lf) { - list($col, $type) = explode(':', $col); + foreach ($this->fieldmap as $colv => $lfv) { + list($col, $type) = explode(':', $colv); + list($lf, $limit, $delim) = explode(':', $lfv); + + if ($limit == '*') $limit = null; + else $limit = max(1, intval($limit)); + if (!is_array($this->coltypes[$col])) { $subtypes = $type ? array($type) : null; - $this->coltypes[$col] = array('limit' => 1, 'subtypes' => $subtypes); + $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes); } elseif ($type) { $this->coltypes[$col]['subtypes'][] = $type; - $this->coltypes[$col]['limit']++; + $this->coltypes[$col]['limit'] += $limit; } + + if ($delim) + $this->coltypes[$col]['serialized'][$type] = $delim; + if ($type && !$this->fieldmap[$col]) - $this->fieldmap[$col] = $lf; + $this->fieldmap[$col] = $lf; + + $this->fieldmap[$colv] = $lf; } // support for composite address if ($this->fieldmap['street'] && $this->fieldmap['locality']) { - $this->coltypes['address'] = array('limit' => max(1, $this->coltypes['locality']['limit']), 'subtypes' => $this->coltypes['locality']['subtypes'], 'childs' => array()); + $this->coltypes['address'] = array( + 'limit' => max(1, $this->coltypes['locality']['limit'] + $this->coltypes['address']['limit']), + 'subtypes' => array_merge((array)$this->coltypes['address']['subtypes'], (array)$this->coltypes['locality']['subtypes']), + 'childs' => array(), + ) + (array)$this->coltypes['address']; + foreach (array('street','locality','zipcode','region','country') as $childcol) { if ($this->fieldmap[$childcol]) { $this->coltypes['address']['childs'][$childcol] = array('type' => 'text'); unset($this->coltypes[$childcol]); // remove address child col from global coltypes list } } + + // at least one address type must be specified + if (empty($this->coltypes['address']['subtypes'])) { + $this->coltypes['address']['subtypes'] = array('home'); + } } else if ($this->coltypes['address']) { - $this->coltypes['address'] = array('type' => 'textarea', 'childs' => null, 'limit' => 1, 'size' => 40); + $this->coltypes['address'] += array('type' => 'textarea', 'childs' => null, 'size' => 40); + + // 'serialized' means the UI has to present a composite address field + if ($this->coltypes['address']['serialized']) { + $childprop = array('type' => 'text'); + $this->coltypes['address']['type'] = 'composite'; + $this->coltypes['address']['childs'] = array('street' => $childprop, 'locality' => $childprop, 'zipcode' => $childprop, 'country' => $childprop); + } } // make sure 'required_fields' is an array @@ -993,10 +1021,13 @@ if ($missing) { // try to complete record automatically if ($autofix) { - $reverse_map = array_flip($this->fieldmap); - $name_parts = preg_split('/[\s,.]+/', $save_data['name']); $sn_field = $this->fieldmap['surname']; $fn_field = $this->fieldmap['firstname']; + $mail_field = $this->fieldmap['email']; + + // try to extract surname and firstname from displayname + $reverse_map = array_flip($this->fieldmap); + $name_parts = preg_split('/[\s,.]+/', $save_data['name']); if ($sn_field && $missing[$sn_field]) { $save_data['surname'] = array_pop($name_parts); @@ -1006,6 +1037,16 @@ if ($fn_field && $missing[$fn_field]) { $save_data['firstname'] = array_shift($name_parts); unset($missing[$fn_field]); + } + + // try to fix missing e-mail, very often on import + // from vCard we have email:other only defined + if ($mail_field && $missing[$mail_field]) { + $emails = $this->get_col_values('email', $save_data, true); + if (!empty($emails) && ($email = array_shift($emails))) { + $save_data['email'] = $email; + unset($missing[$mail_field]); + } } } @@ -1109,6 +1150,14 @@ $ldap_data = $this->_map_data($save_cols); $old_data = $record['_raw_attrib']; + // special handling of photo col + if ($photo_fld = $this->fieldmap['photo']) { + // undefined means keep old photo + if (!array_key_exists('photo', $save_cols)) { + $ldap_data[$photo_fld] = $record['photo']; + } + } + foreach ($this->fieldmap as $col => $fld) { if ($fld) { $val = $ldap_data[$fld]; @@ -1120,6 +1169,9 @@ // make sure comparing array with one element with a string works as expected if (is_array($old) && count($old) == 1 && !is_array($val)) { $old = array_pop($old); + } + if (is_array($val) && count($val) == 1 && !is_array($old)) { + $val = array_pop($val); } // Subentries must be handled separately if (!empty($this->prop['sub_fields']) && isset($this->prop['sub_fields'][$fld])) { @@ -1136,6 +1188,7 @@ } continue; } + // The field does exist compare it to the ldap record. if ($old != $val) { // Changed, but find out how. @@ -1146,8 +1199,11 @@ else if ($val == '') { // Field supplied is empty, verify that it is not required. if (!in_array($fld, $this->prop['required_fields'])) { - // It is not, safe to clear. - $deletedata[$fld] = $old_data[$fld]; + // ...It is not, safe to clear. + // #1488420: Workaround "ldap_mod_del(): Modify: Inappropriate matching in..." + // jpegPhoto attribute require an array() here. It looks to me that it works for other attribs too + $deletedata[$fld] = array(); + //$deletedata[$fld] = $old_data[$fld]; } } else { @@ -1157,18 +1213,9 @@ } // end if } // end if } // end foreach -/* - console($old_data); - console($ldap_data); - console('----'); - console($newdata); - console($replacedata); - console($deletedata); - console('----'); - console($subdata); - console($subnewdata); - console($subdeldata); -*/ + + // console($old_data, $ldap_data, '----', $newdata, $replacedata, $deletedata, '----', $subdata, $subnewdata, $subdeldata); + $dn = self::dn_decode($id); // Update the entry as required. @@ -1456,6 +1503,8 @@ $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain); else if (in_array($col, array('street','zipcode','locality','country','region'))) $out['address'.($subtype?':':'').$subtype][$i][$col] = $value; + else if ($col == 'address' && strpos($value, '$') !== false) // address data is represented as string separated with $ + list($out[$rf][$i]['street'], $out[$rf][$i]['locality'], $out[$rf][$i]['zipcode'], $out[$rf][$i]['country']) = explode('$', $value); else if ($rec[$lf]['count'] > 1) $out[$rf][] = $value; else @@ -1498,6 +1547,15 @@ } } } + + // if addresses are to be saved as serialized string, do so + if (is_array($colprop['serialized'])) { + foreach ($colprop['serialized'] as $subtype => $delim) { + $key = $col.':'.$subtype; + foreach ((array)$save_cols[$key] as $i => $val) + $save_cols[$key][$i] = join($delim, array($val['street'], $val['locality'], $val['zipcode'], $val['country'])); + } + } } $ldap_data = array(); @@ -1518,17 +1576,21 @@ /** * Returns unified attribute name (resolving aliases) */ - private static function _attr_name($name) + private static function _attr_name($namev) { // list of known attribute aliases - $aliases = array( + static $aliases = array( 'gn' => 'givenname', 'rfc822mailbox' => 'email', 'userid' => 'uid', 'emailaddress' => 'email', 'pkcs9email' => 'email', ); - return isset($aliases[$name]) ? $aliases[$name] : $name; + + list($name, $limit) = explode(':', $namev, 2); + $suffix = $limit ? ':'.$limit : ''; + + return (isset($aliases[$name]) ? $aliases[$name] : $name) . $suffix; } -- Gitblit v1.9.1