From 029d18f13bcf01aa2f1f08dbdfc6400c081bf7cb Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Thu, 4 Apr 2013 16:08:53 +0200 Subject: [PATCH 01/38] Replaced nasty eval() expressions. --- program/include/rcmail_output_html.php | 35 ++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index 1290e173e..795c0b381 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -722,7 +722,7 @@ class rcmail_output_html extends rcmail_output */ protected function check_condition($condition) { - return eval("return (".$this->parse_expression($condition).");"); + return $this->eval_expression($condition); } @@ -773,6 +773,37 @@ class rcmail_output_html extends rcmail_output $expression); } + protected function eval_expression ($expression) { + return preg_replace_callback( + array( + '/session:([a-z0-9_]+)/i', + '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i', + '/env:([a-z0-9_]+)/i', + '/request:([a-z0-9_]+)/i', + '/cookie:([a-z0-9_]+)/i', + '/browser:([a-z0-9_]+)/i', + '/template:name/i', + ), + function($match) { + if(preg_match('/session:([a-z0-9_]+)/i', $match, $matches)) { + return $_SESSION[$matches[1]]; + } else if(preg_match('/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i', $match, $matches)) { + return $this->app->config->get($matches[1],rcube_utils::get_boolean($matches[3])); + } else if(preg_match('/env:([a-z0-9_]+)/i', $match, $matches)) { + return $this->env[$matches[1]]; + } else if(preg_match('/request:([a-z0-9_]+)/i', $match, $matches)) { + return rcube_utils::get_input_value($matches[1], rcube_utils::INPUT_GPC); + } else if(preg_match('/cookie:([a-z0-9_]+)/i', $match, $matches)) { + return $_COOKIE[$matches[1]]; + } else if(preg_match('/browser:([a-z0-9_]+)/i', $match, $matches)) { + return $this->browser->{$matches[1]}; + } else if(preg_match('/template:name/i', $match, $matches)) { + return $this->template_name; + } + }, + $expression); + } + /** * Search for special tags in input and replace them @@ -955,7 +986,7 @@ class rcmail_output_html extends rcmail_output // return code for a specified eval expression case 'exp': $value = $this->parse_expression($attrib['expression']); - return eval("return html::quote($value);"); + return html::quote( $this->eval_expression($attrib['expression']) ); // return variable case 'var': From d67485bebe161c8c46ffe4852e4b4446910ed342 Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Fri, 5 Apr 2013 12:02:04 +0200 Subject: [PATCH 02/38] Replaced stupid fix by create_function() based approach. --- program/include/rcmail_output_html.php | 51 +++++++++----------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index f2bdd95a7..3e0a4e674 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -731,7 +731,6 @@ class rcmail_output_html extends rcmail_output /** * Determines if a given condition is met * - * @todo Get rid off eval() once I understand what this does. * @todo Extend this to allow real conditions, not just "set" * @param string Condition statement * @return boolean True if condition is met, False if not @@ -779,45 +778,30 @@ class rcmail_output_html extends rcmail_output ), array( "\$_SESSION['\\1']", - "\$this->app->config->get('\\1',rcube_utils::get_boolean('\\3'))", - "\$this->env['\\1']", + "\$app->config->get('\\1',rcube_utils::get_boolean('\\3'))", + "\$env['\\1']", "rcube_utils::get_input_value('\\1', rcube_utils::INPUT_GPC)", "\$_COOKIE['\\1']", - "\$this->browser->{'\\1'}", + "\$browser->{'\\1'}", $this->template_name, ), $expression); } - + + /** + * Evaluate a given expression and return its result. + * @param string Expression statement + */ protected function eval_expression ($expression) { - return preg_replace_callback( - array( - '/session:([a-z0-9_]+)/i', - '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i', - '/env:([a-z0-9_]+)/i', - '/request:([a-z0-9_]+)/i', - '/cookie:([a-z0-9_]+)/i', - '/browser:([a-z0-9_]+)/i', - '/template:name/i', - ), - function($match) { - if(preg_match('/session:([a-z0-9_]+)/i', $match, $matches)) { - return $_SESSION[$matches[1]]; - } else if(preg_match('/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i', $match, $matches)) { - return $this->app->config->get($matches[1],rcube_utils::get_boolean($matches[3])); - } else if(preg_match('/env:([a-z0-9_]+)/i', $match, $matches)) { - return $this->env[$matches[1]]; - } else if(preg_match('/request:([a-z0-9_]+)/i', $match, $matches)) { - return rcube_utils::get_input_value($matches[1], rcube_utils::INPUT_GPC); - } else if(preg_match('/cookie:([a-z0-9_]+)/i', $match, $matches)) { - return $_COOKIE[$matches[1]]; - } else if(preg_match('/browser:([a-z0-9_]+)/i', $match, $matches)) { - return $this->browser->{$matches[1]}; - } else if(preg_match('/template:name/i', $match, $matches)) { - return $this->template_name; - } - }, - $expression); + // Prevent function calls in `expression`: + $expression = str_replace("\n", "", $expression); + if(preg_match('#\w+ \s* (/\* .* \*/)* \s* \(#ix', $expression)) + return false; + + // Evaluate expression: + $expression = $this->parse_expression($expression); + $fn = create_function('$app,$browser,$env', "return ($expression);"); + return $fn($this->app, $this->browser, $this->env); } @@ -1002,7 +986,6 @@ class rcmail_output_html extends rcmail_output // return code for a specified eval expression case 'exp': - $value = $this->parse_expression($attrib['expression']); return html::quote( $this->eval_expression($attrib['expression']) ); // return variable From fe245e5f5dbea1c18517471103185e04a52c89b3 Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Fri, 5 Apr 2013 13:49:32 +0200 Subject: [PATCH 03/38] Replaced last eval(). Allowing function calls in expressions. --- program/include/rcmail_output_html.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index 3e0a4e674..772bdccf7 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -793,12 +793,6 @@ class rcmail_output_html extends rcmail_output * @param string Expression statement */ protected function eval_expression ($expression) { - // Prevent function calls in `expression`: - $expression = str_replace("\n", "", $expression); - if(preg_match('#\w+ \s* (/\* .* \*/)* \s* \(#ix', $expression)) - return false; - - // Evaluate expression: $expression = $this->parse_expression($expression); $fn = create_function('$app,$browser,$env', "return ($expression);"); return $fn($this->app, $this->browser, $this->env); @@ -854,7 +848,7 @@ class rcmail_output_html extends rcmail_output // show a label case 'label': if ($attrib['expression']) - $attrib['name'] = eval("return " . $this->parse_expression($attrib['expression']) .";"); + $attrib['name'] = $this->eval_expression($attrib['expression']); if ($attrib['name'] || $attrib['command']) { // @FIXME: 'noshow' is useless, remove? From 58e3a504b98f68595151fa908536b1e35b043b76 Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Mon, 8 Apr 2013 14:31:28 +0200 Subject: [PATCH 04/38] Removed parse_expression() & added error logging to eval_expression(). --- program/include/rcmail_output_html.php | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index 772bdccf7..0fba66080 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -759,14 +759,11 @@ class rcmail_output_html extends rcmail_output /** - * Parses expression and replaces variables - * + * Parse & evaluate a given expression and return its result. * @param string Expression statement - * @return string Expression value */ - protected function parse_expression($expression) - { - return preg_replace( + protected function eval_expression ($expression) { + $expression = preg_replace( array( '/session:([a-z0-9_]+)/i', '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i', @@ -785,16 +782,19 @@ class rcmail_output_html extends rcmail_output "\$browser->{'\\1'}", $this->template_name, ), - $expression); - } - - /** - * Evaluate a given expression and return its result. - * @param string Expression statement - */ - protected function eval_expression ($expression) { - $expression = $this->parse_expression($expression); + $expression + ); + $fn = create_function('$app,$browser,$env', "return ($expression);"); + if(!$fn) { + rcube::raise_error(array( + 'code' => 505, + 'type' => 'php', + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => "Expression parse error on: ($expression)"), true, false); + } + return $fn($this->app, $this->browser, $this->env); } From 8defd73ee0f86f5fe83c4ae5a4d568d140599736 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 30 Apr 2013 11:49:35 +0200 Subject: [PATCH 05/38] Inlcude SQL query in the log on SQL error (#1489064) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_db.php | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5ac7e5955..898c34f24 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Inlcude SQL query in the log on SQL error (#1489064) - Fix handling untagged responses in IMAP FETCH - "could not load message" error (#1489074) - Fix very small window size in Chrome (#1488931) - Fix list page reset when viewing a message in Larry skin (#1489076) diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index d86e3dd98..c96bccc90 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -405,21 +405,22 @@ class rcube_db $this->db_error_msg = null; // send query - $query = $this->dbh->query($query); + $result = $this->dbh->query($query); - if ($query === false) { + if ($result === false) { $error = $this->dbh->errorInfo(); $this->db_error = true; $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]); rcube::raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $this->db_error_msg), true, false); + 'message' => $this->db_error_msg . " (SQL Query: $query)" + ), true, false); } - $this->last_result = $query; + $this->last_result = $result; - return $query; + return $result; } /** From 609483d9f68f792ebf13441b3056118f4518fa7c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 30 Apr 2013 15:05:41 +0200 Subject: [PATCH 06/38] Support CSV import from Atmail (#1489045) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_csv2vcard.php | 46 ++++++++++++++++++++++- program/localization/en_US/csv2vcard.inc | 17 +++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 898c34f24..f594e4319 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Support CSV import from Atmail (#1489045) - Inlcude SQL query in the log on SQL error (#1489064) - Fix handling untagged responses in IMAP FETCH - "could not load message" error (#1489074) - Fix very small window size in Chrome (#1488931) diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php index 0d3276b84..ed3bb7671 100644 --- a/program/lib/Roundcube/rcube_csv2vcard.php +++ b/program/lib/Roundcube/rcube_csv2vcard.php @@ -130,6 +130,23 @@ class rcube_csv2vcard 'work_state' => 'region:work', 'home_city_short' => 'locality:home', 'home_state_short' => 'region:home', + + // Atmail + 'date_of_birth' => 'birthday', + 'email' => 'email:pref', + 'home_mobile' => 'phone:cell', + 'home_zip' => 'zipcode:home', + 'info' => 'notes', + 'user_photo' => 'photo', + 'url' => 'website:homepage', + 'work_city' => 'locality:work', + 'work_company' => 'organization', + 'work_dept' => 'departament', + 'work_fax' => 'phone:work,fax', + 'work_mobile' => 'phone:work,cell', + 'work_state' => 'region:work', + 'work_title' => 'jobtitle', + 'work_zip' => 'zipcode:work', ); /** @@ -232,6 +249,27 @@ class rcube_csv2vcard //'work_address_2' => "Work Address 2", 'work_country' => "Work Country", 'work_zipcode' => "Work ZipCode", + + // Atmail + 'date_of_birth' => "Date of Birth", + 'email' => "Email", + //'email_2' => "Email2", + //'email_3' => "Email3", + //'email_4' => "Email4", + //'email_5' => "Email5", + 'home_mobile' => "Home Mobile", + 'home_zip' => "Home Zip", + 'info' => "Info", + 'user_photo' => "User Photo", + 'url' => "URL", + 'work_city' => "Work City", + 'work_company' => "Work Company", + 'work_dept' => "Work Dept", + 'work_fax' => "Work Fax", + 'work_mobile' => "Work Mobile", + 'work_state' => "Work State", + 'work_title' => "Work Title", + 'work_zip' => "Work Zip", ); protected $local_label_map = array(); @@ -384,9 +422,13 @@ class rcube_csv2vcard $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d']; } + // Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00" foreach (array('birthday', 'anniversary') as $key) { - if (!empty($contact[$key]) && $contact[$key] == '0/0/00') { // @TODO: localization? - unset($contact[$key]); + if (!empty($contact[$key])) { + $date = preg_replace('/[0[:^word:]]/', '', $contact[$key]); + if (empty($date)) { + unset($contact[$key]); + } } } diff --git a/program/localization/en_US/csv2vcard.inc b/program/localization/en_US/csv2vcard.inc index 5412f7e20..e7b86795b 100644 --- a/program/localization/en_US/csv2vcard.inc +++ b/program/localization/en_US/csv2vcard.inc @@ -91,3 +91,20 @@ $map['work_phone'] = "Work Phone"; $map['work_address'] = "Work Address"; $map['work_country'] = "Work Country"; $map['work_zipcode'] = "Work ZipCode"; + +// Atmail +$map['date_of_birth'] = "Date of Birth"; +$map['email'] = "Email"; +$map['home_mobile'] = "Home Mobile"; +$map['home_zip'] = "Home Zip"; +$map['info'] = "Info"; +$map['user_photo'] = "User Photo"; +$map['url'] = "URL"; +$map['work_city'] = "Work City"; +$map['work_company'] = "Work Company"; +$map['work_dept'] = "Work Dept"; +$map['work_fax'] = "Work Fax"; +$map['work_mobile'] = "Work Mobile"; +$map['work_state'] = "Work State"; +$map['work_title'] = "Work Title"; +$map['work_zip'] = "Work Zip"; From 0826b2a896b3898c1f7f442ba01734ed04387f87 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 30 Apr 2013 15:17:06 +0200 Subject: [PATCH 07/38] Small code simplification --- program/js/app.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index 474a1b8c3..87f20679a 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -936,16 +936,13 @@ function rcube_webmail() url._to = props; } else { - // use contact_id passed as command parameter - var n, len, a_cids = []; + var a_cids = []; + // use contact id passed as command parameter if (props) a_cids.push(props); // get selected contacts - else if (this.contact_list) { - var selection = this.contact_list.get_selection(); - for (n=0, len=selection.length; n Date: Tue, 30 Apr 2013 19:28:07 +0200 Subject: [PATCH 08/38] Fix removal of a contact from a group in LDAP addressbook (#1489081) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_addressbook.php | 14 ++++++----- program/lib/Roundcube/rcube_contacts.php | 14 ++++++----- program/lib/Roundcube/rcube_ldap.php | 27 ++++++++++++--------- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f594e4319..9d1a621b4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix removal of a contact from a group in LDAP addressbook (#1489081) - Support CSV import from Atmail (#1489045) - Inlcude SQL query in the log on SQL error (#1489064) - Fix handling untagged responses in IMAP FETCH - "could not load message" error (#1489074) diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index cbc3c6773..5fbcb72af 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -370,9 +370,10 @@ abstract class rcube_addressbook /** * Add the given contact records the a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be added - * @return int Number of contacts added + * @param string Group identifier + * @param array|string List of contact identifiers to be added + * + * @return int Number of contacts added */ function add_to_group($group_id, $ids) { @@ -383,9 +384,10 @@ abstract class rcube_addressbook /** * Remove the given contact records from a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be removed - * @return int Number of deleted group members + * @param string Group identifier + * @param array|string List of contact identifiers to be removed + * + * @return int Number of deleted group members */ function remove_from_group($group_id, $ids) { diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php index e4fd7dc10..6693e558b 100644 --- a/program/lib/Roundcube/rcube_contacts.php +++ b/program/lib/Roundcube/rcube_contacts.php @@ -879,9 +879,10 @@ class rcube_contacts extends rcube_addressbook /** * Add the given contact records the a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be added - * @return int Number of contacts added + * @param string Group identifier + * @param array|string List of contact identifiers to be added + * + * @return int Number of contacts added */ function add_to_group($group_id, $ids) { @@ -926,9 +927,10 @@ class rcube_contacts extends rcube_addressbook /** * Remove the given contact records from a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be removed - * @return int Number of deleted group members + * @param string Group identifier + * @param array|string List of contact identifiers to be removed + * + * @return int Number of deleted group members */ function remove_from_group($group_id, $ids) { diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index a2dd163e9..bae72b724 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -1921,9 +1921,10 @@ class rcube_ldap extends rcube_addressbook /** * Add the given contact records the a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be added - * @return int Number of contacts added + * @param string Group identifier + * @param array|string List of contact identifiers to be added + * + * @return int Number of contacts added */ function add_to_group($group_id, $contact_ids) { @@ -1937,8 +1938,8 @@ class rcube_ldap extends rcube_addressbook $group_name = $group_cache[$group_id]['name']; $member_attr = $group_cache[$group_id]['member_attr']; $group_dn = "cn=$group_name,$base_dn"; + $new_attrs = array(); - $new_attrs = array(); foreach ($contact_ids as $id) $new_attrs[$member_attr][] = self::dn_decode($id); @@ -1949,28 +1950,32 @@ class rcube_ldap extends rcube_addressbook $this->cache->remove('groups'); - return count($new_attrs['member']); + return count($new_attrs[$member_attr]); } /** * Remove the given contact records from a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be removed - * @return int Number of deleted group members + * @param string Group identifier + * @param array|string List of contact identifiers to be removed + * + * @return int Number of deleted group members */ function remove_from_group($group_id, $contact_ids) { if (($group_cache = $this->cache->get('groups')) === null) $group_cache = $this->_fetch_groups(); + if (!is_array($contact_ids)) + $contact_ids = explode(',', $contact_ids); + $base_dn = $this->groups_base_dn; $group_name = $group_cache[$group_id]['name']; $member_attr = $group_cache[$group_id]['member_attr']; $group_dn = "cn=$group_name,$base_dn"; + $del_attrs = array(); - $del_attrs = array(); - foreach (explode(",", $contact_ids) as $id) + foreach ($contact_ids as $id) $del_attrs[$member_attr][] = self::dn_decode($id); if (!$this->ldap_mod_del($group_dn, $del_attrs)) { @@ -1980,7 +1985,7 @@ class rcube_ldap extends rcube_addressbook $this->cache->remove('groups'); - return count($del_attrs['member']); + return count($del_attrs[$member_attr]); } /** From ec433114236f9e1871ec5ff9d5d19de50ab236fd Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 1 May 2013 09:46:29 +0200 Subject: [PATCH 09/38] Fix so addressbook_search_mode works also for group search (#1489079) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_addressbook.php | 7 ++++++- program/lib/Roundcube/rcube_contacts.php | 22 +++++++++++++++++++-- program/lib/Roundcube/rcube_ldap.php | 11 ++++++++--- program/steps/mail/autocomplete.inc | 2 +- 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9d1a621b4..4dc83acf1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix so addressbook_search_mode works also for group search (#1489079) - Fix removal of a contact from a group in LDAP addressbook (#1489081) - Support CSV import from Atmail (#1489045) - Inlcude SQL query in the log on SQL error (#1489064) diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index 5fbcb72af..84bd4bfcd 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -309,9 +309,14 @@ abstract class rcube_addressbook * List all active contact groups of this source * * @param string Optional search string to match group name + * @param int Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) + * * @return array Indexed list of contact groups, each a hash array */ - function list_groups($search = null) + function list_groups($search = null, $mode = 0) { /* empty for address books don't supporting groups */ return array(); diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php index 6693e558b..3919cdc6e 100644 --- a/program/lib/Roundcube/rcube_contacts.php +++ b/program/lib/Roundcube/rcube_contacts.php @@ -137,16 +137,34 @@ class rcube_contacts extends rcube_addressbook * List all active contact groups of this source * * @param string Search string to match group name + * @param int Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) + * * @return array Indexed list of contact groups, each a hash array */ - function list_groups($search = null) + function list_groups($search = null, $mode = 0) { $results = array(); if (!$this->groups) return $results; - $sql_filter = $search ? " AND " . $this->db->ilike('name', '%'.$search.'%') : ''; + if ($search) { + switch (intval($mode)) { + case 1: + $sql_filter = $this->db->ilike('name', $search); + break; + case 2: + $sql_filter = $this->db->ilike('name', $search . '%'); + break; + default: + $sql_filter = $this->db->ilike('name', '%' . $search . '%'); + } + + $sql_filter = " AND $sql_filter"; + } $sql_result = $this->db->query( "SELECT * FROM ".$this->db->table_name($this->db_groups). diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index bae72b724..47e96c32b 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -1715,9 +1715,14 @@ class rcube_ldap extends rcube_addressbook * List all active contact groups of this source * * @param string Optional search string to match group name + * @param int Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) + * * @return array Indexed list of contact groups, each a hash array */ - function list_groups($search = null) + function list_groups($search = null, $mode = 0) { if (!$this->groups) return array(); @@ -1729,10 +1734,10 @@ class rcube_ldap extends rcube_addressbook $groups = array(); if ($search) { - $search = mb_strtolower($search); foreach ($group_cache as $group) { - if (strpos(mb_strtolower($group['name']), $search) !== false) + if ($this->compare_search_value('name', $group['name'], $search, $mode)) { $groups[] = $group; + } } } else diff --git a/program/steps/mail/autocomplete.inc b/program/steps/mail/autocomplete.inc index 55579814c..f9e8d71a4 100644 --- a/program/steps/mail/autocomplete.inc +++ b/program/steps/mail/autocomplete.inc @@ -102,7 +102,7 @@ if (!empty($book_types) && strlen($search)) { // also list matching contact groups if ($abook->groups && count($contacts) < $MAXNUM) { - foreach ($abook->list_groups($search) as $group) { + foreach ($abook->list_groups($search, $mode) as $group) { $abook->reset(); $abook->set_group($group['ID']); $group_prop = $abook->get_group($group['ID']); From 61943150d9c8dfdb710cc22b4cff1e54beaf7574 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 1 May 2013 10:40:46 +0200 Subject: [PATCH 10/38] Fix so Sender: address is added to Cc: field on reply to all (#1489011) --- CHANGELOG | 1 + program/steps/mail/compose.inc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 4dc83acf1..29b11aadb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix so Sender: address is added to Cc: field on reply to all (#1489011) - Fix so addressbook_search_mode works also for group search (#1489079) - Fix removal of a contact from a group in LDAP addressbook (#1489081) - Support CSV import from Atmail (#1489045) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 81b598377..cb22bf8ba 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -327,6 +327,8 @@ foreach ($parts as $header) { $fvalue .= $v; if ($v = $MESSAGE->headers->cc) $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + if ($v = $MESSAGE->headers->get('Sender', false)) + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; } } else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { From d2dff5e86505675961bf5a847e7a502b8131dee6 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 1 May 2013 11:11:39 +0200 Subject: [PATCH 11/38] Fix Reply-To header handling in Reply-All action (#1489037) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_mime.php | 34 +++++++++++++++------------- program/steps/mail/compose.inc | 11 +++++++++ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 29b11aadb..41b84935f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix Reply-To header handling in Reply-All action (#1489037) - Fix so Sender: address is added to Cc: field on reply to all (#1489011) - Fix so addressbook_search_mode works also for group search (#1489079) - Fix removal of a contact from a group in LDAP addressbook (#1489081) diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 96296a57c..0a4bfbddb 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -127,10 +127,11 @@ class rcube_mime * @param int $max List only this number of addresses * @param boolean $decode Decode address strings * @param string $fallback Fallback charset if none specified + * @param boolean $addronly Return flat array with e-mail addresses only * - * @return array Indexed list of addresses + * @return array Indexed list of addresses */ - static function decode_address_list($input, $max = null, $decode = true, $fallback = null) + static function decode_address_list($input, $max = null, $decode = true, $fallback = null, $addronly = false) { $a = self::parse_address_list($input, $decode, $fallback); $out = array(); @@ -145,20 +146,21 @@ class rcube_mime foreach ($a as $val) { $j++; $address = trim($val['address']); - $name = trim($val['name']); - - if ($name && $address && $name != $address) - $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address); - else if ($address) - $string = $address; - else if ($name) - $string = $name; - - $out[$j] = array( - 'name' => $name, - 'mailto' => $address, - 'string' => $string - ); + + if ($addronly) { + $out[$j] = $address; + } + else { + $name = trim($val['name']); + if ($name && $address && $name != $address) + $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address); + else if ($address) + $string = $address; + else if ($name) + $string = $name; + + $out[$j] = array('name' => $name, 'mailto' => $address, 'string' => $string); + } if ($max && $j==$max) break; diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index cb22bf8ba..7205d12da 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -329,6 +329,17 @@ foreach ($parts as $header) { $fvalue .= (!empty($fvalue) ? $separator : '') . $v; if ($v = $MESSAGE->headers->get('Sender', false)) $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + + // When To: and Reply-To: are the same we add From: address to the list (#1489037) + if ($v = $MESSAGE->headers->from) { + $from = rcube_mime::decode_address_list($v, null, false, $MESSAGE->headers->charset, true); + $to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $MESSAGE->headers->charset, true); + $replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $MESSAGE->headers->charset, true); + + if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) { + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + } + } } } else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { From 38c19a20641234a9a3a9a1e77e8f1202163ed13d Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 1 May 2013 11:19:47 +0200 Subject: [PATCH 12/38] Fix csv2vcard test --- program/lib/Roundcube/rcube_csv2vcard.php | 6 ++---- tests/src/Csv2vcard/tb_plain.csv | 2 +- tests/src/Csv2vcard/tb_plain.vcf | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php index ed3bb7671..b0e9c2374 100644 --- a/program/lib/Roundcube/rcube_csv2vcard.php +++ b/program/lib/Roundcube/rcube_csv2vcard.php @@ -139,12 +139,10 @@ class rcube_csv2vcard 'info' => 'notes', 'user_photo' => 'photo', 'url' => 'website:homepage', - 'work_city' => 'locality:work', 'work_company' => 'organization', 'work_dept' => 'departament', 'work_fax' => 'phone:work,fax', 'work_mobile' => 'phone:work,cell', - 'work_state' => 'region:work', 'work_title' => 'jobtitle', 'work_zip' => 'zipcode:work', ); @@ -247,7 +245,9 @@ class rcube_csv2vcard 'work_phone' => "Work Phone", 'work_address' => "Work Address", //'work_address_2' => "Work Address 2", + 'work_city' => "Work City", 'work_country' => "Work Country", + 'work_state' => "Work State", 'work_zipcode' => "Work ZipCode", // Atmail @@ -262,12 +262,10 @@ class rcube_csv2vcard 'info' => "Info", 'user_photo' => "User Photo", 'url' => "URL", - 'work_city' => "Work City", 'work_company' => "Work Company", 'work_dept' => "Work Dept", 'work_fax' => "Work Fax", 'work_mobile' => "Work Mobile", - 'work_state' => "Work State", 'work_title' => "Work Title", 'work_zip' => "Work Zip", ); diff --git a/tests/src/Csv2vcard/tb_plain.csv b/tests/src/Csv2vcard/tb_plain.csv index 94ea766c0..4c4af14ca 100644 --- a/tests/src/Csv2vcard/tb_plain.csv +++ b/tests/src/Csv2vcard/tb_plain.csv @@ -1,2 +1,2 @@ First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Screen Name,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes, -Firstname,Lastname,Displayname,Nick,test@domain.tld,next@domain.tld,,phone work,phone home,fax,pager,mobile,Priv address,,City,region,xx-xxx,USA,Addr work,,city,region,33-333,Poland,title,department,Organization,http://page.com,http://webpage.tld,1970,11,15,,,,,, +Firstname,Lastname,Displayname,Nick,test@domain.tld,next@domain.tld,,phone work,phone home,fax,pager,mobile,Priv address,,City,region,xx-xxx,USA,Addr work,,Wcity,Wstate,33-333,Poland,title,department,Organization,http://page.com,http://webpage.tld,1970,11,15,,,,,, diff --git a/tests/src/Csv2vcard/tb_plain.vcf b/tests/src/Csv2vcard/tb_plain.vcf index b001c3924..2aa91adf8 100644 --- a/tests/src/Csv2vcard/tb_plain.vcf +++ b/tests/src/Csv2vcard/tb_plain.vcf @@ -16,5 +16,5 @@ URL;TYPE=homepage:http://page.com URL;TYPE=other:http://webpage.tld BDAY;VALUE=date:1970-11-15 ADR;TYPE=home:;;Priv address;City;region;xx-xxx;USA -ADR;TYPE=work:;;Addr work;;;33-333;Poland +ADR;TYPE=work:;;Addr work;Wcity;Wstate;33-333;Poland END:VCARD From 969cb03f9a3aa9496da68cff53fedce79acc1071 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 1 May 2013 12:26:23 +0200 Subject: [PATCH 13/38] Add option to display email address together with a name in mail preview (#1488732) --- CHANGELOG | 1 + config/main.inc.php.dist | 3 +++ program/localization/en_GB/labels.inc | 1 + program/localization/en_US/labels.inc | 1 + program/steps/mail/func.inc | 27 ++++++++++++++++++--------- program/steps/settings/func.inc | 11 +++++++++++ program/steps/settings/save_prefs.inc | 1 + 7 files changed, 36 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 41b84935f..d3bbf5bfc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add option to display email address together with a name in mail preview (#1488732) - Fix Reply-To header handling in Reply-All action (#1489037) - Fix so Sender: address is added to Cc: field on reply to all (#1489011) - Fix so addressbook_search_mode works also for group search (#1489079) diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 5a652a5b1..05afed9b8 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -890,4 +890,7 @@ $rcmail_config['autocomplete_single'] = false; // Georgia, Helvetica, Impact, Tahoma, Terminal, Times New Roman, Trebuchet MS, Verdana $rcmail_config['default_font'] = ''; +// Enables display of email address with name instead of a name (and address in title) +$rcmail_config['message_show_email'] = false; + // end of config file diff --git a/program/localization/en_GB/labels.inc b/program/localization/en_GB/labels.inc index 8d5509b64..581a7171a 100644 --- a/program/localization/en_GB/labels.inc +++ b/program/localization/en_GB/labels.inc @@ -397,6 +397,7 @@ $labels['pagesize'] = 'Rows per page'; $labels['signature'] = 'Signature'; $labels['dstactive'] = 'Summer time'; $labels['showinextwin'] = 'Open message in a new window'; +$labels['showemail'] = 'Show email address with display name'; $labels['composeextwin'] = 'Compose in a new window'; $labels['htmleditor'] = 'Compose HTML messages'; $labels['htmlonreply'] = 'on reply to HTML message only'; diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 3e1bde0a5..ab57007dd 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -402,6 +402,7 @@ $labels['htmleditor'] = 'Compose HTML messages'; $labels['htmlonreply'] = 'on reply to HTML message'; $labels['htmlonreplyandforward'] = 'on forward or reply to HTML message'; $labels['htmlsignature'] = 'HTML signature'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Show preview pane'; $labels['skin'] = 'Interface skin'; $labels['logoutclear'] = 'Clear Trash on logout'; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 60db3f310..f00813ea2 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1440,7 +1440,8 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $c = count($a_parts); $j = 0; $out = ''; - $allvalues = array(); + $allvalues = array(); + $show_email = $RCMAIL->config->get('message_show_email'); if ($addicon && !isset($_SESSION['writeable_abook'])) { $_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false; @@ -1453,7 +1454,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $string = $part['string']; // phishing email prevention (#1488981), e.g. "valid@email.addr " - if ($name && $name != $mailto && strpos($name, '@')) { + if (!$show_email && $name && $name != $mailto && strpos($name, '@')) { $name = ''; } @@ -1471,13 +1472,21 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, } else if (check_email($part['mailto'], false)) { if ($linked) { - $address = html::a(array( - 'href' => 'mailto:'.$mailto, - 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), - 'title' => $mailto, - 'class' => "rcmContactAddress", - ), - Q($name ? $name : $mailto)); + $attrs = array( + 'href' => 'mailto:' . $mailto, + 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), + 'class' => "rcmContactAddress", + ); + + if ($show_email && $name && $mailto) { + $content = Q($name ? sprintf('%s <%s>', $name, $mailto) : $mailto); + } + else { + $content = Q($name ? $name : $mailto); + $attrs['title'] = $mailto; + } + + $address = html::a($attrs, $content); } else { $address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 319c58db9..860f36c35 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -418,6 +418,17 @@ function rcmail_user_prefs($current=null) ); } + // show checkbox to show email instead of name + if (!isset($no_override['message_show_email'])) { + $field_id = 'rcmfd_message_show_email'; + $input_msgshowemail = new html_checkbox(array('name' => '_message_show_email', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['message_show_email'] = array( + 'title' => html::label($field_id, Q(rcube_label('showemail'))), + 'content' => $input_msgshowemail->show($config['message_show_email']?1:0), + ); + } + // show checkbox for HTML/plaintext messages if (!isset($no_override['prefer_html'])) { $field_id = 'rcmfd_htmlmsg'; diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index dfb2b13ac..3bb82aa38 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -60,6 +60,7 @@ switch ($CURR_SECTION) case 'mailview': $a_user_prefs = array( 'message_extwin' => intval($_POST['_message_extwin']), + 'message_show_email' => isset($_POST['_message_show_email']) ? TRUE : FALSE, 'prefer_html' => isset($_POST['_prefer_html']) ? TRUE : FALSE, 'inline_images' => isset($_POST['_inline_images']) ? TRUE : FALSE, 'show_images' => isset($_POST['_show_images']) ? intval($_POST['_show_images']) : 0, From f790b443353866c25d28bf32fb5bef20e9186aea Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 1 May 2013 12:57:04 +0200 Subject: [PATCH 14/38] Small code improvements --- program/include/rcmail_output_html.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index 0fba66080..02eef2fd1 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -760,9 +760,13 @@ class rcmail_output_html extends rcmail_output /** * Parse & evaluate a given expression and return its result. - * @param string Expression statement + * + * @param string Expression statement + * + * @return mixed Expression result */ - protected function eval_expression ($expression) { + protected function eval_expression ($expression) + { $expression = preg_replace( array( '/session:([a-z0-9_]+)/i', @@ -784,17 +788,19 @@ class rcmail_output_html extends rcmail_output ), $expression ); - + $fn = create_function('$app,$browser,$env', "return ($expression);"); - if(!$fn) { + if (!$fn) { rcube::raise_error(array( 'code' => 505, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Expression parse error on: ($expression)"), true, false); + + return null; } - + return $fn($this->app, $this->browser, $this->env); } @@ -980,7 +986,7 @@ class rcmail_output_html extends rcmail_output // return code for a specified eval expression case 'exp': - return html::quote( $this->eval_expression($attrib['expression']) ); + return html::quote($this->eval_expression($attrib['expression'])); // return variable case 'var': From c2e1ab4765ea69112791df3607faadf1bbf8b9c9 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 1 May 2013 13:26:07 +0200 Subject: [PATCH 15/38] Escape user input values when used in eval() --- program/lib/Roundcube/rcube_ldap.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 47e96c32b..922c73568 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -1403,13 +1403,15 @@ class rcube_ldap extends rcube_addressbook foreach ((array)$this->prop['autovalues'] as $lf => $templ) { if (empty($attrs[$lf])) { - // replace {attr} placeholders with concrete attribute values - $templ = preg_replace('/\{\w+\}/', '', strtr($templ, $attrvals)); - - if (strpos($templ, '(') !== false) - $attrs[$lf] = eval("return ($templ);"); - else - $attrs[$lf] = $templ; + if (strpos($templ, '(') !== false) { + // replace {attr} placeholders with (escaped!) attribute values to be safely eval'd + $code = preg_replace('/\{\w+\}/', '', strtr($templ, array_map('addslashes', $attrvals))); + $attrs[$lf] = eval("return ($code);"); + } + else { + // replace {attr} placeholders with concrete attribute values + $attrs[$lf] = preg_replace('/\{\w+\}/', '', strtr($templ, $attrvals)); + } } } } From 4741d17c7777ed64b0d90b9265125a5dc0d69432 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 1 May 2013 13:56:35 +0200 Subject: [PATCH 16/38] Use create_function() instead of eval() --- CHANGELOG | 1 + program/lib/Roundcube/rcube_ldap.php | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index d3bbf5bfc..060fd9593 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Make PHP code eval() free, use create_function() - Add option to display email address together with a name in mail preview (#1488732) - Fix Reply-To header handling in Reply-All action (#1489037) - Fix so Sender: address is added to Cc: field on reply to all (#1489011) diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 922c73568..26f46a0f6 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -1396,6 +1396,10 @@ class rcube_ldap extends rcube_addressbook */ protected function add_autovalues(&$attrs) { + if (empty($this->prop['autovalues'])) { + return; + } + $attrvals = array(); foreach ($attrs as $k => $v) { $attrvals['{'.$k.'}'] = is_array($v) ? $v[0] : $v; @@ -1406,7 +1410,16 @@ class rcube_ldap extends rcube_addressbook if (strpos($templ, '(') !== false) { // replace {attr} placeholders with (escaped!) attribute values to be safely eval'd $code = preg_replace('/\{\w+\}/', '', strtr($templ, array_map('addslashes', $attrvals))); - $attrs[$lf] = eval("return ($code);"); + $fn = create_function('', "return ($code);"); + if (!$fn) { + rcube::raise_error(array( + 'code' => 505, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Expression parse error on: ($code)"), true, false); + continue; + } + + $attrs[$lf] = $fn(); } else { // replace {attr} placeholders with concrete attribute values From 93580fab12e115bc7b39fa37c7a0bcb208229800 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 2 May 2013 09:53:47 +0200 Subject: [PATCH 17/38] Fix opened window size on small screens in browsers where height is an innerHeight (eg. Safari) --- program/js/app.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index 87f20679a..962651d17 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1629,13 +1629,17 @@ function rcube_webmail() this.open_window = function(url, width, height) { - var w = Math.min(width, screen.width - 10), - h = Math.min(height, screen.height - 100), - l = (screen.width - w) / 2 + (screen.left || 0), - t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20), + var dh = (window.outerHeight || 0) - (window.innerHeight || 0), + dw = (window.outerWidth || 0) - (window.innerWidth || 0), + sh = screen.availHeight || screen.height, + sw = screen.availWidth || screen.width, + w = Math.min(width, sw), + h = Math.min(height, sh), + l = Math.max(0, (sw - w) / 2 + (screen.left || 0)), + t = Math.max(0, (sh - h) / 2 + (screen.top || 0)), wname = 'rcmextwin' + new Date().getTime(), extwin = window.open(url + (url.match(/\?/) ? '&' : '?') + '_extwin=1', wname, - 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no'); + 'width='+(w-dw)+',height='+(h-dh)+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no'); // write loading... message to empty windows if (!url && extwin.document) { From b099d12965b1a430c64353ce58217f0305a0a3a7 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 2 May 2013 20:41:11 +0200 Subject: [PATCH 18/38] Revert fix for #1489058 because it opened another IE8 focus issue --- program/js/list.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/program/js/list.js b/program/js/list.js index c6b0d3fb8..b3b619073 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -231,8 +231,6 @@ focus: function(e) // Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620) $(':focus:not(body)').blur(); - // un-focus iframe bodies (#1489058), this doesn't work in Opera and Chrome - $('iframe').contents().find('body').blur(); if (e || (e = window.event)) rcube_event.cancel(e); From cdb53ccb6a15e54ef5c23c134fd346040ec052bf Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 3 May 2013 08:10:03 +0200 Subject: [PATCH 19/38] Remove changelog entry of reverted change --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 060fd9593..675c14857 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,7 +14,6 @@ CHANGELOG Roundcube Webmail - Fix list page reset when viewing a message in Larry skin (#1489076) - Fix min_refresh_interval handling on preferences save (#1489073) - Fix PDF support detection for Firefox PDF.js (#1488972) -- Fix messages list focus issue in Internet Explorer (#1489058) - Add db_prefix configuration option in place of db_table_*/db_sequence_* options - Make possible to use db_prefix for schema initialization in Installer (#1489067) - Fix updatedb.sh script so it recognizes also table prefix for external DDL files From 2ce01932fef0abfc6d76dc134024c879a72f9cb7 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 3 May 2013 08:24:26 +0200 Subject: [PATCH 20/38] Fix another text wrap issue (added test case) --- program/lib/Roundcube/rcube_mime.php | 4 ++-- tests/Framework/Mime.php | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 0a4bfbddb..53724cbba 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -659,8 +659,8 @@ class rcube_mime $cutLength = $spacePos + 1; } else { - $subString = $string; - $cutLength = null; + $subString = $substr_func($string, 0, $breakPos, $charset); + $cutLength = $breakPos + 1; } } else { diff --git a/tests/Framework/Mime.php b/tests/Framework/Mime.php index 61123dd85..3035ba062 100644 --- a/tests/Framework/Mime.php +++ b/tests/Framework/Mime.php @@ -185,6 +185,10 @@ class Framework_Mime extends PHPUnit_Framework_TestCase array("----------------------------------------------------------------------------------------\nabc def123456789012345", 76), "----------------------------------------------------------------------------------------\nabc def123456789012345", ), + array( + array("-------\nabc def", 5), + "-------\nabc\ndef", + ), ); foreach ($samples as $sample) { From b92ec5c86d2f85c43705ada6fbcb8912f48907f0 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 3 May 2013 09:26:13 +0200 Subject: [PATCH 21/38] Fix bug where multi-level quoting was replaced with one-level quoted text after format=flowed wrapping --- program/lib/Roundcube/rcube_mime.php | 14 ++++++++------ tests/src/format-flowed-unfolded.txt | 2 +- tests/src/format-flowed.txt | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 53724cbba..63549fbec 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -478,9 +478,10 @@ class rcube_mime $q_level = 0; foreach ($text as $idx => $line) { - if ($line[0] == '>') { - // remove quote chars, store level in $q - $line = preg_replace('/^>+/', '', $line, -1, $q); + if (preg_match('/^(>+)/', $line, $m)) { + // remove quote chars + $q = strlen($m[1]); + $line = preg_replace('/^>+/', '', $line); // remove (optional) space-staffing $line = preg_replace('/^ /', '', $line); @@ -543,9 +544,10 @@ class rcube_mime foreach ($text as $idx => $line) { if ($line != '-- ') { - if ($line[0] == '>') { - // remove quote chars, store level in $level - $line = preg_replace('/^>+/', '', $line, -1, $level); + if (preg_match('/^(>+)/', $line, $m)) { + // remove quote chars + $level = strlen($m[1]); + $line = preg_replace('/^>+/', '', $line); // remove (optional) space-staffing and spaces before the line end $line = preg_replace('/(^ | +$)/', '', $line); $prefix = str_repeat('>', $level) . ' '; diff --git a/tests/src/format-flowed-unfolded.txt b/tests/src/format-flowed-unfolded.txt index 14e526be4..0af9b7130 100644 --- a/tests/src/format-flowed-unfolded.txt +++ b/tests/src/format-flowed-unfolded.txt @@ -5,7 +5,7 @@ X On XX.YY.YYYY Y:YY, Somebody wrote: > This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed() -> has to be careful with empty quoted lines because they might end with a +>> has to be careful with empty quoted lines because they might end with a > space but still shouldn't be considered as flowed! > > The above empty line should persist after unfolding. diff --git a/tests/src/format-flowed.txt b/tests/src/format-flowed.txt index 359a41aec..da36064e0 100644 --- a/tests/src/format-flowed.txt +++ b/tests/src/format-flowed.txt @@ -7,7 +7,7 @@ X On XX.YY.YYYY Y:YY, Somebody wrote: > This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed() -> has to be careful with empty quoted lines because they might end with a +>> has to be careful with empty quoted lines because they might end with a > space but still shouldn't be considered as flowed! > > The above empty line should persist after unfolding. From 517dae3e74e39aceabaf2c5da330849a21e82d81 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 3 May 2013 11:38:52 +0200 Subject: [PATCH 22/38] Experimental: refactored list.js and html_table class to render lists with different html structures (e.g. table, ul, div). This show provide more flexibility to skin designers and improve mobile device support --- program/include/rcmail.php | 2 +- program/js/app.js | 55 ++++------- program/js/list.js | 173 ++++++++++++++++++++++++--------- program/lib/Roundcube/html.php | 34 ++++++- program/steps/mail/func.inc | 16 ++- 5 files changed, 183 insertions(+), 97 deletions(-) diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 7acb3490d..6257f4925 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1167,7 +1167,7 @@ class rcmail extends rcube */ public function table_output($attrib, $table_data, $a_show_cols, $id_col) { - $table = new html_table(/*array('cols' => count($a_show_cols))*/); + $table = new html_table($attrib); // add table header if (!$attrib['noheader']) { diff --git a/program/js/app.js b/program/js/app.js index 962651d17..a652b8985 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1579,7 +1579,7 @@ function rcube_webmail() this.msglist_set_coltypes = function(list) { - var i, found, name, cols = list.list.tHead.rows[0].cells; + var i, found, name, cols = list.thead.rows[0].cells; this.env.coltypes = []; @@ -1733,10 +1733,7 @@ function rcube_webmail() + (flags.flagged ? ' flagged' : '') + (flags.unread_children && flags.seen && !this.env.autoexpand_threads ? ' unroot' : '') + (message.selected ? ' selected' : ''), - // for performance use DOM instead of jQuery here - row = document.createElement('tr'); - - row.id = 'rcmrow'+uid; + row = { cols:[], style:{}, id:'rcmrow'+uid }; // message status icons css_class = 'msgicon'; @@ -1800,8 +1797,7 @@ function rcube_webmail() // add each submitted col for (n in this.env.coltypes) { c = this.env.coltypes[n]; - col = document.createElement('td'); - col.className = String(c).toLowerCase(); + col = { className: String(c).toLowerCase() }; if (c == 'flag') { css_class = (flags.flagged ? 'flagged' : 'unflagged'); @@ -1846,8 +1842,7 @@ function rcube_webmail() html = cols[c]; col.innerHTML = html; - - row.appendChild(col); + row.cols.push(col); } list.insert_row(row, attop); @@ -2210,7 +2205,7 @@ function rcube_webmail() if (root) row = rows[root] ? rows[root].obj : null; else - row = this.message_list.list.tBodies[0].firstChild; + row = this.message_list.tbody.firstChild; while (row) { if (row.nodeType == 1 && (r = rows[row.uid])) { @@ -2386,7 +2381,7 @@ function rcube_webmail() this.delete_excessive_thread_rows = function() { var rows = this.message_list.rows, - tbody = this.message_list.list.tBodies[0], + tbody = this.message_list.tbody, row = tbody.firstChild, cnt = this.env.pagesize + 1; @@ -4329,21 +4324,7 @@ function rcube_webmail() newcid = newcid+'-'+source; } - if (list.rows[cid] && (row = list.rows[cid].obj)) { - for (c=0; c').attr('id', 'rcmrow'+rid).get(0); - col = $('').addClass('mail').html(name).appendTo(row); - list.insert_row(row); + if (add) { + list.insert_row({ id:'rcmrow'+rid, cols:[ { className:'mail', innerHTML:name } ] }); list.select(rid); } + else { + list.update_row(rid, [ name ]); + } }; @@ -5751,7 +5730,7 @@ function rcube_webmail() this.set_message_coltypes = function(coltypes, repl, smart_col) { var list = this.message_list, - thead = list ? list.list.tHead : null, + thead = list ? list.thead : null, cell, col, n, len, th, tr; this.env.coltypes = coltypes; diff --git a/program/js/list.js b/program/js/list.js index b3b619073..dd99fd2f2 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -30,6 +30,9 @@ function rcube_list_widget(list, p) this.BACKSPACE_KEY = 8; this.list = list ? list : null; + this.tagname = this.list ? this.list.nodeName.toLowerCase() : 'table'; + this.thead; + this.tbody; this.frame = null; this.rows = []; this.selection = []; @@ -56,7 +59,7 @@ function rcube_list_widget(list, p) this.focused = false; this.drag_mouse_start = null; this.dblclick_time = 600; - this.row_init = function(){}; + this.row_init = function(){}; // @deprecated; use list.addEventListener('initrow') instead // overwrite default paramaters if (p && typeof p === 'object') @@ -73,11 +76,19 @@ rcube_list_widget.prototype = { */ init: function() { - if (this.list && this.list.tBodies[0]) { + if (this.tagname == 'table' && this.list && this.list.tBodies[0]) { + this.thead = this.list.tHead; + this.tbody = this.list.tBodies[0]; + } + else if (this.tagname != 'table' && this.list) { + this.tbody = this.list; + } + + if (this.tbody) { this.rows = []; this.rowcount = 0; - var r, len, rows = this.list.tBodies[0].rows; + var r, len, rows = this.tbody.childNodes; for (r=0, len=rows.length; r=0; i--) if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) @@ -632,6 +691,22 @@ get_last_row: function() return null; }, +row_tagname: function() +{ + var row_tagnames = { table:'tr', ul:'li', '*':'div' }; + return row_tagnames[this.tagname] || row_tagnames['*']; +}, + +col_tagname: function() +{ + var col_tagnames = { table:'td', '*':'span' }; + return col_tagnames[this.tagname] || col_tagnames['*']; +}, + +get_cell: function(row, index) +{ + return $(this.col_tagname(), row).eq(index); +}, /** * selects or unselects the proper row depending on the modifier key pressed @@ -779,19 +854,19 @@ shift_select: function(id, control) this.shift_start = id; var n, i, j, to_row = this.rows[id], - from_rowIndex = this.rows[this.shift_start].obj.rowIndex, - to_rowIndex = to_row.obj.rowIndex; + from_rowIndex = this._rowIndex(this.rows[this.shift_start].obj), + to_rowIndex = this._rowIndex(to_row.obj); if (!to_row.expanded && to_row.has_children) if (to_row = this.rows[(this.row_children(id)).pop()]) - to_rowIndex = to_row.obj.rowIndex; + to_rowIndex = this._rowIndex(to_row.obj); i = ((from_rowIndex < to_rowIndex) ? from_rowIndex : to_rowIndex), j = ((from_rowIndex > to_rowIndex) ? from_rowIndex : to_rowIndex); // iterate through the entire message list for (n in this.rows) { - if (this.rows[n].obj.rowIndex >= i && this.rows[n].obj.rowIndex <= j) { + if (this._rowIndex(this.rows[n].obj) >= i && this._rowIndex(this.rows[n].obj) <= j) { if (!this.in_selection(n)) { this.highlight_row(n, true); } @@ -804,6 +879,13 @@ shift_select: function(id, control) } }, +/** + * Helper method to emulate the rowIndex property of non-tr elements + */ +_rowIndex: function(obj) +{ + return (obj.rowIndex !== undefined) ? obj.rowIndex : $(obj).prevAll().length; +}, /** * Check if given id is part of the current selection @@ -1148,7 +1230,7 @@ drag_mouse_move: function(e) this.draglayer.html(''); // get subjects of selected messages - var i, n, obj; + var i, n, obj, me; for (n=0; n12) { @@ -1156,29 +1238,28 @@ drag_mouse_move: function(e) break; } + me = this; if (obj = this.rows[this.selection[n]].obj) { - for (i=0; i '+this.col_tagname(), obj).each(function(i,elem){ + if (n == 0) + me.drag_start_pos = $(elem).offset(); - if (this.subject_col < 0 || (this.subject_col >= 0 && this.subject_col == i)) { - var subject = $(obj.childNodes[i]).text(); - - if (!subject) - break; + if (me.subject_col < 0 || (me.subject_col >= 0 && me.subject_col == i)) { + var subject = $(elem).text(); + if (subject) { // remove leading spaces subject = $.trim(subject); // truncate line to 50 characters subject = (subject.length > 50 ? subject.substring(0, 50) + '...' : subject); var entry = $('
').text(subject); - this.draglayer.append(entry); - break; + me.draglayer.append(entry); } + + return false; // break } - } + }); } } @@ -1253,7 +1334,7 @@ column_drag_mouse_move: function(e) if (!this.col_draglayer) { var lpos = $(this.list).offset(), - cells = this.list.tHead.rows[0].cells; + cells = this.thead.rows[0].cells; // create dragging layer this.col_draglayer = $('
').attr('id', 'rcmcoldraglayer') @@ -1409,7 +1490,11 @@ del_dragfix: function() */ column_replace: function(from, to) { - var len, cells = this.list.tHead.rows[0].cells, + // only supported for lists + if (!this.thead || !this.thead.rows) + return; + + var len, cells = this.thead.rows[0].cells, elem = cells[from], before = cells[to], td = document.createElement('td'); @@ -1422,8 +1507,8 @@ column_replace: function(from, to) cells[0].parentNode.replaceChild(elem, td); // replace list cells - for (r=0, len=this.list.tBodies[0].rows.length; r '', 'border' => 0) : array(); $this->attrib = array_merge($attrib, $default_attrib); + + if (!empty($attrib['tagname']) && $attrib['tagname'] != 'table') { + $this->tagname = $attrib['tagname']; + $this->allowed = self::$common_attrib; + } } /** @@ -816,19 +821,20 @@ class html_table extends html if (!empty($this->header)) { $rowcontent = ''; foreach ($this->header as $c => $col) { - $rowcontent .= self::tag('td', $col->attrib, $col->content); + $rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content); } - $thead = self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)); + $thead = $this->tagname == 'table' ? self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)) : + self::tag($this->_row_tagname(), array('class' => 'thead'), $rowcontent, parent::$common_attrib); } foreach ($this->rows as $r => $row) { $rowcontent = ''; foreach ($row->cells as $c => $col) { - $rowcontent .= self::tag('td', $col->attrib, $col->content); + $rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content); } if ($r < $this->rowindex || count($row->cells)) { - $tbody .= self::tag('tr', $row->attrib, $rowcontent, parent::$common_attrib); + $tbody .= self::tag($this->_row_tagname(), $row->attrib, $rowcontent, parent::$common_attrib); } } @@ -837,7 +843,7 @@ class html_table extends html } // add - $this->content = $thead . self::tag('tbody', null, $tbody); + $this->content = $thead . ($this->tagname == 'table' ? self::tag('tbody', null, $tbody) : $tbody); unset($this->attrib['cols'], $this->attrib['rowsonly']); return parent::show(); @@ -862,4 +868,22 @@ class html_table extends html $this->rowindex = 0; } + /** + * Getter for the corresponding tag name for table row elements + */ + private function _row_tagname() + { + static $row_tagnames = array('table' => 'tr', 'ul' => 'li', '*' => 'div'); + return $row_tagnames[$this->tagname] ?: $row_tagnames['*']; + } + + /** + * Getter for the corresponding tag name for table cell elements + */ + private function _col_tagname() + { + static $col_tagnames = array('table' => 'td', '*' => 'span'); + return $col_tagnames[$this->tagname] ?: $col_tagnames['*']; + } + } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index f00813ea2..37f37d08f 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -236,15 +236,13 @@ function rcmail_message_list($attrib) $OUTPUT->include_script('list.js'); - $thead = ''; - foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) - $thead .= html::tag('td', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); - - return html::tag('table', - $attrib, - html::tag('thead', null, html::tag('tr', null, $thead)) . - html::tag('tbody', null, ''), - array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); + $table = new html_table($attrib); + if (!$attrib['noheader']) { + foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) + $table->add_header(array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); + } + + return $table->show(); } From b15cc7d6f4c77fb941c74670eb58fb07bd9c7d9c Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 3 May 2013 12:09:57 +0200 Subject: [PATCH 23/38] Check Google spell check service response for errors and report them accordingly --- program/lib/Roundcube/rcube_spellchecker.php | 15 ++++++++++----- program/steps/utils/spell.inc | 7 +++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/program/lib/Roundcube/rcube_spellchecker.php b/program/lib/Roundcube/rcube_spellchecker.php index 816bcad2f..2b48fca92 100644 --- a/program/lib/Roundcube/rcube_spellchecker.php +++ b/program/lib/Roundcube/rcube_spellchecker.php @@ -314,11 +314,6 @@ class rcube_spellchecker if (!$this->plink) { if (!extension_loaded('pspell')) { $this->error = "Pspell extension not available"; - rcube::raise_error(array( - 'code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => $this->error), true, false); - return; } @@ -372,9 +367,19 @@ class rcube_spellchecker fclose($fp); } + // parse HTTP response + if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) { + $http_status = $m[1]; + if ($http_status != '200') + $this->error = 'HTTP ' . $m[1] . $m[2]; + } + if (!$store) { $this->error = "Empty result from spelling engine"; } + else if (preg_match('/error = "Error code $m[1] returned"; + } preg_match_all('/([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER); diff --git a/program/steps/utils/spell.inc b/program/steps/utils/spell.inc index a0dd35d27..b59fe7998 100644 --- a/program/steps/utils/spell.inc +++ b/program/steps/utils/spell.inc @@ -42,6 +42,13 @@ else { $result = $spellchecker->get_xml(); } +if ($err = $spellchecker->error()) { + raise_error(array('code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => sprintf("Spell check engine error: " . $err)), + true, false); +} + // set response length header("Content-Length: " . strlen($result)); From 3db62ce1015c134ff7a6b83294f8c2cbf1f1a096 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 3 May 2013 12:14:50 +0200 Subject: [PATCH 24/38] Fix messages list focus issue in Opera and Webkit (#1489058) --- CHANGELOG | 1 + program/js/list.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 675c14857..8aa7948fe 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix messages list focus issue in Opera and Webkit (#1489058) - Make PHP code eval() free, use create_function() - Add option to display email address together with a name in mail preview (#1488732) - Fix Reply-To header handling in Reply-All action (#1489037) diff --git a/program/js/list.js b/program/js/list.js index dd99fd2f2..0385092d6 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -289,7 +289,9 @@ focus: function(e) } // Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620) + // It looks that window.focus() does the job for all browsers, but not Firefox (#1489058) $(':focus:not(body)').blur(); + window.focus(); if (e || (e = window.event)) rcube_event.cancel(e); From cfe2fc8b30e7e5c21452239a36301fdaeffdfd7d Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 3 May 2013 12:33:02 +0200 Subject: [PATCH 25/38] Log spellchecker error also in html mode --- program/steps/utils/spell.inc | 2 +- program/steps/utils/spell_html.inc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/program/steps/utils/spell.inc b/program/steps/utils/spell.inc index b59fe7998..38e4ca285 100644 --- a/program/steps/utils/spell.inc +++ b/program/steps/utils/spell.inc @@ -43,7 +43,7 @@ else { } if ($err = $spellchecker->error()) { - raise_error(array('code' => 500, 'type' => 'php', + rcube::raise_error(array('code' => 500, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => sprintf("Spell check engine error: " . $err)), true, false); diff --git a/program/steps/utils/spell_html.inc b/program/steps/utils/spell_html.inc index 861e4ba48..96b41e230 100644 --- a/program/steps/utils/spell_html.inc +++ b/program/steps/utils/spell_html.inc @@ -46,6 +46,11 @@ else if ($request['method'] == 'learnWord') { } if ($error = $spellchecker->error()) { + rcube::raise_error(array('code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => sprintf("Spell check engine error: " . $error)), + true, false); + echo '{"error":{"errstr":"' . addslashes($error) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}'; exit; } From ceb508620e665309972e96225c45f23ab2dea84b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 4 May 2013 16:53:47 +0200 Subject: [PATCH 26/38] Implemented updatecss.sh script for background images cache issues fix (#1489047) --- bin/updatecss.sh | 122 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100755 bin/updatecss.sh diff --git a/bin/updatecss.sh b/bin/updatecss.sh new file mode 100755 index 000000000..c477171ff --- /dev/null +++ b/bin/updatecss.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env php + | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH . 'program/include/clisetup.php'; + +// get arguments +$opts = rcube_utils::get_opt(array( + 'd' => 'dir', +)); + +if (empty($opts['dir'])) { + print "Skin directory not specified (--dir). Using skins/ and plugins/skins/.\n"; + + $dir = INSTALL_PATH . 'skins'; + $dir_p = INSTALL_PATH . 'plugins'; + $skins = glob("$dir/*", GLOB_ONLYDIR); + $skins_p = glob("$dir_p/*/skins/*", GLOB_ONLYDIR); + + $dirs = array_merge($skins, $skins_p); +} +// Check if directory exists +else if (!file_exists($opts['dir'])) { + rcube::raise_error("Specified directory doesn't exist.", false, true); +} +else { + $dirs = array($opts['dir']); +} + +foreach ($dirs as $dir) { + $img_dir = $dir . '/images'; + if (!file_exists($img_dir)) { + continue; + } + + $files = get_files($dir); + $images = get_images($img_dir); + $find = array(); + $replace = array(); + + // build regexps array + foreach ($images as $path => $sum) { + $path_ex = str_replace('.', '\\.', $path); + $find[] = "#url\(['\"]?images/$path_ex(\?v=[a-f0-9-\.]+)?['\"]?\)#"; + $replace[] = "url(images/$path?v=$sum)"; + } + + foreach ($files as $file) { + $file = $dir . '/' . $file; + print "File: $file\n"; + $content = file_get_contents($file); + $content = preg_replace($find, $replace, $content, -1, $count); + if ($count) { + file_put_contents($file, $content); + } + } +} + + +function get_images($dir) +{ + $images = array(); + $dh = opendir($dir); + + while ($file = readdir($dh)) { + if (preg_match('/^(.+)\.(gif|ico|png|jpg|jpeg)$/', $file, $m)) { + $filepath = "$dir/$file"; + $images[$file] = substr(md5_file($filepath), 0, 4) . '.' . filesize($filepath); + print "Image: $filepath ({$images[$file]})\n"; + } + else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) { + foreach (get_images($dir . '/' . $file) as $img => $sum) { + $images[$file . '/' . $img] = $sum; + } + } + } + + closedir($dh); + + return $images; +} + +function get_files($dir) +{ + $files = array(); + $dh = opendir($dir); + + while ($file = readdir($dh)) { + if (preg_match('/^(.+)\.(css|html)$/', $file, $m)) { + $files[] = $file; + } + else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) { + foreach (get_files($dir . '/' . $file) as $f) { + $files[] = $file . '/' . $f; + } + } + } + + closedir($dh); + + return $files; +} + +?> From 49311c55dd3a763306f70fbed44919f9c96ea186 Mon Sep 17 00:00:00 2001 From: Zou Guangxian Date: Sat, 4 May 2013 23:15:28 +0800 Subject: [PATCH 27/38] * fixed: modsecurity warning: AppDefect: Cache-Control Response Header Missing 'no-store' flag. http://websecuritytool.codeplex.com/wikipage?title=Checks#http-cache-control-header-no-store --- program/lib/Roundcube/rcube_output.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/lib/Roundcube/rcube_output.php b/program/lib/Roundcube/rcube_output.php index b8ae86cf6..7ccf9a02e 100644 --- a/program/lib/Roundcube/rcube_output.php +++ b/program/lib/Roundcube/rcube_output.php @@ -162,7 +162,7 @@ abstract class rcube_output header("Cache-Control: private, must-revalidate"); } else { - header("Cache-Control: private, no-cache, must-revalidate, post-check=0, pre-check=0"); + header("Cache-Control: private, no-cache, no-store, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); } } From 0b0caee40b6c68263a349b54bc989ceb53af1b63 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 5 May 2013 13:11:34 +0200 Subject: [PATCH 28/38] Fix csv import from Thunderbird with French localization (#1489059) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_csv2vcard.php | 6 ++ program/localization/fr_FR/csv2vcard.inc | 96 +++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 program/localization/fr_FR/csv2vcard.inc diff --git a/CHANGELOG b/CHANGELOG index 8aa7948fe..56d5d7b72 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix csv import from Thunderbird with French localization (#1489059) - Fix messages list focus issue in Opera and Webkit (#1489058) - Make PHP code eval() free, use create_function() - Add option to display email address together with a name in mail preview (#1488732) diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php index b0e9c2374..fa22fa41b 100644 --- a/program/lib/Roundcube/rcube_csv2vcard.php +++ b/program/lib/Roundcube/rcube_csv2vcard.php @@ -389,6 +389,12 @@ class rcube_csv2vcard if (!empty($this->local_label_map)) { for ($i = 0; $i < $size; $i++) { $label = $this->local_label_map[$elements[$i]]; + + // special localization label + if ($label && $label[0] == '_') { + $label = substr($label, 1); + } + if ($label && !empty($this->csv2vcard_map[$label])) { $map2[$i] = $this->csv2vcard_map[$label]; } diff --git a/program/localization/fr_FR/csv2vcard.inc b/program/localization/fr_FR/csv2vcard.inc new file mode 100644 index 000000000..bb77001b5 --- /dev/null +++ b/program/localization/fr_FR/csv2vcard.inc @@ -0,0 +1,96 @@ +/csv2vcard.inc | + | | + | Localization file of the Roundcube Webmail client | + | 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. | + | See the README file for a full license statement. | + | | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak | + +-----------------------------------------------------------------------+ +*/ + +// This is a list of CSV column names specified in CSV file header +// These must be original texts used in Outlook/Thunderbird exported csv files +// Encoding UTF-8 + +$map = array(); + +// MS Outlook 2010 +$map['anniversary'] = "Anniversaire de mariage ou fête"; +$map['assistants_name'] = "Nom de l''assistant(e)"; +$map['assistants_phone'] = "Téléphone de l''assistant(e)"; +$map['birthday'] = "Anniversaire"; +$map['business_city'] = "Ville (bureau)"; +$map['business_countryregion'] = "Pays/Région (bureau)"; +$map['business_fax'] = "Télécopie (bureau)"; +$map['business_phone'] = "Téléphone (bureau)"; +$map['business_phone_2'] = "Téléphone 2 (bureau)"; +$map['business_postal_code'] = "Code postal (bureau)"; +$map['business_state'] = "Dép/Région (bureau)"; +$map['business_street'] = "Rue (bureau)"; +$map['car_phone'] = "Téléphone (voiture)"; +$map['categories'] = "Catégories"; +$map['company'] = "Société"; +$map['department'] = "Service"; +$map['email_address'] = "Adresse de messagerie"; +$map['first_name'] = "Prénom"; +$map['gender'] = "Sexe"; +$map['home_city'] = "Ville (domicile)"; +$map['home_countryregion'] = "Pays/Région (domicile)"; +$map['home_fax'] = "Télécopie (domicile)"; +$map['home_phone'] = "Téléphone (domicile)"; +$map['home_phone_2'] = "Téléphone 2 (domicile)"; +$map['home_postal_code'] = "Code postal (domicile)"; +$map['home_state'] = "Dép/Région (domicile)"; +$map['home_street'] = "Rue (domicile)"; +$map['job_title'] = "Profession"; +$map['last_name'] = "Nom"; +$map['managers_name'] = "Manager's Name"; +$map['middle_name'] = "Deuxième prénom"; +$map['mobile_phone'] = "Tél. mobile"; +$map['notes'] = "Notes"; +$map['other_city'] = "Ville (autre)"; +$map['other_countryregion'] = "Pays/Région (autre)"; +$map['other_fax'] = "Télécopie (autre)"; +$map['other_phone'] = "Téléphone (autre)"; +$map['other_postal_code'] = "Code postal (autre)"; +$map['other_state'] = "Dép/Région (autre)"; +$map['other_street'] = "Rue (autre)"; +$map['pager'] = "Récepteur de radiomessagerie"; +$map['primary_phone'] = "Téléphone principal"; +$map['spouse'] = "Conjoint(e)"; +$map['suffix'] = "Suffixe"; +$map['title'] = "Titre"; +$map['web_page'] = "Page Web"; + +// Thunderbird +$map['birth_day'] = "Jour"; +$map['birth_month'] = "Mois"; +$map['birth_year'] = "Année de naissance"; +$map['display_name'] = "Nom à afficher"; +$map['fax_number'] = "Fax"; +$map['home_address'] = "Adresse privée"; +$map['home_country'] = "Région"; +$map['home_zipcode'] = "Code postal"; +$map['mobile_number'] = "Portable"; +$map['nickname'] = "Surnom"; +$map['organization'] = "Société"; +$map['pager_number'] = "Pager"; +$map['primary_email'] = "Adresse électronique principale"; +$map['secondary_email'] = "Adresse électronique secondaire"; +$map['web_page_1'] = "Site Web 1"; +$map['web_page_2'] = "Site Web 2"; +$map['work_phone'] = "Tél. professionnel"; +$map['work_address'] = "Adresse professionnelle"; +$map['work_country'] = "Région"; +$map['work_zipcode'] = "Code postal"; + +// Other +$map['_home_city'] = "Ville"; From 3a0dc87856cc0c2a47649e58e930621506e64cbf Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 5 May 2013 16:38:58 +0200 Subject: [PATCH 29/38] Fix backslash character handling on vCard import (#1489085) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_vcard.php | 23 ++++++++++++++++++++++- tests/Framework/VCard.php | 14 ++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 56d5d7b72..c97df8c96 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix backslash character handling on vCard import (#1489085) - Fix csv import from Thunderbird with French localization (#1489059) - Fix messages list focus issue in Opera and Webkit (#1489058) - Make PHP code eval() free, use create_function() diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php index 54bb9521d..cc3a35850 100644 --- a/program/lib/Roundcube/rcube_vcard.php +++ b/program/lib/Roundcube/rcube_vcard.php @@ -784,9 +784,30 @@ class rcube_vcard } return $result; } + + $s = strtr($s, $rep2); + } + + // some implementations (GMail) use non-standard backslash before colon (#1489085) + // we will handle properly any backslashed character - removing dummy backslahes + // return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';')); + + $s = str_replace("\r", '', $s); + $pos = 0; + + while (($pos = strpos($s, '\\', $pos)) !== false) { + $next = substr($s, $pos + 1, 1); + if ($next == 'n' || $next == 'N') { + $s = substr_replace($s, "\n", $pos, 2); + } + else { + $s = substr_replace($s, '', $pos, 1); + } + + $pos += 1; } - return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';')); + return $s; } /** diff --git a/tests/Framework/VCard.php b/tests/Framework/VCard.php index 15aa5d816..3353b5b13 100644 --- a/tests/Framework/VCard.php +++ b/tests/Framework/VCard.php @@ -65,6 +65,20 @@ class Framework_VCard extends PHPUnit_Framework_TestCase $this->assertEquals("prefix", $vcard['prefix'], "Decode backslash character"); } + /** + * Backslash parsing test (#1489085) + */ + function test_parse_five() + { + $vcard = "BEGIN:VCARD\nVERSION:3.0\nN:last\\\\\\a;fir\\nst\nURL:http\\://domain.tld\nEND:VCARD"; + $vcard = new rcube_vcard($vcard, null); + $vcard = $vcard->get_assoc(); + + $this->assertEquals("last\\a", $vcard['surname'], "Decode dummy backslash character"); + $this->assertEquals("fir\nst", $vcard['firstname'], "Decode backslash character"); + $this->assertEquals("http://domain.tld", $vcard['website:other'][0], "Decode dummy backslash character"); + } + function test_import() { $input = file_get_contents($this->_srcpath('apple.vcf')); From c027ba7709a86c23038428de15ffed503e67c522 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 6 May 2013 12:07:05 +0200 Subject: [PATCH 30/38] Fix bugs caught by static analysis --- plugins/acl/acl.php | 5 +++-- plugins/password/drivers/sql.php | 2 +- program/lib/Roundcube/rcube_addressbook.php | 3 +-- program/lib/Roundcube/rcube_db_mysql.php | 2 +- program/lib/Roundcube/rcube_imap.php | 4 ++-- program/lib/Roundcube/rcube_imap_generic.php | 8 ++++---- program/lib/Roundcube/rcube_spellchecker.php | 2 +- program/lib/Roundcube/rcube_vcard.php | 2 +- program/lib/utf8.class.php | 4 ++-- program/steps/addressbook/func.inc | 2 +- program/steps/addressbook/import.inc | 4 ++-- program/steps/addressbook/show.inc | 2 +- program/steps/mail/compose.inc | 5 +++-- 13 files changed, 23 insertions(+), 22 deletions(-) diff --git a/plugins/acl/acl.php b/plugins/acl/acl.php index 938287b1a..8879a6050 100644 --- a/plugins/acl/acl.php +++ b/plugins/acl/acl.php @@ -433,8 +433,9 @@ class acl extends rcube_plugin $acl = trim(rcube_utils::get_input_value('_acl', rcube_utils::INPUT_GPC)); $oldid = trim(rcube_utils::get_input_value('_old', rcube_utils::INPUT_GPC)); - $acl = array_intersect(str_split($acl), $this->rights_supported()); - $users = $oldid ? array($user) : explode(',', $user); + $acl = array_intersect(str_split($acl), $this->rights_supported()); + $users = $oldid ? array($user) : explode(',', $user); + $result = 0; foreach ($users as $user) { $user = trim($user); diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php index e02bff146..de9ea0a3f 100644 --- a/plugins/password/drivers/sql.php +++ b/plugins/password/drivers/sql.php @@ -183,7 +183,7 @@ class rcube_sql_password $res = $db->query($sql, $sql_vars); if (!$db->is_error()) { - if (strtolower(substr(trim($query),0,6))=='select') { + if (strtolower(substr(trim($sql),0,6)) == 'select') { if ($result = $db->fetch_array($res)) return PASSWORD_SUCCESS; } else { diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index 84bd4bfcd..a1b29c3da 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -535,7 +535,7 @@ abstract class rcube_addressbook */ public static function compose_contact_key($contact, $sort_col) { - $key = $contact[$sort_col] . ':' . $row['sourceid']; + $key = $contact[$sort_col] . ':' . $contact['sourceid']; // add email to a key to not skip contacts with the same name (#1488375) if (!empty($contact['email'])) { @@ -545,7 +545,6 @@ abstract class rcube_addressbook return $key; } - /** * Compare search value with contact data * diff --git a/program/lib/Roundcube/rcube_db_mysql.php b/program/lib/Roundcube/rcube_db_mysql.php index 8ab6403c8..de81ede98 100644 --- a/program/lib/Roundcube/rcube_db_mysql.php +++ b/program/lib/Roundcube/rcube_db_mysql.php @@ -147,7 +147,7 @@ class rcube_db_mysql extends rcube_db $result = $this->query('SHOW VARIABLES'); - while ($sql_arr = $this->fetch_array($result)) { + while ($row = $this->fetch_array($result)) { $this->variables[$row[0]] = $row[1]; } } diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index c67985186..696f485eb 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -981,7 +981,7 @@ class rcube_imap extends rcube_storage // use memory less expensive (and quick) method for big result set $index = clone $this->index('', $this->sort_field, $this->sort_order); // get messages uids for one page... - $index->slice($start_msg, min($cnt-$from, $this->page_size)); + $index->slice($from, min($cnt-$from, $this->page_size)); if ($slice) { $index->slice(-$slice, $slice); @@ -2727,7 +2727,7 @@ class rcube_imap extends rcube_storage // filter folders list according to rights requirements if ($rights && $this->get_capability('ACL')) { - $a_folders = $this->filter_rights($a_folders, $rights); + $a_mboxes = $this->filter_rights($a_mboxes, $rights); } // filter folders and sort them diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index db50ffbab..fd8b130db 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -1077,7 +1077,7 @@ class rcube_imap_generic } if (!$this->data['READ-WRITE']) { - $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'EXPUNGE'); + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); return false; } @@ -1936,7 +1936,7 @@ class rcube_imap_generic } if (!$this->data['READ-WRITE']) { - $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE'); + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); return false; } @@ -1997,7 +1997,7 @@ class rcube_imap_generic } if (!$this->data['READ-WRITE']) { - $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE'); + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); return false; } @@ -2508,7 +2508,7 @@ class rcube_imap_generic $tokens = $this->tokenizeResponse(preg_replace('/(^\(|\)$)/', '', $line)); for ($i=0; $irc->db->query( + $sql_result = $this->rc->db->query( "SELECT data FROM ".$this->rc->db->table_name('dictionary') ." WHERE user_id ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php index cc3a35850..aded4aa78 100644 --- a/program/lib/Roundcube/rcube_vcard.php +++ b/program/lib/Roundcube/rcube_vcard.php @@ -90,7 +90,7 @@ class rcube_vcard */ public function __construct($vcard = null, $charset = RCUBE_CHARSET, $detect = false, $fieldmap = array()) { - if (!empty($fielmap)) { + if (!empty($fieldmap)) { $this->extend_fieldmap($fieldmap); } diff --git a/program/lib/utf8.class.php b/program/lib/utf8.class.php index e0dc9e2bd..0446159c7 100644 --- a/program/lib/utf8.class.php +++ b/program/lib/utf8.class.php @@ -60,8 +60,8 @@ Class utf8 { function loadCharset($charset) { $charset = preg_replace(array('/^WINDOWS-*125([0-8])$/', '/^CP-/'), array('CP125\\1', 'CP'), $charset); - if (isset($aliases[$charset])) - $charset = $aliases[$charset]; + if (isset($this->aliases[$charset])) + $charset = $this->aliases[$charset]; $this->charset = $charset; diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index ffc0b3b92..f0fb433bf 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -167,7 +167,7 @@ function rcmail_set_sourcename($abook) // get address book name (for display) if ($abook && $_SESSION['addressbooks_count'] > 1) { $name = $abook->get_name(); - if (!$name && $source == 0) { + if (!$name) { $name = rcube_label('personaladrbook'); } $OUTPUT->set_env('sourcename', html_entity_decode($name, ENT_COMPAT, 'UTF-8')); diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index 72da15078..915aac884 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -88,7 +88,7 @@ function rcmail_import_confirm($attrib) $content = html::p(null, rcube_label(array( 'name' => 'importconfirm', - 'nr' => $IMORT_STATS->inserted, + 'nr' => $IMPORT_STATS->inserted, 'vars' => $vars, )) . ($IMPORT_STATS->names ? ':' : '.')); @@ -98,7 +98,7 @@ function rcmail_import_confirm($attrib) if ($IMPORT_STATS->skipped) { $content .= html::p(null, rcube_label(array( 'name' => 'importconfirmskipped', - 'nr' => $IMORT_STATS->skipped, + 'nr' => $IMPORT_STATS->skipped, 'vars' => $vars, )) . ':'); $content .= html::p('em', join(', ', array_map('Q', $IMPORT_STATS->skipped_names))); diff --git a/program/steps/addressbook/show.inc b/program/steps/addressbook/show.inc index 16be89f94..d583a6d36 100644 --- a/program/steps/addressbook/show.inc +++ b/program/steps/addressbook/show.inc @@ -223,7 +223,7 @@ function rcmail_contact_record_groups($contact_id) } $hiddenfields = new html_hiddenfield(array('name' => '_source', 'value' => get_input_value('_source', RCUBE_INPUT_GPC))); - $hiddenfields->add(array('name' => '_cid', 'value' => $record['ID'])); + $hiddenfields->add(array('name' => '_cid', 'value' => $contact_id)); $form_start = $RCMAIL->output->request_form(array( 'name' => "form", 'method' => "post", diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 7205d12da..f4a1daf58 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -639,7 +639,7 @@ function rcmail_prepare_message_body() function rcmail_compose_part_body($part, $isHtml = false) { - global $RCMAIL, $MESSAGE, $compose_mode; + global $RCMAIL, $MESSAGE, $LINE_LENGTH, $compose_mode; // Check if we have enough memory to handle the message in it // #1487424: we need up to 10x more memory than the body @@ -1224,10 +1224,11 @@ function rcmail_save_image($path, $mimetype='') // handle attachments in memory $data = file_get_contents($path); + $name = rcmail_basename($path); $attachment = array( 'group' => $COMPOSE['id'], - 'name' => rcmail_basename($path), + 'name' => $name, 'mimetype' => $mimetype ? $mimetype : rc_mime_content_type($path, $name), 'data' => $data, 'size' => strlen($data), From ce89ecd54277fdd8113320ba463dfab6d504b00c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 6 May 2013 12:23:27 +0200 Subject: [PATCH 31/38] Fix various PHP code bugs found using static analysis (#1489086) --- CHANGELOG | 1 + plugins/enigma/enigma.php | 3 ++- plugins/enigma/lib/enigma_engine.php | 18 +++++++----------- plugins/password/drivers/pam.php | 3 ++- program/lib/Roundcube/rcube_db.php | 2 +- program/lib/Roundcube/rcube_smtp.php | 2 +- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c97df8c96..5cba239ea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix various PHP code bugs found using static analysis (#1489086) - Fix backslash character handling on vCard import (#1489085) - Fix csv import from Thunderbird with French localization (#1489059) - Fix messages list focus issue in Opera and Webkit (#1489058) diff --git a/plugins/enigma/enigma.php b/plugins/enigma/enigma.php index c96b94620..1194d26c8 100644 --- a/plugins/enigma/enigma.php +++ b/plugins/enigma/enigma.php @@ -47,6 +47,8 @@ class enigma extends rcube_plugin $rcmail = rcmail::get_instance(); $this->rc = $rcmail; + $section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GET); + if ($this->rc->task == 'mail') { // message parse/display hooks $this->add_hook('message_part_structure', array($this, 'parse_structure')); @@ -79,7 +81,6 @@ class enigma extends rcube_plugin $this->register_action('plugin.enigma', array($this, 'preferences_ui')); // grab keys/certs management iframe requests - $section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GET); if ($this->rc->action == 'edit-prefs' && preg_match('/^enigma(certs|keys)/', $section)) { $this->load_ui(); $this->ui->init($section); diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php index 220d6c0b3..a30a517ec 100644 --- a/plugins/enigma/lib/enigma_engine.php +++ b/plugins/enigma/lib/enigma_engine.php @@ -374,17 +374,15 @@ class enigma_engine { // @TODO: Handle big bodies using (temp) files // @TODO: caching of verification result - - $sig = $this->pgp_driver->verify($msg_body, $sig_body); + $sig = $this->pgp_driver->verify($msg_body, $sig_body); - if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND) - rcube::raise_error(array( + if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND) + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Enigma plugin: " . $error->getMessage() + 'message' => "Enigma plugin: " . $sig->getMessage() ), true, false); -//print_r($sig); return $sig; } @@ -399,11 +397,9 @@ class enigma_engine { // @TODO: Handle big bodies using (temp) files // @TODO: caching of verification result - + $key = ''; $pass = ''; // @TODO $result = $this->pgp_driver->decrypt($msg_body, $key, $pass); -//print_r($result); - if ($result instanceof enigma_error) { $err_code = $result->getCode(); if (!in_array($err_code, array(enigma_error::E_KEYNOTFOUND, enigma_error::E_BADPASS))) @@ -430,7 +426,7 @@ class enigma_engine { $this->load_pgp_driver(); $result = $this->pgp_driver->list_keys($pattern); - + if ($result instanceof enigma_error) { rcube::raise_error(array( 'code' => 600, 'type' => 'php', @@ -438,7 +434,7 @@ class enigma_engine 'message' => "Enigma plugin: " . $result->getMessage() ), true, false); } - + return $result; } diff --git a/plugins/password/drivers/pam.php b/plugins/password/drivers/pam.php index 8cd94c737..4d0ba1656 100644 --- a/plugins/password/drivers/pam.php +++ b/plugins/password/drivers/pam.php @@ -11,7 +11,8 @@ class rcube_pam_password { function save($currpass, $newpass) { - $user = $_SESSION['username']; + $user = $_SESSION['username']; + $error = ''; if (extension_loaded('pam') || extension_loaded('pam_auth')) { if (pam_auth($user, $currpass, $error, false)) { diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index c96bccc90..4b9ab131c 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -128,7 +128,7 @@ class rcube_db $dsn_string = $this->dsn_string($dsn); $dsn_options = $this->dsn_options($dsn); - if ($db_pconn) { + if ($this->db_pconn) { $dsn_options[PDO::ATTR_PERSISTENT] = true; } diff --git a/program/lib/Roundcube/rcube_smtp.php b/program/lib/Roundcube/rcube_smtp.php index 5c7d2203c..201e8269e 100644 --- a/program/lib/Roundcube/rcube_smtp.php +++ b/program/lib/Roundcube/rcube_smtp.php @@ -119,7 +119,7 @@ class rcube_smtp } // try to connect to server and exit on failure - $result = $this->conn->connect($smtp_timeout); + $result = $this->conn->connect($CONFIG['smtp_timeout']); if (PEAR::isError($result)) { $this->response[] = "Connection failed: ".$result->getMessage(); From ef1d6525c2333794d954ccce33de1bcd533f85c8 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 6 May 2013 15:05:27 +0200 Subject: [PATCH 32/38] Fix display issue on addressbooks/groups list (#1489039) --- program/js/app.js | 21 +++++++++++++++++---- program/steps/addressbook/func.inc | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index a652b8985..af09572ff 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -4453,11 +4453,22 @@ function rcube_webmail() this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); }); this.name_input_li = $('
  • ').addClass(type).append(this.name_input); - var li = type == 'contactsearch' ? $('li:last', this.gui_objects.folderlist) : $('ul.groups li:last', this.get_folder_li(this.env.source,'',true)); + var ul, li; + + // find list (UL) element + if (type == 'contactsearch') + ul = this.gui_objects.folderlist; + else + ul = $('ul.groups', this.get_folder_li(this.env.source,'',true)); + + // append to the list + li = $('li:last', ul); if (li.length) this.name_input_li.insertAfter(li); - else - this.name_input_li.appendTo(type == 'contactsearch' ? this.gui_objects.folderlist : $('ul.groups', this.get_folder_li(this.env.source,'',true))); + else { + this.name_input_li.appendTo(ul); + ul.show(); // make sure the list is visible + } } this.name_input.select().focus(); @@ -4514,11 +4525,13 @@ function rcube_webmail() this.reset_add_input = function() { if (this.name_input) { + var li = this.name_input.parent(); if (this.env.group_renaming) { - var li = this.name_input.parent(); li.children().last().show(); this.env.group_renaming = false; } + else if ($('li', li.parent()).length == 1) + li.parent().hide(); this.name_input.remove(); diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index f0fb433bf..d8a8e2556 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -297,7 +297,7 @@ function rcmail_contact_groups($args) } $args['out'] .= html::tag('ul', - array('class' => 'groups', 'style' => ($is_collapsed ? "display:none;" : null)), + array('class' => 'groups', 'style' => ($is_collapsed || empty($groups) ? "display:none;" : null)), $groups_html); return $args; From 2193f6a1301edcb62de6f0cf338acccdbf5ec2f1 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 7 May 2013 13:51:23 +0200 Subject: [PATCH 33/38] Avoid unused local variables --- plugins/acl/acl.php | 1 - plugins/autologon/autologon.php | 4 +--- plugins/debug_logger/runlog/runlog.php | 2 +- plugins/enigma/enigma.php | 6 +++--- plugins/enigma/lib/enigma_engine.php | 16 +++------------- plugins/enigma/lib/enigma_ui.php | 5 ++--- plugins/help/help.php | 2 -- .../lib/Roundcube/rcube_sieve_script.php | 6 ++---- plugins/managesieve/managesieve.php | 8 ++++---- plugins/new_user_identity/new_user_identity.php | 2 -- plugins/password/drivers/directadmin.php | 1 - plugins/password/drivers/sql.php | 5 +++-- plugins/password/drivers/xmail.php | 4 ++-- .../squirrelmail_usercopy.php | 2 +- plugins/vcard_attachments/vcard_attachments.php | 3 +-- plugins/zipdownload/zipdownload.php | 4 ++-- 16 files changed, 25 insertions(+), 46 deletions(-) diff --git a/plugins/acl/acl.php b/plugins/acl/acl.php index 8879a6050..28139e92c 100644 --- a/plugins/acl/acl.php +++ b/plugins/acl/acl.php @@ -384,7 +384,6 @@ class acl extends rcube_plugin $table->add_header(array('class' => 'acl'.$key, 'title' => $label), $label); } - $i = 1; $js_table = array(); foreach ($acl as $user => $rights) { if ($this->rc->storage->conn->user == $user) { diff --git a/plugins/autologon/autologon.php b/plugins/autologon/autologon.php index 63ffb943e..9c7d5b6fc 100644 --- a/plugins/autologon/autologon.php +++ b/plugins/autologon/autologon.php @@ -19,8 +19,6 @@ class autologon extends rcube_plugin function startup($args) { - $rcmail = rcmail::get_instance(); - // change action to login if (empty($_SESSION['user_id']) && !empty($_GET['_autologin']) && $this->is_localhost()) $args['action'] = 'login'; @@ -37,7 +35,7 @@ class autologon extends rcube_plugin $args['cookiecheck'] = false; $args['valid'] = true; } - + return $args; } diff --git a/plugins/debug_logger/runlog/runlog.php b/plugins/debug_logger/runlog/runlog.php index c9f672615..0c766a13c 100644 --- a/plugins/debug_logger/runlog/runlog.php +++ b/plugins/debug_logger/runlog/runlog.php @@ -194,7 +194,7 @@ class runlog { public function print_totals(){ $totals = array(); - foreach ( $this->run_log as $k => $entry ) { + foreach ($this->run_log as $entry) { if ( $entry['type'] == 'start' && $entry['ended'] == true) { $totals[$entry['value']]['duration'] += $entry['duration']; $totals[$entry['value']]['count'] += 1; diff --git a/plugins/enigma/enigma.php b/plugins/enigma/enigma.php index 1194d26c8..25520a27d 100644 --- a/plugins/enigma/enigma.php +++ b/plugins/enigma/enigma.php @@ -149,7 +149,7 @@ class enigma extends rcube_plugin */ function parse_structure($p) { - $struct = $p['structure']; +// $struct = $p['structure']; if ($p['mimetype'] == 'text/plain' || $p['mimetype'] == 'application/pgp') { $this->parse_plain($p); @@ -391,7 +391,7 @@ class enigma extends rcube_plugin function message_load($p) { $this->message = $p['object']; - + // handle attachments vcard attachments foreach ((array)$this->message->attachments as $attachment) { if ($this->is_keys_part($attachment)) { @@ -399,7 +399,7 @@ class enigma extends rcube_plugin } } // the same with message bodies - foreach ((array)$this->message->parts as $idx => $part) { + foreach ((array)$this->message->parts as $part) { if ($this->is_keys_part($part)) { $this->keys_parts[] = $part->mime_id; $this->keys_bodies[] = $part->mime_id; diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php index a30a517ec..8a64c07ff 100644 --- a/plugins/enigma/lib/enigma_engine.php +++ b/plugins/enigma/lib/enigma_engine.php @@ -497,9 +497,11 @@ class enigma_engine $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST); $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST); $mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST); + $storage = $this->rc->get_storage(); if ($uid && $mime_id) { - $part = $this->rc->storage->get_message_part($uid, $mime_id); + $storage->set_folder($mbox); + $part = $storage->get_message_part($uid, $mime_id); } if ($part && is_array($result = $this->import_key($part))) { @@ -528,16 +530,4 @@ class enigma_engine $uid, $part->mime_id, $part); } } - - /** - * Adds CSS style file to the page header. - */ - private function add_css() - { - $skin = $this->rc->config->get('skin'); - if (!file_exists($this->home . "/skins/$skin/enigma.css")) - $skin = 'default'; - - $this->include_stylesheet("skins/$skin/enigma.css"); - } } diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index 47366b7e8..adb619d0c 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -176,8 +176,7 @@ class enigma_ui $search = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GPC); // define list of cols to be displayed - $a_show_cols = array('name'); - $result = array(); +// $a_show_cols = array('name'); // Get the list $list = $this->enigma->engine->list_keys($search); @@ -200,7 +199,7 @@ class enigma_ui $size = count($list); // Add rows - foreach($list as $idx => $key) { + foreach ($list as $key) { $this->rc->output->command('enigma_add_list_row', array('name' => rcube::Q($key->name), 'id' => $key->id)); } diff --git a/plugins/help/help.php b/plugins/help/help.php index 4b11dceb3..69da6828e 100644 --- a/plugins/help/help.php +++ b/plugins/help/help.php @@ -21,8 +21,6 @@ class help extends rcube_plugin function init() { - $rcmail = rcmail::get_instance(); - $this->add_texts('localization/', false); // register task diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php b/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php index 80f590f4b..0e95b0fba 100644 --- a/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php @@ -206,7 +206,6 @@ class rcube_sieve_script // rules foreach ($this->content as $rule) { - $extension = ''; $script = ''; $tests = array(); $i = 0; @@ -1015,11 +1014,10 @@ class rcube_sieve_script * @param mixed $num Number of tokens to return, 0 for all * or True for all tokens until separator is found. * Separator will be returned as last token. - * @param int $in_list Enable to call recursively inside a list * * @return mixed Tokens array or string if $num=1 */ - static function tokenize(&$str, $num=0, $in_list=false) + static function tokenize(&$str, $num=0) { $result = array(); @@ -1054,7 +1052,7 @@ class rcube_sieve_script // Parenthesized list case '[': $str = substr($str, 1); - $result[] = self::tokenize($str, 0, true); + $result[] = self::tokenize($str, 0); break; case ']': $str = substr($str, 1); diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php index 817fa8650..fc2a79ddb 100644 --- a/plugins/managesieve/managesieve.php +++ b/plugins/managesieve/managesieve.php @@ -1640,7 +1640,7 @@ class managesieve extends rcube_plugin .'value="' . rcube::Q($action['value']) . '" size="35" ' . $this->error_class($id, 'action', 'value', 'action_varvalue') .' />'; $out .= '
    ' .rcube::Q($this->gettext('setvarmodifiers')) . '
    '; - foreach ($set_modifiers as $j => $s_m) { + foreach ($set_modifiers as $s_m) { $s_m_id = 'action_varmods' . $id . $s_m; $out .= sprintf('%s
    ', $id, $s_m, $s_m_id, @@ -1902,7 +1902,7 @@ class managesieve extends rcube_plugin $user_script = $_SESSION['managesieve_user_script']; // if the script is not active... - if ($user_script && ($key = array_search($name, $this->active)) === false) { + if ($user_script && array_search($name, $this->active) === false) { // ...rewrite USER file adding appropriate include command if ($this->sieve->load($user_script)) { $script = $this->sieve->script->as_array(); @@ -1920,7 +1920,7 @@ class managesieve extends rcube_plugin // get all active scripts for sorting foreach ($script as $rid => $rules) { - foreach ($rules['actions'] as $aid => $action) { + foreach ($rules['actions'] as $action) { if ($action['type'] == 'include' && empty($action['global'])) { $target = $extension ? preg_replace($regexp, '', $action['target']) : $action['target']; $list[] = $target; @@ -1988,7 +1988,7 @@ class managesieve extends rcube_plugin $name = $name.$extension; foreach ($script as $rid => $rules) { - foreach ($rules['actions'] as $aid => $action) { + foreach ($rules['actions'] as $action) { if ($action['type'] == 'include' && empty($action['global']) && $action['target'] == $name ) { diff --git a/plugins/new_user_identity/new_user_identity.php b/plugins/new_user_identity/new_user_identity.php index f98145b6c..d32051e00 100644 --- a/plugins/new_user_identity/new_user_identity.php +++ b/plugins/new_user_identity/new_user_identity.php @@ -33,8 +33,6 @@ class new_user_identity extends rcube_plugin function lookup_user_name($args) { - $rcmail = rcmail::get_instance(); - if ($this->init_ldap($args['host'])) { $results = $this->ldap->search('*', $args['user'], true); if (count($results->records) == 1) { diff --git a/plugins/password/drivers/directadmin.php b/plugins/password/drivers/directadmin.php index 8bf0dc613..44ecea406 100644 --- a/plugins/password/drivers/directadmin.php +++ b/plugins/password/drivers/directadmin.php @@ -297,7 +297,6 @@ class HTTPSocket { $status = socket_get_status($socket); $startTime = time(); $length = 0; - $prevSecond = 0; while ( !feof($socket) && !$status['timed_out'] ) { $chunk = fgets($socket,1024); diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php index de9ea0a3f..7a51dfe44 100644 --- a/plugins/password/drivers/sql.php +++ b/plugins/password/drivers/sql.php @@ -34,8 +34,9 @@ class rcube_sql_password $db = $rcmail->get_dbh(); } - if ($err = $db->is_error()) + if ($db->is_error()) { return PASSWORD_ERROR; + } // crypted password if (strpos($sql, '%c') !== FALSE) { @@ -184,7 +185,7 @@ class rcube_sql_password if (!$db->is_error()) { if (strtolower(substr(trim($sql),0,6)) == 'select') { - if ($result = $db->fetch_array($res)) + if ($db->fetch_array($res)) return PASSWORD_SUCCESS; } else { // This is the good case: 1 row updated diff --git a/plugins/password/drivers/xmail.php b/plugins/password/drivers/xmail.php index 37abc3001..59e467c5b 100644 --- a/plugins/password/drivers/xmail.php +++ b/plugins/password/drivers/xmail.php @@ -67,7 +67,7 @@ class XMail { function send($msg) { socket_write($this->socket,$msg); - if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { + if (substr(socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { return false; } return true; @@ -85,7 +85,7 @@ class XMail { return false; } - if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { + if (substr(socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { socket_close($this->socket); return false; } diff --git a/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php b/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php index d5d0d47ec..e882a2f37 100644 --- a/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php +++ b/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php @@ -63,7 +63,7 @@ class squirrelmail_usercopy extends rcube_plugin if ($this->prefs['___sig'.$i.'___']) $ident_data['signature'] = $this->prefs['___sig'.$i.'___']; // insert identity - $identid = $rcmail->user->insert_identity($ident_data); + $rcmail->user->insert_identity($ident_data); } } diff --git a/plugins/vcard_attachments/vcard_attachments.php b/plugins/vcard_attachments/vcard_attachments.php index 4905b373e..cf7e22d3a 100644 --- a/plugins/vcard_attachments/vcard_attachments.php +++ b/plugins/vcard_attachments/vcard_attachments.php @@ -45,7 +45,7 @@ class vcard_attachments extends rcube_plugin } } // the same with message bodies - foreach ((array)$this->message->parts as $idx => $part) { + foreach ((array)$this->message->parts as $part) { if ($this->is_vcard($part)) { $this->vcard_parts[] = $part->mime_id; $this->vcard_bodies[] = $part->mime_id; @@ -63,7 +63,6 @@ class vcard_attachments extends rcube_plugin function html_output($p) { $attach_script = false; - $icon = 'plugins/vcard_attachments/' .$this->local_skin_path(). '/vcard_add_contact.png'; foreach ($this->vcard_parts as $part) { $vcards = rcube_vcard::import($this->message->get_part_content($part, null, true)); diff --git a/plugins/zipdownload/zipdownload.php b/plugins/zipdownload/zipdownload.php index 7e132bfbb..fbf1d2342 100644 --- a/plugins/zipdownload/zipdownload.php +++ b/plugins/zipdownload/zipdownload.php @@ -169,7 +169,7 @@ class zipdownload extends rcube_plugin for ($i = 0; ($i * $imap->get_pagesize()) <= $count; $i++) { $a_headers = $imap->list_messages($mbox_name, ($i + 1)); - foreach ($a_headers as $n => $header) { + foreach ($a_headers as $header) { if (empty($header)) continue; @@ -199,7 +199,7 @@ class zipdownload extends rcube_plugin $zip = new ZipArchive(); $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE); - foreach ($uids as $key => $uid){ + foreach ($uids as $uid){ $headers = $imap->get_message_headers($uid); $subject = rcube_mime::decode_mime_string((string)$headers->subject); $subject = $this->_convert_filename($subject); From 3725cfb245bfae3a77baf857ea5403e8064b84b9 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 7 May 2013 15:12:22 +0200 Subject: [PATCH 34/38] Avoid uninitialized/unused variables --- installer/rcube_install.php | 9 ++++--- program/include/bc.php | 2 +- program/include/rcmail.php | 28 +++----------------- program/lib/Roundcube/rcube_addressbook.php | 2 +- program/lib/Roundcube/rcube_csv2vcard.php | 3 +-- program/lib/Roundcube/rcube_db_mysql.php | 2 +- program/lib/Roundcube/rcube_enriched.php | 2 +- program/lib/Roundcube/rcube_imap.php | 5 +--- program/lib/Roundcube/rcube_imap_cache.php | 4 +-- program/lib/Roundcube/rcube_imap_generic.php | 8 +++--- program/lib/Roundcube/rcube_ldap.php | 9 +++---- program/lib/Roundcube/rcube_message.php | 2 +- program/lib/Roundcube/rcube_plugin_api.php | 1 - program/lib/Roundcube/rcube_smtp.php | 4 +-- program/lib/Roundcube/rcube_utils.php | 2 +- program/lib/Roundcube/rcube_vcard.php | 2 +- program/steps/addressbook/func.inc | 3 --- program/steps/addressbook/show.inc | 6 ++--- program/steps/mail/compose.inc | 20 +++++++------- program/steps/mail/func.inc | 16 +++++------ program/steps/mail/show.inc | 4 +-- program/steps/settings/edit_prefs.inc | 2 +- program/steps/settings/folders.inc | 3 +-- 23 files changed, 51 insertions(+), 88 deletions(-) diff --git a/installer/rcube_install.php b/installer/rcube_install.php index 32b6a5dd7..e7da54c2c 100644 --- a/installer/rcube_install.php +++ b/installer/rcube_install.php @@ -347,7 +347,7 @@ class rcube_install $this->config = array_merge($this->config, $current); - foreach ((array)$current['ldap_public'] as $key => $values) { + foreach (array_keys((array)$current['ldap_public']) as $key) { $this->config['ldap_public'][$key] = $current['ldap_public'][$key]; } } @@ -356,10 +356,11 @@ class rcube_install * Compare the local database schema with the reference schema * required for this version of Roundcube * - * @param boolean True if the schema schould be updated + * @param rcube_db Database object + * * @return boolean True if the schema is up-to-date, false if not or an error occured */ - function db_schema_check($DB, $update = false) + function db_schema_check($DB) { if (!$this->configured) return false; @@ -583,7 +584,7 @@ class rcube_install } else { // check if all keys are numeric $isnum = true; - foreach ($var as $key => $value) { + foreach (array_keys($var) as $key) { if (!is_numeric($key)) { $isnum = false; break; diff --git a/program/include/bc.php b/program/include/bc.php index df018320c..0ddfb3215 100644 --- a/program/include/bc.php +++ b/program/include/bc.php @@ -62,7 +62,7 @@ function rcmail_url($action, $p=array(), $task=null) function rcmail_temp_gc() { - $rcmail = rcmail::get_instance()->temp_gc(); + rcmail::get_instance()->temp_gc(); } function rcube_charset_convert($str, $from, $to=NULL) diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 6257f4925..c16257d50 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -596,7 +596,7 @@ class rcmail extends rcube $post_host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST); $post_user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST); - list($user, $domain) = explode('@', $post_user); + list(, $domain) = explode('@', $post_user); // direct match in default_host array if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) { @@ -699,28 +699,6 @@ class rcmail extends rcube } - /** - * Create unique authorization hash - * - * @param string Session ID - * @param int Timestamp - * @return string The generated auth hash - */ - private function get_auth_hash($sess_id, $ts) - { - $auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s', - $sess_id, - $ts, - $this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***', - $_SERVER['HTTP_USER_AGENT']); - - if (function_exists('sha1')) - return sha1($auth_string); - else - return md5($auth_string); - } - - /** * Build a valid URL to this instance of Roundcube * @@ -1532,7 +1510,7 @@ class rcmail extends rcube $collapsed = $this->config->get('collapsed_folders'); $out = ''; - foreach ($arrFolders as $key => $folder) { + foreach ($arrFolders as $folder) { $title = null; $folder_class = $this->folder_classname($folder['id']); $is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false; @@ -1618,7 +1596,7 @@ class rcmail extends rcube { $out = ''; - foreach ($arrFolders as $key => $folder) { + foreach ($arrFolders as $folder) { // skip exceptions (and its subfolders) if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { continue; diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index a1b29c3da..d23ad3687 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -432,7 +432,7 @@ abstract class rcube_addressbook $out = array_merge($out, (array)$values); } else { - list($f, $type) = explode(':', $c); + list(, $type) = explode(':', $c); $out[$type] = array_merge((array)$out[$type], (array)$values); } } diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php index fa22fa41b..fb8d8f103 100644 --- a/program/lib/Roundcube/rcube_csv2vcard.php +++ b/program/lib/Roundcube/rcube_csv2vcard.php @@ -304,7 +304,6 @@ class rcube_csv2vcard { // convert to UTF-8 $head = substr($csv, 0, 4096); - $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1? $charset = rcube_charset::detect($head, RCUBE_CHARSET); $csv = rcube_charset::convert($csv, $charset); $head = ''; @@ -312,7 +311,7 @@ class rcube_csv2vcard $this->map = array(); // Parse file - foreach (preg_split("/[\r\n]+/", $csv) as $i => $line) { + foreach (preg_split("/[\r\n]+/", $csv) as $line) { $elements = $this->parse_line($line); if (empty($elements)) { continue; diff --git a/program/lib/Roundcube/rcube_db_mysql.php b/program/lib/Roundcube/rcube_db_mysql.php index de81ede98..b2cbab271 100644 --- a/program/lib/Roundcube/rcube_db_mysql.php +++ b/program/lib/Roundcube/rcube_db_mysql.php @@ -127,7 +127,7 @@ class rcube_db_mysql extends rcube_db $result[PDO::MYSQL_ATTR_FOUND_ROWS] = true; // Enable AUTOCOMMIT mode (#1488902) - $dsn_options[PDO::ATTR_AUTOCOMMIT] = true; + $result[PDO::ATTR_AUTOCOMMIT] = true; return $result; } diff --git a/program/lib/Roundcube/rcube_enriched.php b/program/lib/Roundcube/rcube_enriched.php index 8c628c912..12deb33ce 100644 --- a/program/lib/Roundcube/rcube_enriched.php +++ b/program/lib/Roundcube/rcube_enriched.php @@ -118,7 +118,7 @@ class rcube_enriched $quoted = ''; $lines = explode('
    ', $a[2]); - foreach ($lines as $n => $line) + foreach ($lines as $line) $quoted .= '>'.$line.'
    '; $body = $a[1].''.$quoted.''.$a[3]; diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index 696f485eb..43c61fd81 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -1423,8 +1423,6 @@ class rcube_imap extends rcube_storage */ protected function search_index($folder, $criteria='ALL', $charset=NULL, $sort_field=NULL) { - $orig_criteria = $criteria; - if (!$this->check_connection()) { if ($this->threading) { return new rcube_result_thread(); @@ -2783,7 +2781,6 @@ class rcube_imap extends rcube_storage */ private function list_folders_update(&$result, $type = null) { - $delim = $this->get_hierarchy_delimiter(); $namespace = $this->get_namespace(); $search = array(); @@ -3846,7 +3843,7 @@ class rcube_imap extends rcube_storage $delimiter = $this->get_hierarchy_delimiter(); // find default folders and skip folders starting with '.' - foreach ($a_folders as $i => $folder) { + foreach ($a_folders as $folder) { if ($folder[0] == '.') { continue; } diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php index 748474af2..47d9aaf4a 100644 --- a/program/lib/Roundcube/rcube_imap_cache.php +++ b/program/lib/Roundcube/rcube_imap_cache.php @@ -430,7 +430,7 @@ class rcube_imap_cache ." AND uid = ?", $flags, $msg, $this->userid, $mailbox, (int) $message->uid); - if ($this->db->affected_rows()) { + if ($this->db->affected_rows($res)) { return; } } @@ -983,7 +983,7 @@ class rcube_imap_cache $uids, true, array('FLAGS'), $index['modseq'], $qresync); if (!empty($result)) { - foreach ($result as $id => $msg) { + foreach ($result as $msg) { $uid = $msg->uid; // Remove deleted message if ($this->skip_deleted && !empty($msg->flags['DELETED'])) { diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index fd8b130db..f7c1f86d7 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -1652,7 +1652,6 @@ class rcube_imap_generic } if (!empty($criteria)) { - $modseq = stripos($criteria, 'MODSEQ') !== false; $params .= ($params ? ' ' : '') . $criteria; } else { @@ -1791,7 +1790,6 @@ class rcube_imap_generic if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { $flags = explode(' ', strtoupper($matches[1])); if (in_array('\\DELETED', $flags)) { - $deleted[$id] = $id; continue; } } @@ -2172,7 +2170,7 @@ class rcube_imap_generic // create array with header field:data if (!empty($headers)) { $headers = explode("\n", trim($headers)); - foreach ($headers as $hid => $resln) { + foreach ($headers as $resln) { if (ord($resln[0]) <= 32) { $lines[$ln] .= (empty($lines[$ln]) ? '' : "\n") . trim($resln); } else { @@ -2180,7 +2178,7 @@ class rcube_imap_generic } } - while (list($lines_key, $str) = each($lines)) { + foreach ($lines as $str) { list($field, $string) = explode(':', $str, 2); $field = strtolower($field); @@ -3540,7 +3538,7 @@ class rcube_imap_generic if (is_array($element)) { reset($element); - while (list($key, $value) = each($element)) { + foreach ($element as $value) { $string .= ' ' . self::r_implode($value); } } diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 26f46a0f6..70163b21c 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -169,7 +169,7 @@ class rcube_ldap extends rcube_addressbook // Build sub_fields filter if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { $this->sub_filter = ''; - foreach ($this->prop['sub_fields'] as $attr => $class) { + foreach ($this->prop['sub_fields'] as $class) { if (!empty($class)) { $class = is_array($class) ? array_pop($class) : $class; $this->sub_filter .= '(objectClass=' . $class . ')'; @@ -1035,7 +1035,6 @@ class rcube_ldap extends rcube_addressbook $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]) { @@ -1107,7 +1106,7 @@ class rcube_ldap extends rcube_addressbook // Remove attributes that need to be added separately (child objects) $xfields = array(); if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { - foreach ($this->prop['sub_fields'] as $xf => $xclass) { + foreach (array_keys($this->prop['sub_fields']) as $xf) { if (!empty($newentry[$xf])) { $xfields[$xf] = $newentry[$xf]; unset($newentry[$xf]); @@ -1170,7 +1169,7 @@ class rcube_ldap extends rcube_addressbook } } - foreach ($this->fieldmap as $col => $fld) { + foreach ($this->fieldmap as $fld) { if ($fld) { $val = $ldap_data[$fld]; $old = $old_data[$fld]; @@ -1783,7 +1782,7 @@ class rcube_ldap extends rcube_addressbook $vlv_active = $this->_vlv_set_controls($this->prop['groups'], $vlv_page+1, $page_size); } - $function = $this->_scope2func($this->prop['groups']['scope'], $ns_function); + $function = $this->_scope2func($this->prop['groups']['scope']); $res = @$function($this->conn, $base_dn, $filter, array_unique(array('dn', 'objectClass', $name_attr, $email_attr, $sort_attr))); if ($res === false) { diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index 9db1fa30a..a42d3fb28 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -362,7 +362,7 @@ class rcube_message // parse headers from message/rfc822 part if (!isset($structure->headers['subject']) && !isset($structure->headers['from'])) { - list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768)); + list($headers, ) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768)); $structure->headers = rcube_mime::parse_headers($headers); } } diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php index 4bb6c6677..33f04eaa5 100644 --- a/program/lib/Roundcube/rcube_plugin_api.php +++ b/program/lib/Roundcube/rcube_plugin_api.php @@ -313,7 +313,6 @@ class rcube_plugin_api $doc->loadXML($file); $xpath = new DOMXPath($doc); $xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0"); - $data = array(); // XPaths of plugin metadata elements $metadata = array( diff --git a/program/lib/Roundcube/rcube_smtp.php b/program/lib/Roundcube/rcube_smtp.php index 201e8269e..0f3ac0407 100644 --- a/program/lib/Roundcube/rcube_smtp.php +++ b/program/lib/Roundcube/rcube_smtp.php @@ -433,9 +433,9 @@ class rcube_smtp $recipients = rcube_utils::explode_quoted_string(',', $recipients); reset($recipients); - while (list($k, $recipient) = each($recipients)) { + foreach ($recipients as $recipient) { $a = rcube_utils::explode_quoted_string(' ', $recipient); - while (list($k2, $word) = each($a)) { + foreach ($a as $word) { if (strpos($word, "@") > 0 && $word[strlen($word)-1] != '"') { $word = preg_replace('/^<|>$/', '', trim($word)); if (in_array($word, $addresses) === false) { diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php index fabe0f060..8467107fe 100644 --- a/program/lib/Roundcube/rcube_utils.php +++ b/program/lib/Roundcube/rcube_utils.php @@ -404,7 +404,7 @@ class rcube_utils $out = array(); $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST); - foreach ($src as $key => $value) { + foreach (array_keys($src) as $key) { $fname = $key[0] == '_' ? substr($key, 1) : $key; if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) { $out[$fname] = self::get_input_value($key, $mode); diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php index aded4aa78..90acb2110 100644 --- a/program/lib/Roundcube/rcube_vcard.php +++ b/program/lib/Roundcube/rcube_vcard.php @@ -481,7 +481,7 @@ class rcube_vcard $vcard_block = ''; $in_vcard_block = false; - foreach (preg_split("/[\r\n]+/", $data) as $i => $line) { + foreach (preg_split("/[\r\n]+/", $data) as $line) { if ($in_vcard_block && !empty($line)) { $vcard_block .= $line . "\n"; } diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index d8a8e2556..8faf76f78 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -183,7 +183,6 @@ function rcmail_directory_list($attrib) $attrib['id'] = 'rcmdirectorylist'; $out = ''; - $local_id = '0'; $jsdata = array(); $line_templ = html::tag('li', array( @@ -270,7 +269,6 @@ function rcmail_contact_groups($args) $groups_html = ''; $groups = $RCMAIL->get_address_book($args['source'])->list_groups(); - $js_id = $RCMAIL->JQ($args['source']); if (!empty($groups)) { $line_templ = html::tag('li', array( @@ -283,7 +281,6 @@ function rcmail_contact_groups($args) $is_collapsed = strpos($RCMAIL->config->get('collapsed_abooks',''), '&'.rawurlencode($args['source']).'&') !== false; $args['out'] .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), ' '); - $jsdata = array(); foreach ($groups as $group) { $groups_html .= sprintf($line_templ, rcube_utils::html_identifier('G' . $args['source'] . $group['ID'], true), diff --git a/program/steps/addressbook/show.inc b/program/steps/addressbook/show.inc index d583a6d36..1a97c65b1 100644 --- a/program/steps/addressbook/show.inc +++ b/program/steps/addressbook/show.inc @@ -101,8 +101,6 @@ function rcmail_contact_head($attrib) return false; } - $microformats = array('name' => 'fn', 'email' => 'email'); - $form = array( 'head' => array( // section 'head' is magic! 'content' => array( @@ -177,7 +175,7 @@ function rcmail_contact_details($attrib) } -function rcmail_render_email_value($email, $col) +function rcmail_render_email_value($email) { return html::a(array( 'href' => 'mailto:' . $email, @@ -188,7 +186,7 @@ function rcmail_render_email_value($email, $col) } -function rcmail_render_url_value($url, $col) +function rcmail_render_url_value($url) { $prefix = preg_match('!^(http|ftp)s?://!', $url) ? '' : 'http://'; return html::a(array( diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index f4a1daf58..c3fc715a6 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -399,7 +399,7 @@ function rcmail_compose_headers($attrib) { global $MESSAGE; - list($form_start, $form_end) = get_form_tags($attrib); + list($form_start,) = get_form_tags($attrib); $out = ''; $part = strtolower($attrib['part']); @@ -463,7 +463,7 @@ function rcmail_compose_headers($attrib) function rcmail_compose_header_from($attrib) { - global $MESSAGE, $OUTPUT, $RCMAIL, $compose_mode; + global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode; // pass the following attributes to the form class $field_attrib = array('name' => '_from'); @@ -566,7 +566,7 @@ function rcmail_message_is_html() function rcmail_prepare_message_body() { - global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $LINE_LENGTH, $HTML_MODE; + global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE; // use posted message body if (!empty($_POST['_message'])) { @@ -715,7 +715,7 @@ function rcmail_compose_part_body($part, $isHtml = false) function rcmail_compose_body($attrib) { - global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $LINE_LENGTH, $HTML_MODE, $MESSAGE_BODY; + global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $HTML_MODE, $MESSAGE_BODY; list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); @@ -899,8 +899,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml) if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); - $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); - $charset = $RCMAIL->output->get_charset(); + $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); if (!$bodyIsHtml) { $prefix = "\n\n\n-------- " . rcube_label('originalmessage') . " --------\n"; @@ -954,7 +953,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml) function rcmail_create_draft_body($body, $bodyIsHtml) { - global $MESSAGE, $OUTPUT, $COMPOSE; + global $MESSAGE, $COMPOSE; /** * add attachments @@ -1002,7 +1001,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) global $RCMAIL, $COMPOSE, $compose_mode; $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $id => $attachment) { + foreach ((array)$COMPOSE['attachments'] as $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; } @@ -1089,7 +1088,7 @@ function rcmail_write_forward_attachments() $names = array(); $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $id => $attachment) { + foreach ((array)$COMPOSE['attachments'] as $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; } @@ -1498,7 +1497,7 @@ function rcmail_editor_selector($attrib) $select->add(Q(rcube_label('plaintoggle')), 'plain'); return $select->show($useHtml ? 'html' : 'plain'); - +/* foreach ($choices as $value => $text) { $attrib['id'] = '_' . $value; $attrib['value'] = $value; @@ -1506,6 +1505,7 @@ function rcmail_editor_selector($attrib) } return $selector; +*/ } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 37f37d08f..17ab6f97d 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -224,7 +224,7 @@ function rcmail_message_list($attrib) if (!in_array('threads', $a_show_cols)) array_unshift($a_show_cols, 'threads'); - $skin_path = $_SESSION['skin_path'] = $CONFIG['skin_path']; + $_SESSION['skin_path'] = $CONFIG['skin_path']; // set client env $OUTPUT->add_gui_object('messagelist', $attrib['id']); @@ -289,7 +289,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL; // get name of smart From/To column in folder context - if (($f = array_search('fromto', $a_show_cols)) !== false) { + if (array_search('fromto', $a_show_cols) !== false) { $smart_col = rcmail_message_list_smart_column_name(); } @@ -305,7 +305,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null } // loop through message headers - foreach ($a_headers as $n => $header) { + foreach ($a_headers as $header) { if (empty($header)) continue; @@ -379,7 +379,6 @@ function rcmail_message_list_head($attrib, $a_show_cols) global $RCMAIL; $skin_path = $_SESSION['skin_path']; - $image_tag = html::img(array('src' => "%s%s", 'alt' => "%s")); // check to see if we have some settings for sorting $sort_col = $_SESSION['sort_col']; @@ -415,7 +414,7 @@ function rcmail_message_list_head($attrib, $a_show_cols) $cells = array(); // get name of smart From/To column in folder context - if (($f = array_search('fromto', $a_show_cols)) !== false) { + if (array_search('fromto', $a_show_cols) !== false) { $smart_col = rcmail_message_list_smart_column_name(); } @@ -895,7 +894,7 @@ function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) */ function rcmail_message_headers($attrib, $headers=null) { - global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL; + global $MESSAGE, $PRINT_MODE, $RCMAIL; static $sa_attrib; // keep header table attrib @@ -1080,7 +1079,7 @@ function rcmail_message_body($attrib) $header_attrib[$regs[1]] = $value; if (!empty($MESSAGE->parts)) { - foreach ($MESSAGE->parts as $i => $part) { + foreach ($MESSAGE->parts as $part) { if ($part->type == 'headers') { $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); } @@ -1737,8 +1736,7 @@ function rcmail_send_mdn($message, &$smtp_error) $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options); - if ($sent) - { + if ($sent) { $RCMAIL->storage->set_flag($message->uid, 'MDNSENT'); return true; } diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index 1947c0f29..2ad1ba9bd 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -228,11 +228,11 @@ function rcmail_remote_objects_msg() function rcmail_message_buttons() { - global $MESSAGE, $RCMAIL, $CONFIG; + global $RCMAIL; $mbox = $RCMAIL->storage->get_folder(); $delim = $RCMAIL->storage->get_hierarchy_delimiter(); - $dbox = $CONFIG['drafts_mbox']; + $dbox = $RCMAIL->config->get('drafts_mbox'); // the message is not a draft if ($mbox != $dbox && strpos($mbox, $dbox.$delim) !== 0) { diff --git a/program/steps/settings/edit_prefs.inc b/program/steps/settings/edit_prefs.inc index 971ed60b6..468e4994d 100644 --- a/program/steps/settings/edit_prefs.inc +++ b/program/steps/settings/edit_prefs.inc @@ -40,7 +40,7 @@ function rcmail_user_prefs_form($attrib) $out = $form_start; - foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $idx => $block) { + foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $block) { if (!empty($block['options'])) { $table = new html_table(array('cols' => 2)); diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 0c7d9063f..34a72dd95 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -283,7 +283,6 @@ function rcube_subscription_form($attrib) $noselect = false; $classes = array($i%2 ? 'even' : 'odd'); - $folder_js = Q($folder['id']); $folder_utf8 = rcube_charset_convert($folder['id'], 'UTF7-IMAP'); $display_folder = str_repeat('    ', $folder['level']) . Q($protected ? rcmail_localize_foldername($folder['id']) : $folder['name']); @@ -394,7 +393,7 @@ function rcmail_rename_folder($oldname, $newname) $a_threaded = (array) $RCMAIL->config->get('message_threading', array()); $oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/'; - foreach ($a_threaded as $key => $val) { + foreach (array_keys($a_threaded) as $key) { if ($key == $oldname) { unset($a_threaded[$key]); $a_threaded[$newname] = true; From 95b90be8c22aa51f5b5e2d8bfa8031b50fa15e49 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 7 May 2013 18:19:38 +0200 Subject: [PATCH 35/38] Fix IMAP connection issue with default_socket_timeout < 0 and imap_timeout < 0 (#1489090) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_imap_generic.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5cba239ea..7542fde2a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix IMAP connection issue with default_socket_timeout < 0 and imap_timeout < 0 (#1489090) - Fix various PHP code bugs found using static analysis (#1489086) - Fix backslash character handling on vCard import (#1489085) - Fix csv import from Thunderbird with French localization (#1489059) diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index f7c1f86d7..6c1b85552 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -746,7 +746,7 @@ class rcube_imap_generic } if ($this->prefs['timeout'] <= 0) { - $this->prefs['timeout'] = ini_get('default_socket_timeout'); + $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout'))); } // Connect From 864745bc9a14afaee640f9960e16ccdbc57e237d Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 8 May 2013 09:24:34 +0200 Subject: [PATCH 36/38] Attachment_reminder plugin - ported from https://github.com/thomasysliu/Roundcube-Plugin-Attachment-Reminder and added user preference to disable plugin, larry support, some fixes/improvements --- CHANGELOG | 1 + .../attachment_reminder.js | 54 +++++++++++++ .../attachment_reminder.php | 81 +++++++++++++++++++ .../localization/de_CH.inc | 5 ++ .../localization/de_DE.inc | 5 ++ .../localization/en_US.inc | 6 ++ .../localization/es_ES.inc | 5 ++ .../localization/fr_FR.inc | 5 ++ .../localization/it_IT.inc | 6 ++ .../localization/nl_NL.inc | 5 ++ .../localization/pl_PL.inc | 6 ++ .../localization/zh_CN.inc | 5 ++ .../localization/zh_TW.inc | 5 ++ plugins/attachment_reminder/package.xml | 66 +++++++++++++++ 14 files changed, 255 insertions(+) create mode 100755 plugins/attachment_reminder/attachment_reminder.js create mode 100755 plugins/attachment_reminder/attachment_reminder.php create mode 100644 plugins/attachment_reminder/localization/de_CH.inc create mode 100644 plugins/attachment_reminder/localization/de_DE.inc create mode 100644 plugins/attachment_reminder/localization/en_US.inc create mode 100644 plugins/attachment_reminder/localization/es_ES.inc create mode 100644 plugins/attachment_reminder/localization/fr_FR.inc create mode 100644 plugins/attachment_reminder/localization/it_IT.inc create mode 100644 plugins/attachment_reminder/localization/nl_NL.inc create mode 100644 plugins/attachment_reminder/localization/pl_PL.inc create mode 100644 plugins/attachment_reminder/localization/zh_CN.inc create mode 100644 plugins/attachment_reminder/localization/zh_TW.inc create mode 100644 plugins/attachment_reminder/package.xml diff --git a/CHANGELOG b/CHANGELOG index 7542fde2a..43935159f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Added attachment_reminder plugin - Fix IMAP connection issue with default_socket_timeout < 0 and imap_timeout < 0 (#1489090) - Fix various PHP code bugs found using static analysis (#1489086) - Fix backslash character handling on vCard import (#1489085) diff --git a/plugins/attachment_reminder/attachment_reminder.js b/plugins/attachment_reminder/attachment_reminder.js new file mode 100755 index 000000000..01f2b4993 --- /dev/null +++ b/plugins/attachment_reminder/attachment_reminder.js @@ -0,0 +1,54 @@ +/* Attachment Reminder plugin script */ + +function rcmail_get_compose_message() +{ + var msg; + + if (window.tinyMCE && (ed = tinyMCE.get(rcmail.env.composebody))) { + msg = ed.getContent(); + msg = msg.replace(/]*>(.|[\r\n])*<\/blockquote>/gmi, ''); + } + else { + msg = $('#' + rcmail.env.composebody).val(); + msg = msg.replace(/^>.*$/gmi, ''); + } + + return msg; +} + +function rcmail_check_message(msg) +{ + var i, rg, keywords = rcmail.gettext('keywords', 'attachment_reminder').split(",").concat([".doc", ".pdf"]); + + for (i=0; i + * + * Copyright (C) 2013 Thomas Yu - Sian, Liu + * Copyright (C) 2013, Kolab Systems AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +class attachment_reminder extends rcube_plugin +{ + public $task = 'mail|settings'; + public $noajax = true; + + + function init() + { + $rcmail = rcube::get_instance(); + + if ($rcmail->task == 'mail' && $rcmail->action == 'compose') { + $this->include_script('attachment_reminder.js'); + $this->add_texts('localization/', array('keywords', 'forgotattachment')); + } + + if ($rcmail->task == 'settings') { + $dont_override = $rcmail->config->get('dont_override', array()); + + if (!in_array('attachment_reminder', $dont_override)) { + $this->add_hook('preferences_list', array($this, 'prefs_list')); + $this->add_hook('preferences_save', array($this, 'prefs_save')); + } + } + } + + function prefs_list($args) + { + if ($args['section'] == 'compose') { + $this->add_texts('localization/'); + $reminder = rcube::get_instance()->config->get('attachment_reminder'); + $field_id = 'rcmfd_attachment_reminder'; + $checkbox = new html_checkbox(array('name' => '_attachment_reminder', 'id' => $field_id, 'value' => 1)); + + $args['blocks']['main']['options']['attachment_reminder'] = array( + 'title' => html::label($field_id, rcube::Q($this->gettext('reminderoption'))), + 'content' => $checkbox->show($reminder ? 1 : 0), + ); + } + + return $args; + } + + function prefs_save($args) + { + if ($args['section'] == 'compose') { + $dont_override = rcube::get_instance()->config->get('dont_override', array()); + if (!in_array('attachment_reminder', $dont_override)) { + $args['prefs']['attachment_reminder'] = !empty($_POST['_attachment_reminder']); + } + } + return $args; + } + +} diff --git a/plugins/attachment_reminder/localization/de_CH.inc b/plugins/attachment_reminder/localization/de_CH.inc new file mode 100644 index 000000000..bf6eef721 --- /dev/null +++ b/plugins/attachment_reminder/localization/de_CH.inc @@ -0,0 +1,5 @@ + + + Attachment Reminder + Roundcube plugin that prompts you if it looks like you wanted to attach a file but you didn't. + + This Roundcube plugin reminds the user to attach a file if the composed message text indicates that there should be any. + + + Aleksander Machniak + alec + alec@alec.pl + yes + + + Thomas Yu - Sian , Liu + yes + + + 1.1 + 1.0 + + + stable + stable + + GNU GPLv2 + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5.2.1 + + + 1.7.0 + + + + + From dffdd168aebfc5f67bf61baee9739b5bf96b5e50 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 8 May 2013 09:42:17 +0200 Subject: [PATCH 37/38] Improved regexp --- plugins/attachment_reminder/attachment_reminder.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/attachment_reminder/attachment_reminder.js b/plugins/attachment_reminder/attachment_reminder.js index 01f2b4993..a4f3e6325 100755 --- a/plugins/attachment_reminder/attachment_reminder.js +++ b/plugins/attachment_reminder/attachment_reminder.js @@ -18,15 +18,12 @@ function rcmail_get_compose_message() function rcmail_check_message(msg) { - var i, rg, keywords = rcmail.gettext('keywords', 'attachment_reminder').split(",").concat([".doc", ".pdf"]); + var i, rx, keywords = rcmail.gettext('keywords', 'attachment_reminder').split(",").concat([".doc", ".pdf"]); - for (i=0; i Date: Wed, 8 May 2013 10:35:24 +0200 Subject: [PATCH 38/38] Change license to GPLv3+ --- .../attachment_reminder/attachment_reminder.php | 14 +++++++------- plugins/attachment_reminder/package.xml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/attachment_reminder/attachment_reminder.php b/plugins/attachment_reminder/attachment_reminder.php index 6eed3a96b..0a2597329 100755 --- a/plugins/attachment_reminder/attachment_reminder.php +++ b/plugins/attachment_reminder/attachment_reminder.php @@ -11,18 +11,18 @@ * Copyright (C) 2013 Thomas Yu - Sian, Liu * Copyright (C) 2013, Kolab Systems AG * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see */ class attachment_reminder extends rcube_plugin diff --git a/plugins/attachment_reminder/package.xml b/plugins/attachment_reminder/package.xml index 39b0f4617..43861182e 100644 --- a/plugins/attachment_reminder/package.xml +++ b/plugins/attachment_reminder/package.xml @@ -26,7 +26,7 @@ stable stable - GNU GPLv2 + GNU GPLv3+ -