summaryrefslogtreecommitdiff
path: root/program/lib
diff options
context:
space:
mode:
Diffstat (limited to 'program/lib')
-rw-r--r--program/lib/Roundcube/html.php6
-rw-r--r--program/lib/Roundcube/rcube_addressbook.php6
-rw-r--r--program/lib/Roundcube/rcube_csv2vcard.php10
-rw-r--r--program/lib/Roundcube/rcube_db.php29
-rw-r--r--program/lib/Roundcube/rcube_html2text.php4
-rw-r--r--program/lib/Roundcube/rcube_ldap.php73
-rw-r--r--program/lib/Roundcube/rcube_mime.php2
-rw-r--r--program/lib/Roundcube/rcube_session.php45
-rw-r--r--program/lib/Roundcube/rcube_spellchecker.php3
-rw-r--r--program/lib/Roundcube/rcube_user.php12
-rw-r--r--program/lib/Roundcube/rcube_utils.php82
-rw-r--r--program/lib/Roundcube/rcube_vcard.php33
12 files changed, 216 insertions, 89 deletions
diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php
index 4f87d2599..f6f744cb2 100644
--- a/program/lib/Roundcube/html.php
+++ b/program/lib/Roundcube/html.php
@@ -3,7 +3,7 @@
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2011, The Roundcube Dev Team |
+ | Copyright (C) 2005-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -32,8 +32,8 @@ class html
public static $doctype = 'xhtml';
public static $lc_tags = true;
- public static $common_attrib = array('id','class','style','title','align');
- public static $containers = array('iframe','div','span','p','h1','h2','h3','form','textarea','table','thead','tbody','tr','th','td','style','script');
+ public static $common_attrib = array('id','class','style','title','align','unselectable');
+ public static $containers = array('iframe','div','span','p','h1','h2','h3','ul','form','textarea','table','thead','tbody','tr','th','td','style','script');
/**
diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php
index f57a30eb9..886f65cb9 100644
--- a/program/lib/Roundcube/rcube_addressbook.php
+++ b/program/lib/Roundcube/rcube_addressbook.php
@@ -532,8 +532,12 @@ abstract class rcube_addressbook
$fn = join(' ', array($contact['surname'], $contact['firstname'], $contact['middlename']));
else if ($compose_mode == 1)
$fn = join(' ', array($contact['firstname'], $contact['middlename'], $contact['surname']));
- else
+ else if ($compose_mode == 0)
$fn = !empty($contact['name']) ? $contact['name'] : join(' ', array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix']));
+ else {
+ $plugin = rcube::get_instance()->plugins->exec_hook('contact_listname', array('contact' => $contact));
+ $fn = $plugin['fn'];
+ }
$fn = trim($fn, ', ');
diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php
index 00e6d4e20..aa385dce4 100644
--- a/program/lib/Roundcube/rcube_csv2vcard.php
+++ b/program/lib/Roundcube/rcube_csv2vcard.php
@@ -47,7 +47,7 @@ class rcube_csv2vcard
//'business_street_2' => '',
//'business_street_3' => '',
'car_phone' => 'phone:car',
- 'categories' => 'categories',
+ 'categories' => 'groups',
//'children' => '',
'company' => 'organization',
//'company_main_phone' => '',
@@ -146,6 +146,9 @@ class rcube_csv2vcard
'work_title' => 'jobtitle',
'work_zip' => 'zipcode:work',
'group' => 'groups',
+
+ // GMail
+ 'groups' => 'groups',
);
/**
@@ -427,6 +430,11 @@ class rcube_csv2vcard
$contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d'];
}
+ // categories/groups separator in vCard is ',' not ';'
+ if (!empty($contact['groups'])) {
+ $contact['groups'] = str_replace(';', ',', $contact['groups']);
+ }
+
// Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00"
foreach (array('birthday', 'anniversary') as $key) {
if (!empty($contact[$key])) {
diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php
index aaba28172..2828f26ee 100644
--- a/program/lib/Roundcube/rcube_db.php
+++ b/program/lib/Roundcube/rcube_db.php
@@ -392,7 +392,7 @@ class rcube_db
*/
protected function _query($query, $offset, $numrows, $params)
{
- $query = trim($query);
+ $query = ltrim($query);
$this->db_connect($this->dsn_select($query), true);
@@ -405,27 +405,28 @@ class rcube_db
$query = $this->set_limit($query, $numrows, $offset);
}
- $params = (array) $params;
-
// Because in Roundcube we mostly use queries that are
// executed only once, we will not use prepared queries
$pos = 0;
$idx = 0;
- while ($pos = strpos($query, '?', $pos)) {
- if ($query[$pos+1] == '?') { // skip escaped ?
- $pos += 2;
- }
- else {
- $val = $this->quote($params[$idx++]);
- unset($params[$idx-1]);
- $query = substr_replace($query, $val, $pos, 1);
- $pos += strlen($val);
+ if (count($params)) {
+ while ($pos = strpos($query, '?', $pos)) {
+ if ($query[$pos+1] == '?') { // skip escaped '?'
+ $pos += 2;
+ }
+ else {
+ $val = $this->quote($params[$idx++]);
+ unset($params[$idx-1]);
+ $query = substr_replace($query, $val, $pos, 1);
+ $pos += strlen($val);
+ }
}
}
- // replace escaped ? back to normal
- $query = rtrim(strtr($query, array('??' => '?')), ';');
+ // replace escaped '?' back to normal, see self::quote()
+ $query = str_replace('??', '?', $query);
+ $query = rtrim($query, " \t\n\r\0\x0B;");
$this->debug($query);
diff --git a/program/lib/Roundcube/rcube_html2text.php b/program/lib/Roundcube/rcube_html2text.php
index 6f79e2f8e..01362e6fb 100644
--- a/program/lib/Roundcube/rcube_html2text.php
+++ b/program/lib/Roundcube/rcube_html2text.php
@@ -608,7 +608,7 @@ class rcube_html2text
$this->width = $p_width;
// Add citation markers and create <pre> block
- $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_ballback'), trim($body));
+ $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_callback'), trim($body));
$body = '<pre>' . htmlspecialchars($body) . '</pre>';
$text = substr_replace($text, $body . "\n", $start, $end + 13 - $start);
@@ -624,7 +624,7 @@ class rcube_html2text
/**
* Callback function to correctly add citation markers for blockquote contents
*/
- public function blockquote_citation_ballback($m)
+ public function blockquote_citation_callback($m)
{
$line = ltrim($m[2]);
$space = $line[0] == '>' ? '' : ' ';
diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php
index 64288f973..b733e2465 100644
--- a/program/lib/Roundcube/rcube_ldap.php
+++ b/program/lib/Roundcube/rcube_ldap.php
@@ -52,7 +52,7 @@ class rcube_ldap extends rcube_addressbook
*
* @var array
*/
- private static $group_types = array(
+ private $group_types = array(
'group' => 'member',
'groupofnames' => 'member',
'kolabgroupofnames' => 'member',
@@ -94,6 +94,9 @@ class rcube_ldap extends rcube_addressbook
$this->prop['groups']['name_attr'] = 'cn';
if (empty($this->prop['groups']['scope']))
$this->prop['groups']['scope'] = 'sub';
+ // extend group objectclass => member attribute mapping
+ if (!empty($this->prop['groups']['class_member_attr']))
+ $this->group_types = array_merge($this->group_types, $this->prop['groups']['class_member_attr']);
// add group name attrib to the list of attributes to be fetched
$fetch_attributes[] = $this->prop['groups']['name_attr'];
@@ -292,6 +295,14 @@ class rcube_ldap extends rcube_addressbook
if ($this->prop['search_base_dn'] && $this->prop['search_filter']
&& (strstr($bind_dn, '%dn') || strstr($this->base_dn, '%dn') || strstr($this->groups_base_dn, '%dn'))
) {
+ $search_attribs = array('uid');
+ if ($search_bind_attrib = (array)$this->prop['search_bind_attrib']) {
+ foreach ($search_bind_attrib as $r => $attr) {
+ $search_attribs[] = $attr;
+ $replaces[$r] = '';
+ }
+ }
+
$search_bind_dn = strtr($this->prop['search_bind_dn'], $replaces);
$search_base_dn = strtr($this->prop['search_base_dn'], $replaces);
$search_filter = strtr($this->prop['search_filter'], $replaces);
@@ -321,10 +332,18 @@ class rcube_ldap extends rcube_addressbook
}
}
- $res = $ldap->search($search_base_dn, $search_filter, 'sub', array('uid'));
+ $res = $ldap->search($search_base_dn, $search_filter, 'sub', $search_attribs);
if ($res) {
$res->rewind();
$replaces['%dn'] = $res->get_dn();
+
+ // add more replacements from 'search_bind_attrib' config
+ if ($search_bind_attrib) {
+ $res = $res->current();
+ foreach ($search_bind_attrib as $r => $attr) {
+ $replaces[$r] = $res[$attr][0];
+ }
+ }
}
if ($ldap != $this->ldap) {
@@ -355,6 +374,23 @@ class rcube_ldap extends rcube_addressbook
$this->base_dn = strtr($this->base_dn, $replaces);
$this->groups_base_dn = strtr($this->groups_base_dn, $replaces);
+ // replace placeholders in filter settings
+ if (!empty($this->prop['filter']))
+ $this->prop['filter'] = strtr($this->prop['filter'], $replaces);
+ if (!empty($this->prop['groups']['filter']))
+ $this->prop['groups']['filter'] = strtr($this->prop['groups']['filter'], $replaces);
+ if (!empty($this->prop['groups']['member_filter']))
+ $this->prop['groups']['member_filter'] = strtr($this->prop['groups']['member_filter'], $replaces);
+
+ if (!empty($this->prop['group_filters'])) {
+ foreach ($this->prop['group_filters'] as $i => $gf) {
+ if (!empty($gf['base_dn']))
+ $this->prop['group_filters'][$i]['base_dn'] = strtr($gf['base_dn'], $replaces);
+ if (!empty($gf['filter']))
+ $this->prop['group_filters'][$i]['filter'] = strtr($gf['filter'], $replaces);
+ }
+ }
+
if (empty($bind_user)) {
$bind_user = $u;
}
@@ -559,9 +595,10 @@ class rcube_ldap extends rcube_addressbook
/**
* Get all members of the given group
*
- * @param string Group DN
- * @param array Group entries (if called recursively)
- * @return array Accumulated group members
+ * @param string Group DN
+ * @param boolean Count only
+ * @param array Group entries (if called recursively)
+ * @return array Accumulated group members
*/
function list_group_members($dn, $count = false, $entries = null)
{
@@ -569,7 +606,7 @@ class rcube_ldap extends rcube_addressbook
// fetch group object
if (empty($entries)) {
- $attribs = array('dn','objectClass','member','uniqueMember','memberURL');
+ $attribs = array_merge(array('dn','objectClass','memberURL'), array_values($this->group_types));
$entries = $this->ldap->read_entries($dn, '(objectClass=*)', $attribs);
if ($entries === false) {
return $group_members;
@@ -581,17 +618,17 @@ class rcube_ldap extends rcube_addressbook
$attrs = array();
foreach ((array)$entry['objectclass'] as $objectclass) {
- if (strtolower($objectclass) == 'groupofurls') {
- $members = $this->_list_group_memberurl($dn, $entry, $count);
- $group_members = array_merge($group_members, $members);
- }
- else if (($member_attr = $this->get_group_member_attr(array($objectclass), ''))
+ if (($member_attr = $this->get_group_member_attr(array($objectclass), ''))
&& ($member_attr = strtolower($member_attr)) && !in_array($member_attr, $attrs)
) {
$members = $this->_list_group_members($dn, $entry, $member_attr, $count);
$group_members = array_merge($group_members, $members);
$attrs[] = $member_attr;
}
+ else if (!empty($entry['memberurl'])) {
+ $members = $this->_list_group_memberurl($dn, $entry, $count);
+ $group_members = array_merge($group_members, $members);
+ }
if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) {
break 2;
@@ -608,6 +645,7 @@ class rcube_ldap extends rcube_addressbook
* @param string Group DN
* @param array Group entry
* @param string Member attribute to use
+ * @param boolean Count only
* @return array Accumulated group members
*/
private function _list_group_members($dn, $entry, $attr, $count)
@@ -621,8 +659,7 @@ class rcube_ldap extends rcube_addressbook
// read these attributes for all members
$attrib = $count ? array('dn','objectClass') : $this->prop['list_attributes'];
- $attrib[] = 'member';
- $attrib[] = 'uniqueMember';
+ $attrib = array_merge($attrib, array_values($this->group_types));
$attrib[] = 'memberURL';
$filter = $this->prop['groups']['member_filter'] ? $this->prop['groups']['member_filter'] : '(objectclass=*)';
@@ -669,7 +706,7 @@ class rcube_ldap extends rcube_addressbook
if ($result = $this->ldap->search($m[1], $filter, $m[2], $attrs, $this->group_data)) {
$entries = $result->entries();
for ($j = 0; $j < $entries['count']; $j++) {
- if (self::is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count)))
+ if ($this->is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count)))
$group_members = array_merge($group_members, $nested_group_members);
else
$group_members[] = $entries[$j];
@@ -1354,7 +1391,7 @@ class rcube_ldap extends rcube_addressbook
$out[$this->primary_key] = self::dn_encode($rec['dn']);
// determine record type
- if (self::is_group_entry($rec)) {
+ if ($this->is_group_entry($rec)) {
$out['_type'] = 'group';
$out['readonly'] = true;
$fieldmap['name'] = $this->group_data['name_attr'] ? $this->group_data['name_attr'] : $this->prop['groups']['name_attr'];
@@ -1479,11 +1516,11 @@ class rcube_ldap extends rcube_addressbook
/**
* Determines whether the given LDAP entry is a group record
*/
- private static function is_group_entry($entry)
+ private function is_group_entry($entry)
{
$classes = array_map('strtolower', (array)$entry['objectclass']);
- return count(array_intersect(array_keys(self::$group_types), $classes)) > 0;
+ return count(array_intersect(array_keys($this->group_types), $classes)) > 0;
}
/**
@@ -1914,7 +1951,7 @@ class rcube_ldap extends rcube_addressbook
if (!empty($object_classes)) {
foreach ((array)$object_classes as $oc) {
- if ($attr = self::$group_types[strtolower($oc)]) {
+ if ($attr = $this->group_types[strtolower($oc)]) {
return $attr;
}
}
diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php
index 9c2220328..a931c27c1 100644
--- a/program/lib/Roundcube/rcube_mime.php
+++ b/program/lib/Roundcube/rcube_mime.php
@@ -810,7 +810,7 @@ class rcube_mime
}
$mime_types = $mime_extensions = array();
- $regex = "/([\w\+\-\.\/]+)\t+([\w\s]+)/i";
+ $regex = "/([\w\+\-\.\/]+)\s+([\w\s]+)/i";
foreach((array)$lines as $line) {
// skip comments or mime types w/o any extensions
if ($line[0] == '#' || !preg_match($regex, $line, $matches))
diff --git a/program/lib/Roundcube/rcube_session.php b/program/lib/Roundcube/rcube_session.php
index 67072df41..caca262c6 100644
--- a/program/lib/Roundcube/rcube_session.php
+++ b/program/lib/Roundcube/rcube_session.php
@@ -34,6 +34,7 @@ class rcube_session
private $changed;
private $time_diff = 0;
private $reloaded = false;
+ private $appends = array();
private $unsets = array();
private $gc_handlers = array();
private $cookiename = 'roundcube_sessauth';
@@ -441,8 +442,19 @@ class rcube_session
$node = &$this->get_node(explode('.', $path), $_SESSION);
- if ($key !== null) $node[$key] = $value;
- else $node[] = $value;
+ if ($key !== null) {
+ $node[$key] = $value;
+ $path .= '.' . $key;
+ }
+ else {
+ $node[] = $value;
+ }
+
+ $this->appends[] = $path;
+
+ // when overwriting a previously unset variable
+ if ($this->unsets[$path])
+ unset($this->unsets[$path]);
}
@@ -491,13 +503,40 @@ class rcube_session
*/
public function reload()
{
+ // collect updated data from previous appends
+ $merge_data = array();
+ foreach ((array)$this->appends as $var) {
+ $path = explode('.', $var);
+ $value = $this->get_node($path, $_SESSION);
+ $k = array_pop($path);
+ $node = &$this->get_node($path, $merge_data);
+ $node[$k] = $value;
+ }
+
if ($this->key && $this->memcache)
$data = $this->mc_read($this->key);
else if ($this->key)
$data = $this->db_read($this->key);
- if ($data)
+ if ($data) {
session_decode($data);
+
+ // apply appends and unsets to reloaded data
+ $_SESSION = array_merge_recursive($_SESSION, $merge_data);
+
+ foreach ((array)$this->unsets as $var) {
+ if (isset($_SESSION[$var])) {
+ unset($_SESSION[$var]);
+ }
+ else {
+ $path = explode('.', $var);
+ $k = array_pop($path);
+ $node = &$this->get_node($path, $_SESSION);
+ unset($node[$k]);
+ }
+ }
+ }
+
}
/**
diff --git a/program/lib/Roundcube/rcube_spellchecker.php b/program/lib/Roundcube/rcube_spellchecker.php
index d087d2584..3182ff378 100644
--- a/program/lib/Roundcube/rcube_spellchecker.php
+++ b/program/lib/Roundcube/rcube_spellchecker.php
@@ -104,6 +104,9 @@ class rcube_spellchecker
}
}
+ // remove possible duplicates (#1489395)
+ $languages = array_unique($languages);
+
asort($languages);
return $languages;
diff --git a/program/lib/Roundcube/rcube_user.php b/program/lib/Roundcube/rcube_user.php
index 5e9c9af80..57f63361d 100644
--- a/program/lib/Roundcube/rcube_user.php
+++ b/program/lib/Roundcube/rcube_user.php
@@ -163,8 +163,16 @@ class rcube_user
if (!$this->ID)
return false;
- $config = $this->rc->config;
- $old_prefs = (array)$this->get_prefs();
+ $plugin = $this->rc->plugins->exec_hook('preferences_update', array(
+ 'userid' => $this->ID, 'prefs' => $a_user_prefs, 'old' => (array)$this->get_prefs()));
+
+ if (!empty($plugin['abort'])) {
+ return;
+ }
+
+ $a_user_prefs = $plugin['prefs'];
+ $old_prefs = $plugin['old'];
+ $config = $this->rc->config;
// merge (partial) prefs array with existing settings
$save_prefs = $a_user_prefs + $old_prefs;
diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php
index b73bc0812..27a618d83 100644
--- a/program/lib/Roundcube/rcube_utils.php
+++ b/program/lib/Roundcube/rcube_utils.php
@@ -454,6 +454,9 @@ class rcube_utils
// cut out all contents between { and }
while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) {
+ $nested = strpos($source, '{', $pos+1);
+ if ($nested && $nested < $pos2) // when dealing with nested blocks (e.g. @media), take the inner one
+ $pos = $nested;
$length = $pos2 - $pos - 1;
$styles = substr($source, $pos+1, $length);
@@ -744,40 +747,13 @@ class rcube_utils
*/
public static function strtotime($date)
{
- $date = trim($date);
-
- // check for MS Outlook vCard date format YYYYMMDD
- if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) {
- return mktime(0,0,0, intval($m[2]), intval($m[3]), intval($m[1]));
- }
-
- // common little-endian formats, e.g. dd/mm/yyyy (not all are supported by strtotime)
- if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m)
- && $m[1] > 0 && $m[1] <= 31 && $m[2] > 0 && $m[2] <= 12 && $m[3] >= 1970
- ) {
- return mktime(0,0,0, intval($m[2]), intval($m[1]), intval($m[3]));
- }
+ $date = self::clean_datestr($date);
// unix timestamp
if (is_numeric($date)) {
return (int) $date;
}
- // Clean malformed data
- $date = preg_replace(
- array(
- '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal
- '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters
- '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names
- ),
- array(
- '\\1',
- '',
- '',
- ), $date);
-
- $date = trim($date);
-
// if date parsing fails, we have a date in non-rfc format.
// remove token from the end and try again
while ((($ts = @strtotime($date)) === false) || ($ts < 0)) {
@@ -805,8 +781,8 @@ class rcube_utils
return $date;
}
- $dt = false;
- $date = trim($date);
+ $dt = false;
+ $date = self::clean_datestr($date);
// try to parse string with DateTime first
if (!empty($date)) {
@@ -831,6 +807,52 @@ class rcube_utils
return $dt;
}
+ /**
+ * Clean up date string for strtotime() input
+ *
+ * @param string $date Date string
+ *
+ * @return string Date string
+ */
+ public static function clean_datestr($date)
+ {
+ $date = trim($date);
+
+ // check for MS Outlook vCard date format YYYYMMDD
+ if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) {
+ return sprintf('%04d-%02d-%02d 00:00:00', intval($m[1]), intval($m[2]), intval($m[3]));
+ }
+
+ // Clean malformed data
+ $date = preg_replace(
+ array(
+ '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal
+ '/[^a-z0-9\x20\x09:+-\/]/i', // remove any invalid characters
+ '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names
+ ),
+ array(
+ '\\1',
+ '',
+ '',
+ ), $date);
+
+ $date = trim($date);
+
+ // try to fix dd/mm vs. mm/dd discrepancy, we can't do more here
+ if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m)) {
+ $mdy = $m[2] > 12 && $m[1] <= 12;
+ $day = $mdy ? $m[2] : $m[1];
+ $month = $mdy ? $m[1] : $m[2];
+ $date = sprintf('%04d-%02d-%02d 00:00:00', intval($m[3]), $month, $day);
+ }
+ // I've found that YYYY.MM.DD is recognized wrong, so here's a fix
+ else if (preg_match('/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/', $date)) {
+ $date = str_replace('.', '-', $date) . ' 00:00:00';
+ }
+
+ return $date;
+ }
+
/*
* Idn_to_ascii wrapper.
* Intl/Idn modules version of this function doesn't work with e-mail address
diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php
index d54dc56ad..a54ee7e11 100644
--- a/program/lib/Roundcube/rcube_vcard.php
+++ b/program/lib/Roundcube/rcube_vcard.php
@@ -378,7 +378,7 @@ class rcube_vcard
default:
if ($field == 'phone' && $this->phonetypemap[$type_uc]) {
$type = $this->phonetypemap[$type_uc];
- }
+ }
if (($tag = self::$fieldmap[$field]) && (is_array($value) || strlen($value))) {
$index = count($this->raw[$tag]);
@@ -518,20 +518,28 @@ class rcube_vcard
*/
public static function cleanup($vcard)
{
- // Convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
- $vcard = preg_replace(
- '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
- '\2;type=\5\3:\4',
- $vcard);
-
// convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility
$vcard = preg_replace_callback(
'/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
array('self', 'x_abrelatednames_callback'),
$vcard);
- // Remove cruft like item1.X-AB*, item1.ADR instead of ADR, and empty lines
- $vcard = preg_replace(array('/^item\d*\.X-AB.*$/m', '/^item\d*\./m', "/\n+/"), array('', '', "\n"), $vcard);
+ // Cleanup
+ $vcard = preg_replace(array(
+ // convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
+ '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
+ '/^item\d*\.X-AB.*$/m', // remove cruft like item1.X-AB*
+ '/^item\d*\./m', // remove item1.ADR instead of ADR
+ '/\n+/', // remove empty lines
+ '/^(N:[^;\R]*)$/m', // if N doesn't have any semicolons, add some
+ ),
+ array(
+ '\2;type=\5\3:\4',
+ '',
+ '',
+ "\n",
+ '\1;;;;',
+ ), $vcard);
// convert X-WAB-GENDER to X-GENDER
if (preg_match('/X-WAB-GENDER:(\d)/', $vcard, $matches)) {
@@ -539,9 +547,6 @@ class rcube_vcard
$vcard = preg_replace('/X-WAB-GENDER:\d/', 'X-GENDER:' . $value, $vcard);
}
- // if N doesn't have any semicolons, add some
- $vcard = preg_replace('/^(N:[^;\R]*)$/m', '\1;;;;', $vcard);
-
return $vcard;
}
@@ -612,8 +617,8 @@ class rcube_vcard
$enc = null;
foreach($regs2[1] as $attrid => $attr) {
+ $attr = preg_replace('/[\s\t\n\r\0\x0B]/', '', $attr);
if ((list($key, $value) = explode('=', $attr)) && $value) {
- $value = trim($value);
if ($key == 'ENCODING') {
$value = strtoupper($value);
// add next line(s) to value string if QP line end detected
@@ -792,7 +797,7 @@ class rcube_vcard
return $result;
}
- $s = strtr($s, $rep2);
+ $s = trim(strtr($s, $rep2));
}
// some implementations (GMail) use non-standard backslash before colon (#1489085)