summaryrefslogtreecommitdiff
path: root/program
diff options
context:
space:
mode:
Diffstat (limited to 'program')
-rw-r--r--program/include/rcube_addressbook.php5
-rw-r--r--program/include/rcube_ldap.php59
-rw-r--r--program/include/rcube_vcard.php24
-rw-r--r--program/js/app.js26
-rw-r--r--program/localization/en_US/labels.inc3
-rw-r--r--program/steps/mail/func.inc88
-rw-r--r--program/steps/settings/folders.inc60
7 files changed, 183 insertions, 82 deletions
diff --git a/program/include/rcube_addressbook.php b/program/include/rcube_addressbook.php
index f4f255322..892ae263a 100644
--- a/program/include/rcube_addressbook.php
+++ b/program/include/rcube_addressbook.php
@@ -434,6 +434,11 @@ abstract class rcube_addressbook
}
}
+ // remove duplicates
+ if ($flat && !empty($out)) {
+ $out = array_unique($out);
+ }
+
return $out;
}
diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php
index ad2ccddeb..b9b6490fa 100644
--- a/program/include/rcube_ldap.php
+++ b/program/include/rcube_ldap.php
@@ -109,24 +109,22 @@ class rcube_ldap extends rcube_addressbook
if (!is_array($this->coltypes[$col])) {
$subtypes = $type ? array($type) : null;
- $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes);
+ $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes, 'attributes' => array($lf));
}
elseif ($type) {
$this->coltypes[$col]['subtypes'][] = $type;
+ $this->coltypes[$col]['attributes'][] = $lf;
$this->coltypes[$col]['limit'] += $limit;
}
if ($delim)
$this->coltypes[$col]['serialized'][$type] = $delim;
- if ($type && !$this->fieldmap[$col])
- $this->fieldmap[$col] = $lf;
-
- $this->fieldmap[$colv] = $lf;
+ $this->fieldmap[$colv] = $lf;
}
// support for composite address
- if ($this->fieldmap['street'] && $this->fieldmap['locality']) {
+ if ($this->coltypes['street'] && $this->coltypes['locality']) {
$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']),
@@ -134,7 +132,7 @@ class rcube_ldap extends rcube_addressbook
) + (array)$this->coltypes['address'];
foreach (array('street','locality','zipcode','region','country') as $childcol) {
- if ($this->fieldmap[$childcol]) {
+ if ($this->coltypes[$childcol]) {
$this->coltypes['address']['childs'][$childcol] = array('type' => 'text');
unset($this->coltypes[$childcol]); // remove address child col from global coltypes list
}
@@ -468,8 +466,8 @@ class rcube_ldap extends rcube_addressbook
*/
function set_sort_order($sort_col, $sort_order = null)
{
- if ($this->fieldmap[$sort_col])
- $this->sort_col = $this->fieldmap[$sort_col];
+ if ($this->coltypes[$sort_col]['attributes'])
+ $this->sort_col = $this->coltypes[$sort_col]['attributes'][0];
}
@@ -858,8 +856,13 @@ class rcube_ldap extends rcube_addressbook
{
foreach ((array)$fields as $idx => $field) {
$val = is_array($value) ? $value[$idx] : $value;
- if ($f = $this->_map_field($field)) {
- $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)";
+ if ($attrs = $this->_map_field($field)) {
+ if (count($attrs) > 1)
+ $filter .= '(|';
+ foreach ($attrs as $f)
+ $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)";
+ if (count($attrs) > 1)
+ $filter .= ')';
}
}
}
@@ -867,9 +870,16 @@ class rcube_ldap extends rcube_addressbook
// add required (non empty) fields filter
$req_filter = '';
- foreach ((array)$required as $field)
- if ($f = $this->_map_field($field))
- $req_filter .= "($f=*)";
+ foreach ((array)$required as $field) {
+ if ($attrs = $this->_map_field($field)) {
+ if (count($attrs) > 1)
+ $req_filter .= '(|';
+ foreach ($attrs as $f)
+ $req_filter .= "($f=*)";
+ if (count($attrs) > 1)
+ $req_filter .= ')';
+ }
+ }
if (!empty($req_filter))
$filter = '(&' . $req_filter . $filter . ')';
@@ -1498,7 +1508,7 @@ class rcube_ldap extends rcube_addressbook
list($col, $subtype) = explode(':', $rf);
$out['_raw_attrib'][$lf][$i] = $value;
- if ($rf == 'email' && $this->mail_domain && !strpos($value, '@'))
+ if ($col == 'email' && $this->mail_domain && !strpos($value, '@'))
$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;
@@ -1521,11 +1531,11 @@ class rcube_ldap extends rcube_addressbook
/**
- * Return real field name (from fields map)
+ * Return LDAP attribute(s) for the given field
*/
private function _map_field($field)
{
- return $this->fieldmap[$field];
+ return (array)$this->coltypes[$field]['attributes'];
}
@@ -1558,8 +1568,19 @@ class rcube_ldap extends rcube_addressbook
}
$ldap_data = array();
- foreach ($this->fieldmap as $col => $fld) {
- $val = $save_cols[$col];
+ foreach ($this->fieldmap as $rf => $fld) {
+ $val = $save_cols[$rf];
+
+ // check for value in base field (eg.g email instead of email:foo)
+ list($col, $subtype) = explode(':', $rf);
+ if (!$val && !empty($save_cols[$col])) {
+ $val = $save_cols[$col];
+ unset($save_cols[$col]); // only use this value once
+ }
+ else if (!$val && !$subtype) { // extract values from subtype cols
+ $val = $this->get_col_values($col, $save_cols, true);
+ }
+
if (is_array($val))
$val = array_filter($val); // remove empty entries
if ($fld && $val) {
diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php
index 49b312c5c..00903c257 100644
--- a/program/include/rcube_vcard.php
+++ b/program/include/rcube_vcard.php
@@ -50,7 +50,7 @@ class rcube_vcard
'spouse' => 'X-SPOUSE',
'edit' => 'X-AB-EDIT',
);
- private $typemap = array('iPhone' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax');
+ private $typemap = array('IPHONE' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax');
private $phonetypemap = array('HOME1' => 'HOME', 'BUSINESS1' => 'WORK', 'BUSINESS2' => 'WORK2', 'BUSINESSFAX' => 'WORK,FAX');
private $addresstypemap = array('BUSINESS' => 'WORK');
private $immap = array('X-JABBER' => 'jabber', 'X-ICQ' => 'icq', 'X-MSN' => 'msn', 'X-AIM' => 'aim', 'X-YAHOO' => 'yahoo', 'X-SKYPE' => 'skype', 'X-SKYPE-USERNAME' => 'skype');
@@ -159,7 +159,18 @@ class rcube_vcard
if (!empty($raw['type'])) {
$combined = join(',', self::array_filter((array)$raw['type'], 'internet,pref', true));
- $subtype = $typemap[$combined] ? $typemap[$combined] : ($typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]));
+ $combined = strtoupper($combined);
+
+ if ($typemap[$combined]) {
+ $subtype = $typemap[$combined];
+ }
+ else if ($typemap[$raw['type'][++$k]]) {
+ $subtype = $typemap[$raw['type'][$k]];
+ }
+ else {
+ $subtype = strtolower($raw['type'][$k]);
+ }
+
while ($k < count($raw['type']) && ($subtype == 'internet' || $subtype == 'pref'))
$subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]);
}
@@ -167,8 +178,11 @@ class rcube_vcard
// read vcard 2.1 subtype
if (!$subtype) {
foreach ($raw as $k => $v) {
- if (!is_numeric($k) && $v === true && !in_array(strtolower($k), array('pref','internet','voice','base64'))) {
- $subtype = $typemap[$k] ? $typemap[$k] : strtolower($k);
+ if (!is_numeric($k) && $v === true && ($k = strtolower($k))
+ && !in_array($k, array('pref','internet','voice','base64'))
+ ) {
+ $k_uc = strtoupper($k);
+ $subtype = $typemap[$k_uc] ? $typemap[$k_uc] : $k;
break;
}
}
@@ -335,7 +349,7 @@ class rcube_vcard
$index = count($this->raw[$tag]);
$this->raw[$tag][$index] = (array)$value;
if ($type)
- $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type] ? $typemap[$type] : $type));
+ $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type));
}
break;
}
diff --git a/program/js/app.js b/program/js/app.js
index 4d784e532..06eb9295c 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -5624,6 +5624,32 @@ function rcube_webmail()
this.messages = {};
};
+ // open a jquery UI dialog with the given content
+ this.show_popup_dialog = function(html, title)
+ {
+ // forward call to parent window
+ if (this.is_framed()) {
+ parent.rcmail.show_popup_dialog(html, title);
+ return;
+ }
+
+ var popup = $('<div class="popup">')
+ .html(html)
+ .dialog({
+ title: title,
+ modal: true,
+ resizable: true,
+ width: 580,
+ close: function(event, ui) { $(this).remove() }
+ });
+
+ // resize and center popup
+ var win = $(window), w = win.width(), h = win.height(),
+ width = popup.width(), height = popup.height();
+ popup.dialog('option', { height: Math.min(h-40, height+50), width: Math.min(w-20, width+50) })
+ .dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?)
+ };
+
// enable/disable buttons for page shifting
this.set_page_buttons = function()
{
diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc
index 9882c19b5..fbc154b88 100644
--- a/program/localization/en_US/labels.inc
+++ b/program/localization/en_US/labels.inc
@@ -236,6 +236,9 @@ $labels['nosubject'] = '(no subject)';
$labels['showimages'] = 'Display images';
$labels['alwaysshow'] = 'Always show images from $sender';
$labels['isdraft'] = 'This is a draft message.';
+$labels['andnmore'] = '$nr more...';
+$labels['togglemoreheaders'] = 'Show more message headers';
+$labels['togglefullheaders'] = 'Toggle raw message headers';
$labels['htmltoggle'] = 'HTML';
$labels['plaintoggle'] = 'Plain text';
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 8bf80a6ee..e3866aa57 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -319,7 +319,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
$col_name = $col == 'fromto' ? $smart_col : $col;
if (in_array($col_name, array('from', 'to', 'cc', 'replyto')))
- $cont = Q(rcmail_address_string($header->$col_name, 3, false, null, $header->charset), 'show');
+ $cont = rcmail_address_string($header->$col_name, 3, false, null, $header->charset);
else if ($col == 'subject') {
$cont = trim(rcube_mime::decode_header($header->$col, $header->charset));
if (!$cont) $cont = rcube_label('nosubject');
@@ -957,6 +957,8 @@ function rcmail_message_headers($attrib, $headers=NULL)
$output_headers = array();
foreach ($standard_headers as $hkey) {
+ $ishtml = false;
+
if ($headers[$hkey])
$value = $headers[$hkey];
else if ($headers['others'][$hkey])
@@ -967,6 +969,8 @@ function rcmail_message_headers($attrib, $headers=NULL)
if (in_array($hkey, $exclude_headers))
continue;
+ $header_title = rcube_label(preg_replace('/(^mail-|-)/', '', $hkey));
+
if ($hkey == 'date') {
if ($PRINT_MODE)
$header_value = format_date($value, $RCMAIL->config->get('date_long', 'x'));
@@ -981,32 +985,41 @@ function rcmail_message_headers($attrib, $headers=NULL)
continue;
}
else if ($hkey == 'replyto') {
- if ($headers['replyto'] != $headers['from'])
- $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']);
+ if ($headers['replyto'] != $headers['from']) {
+ $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title);
+ $ishtml = true;
+ }
else
continue;
}
else if ($hkey == 'mail-reply-to') {
if ($headers['mail-replyto'] != $headers['reply-to']
&& $headers['reply-to'] != $headers['from']
- )
- $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']);
+ ) {
+ $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title);
+ $ishtml = true;
+ }
else
continue;
}
else if ($hkey == 'mail-followup-to') {
- $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']);
+ $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title);
+ $ishtml = true;
+ }
+ else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) {
+ $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title);
+ $ishtml = true;
}
- else if (in_array($hkey, array('from', 'to', 'cc', 'bcc')))
- $header_value = rcmail_address_string($value, null, true, $attrib['addicon'], $headers['charset']);
else if ($hkey == 'subject' && empty($value))
$header_value = rcube_label('nosubject');
else
$header_value = trim(rcube_mime::decode_header($value, $headers['charset']));
$output_headers[$hkey] = array(
- 'title' => rcube_label(preg_replace('/(^mail-|-)/', '', $hkey)),
- 'value' => $header_value, 'raw' => $value
+ 'title' => $header_title,
+ 'value' => $header_value,
+ 'raw' => $value,
+ 'html' => $ishtml,
);
}
@@ -1022,7 +1035,7 @@ function rcmail_message_headers($attrib, $headers=NULL)
foreach ($plugin['output'] as $hkey => $row) {
$table->add(array('class' => 'header-title'), Q($row['title']));
- $table->add(array('class' => 'header '.$hkey), Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show')));
+ $table->add(array('class' => 'header '.$hkey), $row['html'] ? $row['value'] : Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show')));
}
return $table->show($attrib);
@@ -1055,17 +1068,12 @@ function rcmail_message_full_headers($attrib, $headers=NULL)
global $OUTPUT;
$html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), ''));
-
- if (!get_boolean($attrib['no-switch'])) {
- $html .= html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('show-headers','',this)"), '');
- }
-
- unset($attrib['no-switch']);
+ $html .= html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('show-headers','',this)", 'title' => rcube_label('togglefullheaders')), '');
$OUTPUT->add_gui_object('all_headers_row', 'all-headers');
$OUTPUT->add_gui_object('all_headers_box', 'headers-source');
- return count($attrib) > 1 ? html::div($attrib, $html) : $html;
+ return html::div($attrib, $html);
}
@@ -1399,7 +1407,7 @@ function rcmail_alter_html_link($matches)
/**
* decode address string and re-format it as HTML links
*/
-function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $default_charset=null)
+function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $default_charset=null, $title=null)
{
global $RCMAIL, $PRINT_MODE, $CONFIG;
@@ -1411,6 +1419,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
$c = count($a_parts);
$j = 0;
$out = '';
+ $allvalues = array();
if ($addicon && !isset($_SESSION['writeable_abook'])) {
$_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false;
@@ -1418,7 +1427,6 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
foreach ($a_parts as $part) {
$j++;
-
$name = $part['name'];
$mailto = $part['mailto'];
$string = $part['string'];
@@ -1449,7 +1457,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
}
if ($addicon && $_SESSION['writeable_abook']) {
- $address = html::span(null, $address . html::a(array(
+ $address .= html::a(array(
'href' => "#add",
'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, $string),
'title' => rcube_label('addtoaddressbook'),
@@ -1458,26 +1466,46 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
html::img(array(
'src' => $CONFIG['skin_path'] . $addicon,
'alt' => "Add contact",
- ))));
+ )));
}
- $out .= $address;
}
else {
+ $address = '';
if ($name)
- $out .= Q($name);
+ $address .= Q($name);
if ($mailto)
- $out .= (strlen($out) ? ' ' : '') . sprintf('&lt;%s&gt;', Q($mailto));
+ $address .= (strlen($address) ? ' ' : '') . sprintf('&lt;%s&gt;', Q($mailto));
}
- if ($c>$j)
- $out .= ','.($max ? '&nbsp;' : ' ');
+ $address = html::span('adr', $address);
+ $allvalues[] = $address;
- if ($max && $j==$max && $c>$j) {
- $out .= '...';
- break;
+ if (!$moreadrs)
+ $out .= ($out ? ', ' : '') . $address;
+
+ if ($max && $j == $max && $c > $j) {
+ if ($linked) {
+ $moreadrs = $c - $j;
+ }
+ else {
+ $out .= '...';
+ break;
+ }
}
}
+ if ($moreadrs) {
+ $out .= ' ' . html::a(array(
+ 'href' => '#more',
+ 'class' => 'morelink',
+ 'onclick' => sprintf("return %s.show_popup_dialog('%s','%s')",
+ JS_OBJECT_NAME,
+ JQ(join(', ', $allvalues)),
+ JQ($title))
+ ),
+ Q(rcube_label(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs)))));
+ }
+
return $out;
}
diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc
index 3231ed644..12e449e80 100644
--- a/program/steps/settings/folders.inc
+++ b/program/steps/settings/folders.inc
@@ -299,40 +299,44 @@ function rcube_subscription_form($attrib)
$disabled = (($protected && $subscribed) || $noselect);
- // check if the folder is a namespace prefix, then disable subscription option on it
- if (!$disabled && $folder['virtual'] && $folder['level'] == 0 && !empty($namespace)) {
- $fname = $folder['id'] . $delimiter;
- foreach ($namespace as $ns) {
- if (is_array($ns)) {
- foreach ($ns as $item) {
- if ($item[0] === $fname) {
- $disabled = true;
- break 2;
+ // Below we will disable subscription option for "virtual" folders
+ // according to namespaces, but only if they aren't already subscribed.
+ // User should be able to unsubscribe from the folder
+ // even if it doesn't exists or is not accessible (OTRS:1000059)
+ if (!$subscribed && !$disabled && !empty($namespace) && $folder['virtual']) {
+ // check if the folder is a namespace prefix, then disable subscription option on it
+ if (!$disabled && $folder['level'] == 0) {
+ $fname = $folder['id'] . $delimiter;
+ foreach ($namespace as $ns) {
+ if (is_array($ns)) {
+ foreach ($ns as $item) {
+ if ($item[0] === $fname) {
+ $disabled = true;
+ break 2;
+ }
}
}
}
}
- }
- // check if the folder is an other users virtual-root folder, then disable subscription option on it
- if (!$disabled && $folder['virtual'] && $folder['level'] == 1
- && !empty($namespace) && !empty($namespace['other'])
- ) {
- $parts = explode($delimiter, $folder['id']);
- $fname = $parts[0] . $delimiter;
- foreach ($namespace['other'] as $item) {
- if ($item[0] === $fname) {
- $disabled = true;
- break;
+ // check if the folder is an other users virtual-root folder, then disable subscription option on it
+ if (!$disabled && $folder['level'] == 1 && !empty($namespace['other'])) {
+ $parts = explode($delimiter, $folder['id']);
+ $fname = $parts[0] . $delimiter;
+ foreach ($namespace['other'] as $item) {
+ if ($item[0] === $fname) {
+ $disabled = true;
+ break;
+ }
}
}
- }
- // check if the folder is shared, then disable subscription option on it (if not subscribed already)
- if (!$disabled && !$subscribed && $folder['virtual'] && !empty($namespace)) {
- $tmp_ns = array_merge((array)$namespace['other'], (array)$namespace['shared']);
- foreach ($tmp_ns as $item) {
- if (strpos($folder['id'], $item[0]) === 0) {
- $disabled = true;
- break;
+ // check if the folder is shared, then disable subscription option on it (if not subscribed already)
+ if (!$disabled) {
+ $tmp_ns = array_merge((array)$namespace['other'], (array)$namespace['shared']);
+ foreach ($tmp_ns as $item) {
+ if (strpos($folder['id'], $item[0]) === 0) {
+ $disabled = true;
+ break;
+ }
}
}
}