From f12585297974a994bd9b081cd1d70e8ab8d2365e Mon Sep 17 00:00:00 2001 From: jeremie kornobis Date: Mon, 26 Nov 2012 14:12:48 +0100 Subject: Add new identity level: one identity with edit only signature --- program/steps/settings/edit_identity.inc | 7 +++++++ program/steps/settings/save_identity.inc | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index aa1aeea5d..7e7be1f83 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -97,6 +97,13 @@ function rcube_identity_form($attrib) $form['addressing']['content']['email']['class'] = 'disabled'; } + if (IDENTITIES_LEVEL == 4) { + foreach($form['addressing']['content'] as $formfield => $value){ + $form['addressing']['content'][$formfield]['disabled'] = true; + $form['addressing']['content'][$formfield]['class'] = 'disabled'; + } + } + $IDENTITY_RECORD['email'] = rcube_idn_to_utf8($IDENTITY_RECORD['email']); // Allow plugins to modify identity form content diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc index 8515c44f1..7ca54a179 100644 --- a/program/steps/settings/save_identity.inc +++ b/program/steps/settings/save_identity.inc @@ -26,7 +26,7 @@ $a_boolean_cols = array('standard', 'html_signature'); $updated = $default_id = false; // check input -if (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3)) +if (IDENTITIES_LEVEL != 4 && (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3))) { $OUTPUT->show_message('formincomplete', 'warning'); rcmail_overwrite_action('edit-identity'); -- cgit v1.2.3 From c753bc4a8bc96680e0534ab115cb2f0f1fc67512 Mon Sep 17 00:00:00 2001 From: jeremie kornobis Date: Mon, 26 Nov 2012 15:06:54 +0100 Subject: unset email address with new level entity 4 --- program/steps/settings/save_identity.inc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc index 7ca54a179..c3b8cc4a7 100644 --- a/program/steps/settings/save_identity.inc +++ b/program/steps/settings/save_identity.inc @@ -52,9 +52,18 @@ foreach ($a_boolean_cols as $col) } // unset email address if user has no rights to change it -if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3) +if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3 ) unset($save_data['email']); +if (IDENTITIES_LEVEL == 4 ){ + unset($save_data['name']); + unset($save_data['email']); + unset($save_data['organization']); + unset($save_data['reply-to']); + unset($save_data['bcc']); + unset($save_data['standard']); +} + // Validate e-mail addresses $email_checks = array(rcube_idn_to_ascii($save_data['email'])); foreach (array('reply-to', 'bcc') as $item) { -- cgit v1.2.3 From 30cc01f89daea932d15a1a505d25b543913664ac Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 28 Nov 2012 20:21:09 +0100 Subject: Use Delivered-To header as a last resort for identity selection (#1488840) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_imap_generic.php | 10 ++++++---- program/lib/Roundcube/rcube_storage.php | 1 + program/steps/mail/compose.inc | 15 ++++++++++++--- 4 files changed, 20 insertions(+), 7 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 4f6dc1778..140ff6423 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Use Delivered-To header as a last resort for identity selection (#1488840) - Fix XSS vulnerability using Flash files (#1488828) - Fix absolute positioning in HTML messages (#1488819) - Fix cache (in)validation after setting \Deleted flag diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 70fd6eb2c..ae0bfdd6c 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2206,10 +2206,13 @@ class rcube_imap_generic } break; default: - if (strlen($field) > 2) { - $result[$id]->others[$field] = $string; + if (strlen($field) < 3) { + break; } - break; + if ($result[$id]->others[$field]) { + $string = array_merge((array)$result[$id]->others[$field], (array)$string); + } + $result[$id]->others[$field] = $string; } } } @@ -2217,7 +2220,6 @@ class rcube_imap_generic // VANISHED response (QRESYNC RFC5162) // Sample: * VANISHED (EARLIER) 300:310,405,411 - else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) { $line = substr($line, strlen($match[0])); $v_data = $this->tokenizeResponse($line, 1); diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index 1556aae41..245d911c0 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -64,6 +64,7 @@ abstract class rcube_storage 'MAIL-FOLLOWUP-TO', 'MAIL-REPLY-TO', 'RETURN-PATH', + 'DELIVERED-TO', ); const UNKNOWN = 0; diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 92ec88f1b..60662b382 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -298,7 +298,6 @@ else if (count($MESSAGE->identities)) { $from_idx = null; $found_idx = null; $default_identity = 0; // default identity is always first on the list - $return_path = $MESSAGE->headers->others['return-path']; // Select identity foreach ($MESSAGE->identities as $idx => $ident) { @@ -332,8 +331,8 @@ else if (count($MESSAGE->identities)) { $from_idx = $found_idx; } - // Fallback using Return-Path - if ($from_idx === null && $return_path) { + // Try Return-Path + if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { foreach ($MESSAGE->identities as $idx => $ident) { if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) { $from_idx = $idx; @@ -342,6 +341,16 @@ else if (count($MESSAGE->identities)) { } } + // Fallback using Delivered-To + if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { + foreach ($MESSAGE->identities as $idx => $ident) { + if (in_array($ident['email_ascii'], $delivered_to)) { + $from_idx = $idx; + break; + } + } + } + $ident = $MESSAGE->identities[$from_idx !== null ? $from_idx : $default_identity]; $from_id = $ident['identity_id']; -- cgit v1.2.3 From 0247b89c38c7f7ef1a2111239c6a1c8c13394d93 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 28 Nov 2012 20:40:07 +0100 Subject: Move code for identity selection to function, move identities formatting to rcube_user::list_identities() --- program/lib/Roundcube/rcube_user.php | 15 ++- program/steps/mail/compose.inc | 185 +++++++++++++++++------------------ 2 files changed, 102 insertions(+), 98 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_user.php b/program/lib/Roundcube/rcube_user.php index 864f2e098..b027506ac 100644 --- a/program/lib/Roundcube/rcube_user.php +++ b/program/lib/Roundcube/rcube_user.php @@ -240,10 +240,12 @@ class rcube_user /** * Return a list of all identities linked with this user * - * @param string $sql_add Optional WHERE clauses + * @param string $sql_add Optional WHERE clauses + * @param bool $formatted Format identity email and name + * * @return array List of identities */ - function list_identities($sql_add = '') + function list_identities($sql_add = '', $formatted = false) { $result = array(); @@ -255,6 +257,15 @@ class rcube_user $this->ID); while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + if ($formatted) { + $ascii_email = format_email($sql_arr['email']); + $utf8_email = format_email(rcube_utils::idn_to_utf8($ascii_email)); + + $sql_arr['email_ascii'] = $ascii_email; + $sql_arr['email'] = $utf8_email; + $sql_arr['ident'] = format_email_recipient($ascii_email, $ident['name']); + } + $result[] = $sql_arr; } diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 60662b382..c039e42c6 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -249,18 +249,7 @@ else { $MESSAGE->compose = array(); // get user's identities -$MESSAGE->identities = $RCMAIL->user->list_identities(); -if (count($MESSAGE->identities)) -{ - foreach ($MESSAGE->identities as $idx => $ident) { - $ident['email'] = format_email($ident['email']); - $email = format_email(rcube_idn_to_utf8($ident['email'])); - - $MESSAGE->identities[$idx]['email_ascii'] = $ident['email']; - $MESSAGE->identities[$idx]['ident'] = format_email_recipient($ident['email'], $ident['name']); - $MESSAGE->identities[$idx]['email'] = $email; - } -} +$MESSAGE->identities = $RCMAIL->user->list_identities(null, true); // Set From field value if (!empty($_POST['_from'])) { @@ -270,92 +259,10 @@ else if (!empty($COMPOSE['param']['from'])) { $MESSAGE->compose['from'] = $COMPOSE['param']['from']; } else if (count($MESSAGE->identities)) { - $a_recipients = array(); - $a_names = array(); - - // extract all recipients of the reply-message - if (is_object($MESSAGE->headers) && in_array($compose_mode, array(RCUBE_COMPOSE_REPLY, RCUBE_COMPOSE_FORWARD))) - { - $a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset); - foreach ($a_to as $addr) { - if (!empty($addr['mailto'])) { - $a_recipients[] = format_email($addr['mailto']); - $a_names[] = $addr['name']; - } - } - - if (!empty($MESSAGE->headers->cc)) { - $a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset); - foreach ($a_cc as $addr) { - if (!empty($addr['mailto'])) { - $a_recipients[] = format_email($addr['mailto']); - $a_names[] = $addr['name']; - } - } - } - } - - $from_idx = null; - $found_idx = null; - $default_identity = 0; // default identity is always first on the list - - // Select identity - foreach ($MESSAGE->identities as $idx => $ident) { - // use From header - if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { - if ($MESSAGE->headers->from == $ident['ident']) { - $from_idx = $idx; - break; - } - } - // reply to yourself - else if ($compose_mode == RCUBE_COMPOSE_REPLY && $MESSAGE->headers->from == $ident['ident']) { - $from_idx = $idx; - break; - } - // use replied message recipients - else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) { - if ($found_idx === null) { - $found_idx = $idx; - } - // match identity name - if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) { - $from_idx = $idx; - break; - } - } - } - - // If matching by name+address doesn't found any amtches, get first found address (identity) - if ($from_idx === null) { - $from_idx = $found_idx; - } - - // Try Return-Path - if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { - foreach ($MESSAGE->identities as $idx => $ident) { - if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) { - $from_idx = $idx; - break; - } - } - } - - // Fallback using Delivered-To - if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { - foreach ($MESSAGE->identities as $idx => $ident) { - if (in_array($ident['email_ascii'], $delivered_to)) { - $from_idx = $idx; - break; - } - } - } - - $ident = $MESSAGE->identities[$from_idx !== null ? $from_idx : $default_identity]; - $from_id = $ident['identity_id']; + $ident = rcmail_identity_select($MESSAGE, $MESSAGE->identities, $compose_mode); $MESSAGE->compose['from_email'] = $ident['email']; - $MESSAGE->compose['from'] = $from_id; + $MESSAGE->compose['from'] = $ident['identity_id']; } // Set other headers @@ -472,6 +379,92 @@ $MESSAGE_BODY = rcmail_prepare_message_body(); /****** compose mode functions ********/ +function rcmail_identity_select($MESSAGE, $identities, $compose_mode) +{ + $a_recipients = array(); + $a_names = array(); + + // extract all recipients of the reply-message + if (is_object($MESSAGE->headers) && in_array($compose_mode, array(RCUBE_COMPOSE_REPLY, RCUBE_COMPOSE_FORWARD))) { + $a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset); + foreach ($a_to as $addr) { + if (!empty($addr['mailto'])) { + $a_recipients[] = format_email($addr['mailto']); + $a_names[] = $addr['name']; + } + } + + if (!empty($MESSAGE->headers->cc)) { + $a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset); + foreach ($a_cc as $addr) { + if (!empty($addr['mailto'])) { + $a_recipients[] = format_email($addr['mailto']); + $a_names[] = $addr['name']; + } + } + } + } + + $from_idx = null; + $found_idx = null; + $default_identity = 0; // default identity is always first on the list + + // Select identity + foreach ($identities as $idx => $ident) { + // use From header + if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { + if ($MESSAGE->headers->from == $ident['ident']) { + $from_idx = $idx; + break; + } + } + // reply to yourself + else if ($compose_mode == RCUBE_COMPOSE_REPLY && $MESSAGE->headers->from == $ident['ident']) { + $from_idx = $idx; + break; + } + // use replied message recipients + else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) { + if ($found_idx === null) { + $found_idx = $idx; + } + // match identity name + if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) { + $from_idx = $idx; + break; + } + } + } + + // If matching by name+address doesn't found any amtches, get first found address (identity) + if ($from_idx === null) { + $from_idx = $found_idx; + } + + // Try Return-Path + if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { + foreach ($identities as $idx => $ident) { + if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) { + $from_idx = $idx; + break; + } + } + } + + // Fallback using Delivered-To + if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], $delivered_to)) { + $from_idx = $idx; + break; + } + } + } + + return $identities[$from_idx !== null ? $from_idx : $default_identity]; +} + + function rcmail_compose_headers($attrib) { global $MESSAGE; -- cgit v1.2.3 From 876d31d5940f3c4c2f683891130db0201f4a3913 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 29 Nov 2012 09:01:29 +0100 Subject: Fix empty email on identities list after identity update (#1488834) --- CHANGELOG | 1 + program/steps/settings/save_identity.inc | 48 +++++++++++++++++--------------- 2 files changed, 26 insertions(+), 23 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 69b5a030a..ae6d27398 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix empty email on identities list after identity update (#1488834) - Add new identities_level: (4) one identity with possibility to edit only signature - Use Delivered-To header as a last resort for identity selection (#1488840) - Fix XSS vulnerability using Flash files (#1488828) diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc index 88adc795e..34d8be268 100644 --- a/program/steps/settings/save_identity.inc +++ b/program/steps/settings/save_identity.inc @@ -26,17 +26,14 @@ $a_boolean_cols = array('standard', 'html_signature'); $updated = $default_id = false; // check input -if (IDENTITIES_LEVEL != 4 && (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3))) -{ +if (IDENTITIES_LEVEL != 4 && (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3))) { $OUTPUT->show_message('formincomplete', 'warning'); rcmail_overwrite_action('edit-identity'); return; } - $save_data = array(); -foreach ($a_save_cols as $col) -{ +foreach ($a_save_cols as $col) { $fname = '_'.$col; if (isset($_POST[$fname])) $save_data[$col] = get_input_value($fname, RCUBE_INPUT_POST, true); @@ -44,24 +41,23 @@ foreach ($a_save_cols as $col) // set "off" values for checkboxes that were not checked, and therefore // not included in the POST body. -foreach ($a_boolean_cols as $col) -{ +foreach ($a_boolean_cols as $col) { $fname = '_' . $col; if (!isset($_POST[$fname])) $save_data[$col] = 0; } // unset email address if user has no rights to change it -if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3 ) - unset($save_data['email']); - -if (IDENTITIES_LEVEL == 4 ){ - unset($save_data['name']); +if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3) { unset($save_data['email']); - unset($save_data['organization']); - unset($save_data['reply-to']); - unset($save_data['bcc']); - unset($save_data['standard']); +} +// unset all fields except signature +else if (IDENTITIES_LEVEL == 4) { + foreach ($save_data as $idx => $value) { + if ($idx != 'signature' && $idx != 'html_signature') { + unset($save_data[$idx]); + } + } } // Validate e-mail addresses @@ -81,9 +77,16 @@ foreach ($email_checks as $email) { } // update an existing contact -if ($_POST['_iid']) -{ +if ($_POST['_iid']) { $iid = get_input_value('_iid', RCUBE_INPUT_POST); + + if (in_array(IDENTITIES_LEVEL, array(1,3,4))) { + // merge with old identity data, fixes #1488834 + $identity = $RCMAIL->user->get_identity($iid); + $save_data = array_merge($identity, $save_data); + unset($save_data['changed'], $save_data['del'], $save_data['user_id'], $save_data['identity_id']); + } + $plugin = $RCMAIL->plugins->exec_hook('identity_update', array('id' => $iid, 'record' => $save_data)); $save_data = $plugin['record']; @@ -97,8 +100,8 @@ if ($_POST['_iid']) if ($updated) { $OUTPUT->show_message('successfullysaved', 'confirmation'); - if (!empty($_POST['_standard'])) - $default_id = get_input_value('_iid', RCUBE_INPUT_POST); + if (!empty($save_data['standard'])) + $default_id = $iid; if ($_POST['_framed']) { // update the changed col in list @@ -114,8 +117,7 @@ if ($_POST['_iid']) } // insert a new identity record -else if (IDENTITIES_LEVEL < 2) -{ +else if (IDENTITIES_LEVEL < 2) { if (IDENTITIES_LEVEL == 1) { $save_data['email'] = $RCMAIL->get_user_email(); } @@ -136,7 +138,7 @@ else if (IDENTITIES_LEVEL < 2) $_GET['_iid'] = $insert_id; - if (!empty($_POST['_standard'])) + if (!empty($save_data['standard'])) $default_id = $insert_id; if ($_POST['_framed']) { -- cgit v1.2.3 From 7eb7806b211147b40c191d17a983ba34f26b8f1c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 29 Nov 2012 13:51:49 +0100 Subject: Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_imap_generic.php | 186 +++++++++++++-------------- 2 files changed, 94 insertions(+), 93 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index ae6d27398..a47c95dcf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) - Fix empty email on identities list after identity update (#1488834) - Add new identities_level: (4) one identity with possibility to edit only signature - Use Delivered-To header as a last resort for identity selection (#1488840) diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index ae0bfdd6c..0f32d83d1 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2410,8 +2410,9 @@ class rcube_imap_generic $partial = $max_bytes ? sprintf('<0.%d>', $max_bytes) : ''; // format request - $key = $this->nextTag(); - $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id ($fetch_mode.PEEK[$part]$partial)"; + $key = $this->nextTag(); + $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id ($fetch_mode.PEEK[$part]$partial)"; + $result = false; // send request if (!$this->putLine($request)) { @@ -2424,118 +2425,117 @@ class rcube_imap_generic $mode = -1; } - // receive reply line do { - $line = rtrim($this->readLine(1024)); - $a = explode(' ', $line); - } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH'); - - $len = strlen($line); - $result = false; + $line = trim($this->readLine(1024)); - if ($a[2] != 'FETCH') { - } - // handle empty "* X FETCH ()" response - else if ($line[$len-1] == ')' && $line[$len-2] != '(') { - // one line response, get everything between first and last quotes - if (substr($line, -4, 3) == 'NIL') { - // NIL response - $result = ''; - } else { - $from = strpos($line, '"') + 1; - $to = strrpos($line, '"'); - $len = $to - $from; - $result = substr($line, $from, $len); + if (!$line) { + break; } - if ($mode == 1) { - $result = base64_decode($result); - } - else if ($mode == 2) { - $result = quoted_printable_decode($result); - } - else if ($mode == 3) { - $result = convert_uudecode($result); + if (!preg_match('/^\* ([0-9]+) FETCH (.*)$/', $line, $m)) { + continue; } - } else if ($line[$len-1] == '}') { - // multi-line request, find sizes of content and receive that many bytes - $from = strpos($line, '{') + 1; - $to = strrpos($line, '}'); - $len = $to - $from; - $sizeStr = substr($line, $from, $len); - $bytes = (int)$sizeStr; - $prev = ''; + $line = $m[2]; + $last = substr($line, -1); - while ($bytes > 0) { - $line = $this->readLine(8192); + // handle one line response + if ($line[0] == '(' && $last == ')') { + // tokenize content inside brackets + $tokens = $this->tokenizeResponse(preg_replace('/(^\(|\$)/', '', $line)); + $result = count($tokens) == 1 ? $tokens[0] : false; - if ($line === NULL) { - break; + if ($result !== false) { + if ($mode == 1) { + $result = base64_decode($result); + } + else if ($mode == 2) { + $result = quoted_printable_decode($result); + } + else if ($mode == 3) { + $result = convert_uudecode($result); + } } + } + // response with string literal + else if (preg_match('/\{([0-9]+)\}$/', $line, $m)) { + $bytes = (int) $m[1]; + $prev = ''; + + while ($bytes > 0) { + $line = $this->readLine(8192); - $len = strlen($line); + if ($line === NULL) { + break; + } - if ($len > $bytes) { - $line = substr($line, 0, $bytes); $len = strlen($line); - } - $bytes -= $len; - - // BASE64 - if ($mode == 1) { - $line = rtrim($line, "\t\r\n\0\x0B"); - // create chunks with proper length for base64 decoding - $line = $prev.$line; - $length = strlen($line); - if ($length % 4) { - $length = floor($length / 4) * 4; - $prev = substr($line, $length); - $line = substr($line, 0, $length); + + if ($len > $bytes) { + $line = substr($line, 0, $bytes); + $len = strlen($line); + } + $bytes -= $len; + + // BASE64 + if ($mode == 1) { + $line = rtrim($line, "\t\r\n\0\x0B"); + // create chunks with proper length for base64 decoding + $line = $prev.$line; + $length = strlen($line); + if ($length % 4) { + $length = floor($length / 4) * 4; + $prev = substr($line, $length); + $line = substr($line, 0, $length); + } + else { + $prev = ''; + } + $line = base64_decode($line); + } + // QUOTED-PRINTABLE + else if ($mode == 2) { + $line = rtrim($line, "\t\r\0\x0B"); + $line = quoted_printable_decode($line); + } + // UUENCODE + else if ($mode == 3) { + $line = rtrim($line, "\t\r\n\0\x0B"); + if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) { + continue; + } + $line = convert_uudecode($line); + } + // default + else if ($formatted) { + $line = rtrim($line, "\t\r\n\0\x0B") . "\n"; } - else - $prev = ''; - $line = base64_decode($line); - // QUOTED-PRINTABLE - } else if ($mode == 2) { - $line = rtrim($line, "\t\r\0\x0B"); - $line = quoted_printable_decode($line); - // UUENCODE - } else if ($mode == 3) { - $line = rtrim($line, "\t\r\n\0\x0B"); - if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) - continue; - $line = convert_uudecode($line); - // default - } else if ($formatted) { - $line = rtrim($line, "\t\r\n\0\x0B") . "\n"; - } - if ($file) { - if (fwrite($file, $line) === false) - break; + if ($file) { + if (fwrite($file, $line) === false) { + break; + } + } + else if ($print) { + echo $line; + } + else { + $result .= $line; + } } - else if ($print) - echo $line; - else - $result .= $line; } - } - - // read in anything up until last line - if (!$end) - do { - $line = $this->readLine(1024); - } while (!$this->startsWith($line, $key, true)); + } while (!$this->startsWith($line, $key, true)); if ($result !== false) { if ($file) { return fwrite($file, $result); - } else if ($print) { + } + else if ($print) { echo $result; - } else - return $result; - return true; + return true; + } + + return $result; } return false; -- cgit v1.2.3 From 8afbc8aeea10894bc97902912460cafd4681a42d Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 30 Nov 2012 11:13:43 +0100 Subject: Fix attachment Content-Length for in-memory files (#1488844) --- program/steps/mail/get.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index 71a5e1b02..7b2f719c6 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -302,7 +302,7 @@ else if (strlen($pid = get_input_value('_part', RCUBE_INPUT_GET))) { // send part as-it-is else { if ($part->body) { - header("Content-Length: " . sizeof($part->body)); + header("Content-Length: " . strlen($part->body)); echo $part->body; $sent = true; } -- cgit v1.2.3 From 0fa54df638a0b0f514d1bfba3cefb93e38991a35 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 1 Dec 2012 20:02:34 +0100 Subject: enriched.inc -> rcube_enriched --- program/include/bc.php | 6 +- program/lib/Roundcube/rcube_enriched.php | 147 +++++++++++++++++++++++++++++++ program/lib/enriched.inc | 114 ------------------------ program/steps/mail/compose.inc | 9 +- program/steps/mail/func.inc | 3 +- tests/Framework/Enriched.php | 74 ++++++++++++++++ tests/phpunit.xml | 1 + 7 files changed, 231 insertions(+), 123 deletions(-) create mode 100644 program/lib/Roundcube/rcube_enriched.php delete mode 100644 program/lib/enriched.inc create mode 100644 tests/Framework/Enriched.php (limited to 'program') diff --git a/program/include/bc.php b/program/include/bc.php index 5047e0a84..12110c0ad 100644 --- a/program/include/bc.php +++ b/program/include/bc.php @@ -399,7 +399,11 @@ function get_boolean($str) return rcube_utils::get_boolean($str); } +function enriched_to_html($data) +{ + return rcube_enriched::to_html($data); +} + class rcube_html_page extends rcmail_html_page { - } diff --git a/program/lib/Roundcube/rcube_enriched.php b/program/lib/Roundcube/rcube_enriched.php new file mode 100644 index 000000000..8b64fe054 --- /dev/null +++ b/program/lib/Roundcube/rcube_enriched.php @@ -0,0 +1,147 @@ + | + | Author: Ryo Chijiiwa (IlohaMail) | + +-----------------------------------------------------------------------+ +*/ + + +/** + * Class for Enriched to HTML conversion + * + * @package Framework + * @subpackage Utils + */ +class rcube_enriched +{ + protected static function convert_newlines($body) + { + // remove single newlines, convert N newlines to N-1 + $body = str_replace("\r\n", "\n", $body); + $len = strlen($body); + $nl = 0; + $out = ''; + + for ($i=0; $i<$len; $i++) { + $c = $body[$i]; + if (ord($c) == 10) + $nl++; + if ($nl && ord($c) != 10) + $nl = 0; + if ($nl != 1) + $out .= $c; + else + $out .= ' '; + } + + return $out; + } + + protected static function convert_formatting($body) + { + $replace = array( + '' => '', '' => '', + '' => '', '' => '', + '' => '', '' => '', + '' => '', ''=> '', + '' => '', '' => '', + '' => '', '' => '', + '' => '', '' => '', + '' => '', '' => '', + '' => '', '' => '', + '' => '', '' => '', + '' => '', '' => '', + ); + + return str_ireplace(array_keys($replace), array_values($replace), $body); + } + + protected static function convert_font($body) + { + $pattern = '/(.*)\\(.*)\<\/param\>(.*)\<\/fontfamily\>(.*)/ims'; + + while (preg_match($pattern, $body, $a)) { + if (count($a) != 5) + continue; + + $body = $a[1].''.$a[3].''.$a[4]; + } + + return $body; + } + + protected static function convert_color($body) + { + $pattern = '/(.*)\\(.*)\<\/param\>(.*)\<\/color\>(.*)/ims'; + + while (preg_match($pattern, $body, $a)) { + if (count($a) != 5) + continue; + + // extract color (either by name, or ####,####,####) + if (strpos($a[2],',')) { + $rgb = explode(',',$a[2]); + $color = '#'; + for ($i=0; $i<3; $i++) + $color .= substr($rgb[$i], 0, 2); // just take first 2 bytes + } + else { + $color = $a[2]; + } + + // put it all together + $body = $a[1].''.$a[3].''.$a[4]; + } + + return $body; + } + + protected static function convert_excerpt($body) + { + $pattern = '/(.*)\(.*)\<\/excerpt\>(.*)/i'; + + while (preg_match($pattern, $body, $a)) { + if (count($a) != 4) + continue; + + $quoted = ''; + $lines = explode('
', $a[2]); + + foreach ($lines as $n => $line) + $quoted .= '>'.$line.'
'; + + $body = $a[1].''.$quoted.''.$a[3]; + } + + return $body; + } + + public static function to_html($body) + { + $body = str_replace('<<','<',$body); + $body = self::convert_newlines($body); + $body = str_replace("\n", '
', $body); + $body = self::convert_formatting($body); + $body = self::convert_color($body); + $body = self::convert_font($body); + $body = self::convert_excerpt($body); + //$body = nl2br($body); + + return $body; + } +} diff --git a/program/lib/enriched.inc b/program/lib/enriched.inc deleted file mode 100644 index e3abd8c4f..000000000 --- a/program/lib/enriched.inc +++ /dev/null @@ -1,114 +0,0 @@ -'=>'',''=>'',''=>'', - ''=>'',''=>'',''=>'', - ''=>'',''=>'', - ''=>'',''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>'', - ''=>''); - - while(list($find,$replace)=each($a)){ - $body = preg_replace('#'.$find.'#i', $replace, $body); - } - return $body; -} - -function enriched_font($body){ - $pattern = '/(.*)\\(.*)\<\/param\>(.*)\<\/fontfamily\>(.*)/ims'; - while(preg_match($pattern,$body,$a)){ - //print_r($a); - if (count($a)!=5) continue; - $body=$a[1].''.$a[3].''.$a[4]; - } - - return $body; -} - - -function enriched_color($body){ - $pattern = '/(.*)\\(.*)\<\/param\>(.*)\<\/color\>(.*)/ims'; - while(preg_match($pattern,$body,$a)){ - //print_r($a); - if (count($a)!=5) continue; - - //extract color (either by name, or ####,####,####) - if (strpos($a[2],',')){ - $rgb = explode(',',$a[2]); - $color ='#'; - for($i=0;$i<3;$i++) $color.=substr($rgb[$i],0,2); //just take first 2 bytes - }else{ - $color = $a[2]; - } - - //put it all together - $body = $a[1].''.$a[3].''.$a[4]; - } - - return $body; -} - -function enriched_excerpt($body){ - - $pattern = '/(.*)\(.*)\<\/excerpt\>(.*)/i'; - while(preg_match($pattern,$body,$a)){ - //print_r($a); - if (count($a)!=4) continue; - $quoted = ''; - $lines = explode('
',$a[2]); - foreach($lines as $n=>$line) $quoted.='>'.$line.'
'; - $body=$a[1].''.$quoted.''.$a[3]; - } - - return $body; -} - -function enriched_to_html($body){ - $body = str_replace('<<','<',$body); - $body = enriched_convert_newlines($body); - $body = str_replace("\n", '
', $body); - $body = enriched_convert_formatting($body); - $body = enriched_color($body); - $body = enriched_font($body); - $body = enriched_excerpt($body); - //$body = nl2br($body); - return $body; -} - -?> \ No newline at end of file diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index c039e42c6..96391c88b 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -733,8 +733,7 @@ function rcmail_compose_part_body($part, $isHtml = false) if ($part->ctype_secondary == 'html') { } else if ($part->ctype_secondary == 'enriched') { - require_once(INSTALL_PATH . 'program/lib/enriched.inc'); - $body = enriched_to_html($body); + $body = rcube_enriched::to_html($body); } else { // try to remove the signature @@ -750,8 +749,7 @@ function rcmail_compose_part_body($part, $isHtml = false) } else { if ($part->ctype_secondary == 'enriched') { - require_once(INSTALL_PATH . 'program/lib/enriched.inc'); - $body = enriched_to_html($body); + $body = rcube_enriched::to_html($body); $part->ctype_secondary = 'html'; } @@ -763,8 +761,7 @@ function rcmail_compose_part_body($part, $isHtml = false) $body = $txt->get_text(); } else if ($part->ctype_secondary == 'enriched') { - require_once(INSTALL_PATH . 'program/lib/enriched.inc'); - $body = enriched_to_html($body); + $body = rcube_enriched::to_html($body); } else { if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index cb1a5ddae..80dac716e 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -751,8 +751,7 @@ function rcmail_print_body($part, $p = array()) } // text/enriched else if ($data['type'] == 'enriched') { - require_once(INSTALL_PATH . 'program/lib/enriched.inc'); - $body = enriched_to_html($data['body']); + $body = rcube_enriched::to_html($data['body']); $body = rcmail_wash_html($body, $data, $part->replaces); $part->ctype_secondary = 'html'; } diff --git a/tests/Framework/Enriched.php b/tests/Framework/Enriched.php new file mode 100644 index 000000000..26bbc3b4e --- /dev/null +++ b/tests/Framework/Enriched.php @@ -0,0 +1,74 @@ +assertInstanceOf('rcube_enriched', $object, "Class constructor"); + } + + /** + * Test to_html() + */ + function test_to_html() + { + $enriched = 'the-text'; + $expected = 'the-text'; + $result = rcube_enriched::to_html($enriched); + + $this->assertSame($expected, $result); + } + + /** + * Data for test_formatting() + */ + function data_formatting() + { + return array( + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + array('', ''), + ); + } + + /** + * Test formatting conversion + * @dataProvider data_formatting + */ + function test_formatting($enriched, $expected) + { + $result = rcube_enriched::to_html($enriched); + + $this->assertSame($expected, $result); + } +} diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 36ab6d714..c9e229e97 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -10,6 +10,7 @@ Framework/Charset.php Framework/ContentFilter.php Framework/Csv2vcard.php + Framework/Enriched.php Framework/Html.php Framework/Imap.php Framework/ImapGeneric.php -- cgit v1.2.3 From 74cd0a9b62f11bc07c5a1d3ba0098b54883eb0ba Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 4 Dec 2012 09:17:08 +0100 Subject: - Fix XSS vulnerability in vbscript: and data:text links handling (#1488850) --- CHANGELOG | 1 + program/lib/washtml.php | 2 +- tests/MailFunc.php | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index a47c95dcf..af7d29c04 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix XSS vulnerability in vbscript: and data:text links handling (#1488850) - Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) - Fix empty email on identities list after identity update (#1488834) - Add new identities_level: (4) one identity with possibility to edit only signature diff --git a/program/lib/washtml.php b/program/lib/washtml.php index 0d4ffdb4b..d13d66404 100644 --- a/program/lib/washtml.php +++ b/program/lib/washtml.php @@ -214,7 +214,7 @@ class washtml $key = strtolower($key); $value = $node->getAttribute($key); if (isset($this->_html_attribs[$key]) || - ($key == 'href' && !preg_match('!^javascript!i', $value) + ($key == 'href' && !preg_match('!^(javascript|vbscript|data:text)!i', $value) && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value)) ) { $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"'; diff --git a/tests/MailFunc.php b/tests/MailFunc.php index 967277c2a..4d4250c22 100644 --- a/tests/MailFunc.php +++ b/tests/MailFunc.php @@ -96,6 +96,20 @@ class MailFunc extends PHPUnit_Framework_TestCase $this->assertNotRegExp('/font-style:italic/', $washed, "Allow valid styles"); } + /** + * Test the elimination of some XSS vulnerabilities + */ + function test_html_xss3() + { + // #1488850 + $html = '

Firefox' + .'Internet Explorer

'; + $washed = rcmail_wash_html($html, array('safe' => true), array()); + + $this->assertNotRegExp('/data:text/', $washed, "Remove data:text/html links"); + $this->assertNotRegExp('/vbscript:/', $washed, "Remove vbscript: links"); + } + /** * Test washtml class on non-unicode characters (#1487813) */ -- cgit v1.2.3 From c7ff6ec2cb985061438e5b68cfc5691b5a86422c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 5 Dec 2012 09:46:03 +0100 Subject: Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844) --- CHANGELOG | 1 + program/steps/mail/get.inc | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index af7d29c04..5a1b1acd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844) - Fix XSS vulnerability in vbscript: and data:text links handling (#1488850) - Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) - Fix empty email on identities list after identity update (#1488834) diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index 7b2f719c6..7f06feb1a 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -259,6 +259,13 @@ else if (strlen($pid = get_input_value('_part', RCUBE_INPUT_GET))) { $disposition = !empty($plugin['download']) ? 'attachment' : 'inline'; + // Workaround for nasty IE bug (#1488844) + // If Content-Disposition header contains string "attachment" e.g. in filename + // IE handles data as attachment not inline + if ($disposition == 'inline' && $browser->ie && $browser->ver < 9) { + $filename = str_ireplace('attachment', 'attach', $filename); + } + header("Content-Disposition: $disposition; filename=\"$filename\""); // handle tiff to jpeg conversion -- cgit v1.2.3 From 176172c850a6836a9804c24b29b8ada13040670b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 7 Dec 2012 09:44:23 +0100 Subject: Fix PHP warning when replied message contains exactly one Delivered-To header --- program/steps/mail/compose.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 96391c88b..908de950e 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -454,7 +454,7 @@ function rcmail_identity_select($MESSAGE, $identities, $compose_mode) // Fallback using Delivered-To if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { foreach ($identities as $idx => $ident) { - if (in_array($ident['email_ascii'], $delivered_to)) { + if (in_array($ident['email_ascii'], (array)$delivered_to)) { $from_idx = $idx; break; } -- cgit v1.2.3 From 8b748de4ec5e48c7cc0e3f4942669c369710830e Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 7 Dec 2012 10:37:04 +0100 Subject: Plugin API: add 'check_recent' hook with possibility to control folders list used on check-recent action --- program/steps/mail/check_recent.inc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'program') diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc index 90d17c15b..61693b4ed 100644 --- a/program/steps/mail/check_recent.inc +++ b/program/steps/mail/check_recent.inc @@ -25,7 +25,7 @@ if (empty($_REQUEST['_folderlist']) && empty($_REQUEST['_list'])) { return; } -$current = $RCMAIL->storage->get_folder(); +$current = $RCMAIL->storage->get_folder(); $check_all = $RCMAIL->action != 'refresh' || (bool)$RCMAIL->config->get('check_all_folders'); // list of folders to check @@ -34,10 +34,15 @@ if ($check_all) { } else { $a_mailboxes = (array) $current; - if ($a_mailboxes[0] != 'INBOX') + if ($current != 'INBOX') { $a_mailboxes[] = 'INBOX'; + } } +// Control folders list from a plugin +$plugin = $RCMAIL->plugins->exec_hook('check_recent', array('folders' => $a_mailboxes, 'all' => $check_all)); +$a_mailboxes = $plugin['folders']; + // check recent/unseen counts foreach ($a_mailboxes as $mbox_name) { $is_current = $mbox_name == $current; -- cgit v1.2.3 From 996af3bfd9bfcac84396790a9a215d177b17c79e Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 7 Dec 2012 11:13:11 +0100 Subject: Some more rcmail -> rcube cleanup --- program/lib/Roundcube/rcube.php | 2 +- program/lib/Roundcube/rcube_addressbook.php | 4 ++-- program/lib/Roundcube/rcube_plugin.php | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php index c3aa8ffa5..cc4905a14 100644 --- a/program/lib/Roundcube/rcube.php +++ b/program/lib/Roundcube/rcube.php @@ -36,7 +36,7 @@ class rcube /** * Singleton instace of rcube * - * @var rcmail + * @var rcube */ static protected $instance; diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index d14fc587a..ea8df700c 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -209,13 +209,13 @@ abstract class rcube_addressbook */ public function validate(&$save_data, $autofix = false) { - $rcmail = rcube::get_instance(); + $rcube = rcube::get_instance(); // check validity of email addresses foreach ($this->get_col_values('email', $save_data, true) as $email) { if (strlen($email)) { if (!rcube_utils::check_email(rcube_utils::idn_to_ascii($email))) { - $error = $rcmail->gettext(array('name' => 'emailformaterror', 'vars' => array('email' => $email))); + $error = $rcube->gettext(array('name' => 'emailformaterror', 'vars' => array('email' => $email))); $this->set_error(self::ERROR_VALIDATE, $error); return false; } diff --git a/program/lib/Roundcube/rcube_plugin.php b/program/lib/Roundcube/rcube_plugin.php index dbb15e8be..5db85025d 100644 --- a/program/lib/Roundcube/rcube_plugin.php +++ b/program/lib/Roundcube/rcube_plugin.php @@ -203,23 +203,23 @@ abstract class rcube_plugin foreach ($texts as $key => $value) $add[$domain.'.'.$key] = $value; - $rcmail = rcube::get_instance(); - $rcmail->load_language($lang, $add); + $rcube = rcube::get_instance(); + $rcube->load_language($lang, $add); // add labels to client if ($add2client) { $js_labels = is_array($add2client) ? array_map(array($this, 'label_map_callback'), $add2client) : array_keys($add); - $rcmail->output->add_label($js_labels); + $rcube->output->add_label($js_labels); } } } /** - * Wrapper for rcmail::gettext() adding the plugin ID as domain + * Wrapper for rcube::gettext() adding the plugin ID as domain * * @param string $p Message identifier * @return string Localized text - * @see rcmail::gettext() + * @see rcube::gettext() */ public function gettext($p) { @@ -336,8 +336,8 @@ abstract class rcube_plugin */ public function local_skin_path() { - $rcmail = rcube::get_instance(); - foreach (array($rcmail->config->get('skin'), 'larry') as $skin) { + $rcube = rcube::get_instance(); + foreach (array($rcube->config->get('skin'), 'larry') as $skin) { $skin_path = 'skins/' . $skin; if (is_dir(realpath(slashify($this->home) . $skin_path))) break; -- cgit v1.2.3 From a3985963f0df4fffa1a6d272c777f781ebd86d50 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 7 Dec 2012 12:38:08 +0100 Subject: Fix big memory consumption of DB layer (#1488856) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_db.php | 100 ++++++++++++------------------------- 2 files changed, 32 insertions(+), 69 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 5a1b1acd5..79f19b904 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix big memory consumption of DB layer (#1488856) - Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844) - Fix XSS vulnerability in vbscript: and data:text links handling (#1488850) - Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index 5d8c4a534..2c471e74d 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -37,12 +37,11 @@ class rcube_db protected $db_mode; // Connection mode protected $dbh; // Connection handle - protected $db_error = false; - protected $db_error_msg = ''; - protected $conn_failure = false; - protected $a_query_results = array('dummy'); - protected $last_res_id = 0; - protected $db_index = 0; + protected $db_error = false; + protected $db_error_msg = ''; + protected $conn_failure = false; + protected $db_index = 0; + protected $last_result; protected $tables; protected $variables; @@ -267,14 +266,14 @@ class rcube_db /** * Getter for error state * - * @param int $res_id Optional query result identifier + * @param mixed $result Optional query result * * @return string Error message */ - public function is_error($res_id = null) + public function is_error($result = null) { - if ($res_id !== null) { - return $this->_get_result($res_id) === false ? $this->db_error_msg : null; + if ($result !== null) { + return $result === false ? $this->db_error_msg : null; } return $this->db_error ? $this->db_error_msg : null; @@ -343,7 +342,7 @@ class rcube_db * @param int Number of rows for LIMIT statement * @param mixed Values to be inserted in query * - * @return int Query handle identifier + * @return PDOStatement|bool Query handle or False on error */ public function limitquery() { @@ -363,7 +362,7 @@ class rcube_db * @param int $numrows Number of rows for LIMIT statement * @param array $params Values to be inserted in query * - * @return int Query handle identifier + * @return PDOStatement|bool Query handle or False on error */ protected function _query($query, $offset, $numrows, $params) { @@ -374,7 +373,7 @@ class rcube_db // check connection before proceeding if (!$this->is_connected()) { - return null; + return $this->last_result = false; } if ($numrows || $offset) { @@ -417,20 +416,21 @@ class rcube_db 'message' => $this->db_error_msg), true, false); } - // add result, even if it's an error - return $this->_add_result($query); + $this->last_result = $query; + + return $query; } /** * Get number of affected rows for the last query * - * @param number $res_id Optional query handle identifier + * @param mixed $result Optional query handle * * @return int Number of rows or false on failure */ - public function affected_rows($res_id = null) + public function affected_rows($result = null) { - if ($result = $this->_get_result($res_id)) { + if ($result || ($result === null && ($result = $this->last_result))) { return $result->rowCount(); } @@ -464,13 +464,12 @@ class rcube_db * Get an associative array for one row * If no query handle is specified, the last query will be taken as reference * - * @param int $res_id Optional query handle identifier + * @param mixed $result Optional query handle * * @return mixed Array with col values or false on failure */ - public function fetch_assoc($res_id = null) + public function fetch_assoc($result = null) { - $result = $this->_get_result($res_id); return $this->_fetch_row($result, PDO::FETCH_ASSOC); } @@ -478,31 +477,30 @@ class rcube_db * Get an index array for one row * If no query handle is specified, the last query will be taken as reference * - * @param int $res_id Optional query handle identifier + * @param mixed $result Optional query handle * * @return mixed Array with col values or false on failure */ - public function fetch_array($res_id = null) + public function fetch_array($result = null) { - $result = $this->_get_result($res_id); return $this->_fetch_row($result, PDO::FETCH_NUM); } /** * Get col values for a result row * - * @param PDOStatement $result Result handle - * @param int $mode Fetch mode identifier + * @param mixed $result Optional query handle + * @param int $mode Fetch mode identifier * * @return mixed Array with col values or false on failure */ protected function _fetch_row($result, $mode) { - if (!is_object($result) || !$this->is_connected()) { - return false; + if ($result || ($result === null && ($result = $this->last_result))) { + return $result->fetch($mode); } - return $result->fetch($mode); + return false; } /** @@ -538,8 +536,8 @@ class rcube_db if ($this->tables === null) { $q = $this->query('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_NAME'); - if ($res = $this->_get_result($q)) { - $this->tables = $res->fetchAll(PDO::FETCH_COLUMN, 0); + if ($q) { + $this->tables = $q->fetchAll(PDO::FETCH_COLUMN, 0); } else { $this->tables = array(); @@ -561,8 +559,8 @@ class rcube_db $q = $this->query('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ?', array($table)); - if ($res = $this->_get_result($q)) { - return $res->fetchAll(PDO::FETCH_COLUMN, 0); + if ($q) { + return $q->fetchAll(PDO::FETCH_COLUMN, 0); } return array(); @@ -776,42 +774,6 @@ class rcube_db return utf8_decode($input); } - /** - * Adds a query result and returns a handle ID - * - * @param object $res Query handle - * - * @return int Handle ID - */ - protected function _add_result($res) - { - $this->last_res_id = sizeof($this->a_query_results); - $this->a_query_results[$this->last_res_id] = $res; - - return $this->last_res_id; - } - - /** - * Resolves a given handle ID and returns the according query handle - * If no ID is specified, the last resource handle will be returned - * - * @param int $res_id Handle ID - * - * @return mixed Resource handle or false on failure - */ - protected function _get_result($res_id = null) - { - if ($res_id == null) { - $res_id = $this->last_res_id; - } - - if (!empty($this->a_query_results[$res_id])) { - return $this->a_query_results[$res_id]; - } - - return false; - } - /** * Return correct name for a specific database table * -- cgit v1.2.3 From 7c5d4b0d4d01c66768a71e8e6138f5b637d44e4a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 7 Dec 2012 14:54:35 +0100 Subject: Fix typo in identity data parser ('ident' item wasn't set correctly) --- program/lib/Roundcube/rcube_user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_user.php b/program/lib/Roundcube/rcube_user.php index b027506ac..f6b77f5e1 100644 --- a/program/lib/Roundcube/rcube_user.php +++ b/program/lib/Roundcube/rcube_user.php @@ -263,7 +263,7 @@ class rcube_user $sql_arr['email_ascii'] = $ascii_email; $sql_arr['email'] = $utf8_email; - $sql_arr['ident'] = format_email_recipient($ascii_email, $ident['name']); + $sql_arr['ident'] = format_email_recipient($ascii_email, $sql_arr['name']); } $result[] = $sql_arr; -- cgit v1.2.3 From bc1ec6c1a103632e4809bf2ee1c39e486bfe3038 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sat, 8 Dec 2012 14:53:28 +0100 Subject: Added README file for the Roundcube framework --- program/lib/Roundcube/README.md | 101 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 program/lib/Roundcube/README.md (limited to 'program') diff --git a/program/lib/Roundcube/README.md b/program/lib/Roundcube/README.md new file mode 100644 index 000000000..06c6f6a53 --- /dev/null +++ b/program/lib/Roundcube/README.md @@ -0,0 +1,101 @@ +Roundcube Framework +=================== + +INTRODUCTION +------------ +The Roundcube Framework is the basic library used for the Roundcube Webmail +application. It is an extract of classes providing the core functionality for +an email system. They can be used individually or as package for the following +tasks: + +- IMAP mailbox access with optional caching +- MIME message handling +- Email message creation and sending through SMTP +- General caching utilities using the local database +- Database abstraction using PDO +- VCard parsing and writing + + +INSTALLATION +------------ +Copy all files of this directory to your project or install it in the default +include_path directory of your webserver. Some classes of the framework require +one or multiple of the following [PEAR][pear] libraries: + +- Mail_Mime 1.8.1 or newer +- Mail_mimeDecode 1.5.5 or newer +- Net_SMTP (latest from https://github.com/pear/Net_SMTP/) +- Net_IDNA2 0.1.1 or newer +- Auth_SASL 1.0.6 or newer + + +USAGE +----- +The Roundcube Framework provides a bootstrapping file which registers an +autoloader and sets up the environment necessary for the Roundcube classes. +In order to make use of the framework, simply include the bootstrap.php file +from this directory in your application and start using the classes by simply +instantiating them. + +If you wanna use more complex functionality like IMAP access with database +caching or plugins, the rcube singleton helps you loading the necessary files: + +'); +define('RCUBE_PLUGINS_DIR', 'get_storage(); + +// do cool stuff here... + +?> + + +LICENSE +------- +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License (**with exceptions +for plugins**) 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 +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, see [www.gnu.org/licenses/][gpl]. + +This file forms part of the Roundcube Webmail Framework for which the +following exception is added: Plugins which merely make function calls to the +Roundcube Webmail Framework, and for that purpose include it by reference +shall not be considered modifications of the software. + +If you wish to use this file in another project or create a modified +version that will not be part of the Roundcube Webmail Framework, you +may remove the exception above and use this source code under the +original version of the license. + +For more details about licensing and the exceptions for skins and plugins +see [roundcube.net/license][license] + + +CONTACT +------- +For any bug reports or feature requests please refer to the tracking system +at [trac.roundcube.net][tracreport] or subscribe to our mailing list. +See [roundcube.net/support][support] for details. + +You're always welcome to send a message to the project admins: +hello(at)roundcube(dot)net + + +[pear]: http://pear.php.net +[gpl]: http://www.gnu.org/licenses/ +[license]: http://roundcube.net/license +[support]: http://roundcube.net/support +[tracreport]: http://trac.roundcube.net/wiki/Howto_ReportIssues \ No newline at end of file -- cgit v1.2.3 From d414cc05a34eacc579a0678f59f433a7fb11d7bb Mon Sep 17 00:00:00 2001 From: "Thomas B." Date: Sat, 8 Dec 2012 15:01:55 +0100 Subject: Add github syntax highlighting to php code snippet --- program/lib/Roundcube/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/README.md b/program/lib/Roundcube/README.md index 06c6f6a53..88f2d076e 100644 --- a/program/lib/Roundcube/README.md +++ b/program/lib/Roundcube/README.md @@ -40,6 +40,7 @@ instantiating them. If you wanna use more complex functionality like IMAP access with database caching or plugins, the rcube singleton helps you loading the necessary files: +```php '); @@ -53,7 +54,7 @@ $imap = $rcube->get_storage(); // do cool stuff here... ?> - +``` LICENSE ------- -- cgit v1.2.3 From 3bb75a5cc7a7c77950eeb6070631c9c8b76a5a16 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sat, 8 Dec 2012 15:36:55 +0100 Subject: Add default path for mime.types file; map jpg => image/jpeg in fallback list --- program/lib/Roundcube/rcube_mime.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 17cb3f015..4bb5b483f 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -717,6 +717,7 @@ class rcube_mime $file_paths[] = $mime_types; // try common locations + $file_paths[] = '/etc/mime.types'; $file_paths[] = '/etc/httpd/mime.types'; $file_paths[] = '/etc/httpd2/mime.types'; $file_paths[] = '/etc/apache/mime.types'; @@ -749,7 +750,7 @@ class rcube_mime // fallback to some well-known types most important for daily emails if (empty($mime_types)) { $mime_extensions = @include(RCUBE_CONFIG_DIR . '/mimetypes.php'); - $mime_extensions += array('gif' => 'image/gif', 'png' => 'image/png', 'jpg' => 'image/jpg', 'jpeg' => 'image/jpeg', 'tif' => 'image/tiff'); + $mime_extensions += array('gif' => 'image/gif', 'png' => 'image/png', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'tif' => 'image/tiff'); foreach ($mime_extensions as $ext => $mime) $mime_types[$mime][] = $ext; -- cgit v1.2.3 From 4f1c887eaaadcc2b6ab2c6578481991698ea74a3 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 9 Dec 2012 12:12:27 +0100 Subject: Add support for IMAP BINARY (RFC3516) --- program/lib/Roundcube/rcube_imap.php | 7 ++++--- program/lib/Roundcube/rcube_imap_generic.php | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index 8ca24dec7..a2495462a 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -2226,10 +2226,11 @@ class rcube_imap extends rcube_storage * @param boolean $is_file True if $message is a filename * @param array $flags Message flags * @param mixed $date Message internal date + * @param bool $binary Enables BINARY append * * @return int|bool Appended message UID or True on success, False on error */ - public function save_message($folder, &$message, $headers='', $is_file=false, $flags = array(), $date = null) + public function save_message($folder, &$message, $headers='', $is_file=false, $flags = array(), $date = null, $binary = false) { if (!strlen($folder)) { $folder = $this->folder; @@ -2247,10 +2248,10 @@ class rcube_imap extends rcube_storage $date = $this->date_format($date); if ($is_file) { - $saved = $this->conn->appendFromFile($folder, $message, $headers, $flags, $date); + $saved = $this->conn->appendFromFile($folder, $message, $headers, $flags, $date, $binary); } else { - $saved = $this->conn->append($folder, $message, $flags, $date); + $saved = $this->conn->append($folder, $message, $flags, $date, $binary); } if ($saved) { diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 0f32d83d1..28d56c16f 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2548,10 +2548,11 @@ class rcube_imap_generic * @param string $message Message content * @param array $flags Message flags * @param string $date Message internal date + * @param bool $binary Enable BINARY append (RFC3516) * * @return string|bool On success APPENDUID response (if available) or True, False on failure */ - function append($mailbox, &$message, $flags = array(), $date = null) + function append($mailbox, &$message, $flags = array(), $date = null, $binary = false) { unset($this->data['APPENDUID']); @@ -2559,8 +2560,13 @@ class rcube_imap_generic return false; } - $message = str_replace("\r", '', $message); - $message = str_replace("\n", "\r\n", $message); + $binary = $binary && $this->getCapability('BINARY'); + $literal_plus = !$binary && $this->prefs['literal+']; + + if (!$binary) { + $message = str_replace("\r", '', $message); + $message = str_replace("\n", "\r\n", $message); + } $len = strlen($message); if (!$len) { @@ -2573,12 +2579,12 @@ class rcube_imap_generic if (!empty($date)) { $request .= ' ' . $this->escape($date); } - $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}'; + $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}'; // send APPEND command if ($this->putLine($request)) { // Do not wait when LITERAL+ is supported - if (!$this->prefs['literal+']) { + if (!$literal_plus) { $line = $this->readReply(); if ($line[0] != '+') { @@ -2620,10 +2626,11 @@ class rcube_imap_generic * @param string $headers Message headers * @param array $flags Message flags * @param string $date Message internal date + * @param bool $binary Enable BINARY append (RFC3516) * * @return string|bool On success APPENDUID response (if available) or True, False on failure */ - function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null) + function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null, $binary = false) { unset($this->data['APPENDUID']); @@ -2654,18 +2661,21 @@ class rcube_imap_generic $len += strlen($headers) + strlen($body_separator); } + $binary = $binary && $this->getCapability('BINARY'); + $literal_plus = !$binary && $this->prefs['literal+']; + // build APPEND command $key = $this->nextTag(); $request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')'; if (!empty($date)) { $request .= ' ' . $this->escape($date); } - $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}'; + $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}'; // send APPEND command if ($this->putLine($request)) { // Don't wait when LITERAL+ is supported - if (!$this->prefs['literal+']) { + if (!$literal_plus) { $line = $this->readReply(); if ($line[0] != '+') { -- cgit v1.2.3 From 1aaa4bc3937187c54039a8459409a2efd9cb3cd7 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 10 Dec 2012 12:42:45 +0100 Subject: Fix PHP Warning: ldap_parse_virtuallist_control() expects parameter 2 to be resource, null given. This happens on Administrative Limit Exceeded error when using VLV. --- program/lib/Roundcube/rcube_ldap.php | 1 + 1 file changed, 1 insertion(+) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index c9a14d863..c32cea728 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -1455,6 +1455,7 @@ class rcube_ldap extends rcube_addressbook if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) { if (ldap_parse_result($this->conn, $this->ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls) + && $serverctrls // can be null e.g. in case of adm. limit error ) { ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $this->vlv_count, $vresult); -- cgit v1.2.3 From a8a72e2e7ee89caa04f8f13b6067e1b4ad870612 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Mon, 10 Dec 2012 22:26:45 +0100 Subject: Nicely render headers of message/rfc822 parts --- program/lib/Roundcube/rcube_message.php | 9 +++++++- program/lib/Roundcube/rcube_message_header.php | 16 +++++++++++++ program/steps/mail/func.inc | 31 +++++++++++++++++++------- skins/classic/mail.css | 11 +++++++++ skins/larry/mail.css | 24 ++++++++++++++++++-- skins/larry/templates/message.html | 2 +- skins/larry/templates/messagepreview.html | 2 +- 7 files changed, 82 insertions(+), 13 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index 4ef534a0a..c626af08a 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -320,8 +320,15 @@ class rcube_message private function parse_structure($structure, $recursive = false) { // real content-type of message/rfc822 part - if ($structure->mimetype == 'message/rfc822' && $structure->real_mimetype) + if ($structure->mimetype == 'message/rfc822' && $structure->real_mimetype) { $mimetype = $structure->real_mimetype; + + // parse headers from message/rfc822 part + if (!isset($structure->headers['subject'])) { + list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 4096)); + $structure->headers = rcube_mime::parse_headers($headers); + } + } else $mimetype = $structure->mimetype; diff --git a/program/lib/Roundcube/rcube_message_header.php b/program/lib/Roundcube/rcube_message_header.php index 445d0bd39..7009a00af 100644 --- a/program/lib/Roundcube/rcube_message_header.php +++ b/program/lib/Roundcube/rcube_message_header.php @@ -235,6 +235,22 @@ class rcube_message_header $this->others[$name] = $value; } } + + + /** + * Factory method to instantiate headers from a data array + * + * @param array Hash array with header values + * @return object rcube_message_header instance filled with headers values + */ + public static function from_array($arr) + { + $obj = new rcube_message_header; + foreach ($arr as $k => $v) + $obj->set($k, $v); + + return $obj; + } } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 80dac716e..8ae41017e 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -5,7 +5,7 @@ | program/steps/mail/func.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -939,13 +939,13 @@ function rcmail_html_tag_callback($matches) /** * return table with message headers */ -function rcmail_message_headers($attrib, $headers=NULL) +function rcmail_message_headers($attrib, $headers=null) { global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL; static $sa_attrib; // keep header table attrib - if (is_array($attrib) && !$sa_attrib) + if (is_array($attrib) && !$sa_attrib && !$attrib['valueof']) $sa_attrib = $attrib; else if (!is_array($attrib) && is_array($sa_attrib)) $attrib = $sa_attrib; @@ -954,8 +954,13 @@ function rcmail_message_headers($attrib, $headers=NULL) return FALSE; // get associative array of headers object - if (!$headers) - $headers = is_object($MESSAGE->headers) ? get_object_vars($MESSAGE->headers) : $MESSAGE->headers; + if (!$headers) { + $headers_obj = $MESSAGE->headers; + $headers = get_object_vars($MESSAGE->headers); + } + else { + $headers_obj = rcube_message_header::from_array($headers); + } // show these headers $standard_headers = array('subject', 'from', 'to', 'cc', 'bcc', 'replyto', @@ -1031,7 +1036,7 @@ function rcmail_message_headers($attrib, $headers=NULL) } $plugin = $RCMAIL->plugins->exec_hook('message_headers_output', - array('output' => $output_headers, 'headers' => $MESSAGE->headers, 'exclude' => $exclude_headers)); + array('output' => $output_headers, 'headers' => $headers_obj, 'exclude' => $exclude_headers)); // single header value is requested if (!empty($attrib['valueof'])) @@ -1110,8 +1115,9 @@ function rcmail_message_body($attrib) if (!empty($MESSAGE->parts)) { foreach ($MESSAGE->parts as $i => $part) { - if ($part->type == 'headers') - $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers); + if ($part->type == 'headers') { + $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); + } else if ($part->type == 'content') { // unsapported if ($part->realtype) { @@ -1139,6 +1145,15 @@ function rcmail_message_body($attrib) if (!isset($part->body)) $part->body = $MESSAGE->get_part_content($part->mime_id); + // extract headers from message/rfc822 parts + if ($part->mimetype == 'message/rfc822') { + list($hdrs, $body) = explode("\r\n\r\n", $part->body, 2); + if ($hdrs && $body && preg_match('/^[\w-]+:\s/i', $hdrs)) { + $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, rcube_mime::parse_headers($hdrs))); + $part->body = $body; + } + } + // message is cached but not exists (#1485443), or other error if ($part->body === false) { rcmail_message_error($MESSAGE->uid); diff --git a/skins/classic/mail.css b/skins/classic/mail.css index 85c53d569..98325d9d2 100644 --- a/skins/classic/mail.css +++ b/skins/classic/mail.css @@ -1070,6 +1070,17 @@ table.headers-table background-color: #F4F4F4; } +#messagebody table.headers-table +{ + margin: 16px 6px 6px 6px; +} + +div.message-partheaders + div.message-part +{ + border-top: 0; + padding-top: 4px; +} + table.headers-table tr td { font-size: 11px; diff --git a/skins/larry/mail.css b/skins/larry/mail.css index 6512e52a3..12a2b7a82 100644 --- a/skins/larry/mail.css +++ b/skins/larry/mail.css @@ -999,12 +999,14 @@ div.hide-headers { } div.message-part, -div.message-htmlpart { - padding: 0 2px 10px 2px; +div.message-htmlpart, +div.message-partheaders { + padding: 10px 2px; border-top: 1px solid #ccc; } #messagebody div:first-child { + padding-top: 0; border-top: 0; } @@ -1045,6 +1047,24 @@ div.message-part blockquote blockquote blockquote { border-right: 2px solid #bb0000; } +div.message-partheaders { + margin-top: 8px; + padding: 8px 0; +} + +div.message-partheaders .headers-table { + width: 100%; +} + +div.message-partheaders .headers-table td.header-title { + width: auto; + padding-left: 0; +} + +div.message-partheaders .headers-table td.header { + width: 88%; +} + #messagebody > hr { color: #fff; background: #fff; diff --git a/skins/larry/templates/message.html b/skins/larry/templates/message.html index f7e188f5f..04381f5e9 100644 --- a/skins/larry/templates/message.html +++ b/skins/larry/templates/message.html @@ -64,7 +64,7 @@
- +
diff --git a/skins/larry/templates/messagepreview.html b/skins/larry/templates/messagepreview.html index 9eb4d1e00..aef282ac9 100644 --- a/skins/larry/templates/messagepreview.html +++ b/skins/larry/templates/messagepreview.html @@ -47,7 +47,7 @@
- +
-- cgit v1.2.3 From 31521613e40bb57f430591bab30de2c202637db2 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Mon, 10 Dec 2012 22:32:46 +0100 Subject: Append filename extension if missing --- program/steps/mail/get.inc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'program') diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index 7f06feb1a..314a437e7 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -266,6 +266,11 @@ else if (strlen($pid = get_input_value('_part', RCUBE_INPUT_GET))) { $filename = str_ireplace('attachment', 'attach', $filename); } + // add filename extension if missing + if (!pathinfo($filename, PATHINFO_EXTENSION) && ($extensions = rcube_mime::get_mime_extensions($mimetype))) { + $filename .= '.' . $extensions[0]; + } + header("Content-Disposition: $disposition; filename=\"$filename\""); // handle tiff to jpeg conversion -- cgit v1.2.3 From d9f109b56af2015eae7aadc5e87c06365854eda0 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 11 Dec 2012 08:30:49 +0100 Subject: Allow forwarding of multiple emails (#1486854) --- CHANGELOG | 1 + program/js/app.js | 19 ++-- program/steps/mail/compose.inc | 147 +++++++++++++++++------------ program/steps/mail/sendmail.inc | 3 +- skins/classic/includes/messagetoolbar.html | 2 +- skins/larry/includes/mailtoolbar.html | 2 +- 6 files changed, 101 insertions(+), 73 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 79f19b904..ebc279622 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Allow forwarding of multiple emails (#1486854) - Fix big memory consumption of DB layer (#1488856) - Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844) - Fix XSS vulnerability in vbscript: and data:text links handling (#1488850) diff --git a/program/js/app.js b/program/js/app.js index 955c77ff5..4db7fa0c8 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -224,9 +224,10 @@ function rcube_webmail() this.set_button_titles(); - this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', 'forward', - 'moveto', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', 'download', - 'print', 'load-attachment', 'show-headers', 'hide-headers', 'forward-attachment']; + this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', + 'moveto', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', + 'print', 'load-attachment', 'show-headers', 'hide-headers', 'download', + 'forward', 'forward-inline', 'forward-attachment']; if (this.env.action == 'show' || this.env.action == 'preview') { this.enable_command(this.env.message_commands, this.env.uid); @@ -999,10 +1000,12 @@ function rcube_webmail() break; case 'forward-attachment': + case 'forward-inline': case 'forward': - if (uid = this.get_single_uid()) { - url = { _forward_uid: uid, _mbox: this.env.mailbox }; - if (command == 'forward-attachment' || (!props && this.env.forward_attachment)) + var uids = this.env.uid ? [this.env.uid] : (this.message_list ? this.message_list.get_selection() : []); + if (uids.length) { + url = { _forward_uid: this.uids_to_list(uids), _mbox: this.env.mailbox }; + if (command == 'forward-attachment' || (!props && this.env.forward_attachment) || uids.length > 1) url._attachment = 1; this.open_compose_step(url); } @@ -1526,7 +1529,7 @@ function rcube_webmail() if (selected) { // Hide certain command buttons when Drafts folder is selected if (this.env.mailbox == this.env.drafts_mailbox) - this.enable_command('reply', 'reply-all', 'reply-list', 'forward', 'forward-attachment', false); + this.enable_command('reply', 'reply-all', 'reply-list', 'forward', 'forward-attachment', 'forward-inline', false); // Disable reply-list when List-Post header is not set else { var msg = this.env.messages[list.get_single_selection()]; @@ -1535,7 +1538,7 @@ function rcube_webmail() } } // Multi-message commands - this.enable_command('delete', 'moveto', 'copy', 'mark', (list.selection.length > 0 ? true : false)); + this.enable_command('delete', 'moveto', 'copy', 'mark', 'forward', 'forward-attachment', list.selection.length > 0); // reset all-pages-selection if (selected || (list.selection.length && list.selection.length != list.rowcount)) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 908de950e..d181a72e6 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -151,15 +151,22 @@ if ($font && !is_array($font)) { // get reference message and set compose mode if ($msg_uid = $COMPOSE['param']['draft_uid']) { - $RCMAIL->storage->set_folder($CONFIG['drafts_mbox']); $compose_mode = RCUBE_COMPOSE_DRAFT; + $RCMAIL->storage->set_folder($CONFIG['drafts_mbox']); } -else if ($msg_uid = $COMPOSE['param']['reply_uid']) +else if ($msg_uid = $COMPOSE['param']['reply_uid']) { $compose_mode = RCUBE_COMPOSE_REPLY; -else if ($msg_uid = $COMPOSE['param']['forward_uid']) + $OUTPUT->set_env('compose_mode', 'reply'); +} +else if ($msg_uid = $COMPOSE['param']['forward_uid']) { $compose_mode = RCUBE_COMPOSE_FORWARD; -else if ($msg_uid = $COMPOSE['param']['uid']) + $OUTPUT->set_env('compose_mode', 'forward'); + $COMPOSE['forward_uid'] = $msg_uid; + $COMPOSE['as_attachment'] = !empty($COMPOSE['param']['attachment']); +} +else if ($msg_uid = $COMPOSE['param']['uid']) { $compose_mode = RCUBE_COMPOSE_EDIT; +} $config_show_sig = $RCMAIL->config->get('show_sig', 1); if ($config_show_sig == 1) @@ -174,7 +181,7 @@ else // set line length for body wrapping $LINE_LENGTH = $RCMAIL->config->get('line_length', 72); -if (!empty($msg_uid)) +if (!empty($msg_uid) && empty($COMPOSE['as_attachment'])) { // similar as in program/steps/mail/show.inc // re-set 'prefer_html' to have possibility to use html part for compose @@ -188,8 +195,7 @@ if (!empty($msg_uid)) if (!empty($MESSAGE->headers->charset)) $RCMAIL->storage->set_charset($MESSAGE->headers->charset); - if ($compose_mode == RCUBE_COMPOSE_REPLY) - { + if ($compose_mode == RCUBE_COMPOSE_REPLY) { $COMPOSE['reply_uid'] = $msg_uid; $COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID; $COMPOSE['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); @@ -197,8 +203,6 @@ if (!empty($msg_uid)) if (!empty($COMPOSE['param']['all'])) $MESSAGE->reply_all = $COMPOSE['param']['all']; - $OUTPUT->set_env('compose_mode', 'reply'); - // Save the sent message in the same folder of the message being replied to if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox']) && rcmail_check_sent_folder($sent_folder, false) @@ -206,10 +210,8 @@ if (!empty($msg_uid)) $COMPOSE['param']['sent_mbox'] = $sent_folder; } } - else if ($compose_mode == RCUBE_COMPOSE_DRAFT) - { - if ($MESSAGE->headers->others['x-draft-info']) - { + else if ($compose_mode == RCUBE_COMPOSE_DRAFT) { + if ($MESSAGE->headers->others['x-draft-info']) { // get reply_uid/forward_uid to flag the original message when sending $info = rcmail_draftinfo_decode($MESSAGE->headers->others['x-draft-info']); @@ -233,14 +235,6 @@ if (!empty($msg_uid)) $COMPOSE['references'] = $MESSAGE->headers->references; } - else if ($compose_mode == RCUBE_COMPOSE_FORWARD) - { - $COMPOSE['forward_uid'] = $msg_uid; - $OUTPUT->set_env('compose_mode', 'forward'); - - if (!empty($COMPOSE['param']['attachment'])) - $MESSAGE->forward_attachment = true; - } } else { $MESSAGE = new stdClass(); @@ -643,11 +637,11 @@ function rcmail_prepare_message_body() $isHtml = false; } // forward as attachment - else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $MESSAGE->forward_attachment) { + else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $COMPOSE['as_attachment']) { $isHtml = rcmail_compose_editor_mode(); $body = ''; if (empty($COMPOSE['attachments'])) - rcmail_write_forward_attachment($MESSAGE); + rcmail_write_forward_attachments(); } // reply/edit/draft/forward else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || $RCMAIL->config->get('reply_mode') != -1)) { @@ -1135,55 +1129,86 @@ function rcmail_write_inline_attachments(&$message) return $cid_map; } -// Creates an attachment from the forwarded message -function rcmail_write_forward_attachment(&$message) +// Creates attachment(s) from the forwarded message(s) +function rcmail_write_forward_attachments() { - global $RCMAIL, $COMPOSE; + global $RCMAIL, $COMPOSE, $MESSAGE; + + $storage = $RCMAIL->get_storage(); + $mem_limit = parse_bytes(ini_get('memory_limit')); + $curr_mem = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB + $names = array(); - if (strlen($message->subject)) { - $name = mb_substr($message->subject, 0, 64) . '.eml'; + if ($COMPOSE['forward_uid'] == '*') { + $index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order()); + $COMPOSE['forward_uid'] = $index->get(); } else { - $name = 'message_rfc822.eml'; + $COMPOSE['forward_uid'] = explode(',', $COMPOSE['forward_uid']); } - $mem_limit = parse_bytes(ini_get('memory_limit')); - $curr_mem = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB - $data = $path = null; + foreach ((array)$COMPOSE['forward_uid'] as $uid) { + $message = new rcube_message($uid); - // don't load too big attachments into memory - if ($mem_limit > 0 && $message->size > $mem_limit - $curr_mem) { - $temp_dir = unslashify($RCMAIL->config->get('temp_dir')); - $path = tempnam($temp_dir, 'rcmAttmnt'); - if ($fp = fopen($path, 'w')) { - $RCMAIL->storage->get_raw_body($message->uid, $fp); - fclose($fp); - } else - return false; - } else { - $data = $RCMAIL->storage->get_raw_body($message->uid); - } + if (empty($message->headers)) { + continue; + } - $attachment = array( - 'group' => $COMPOSE['id'], - 'name' => $name, - 'mimetype' => 'message/rfc822', - 'data' => $data, - 'path' => $path, - 'size' => $path ? filesize($path) : strlen($data), - ); + if (!empty($message->headers->charset)) { + $storage->set_charset($message->headers->charset); + } - $attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment); + if (empty($MESSAGE->subject)) { + $MESSAGE->subject = $message->subject; + } - if ($attachment['status']) { - unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); - $COMPOSE['attachments'][$attachment['id']] = $attachment; - return true; - } else if ($path) { - @unlink($path); - } + // generate (unique) attachment name + $name = strlen($message->subject) ? mb_substr($message->subject, 0, 64) : 'message_rfc822'; + if (!empty($names[$name])) { + $names[$name]++; + $name .= '_' . $names[$name]; + } + $names[$name] = 1; + $name .= '.eml'; + + $data = $path = null; + + // don't load too big attachments into memory + if ($mem_limit > 0 && $message->size > $mem_limit - $curr_mem) { + $temp_dir = unslashify($RCMAIL->config->get('temp_dir')); + $path = tempnam($temp_dir, 'rcmAttmnt'); + if ($fp = fopen($path, 'w')) { + $storage->get_raw_body($message->uid, $fp); + fclose($fp); + } + else { + return false; + } + } + else { + $data = $storage->get_raw_body($message->uid); + $curr_mem += $message->size; + } - return false; + $attachment = array( + 'group' => $COMPOSE['id'], + 'name' => $name, + 'mimetype' => 'message/rfc822', + 'data' => $data, + 'path' => $path, + 'size' => $path ? filesize($path) : strlen($data), + ); + + $attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment); + + if ($attachment['status']) { + unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); + $COMPOSE['attachments'][$attachment['id']] = $attachment; + } + else if ($path) { + @unlink($path); + } + } } diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index c26d774a2..d48834bb4 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -617,13 +617,12 @@ if (is_array($COMPOSE['attachments'])) $ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914 $file = $attachment['data'] ? $attachment['data'] : $attachment['path']; - // .eml attachments send inline $MAIL_MIME->addAttachment($file, $ctype, $attachment['name'], ($attachment['data'] ? false : true), ($ctype == 'message/rfc822' ? '8bit' : 'base64'), - ($ctype == 'message/rfc822' ? 'inline' : 'attachment'), + 'attachment', '', '', '', $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL, $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL, diff --git a/skins/classic/includes/messagetoolbar.html b/skins/classic/includes/messagetoolbar.html index eebb55708..371c83fd9 100644 --- a/skins/classic/includes/messagetoolbar.html +++ b/skins/classic/includes/messagetoolbar.html @@ -27,7 +27,7 @@
    -
  • +
diff --git a/skins/larry/includes/mailtoolbar.html b/skins/larry/includes/mailtoolbar.html index 31472cbb3..8efcc762c 100644 --- a/skins/larry/includes/mailtoolbar.html +++ b/skins/larry/includes/mailtoolbar.html @@ -17,7 +17,7 @@
    -
  • +
-- cgit v1.2.3 From b01d84d0f7c8b29c9dc52c717708f28a72ecf08e Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 11 Dec 2012 12:02:45 +0100 Subject: Extend just_parse() method with conditions parsing --- program/include/rcmail_output_html.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index 1290e173e..76342c245 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -670,7 +670,10 @@ class rcmail_output_html extends rcmail_output */ public function just_parse($input) { - return $this->parse_xml($input); + $input = $this->parse_conditions($input); + $input = $this->parse_xml($input); + + return $input; } -- cgit v1.2.3 From 463ce6848da1d699031ea0cbd892e00a62fac979 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 11 Dec 2012 14:43:15 +0100 Subject: Fix bug where all messages in a folder were copied on copy action, if search was active and user choose select-all feature. Code improvements. --- program/js/app.js | 110 +++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 4db7fa0c8..f599f7a64 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -2553,27 +2553,18 @@ function rcube_webmail() if (mbox && typeof mbox === 'object') mbox = mbox.id; - // exit if current or no mailbox specified or if selection is empty - if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) + // exit if current or no mailbox specified + if (!mbox || mbox == this.env.mailbox) return; - var a_uids = [], n, selection, - lock = this.display_message(this.get_label('copyingmessage'), 'loading'), - post_data = {_mbox: this.env.mailbox, _target_mbox: mbox, _from: (this.env.action ? this.env.action : '')}; + var post_data = this.selection_post_data({_target_mbox: mbox}); - if (this.env.uid) - a_uids[0] = this.env.uid; - else { - selection = this.message_list.get_selection(); - for (n in selection) { - a_uids.push(selection[n]); - } - } - - post_data._uid = this.uids_to_list(a_uids); + // exit if selection is empty + if (!post_data._uid) + return; // send request to server - this.http_post('copy', post_data, lock); + this.http_post('copy', post_data, this.display_message(this.get_label('copyingmessage'), 'loading')); }; // move selected messages to the specified mailbox @@ -2582,12 +2573,15 @@ function rcube_webmail() if (mbox && typeof mbox === 'object') mbox = mbox.id; - // exit if current or no mailbox specified or if selection is empty - if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) + // exit if current or no mailbox specified + if (!mbox || mbox == this.env.mailbox) return; - var lock = false, - add_post = {_target_mbox: mbox, _from: (this.env.action ? this.env.action : '')}; + var lock = false, post_data = this.selection_post_data({_target_mbox: mbox}); + + // exit if selection is empty + if (!post_data._uid) + return; // show wait message if (this.env.action == 'show') @@ -2598,7 +2592,7 @@ function rcube_webmail() // Hide message command buttons until a message is selected this.enable_command(this.env.message_commands, false); - this._with_selected_messages('moveto', lock, add_post); + this._with_selected_messages('moveto', post_data, lock); }; // delete selected messages from the current mailbox @@ -2606,7 +2600,7 @@ function rcube_webmail() { var uid, i, len, trash = this.env.trash_mailbox, list = this.message_list, - selection = list ? $.merge([], list.get_selection()) : []; + selection = list.get_selection(); // exit if no mailbox specified or if selection is empty if (!this.env.uid && !selection.length) @@ -2625,7 +2619,6 @@ function rcube_webmail() return false; } // if there isn't a defined trash mailbox or we are in it - // @TODO: we should check if defined trash mailbox exists else if (!trash || this.env.mailbox == trash) this.permanently_remove_messages(); // we're in Junk folder and delete_junk is enabled @@ -2648,32 +2641,29 @@ function rcube_webmail() // delete the selected messages permanently this.permanently_remove_messages = function() { - // exit if no mailbox specified or if selection is empty - if (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length)) + var post_data = this.selection_post_data(); + + // exit if selection is empty + if (!post_data._uid) return; this.show_contentframe(false); - this._with_selected_messages('delete', false, {_from: this.env.action ? this.env.action : ''}); + this._with_selected_messages('delete', post_data); }; // Send a specifc moveto/delete request with UIDs of all selected messages // @private - this._with_selected_messages = function(action, lock, post_data) + this._with_selected_messages = function(action, post_data, lock) { - var a_uids = [], count = 0, msg, lock; + var count = 0, msg; - if (typeof(post_data) != 'object') - post_data = {}; - - if (this.env.uid) - a_uids[0] = this.env.uid; - else { + // update the list (remove rows, clear selection) + if (this.message_list) { var n, id, root, roots = [], selection = this.message_list.get_selection(); for (n=0, len=selection.length; n 0) this.delete_excessive_thread_rows(); - post_data._uid = this.uids_to_list(a_uids); - post_data._mbox = this.env.mailbox; - if (!lock) { msg = action == 'moveto' ? 'movingmessage' : 'deletingmessage'; lock = this.display_message(this.get_label(msg), 'loading'); @@ -2718,22 +2701,39 @@ function rcube_webmail() this.http_post(action, post_data, lock); }; + // build post data for message delete/move/copy requests + this.selection_post_data = function(data) + { + var a_uids = this.env.uid ? this.env.uid : this.message_list.get_selection(); + + if (typeof(data) != 'object') + data = {}; + + data._uid = this.uids_to_list(a_uids); + data._mbox = this.env.mailbox; + + if (this.env.action) + data._from = this.env.action; + + // also send search request to get the right messages + if (this.env.search_request) + data._search = this.env.search_request; + + return data; + }; + // set a specific flag to one or more messages this.mark_message = function(flag, uid) { - var a_uids = [], r_uids = [], len, n, id, selection, + var a_uids = [], r_uids = [], len, n, id, list = this.message_list; if (uid) a_uids[0] = uid; else if (this.env.uid) a_uids[0] = this.env.uid; - else if (list) { - selection = list.get_selection(); - for (n=0, len=selection.length; n Date: Tue, 11 Dec 2012 15:12:59 +0100 Subject: More code unification using selection_post_data() --- program/js/app.js | 45 +++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index f599f7a64..4094a67ad 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -2701,17 +2701,19 @@ function rcube_webmail() this.http_post(action, post_data, lock); }; - // build post data for message delete/move/copy requests + // build post data for message delete/move/copy/flag requests this.selection_post_data = function(data) { - var a_uids = this.env.uid ? this.env.uid : this.message_list.get_selection(); - if (typeof(data) != 'object') data = {}; - data._uid = this.uids_to_list(a_uids); data._mbox = this.env.mailbox; + if (!data._uid) { + var uids = this.env.uid ? this.env.uid : this.message_list.get_selection(); + data._uid = this.uids_to_list(uids); + } + if (this.env.action) data._from = this.env.action; @@ -2777,16 +2779,12 @@ function rcube_webmail() this.toggle_read_status = function(flag, a_uids) { var i, len = a_uids.length, - post_data = {_uid: this.uids_to_list(a_uids), _flag: flag}, + post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: flag}), lock = this.display_message(this.get_label('markingmessage'), 'loading'); // mark all message rows as read/unread for (i=0; i Date: Wed, 12 Dec 2012 08:54:33 +0100 Subject: Use also Envelope-To for identity selection (#1488553) --- CHANGELOG | 2 +- program/lib/Roundcube/rcube_storage.php | 1 + program/steps/mail/compose.inc | 10 ++++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index ebc279622..8fd17b407 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,7 +8,7 @@ CHANGELOG Roundcube Webmail - Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) - Fix empty email on identities list after identity update (#1488834) - Add new identities_level: (4) one identity with possibility to edit only signature -- Use Delivered-To header as a last resort for identity selection (#1488840) +- Use Delivered-To and Envelope-To headers for identity selection (#1488840, #1488553) - Fix XSS vulnerability using Flash files (#1488828) - Fix absolute positioning in HTML messages (#1488819) - Fix cache (in)validation after setting \Deleted flag diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index 245d911c0..7ec05b7af 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -65,6 +65,7 @@ abstract class rcube_storage 'MAIL-REPLY-TO', 'RETURN-PATH', 'DELIVERED-TO', + 'ENVELOPE-TO', ); const UNKNOWN = 0; diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index d181a72e6..d764f5289 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -455,6 +455,16 @@ function rcmail_identity_select($MESSAGE, $identities, $compose_mode) } } + // Fallback using Envelope-To + if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], (array)$envelope_to)) { + $from_idx = $idx; + break; + } + } + } + return $identities[$from_idx !== null ? $from_idx : $default_identity]; } -- cgit v1.2.3 From 0435f40999564586dd9bd9669696ec04c16f2e32 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 12 Dec 2012 13:32:24 +0100 Subject: Add EXISTS mode to count() method - return number of all messages in a folder, event if skip_deleted is enabled and/or search is active. --- program/lib/Roundcube/rcube_imap.php | 14 +++++++++----- program/lib/Roundcube/rcube_storage.php | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index a2495462a..ab90fa23f 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -571,7 +571,7 @@ class rcube_imap extends rcube_storage * Get message count for a specific folder * * @param string $folder Folder name - * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] + * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS] * @param boolean $force Force reading from server and update cache * @param boolean $status Enables storing folder status info (max UID/count), * required for folder_status() @@ -592,7 +592,7 @@ class rcube_imap extends rcube_storage * protected method for getting nr of messages * * @param string $folder Folder name - * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] + * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS] * @param boolean $force Force reading from server and update cache * @param boolean $status Enables storing folder status info (max UID/count), * required for folder_status() @@ -614,6 +614,10 @@ class rcube_imap extends rcube_storage } } + // EXISTS is a special alias for ALL, it allows to get the number + // of all messages in a folder also when search is active and with + // any skip_deleted setting + $a_folder_cache = $this->get_cache('messagecount'); // return cached value @@ -644,7 +648,7 @@ class rcube_imap extends rcube_storage $count = $this->conn->countRecent($folder); } // use SEARCH for message counting - else if (!empty($this->options['skip_deleted'])) { + else if ($mode != 'EXISTS' && !empty($this->options['skip_deleted'])) { $search_str = "ALL UNDELETED"; $keys = array('COUNT'); @@ -683,8 +687,8 @@ class rcube_imap extends rcube_storage } else { $count = $this->conn->countMessages($folder); - if ($status) { - $this->set_folder_stats($folder,'cnt', $count); + if ($status && $mode == 'ALL') { + $this->set_folder_stats($folder, 'cnt', $count); $this->set_folder_stats($folder, 'maxuid', $count ? $this->id2uid($count, $folder) : 0); } } diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index 7ec05b7af..763b9155e 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -354,7 +354,7 @@ abstract class rcube_storage * Get messages count for a specific folder. * * @param string $folder Folder name - * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] + * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS] * @param boolean $force Force reading from server and update cache * @param boolean $status Enables storing folder status info (max UID/count), * required for folder_status() -- cgit v1.2.3 From 04689fa7ee89c29b57278a354b39d9ee5397a442 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 12 Dec 2012 19:59:08 +0100 Subject: Fix so compacting of non-empty folder is possible also when messages list is empty (#1488858) --- CHANGELOG | 1 + program/js/app.js | 11 ++++++----- program/steps/mail/check_recent.inc | 4 +++- program/steps/mail/folders.inc | 1 + program/steps/mail/list.inc | 1 + program/steps/mail/move_del.inc | 7 +++---- program/steps/mail/search.inc | 1 + 7 files changed, 16 insertions(+), 10 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 8fd17b407..095a240d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix so compacting of non-empty folder is possible also when messages list is empty (#1488858) - Allow forwarding of multiple emails (#1486854) - Fix big memory consumption of DB layer (#1488856) - Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844) diff --git a/program/js/app.js b/program/js/app.js index 4094a67ad..b5bf1840a 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -651,13 +651,13 @@ function rcube_webmail() break; case 'expunge': - if (this.env.messagecount) + if (this.env.exists) this.expunge_mailbox(this.env.mailbox); break; case 'purge': case 'empty-mailbox': - if (this.env.messagecount) + if (this.env.exists) this.purge_mailbox(this.env.mailbox); break; @@ -2971,7 +2971,7 @@ function rcube_webmail() // test if purge command is allowed this.purge_mailbox_test = function() { - return (this.env.messagecount && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox + return (this.env.exists && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter)) || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter)))); }; @@ -6228,7 +6228,7 @@ function rcube_webmail() case 'purge': case 'expunge': if (this.task == 'mail') { - if (!this.env.messagecount) { + if (!this.env.exists) { // clear preview pane content if (this.env.contentframe) this.show_contentframe(false); @@ -6248,7 +6248,8 @@ function rcube_webmail() this.env.qsearch = null; case 'list': if (this.task == 'mail') { - this.enable_command('show', 'expunge', 'select-all', 'select-none', (this.env.messagecount > 0)); + this.enable_command('show', 'select-all', 'select-none', this.env.messagecount > 0); + this.enable_command('expunge', this.env.exists); this.enable_command('purge', this.purge_mailbox_test()); this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount); diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc index 61693b4ed..4befbf275 100644 --- a/program/steps/mail/check_recent.inc +++ b/program/steps/mail/check_recent.inc @@ -75,13 +75,15 @@ foreach ($a_mailboxes as $mbox_name) { if (!empty($_GET['_quota'])) $OUTPUT->command('set_quota', rcmail_quota_content()); + $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); + // "No-list" mode, don't get messages if (empty($_GET['_list'])) continue; // get overall message count; allow caching because rcube_storage::folder_status() did a refresh $list_mode = $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'; - $all_count = $RCMAIL->storage->count(null, $list_mode, false, false); + $all_count = $RCMAIL->storage->count($mbox_name, $list_mode, false, false); $page = $RCMAIL->storage->get_page(); $page_size = $RCMAIL->storage->get_pagesize(); diff --git a/program/steps/mail/folders.inc b/program/steps/mail/folders.inc index c56c914cd..574d6e975 100644 --- a/program/steps/mail/folders.inc +++ b/program/steps/mail/folders.inc @@ -65,6 +65,7 @@ else if ($RCMAIL->action == 'purge') if (!empty($_REQUEST['_reload'])) { $OUTPUT->set_env('messagecount', 0); $OUTPUT->set_env('pagecount', 0); + $OUTPUT->set_env('exists', 0); $OUTPUT->command('message_list.clear'); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text(), $mbox); $OUTPUT->command('set_unread_count', $mbox, 0); diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index b433f81fc..b8c3ee021 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -95,6 +95,7 @@ $OUTPUT->set_env('messagecount', $count); $OUTPUT->set_env('pagecount', $pages); $OUTPUT->set_env('threading', $threading); $OUTPUT->set_env('current_page', $count ? $RCMAIL->storage->get_page() : 1); +$OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); $OUTPUT->command('set_mailboxname', rcmail_get_mailbox_name_text()); diff --git a/program/steps/mail/move_del.inc b/program/steps/mail/move_del.inc index da43b4000..3e2252683 100644 --- a/program/steps/mail/move_del.inc +++ b/program/steps/mail/move_del.inc @@ -38,7 +38,7 @@ if ($RCMAIL->action=='moveto' && !empty($_POST['_uid']) && strlen($_POST['_targe if (!$moved) { // send error message - if ($_POST['_from'] != 'show') + if ($_POST['_from'] != 'show') $OUTPUT->command('list_mailbox'); rcmail_display_server_error('errormoving'); $OUTPUT->send(); @@ -59,7 +59,7 @@ else if ($RCMAIL->action=='delete' && !empty($_POST['_uid'])) { if (!$del) { // send error message - if ($_POST['_from'] != 'show') + if ($_POST['_from'] != 'show') $OUTPUT->command('list_mailbox'); rcmail_display_server_error('errordeleting'); $OUTPUT->send(); @@ -111,6 +111,7 @@ else $OUTPUT->set_env('messagecount', $msg_count); $OUTPUT->set_env('current_page', $page); $OUTPUT->set_env('pagecount', $pages); + $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox, 'EXISTS', true)); // update mailboxlist $mbox = $RCMAIL->storage->get_folder(); @@ -144,5 +145,3 @@ else // send response $OUTPUT->send(); - - diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index db5424b3b..f9b8f9e67 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -143,5 +143,6 @@ else { $OUTPUT->set_env('search_request', $search_str ? $search_request : ''); $OUTPUT->set_env('messagecount', $count); $OUTPUT->set_env('pagecount', ceil($count/$RCMAIL->storage->get_pagesize())); +$OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count, 1), $mbox); $OUTPUT->send(); -- cgit v1.2.3 From 5b15700d11f7f1338039a436d5c911d297b4ac56 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 13 Dec 2012 14:41:36 +0100 Subject: Rename hook imap_connect to storage_connect --- program/lib/Roundcube/rcube_imap.php | 2 +- program/lib/Roundcube/rcube_plugin_api.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index a2495462a..a92def54d 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -151,7 +151,7 @@ class rcube_imap extends rcube_storage $attempt = 0; do { - $data = rcube::get_instance()->plugins->exec_hook('imap_connect', + $data = rcube::get_instance()->plugins->exec_hook('storage_connect', array_merge($this->options, array('host' => $host, 'user' => $user, 'attempt' => ++$attempt))); diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php index 51cf5d246..47508a2ef 100644 --- a/program/lib/Roundcube/rcube_plugin_api.php +++ b/program/lib/Roundcube/rcube_plugin_api.php @@ -78,7 +78,8 @@ class rcube_plugin_api 'identity_save' => 'identity_update', // to be removed after 0.8 'imap_init' => 'storage_init', - 'mailboxes_list' => 'storage_folders', + 'mailboxes_list' => 'storage_folders', + 'imap_connect' => 'storage_connect', ); /** -- cgit v1.2.3 From a9bb50d8045e5a119ca5f66ec03753ca80aa4d4a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 13 Dec 2012 15:14:56 +0100 Subject: Fix handling of signatures on draft edit: Don't add new signature and don't remove the old-one, the same for Edit as new (#1488798) --- CHANGELOG | 1 + program/steps/mail/compose.inc | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 095a240d4..840c34901 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix handling of signatures on draft edit (#1488798) - Fix so compacting of non-empty folder is possible also when messages list is empty (#1488858) - Allow forwarding of multiple emails (#1486854) - Fix big memory consumption of DB layer (#1488856) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index d764f5289..b4dbd8d9c 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -169,14 +169,15 @@ else if ($msg_uid = $COMPOSE['param']['uid']) { } $config_show_sig = $RCMAIL->config->get('show_sig', 1); -if ($config_show_sig == 1) +if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) { + // don't add signature in draft/edit mode, we'll also not remove the old-one +} +else if ($config_show_sig == 1) $OUTPUT->set_env('show_sig', true); -else if ($config_show_sig == 2 && (empty($compose_mode) || $compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT)) +else if ($config_show_sig == 2 && empty($compose_mode)) $OUTPUT->set_env('show_sig', true); else if ($config_show_sig == 3 && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD)) $OUTPUT->set_env('show_sig', true); -else - $OUTPUT->set_env('show_sig', false); // set line length for body wrapping $LINE_LENGTH = $RCMAIL->config->get('line_length', 72); @@ -741,8 +742,10 @@ function rcmail_compose_part_body($part, $isHtml = false) } else { // try to remove the signature - if ($RCMAIL->config->get('strip_existing_sig', true)) { - $body = rcmail_remove_signature($body); + if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) { + if ($RCMAIL->config->get('strip_existing_sig', true)) { + $body = rcmail_remove_signature($body); + } } // add HTML formatting $body = rcmail_plain_body($body); @@ -773,8 +776,10 @@ function rcmail_compose_part_body($part, $isHtml = false) } // try to remove the signature - if ($RCMAIL->config->get('strip_existing_sig', true)) { - $body = rcmail_remove_signature($body); + if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) { + if ($RCMAIL->config->get('strip_existing_sig', true)) { + $body = rcmail_remove_signature($body); + } } } } -- cgit v1.2.3 From dc67f38cdfd4390a6f5b302ebc177565536e4447 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 13 Dec 2012 19:56:22 +0100 Subject: Properly parse message/rfc822 parts including all headers, body decoding and charset conversion --- program/steps/mail/func.inc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'program') diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 8ae41017e..7d6a51751 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -958,6 +958,10 @@ function rcmail_message_headers($attrib, $headers=null) $headers_obj = $MESSAGE->headers; $headers = get_object_vars($MESSAGE->headers); } + else if (is_object($headers)) { + $headers_obj = $headers; + $headers = get_object_vars($headers_obj); + } else { $headers_obj = rcube_message_header::from_array($headers); } @@ -1147,10 +1151,10 @@ function rcmail_message_body($attrib) // extract headers from message/rfc822 parts if ($part->mimetype == 'message/rfc822') { - list($hdrs, $body) = explode("\r\n\r\n", $part->body, 2); - if ($hdrs && $body && preg_match('/^[\w-]+:\s/i', $hdrs)) { - $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, rcube_mime::parse_headers($hdrs))); - $part->body = $body; + $msgpart = rcube_mime::parse_message($part->body); + if (!empty($msgpart->headers)) { + $part = $msgpart; + $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); } } -- cgit v1.2.3 From 0f4e2f81342caed51709674c96ce5919cfc5913b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 14 Dec 2012 12:38:42 +0100 Subject: Remove brackets for recipients without name --- program/steps/mail/sendmail.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'program') diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index d48834bb4..36d850f8f 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -219,11 +219,11 @@ function rcmail_email_input_format($mailto, $count=false, $check=true) // address in brackets without name (do nothing) if (preg_match('/^<'.$email_regexp.'>$/', $item)) { $item = rcube_idn_to_ascii(trim($item, '<>')); - $result[] = '<' . $item . '>'; + $result[] = $item; // address without brackets and without name (add brackets) } else if (preg_match('/^'.$email_regexp.'$/', $item)) { $item = rcube_idn_to_ascii($item); - $result[] = '<' . $item . '>'; + $result[] = $item; // address with name (handle name) } else if (preg_match('/<*'.$email_regexp.'>*$/', $item, $matches)) { $address = $matches[0]; -- cgit v1.2.3 From a0e3dcf170502bd74f74c5ac5952cd7ad6de3863 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 14 Dec 2012 13:42:23 +0100 Subject: Use matching identity in MDN response (#1488864) --- CHANGELOG | 1 + program/steps/mail/compose.inc | 107 ++--------------------------------------- program/steps/mail/func.inc | 107 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 110 insertions(+), 105 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 43ba0c2e4..039d833c3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Use matching identity in MDN response (#1488864) - Fix unwanted horizontal scrollbar in message preview header (#1488866) - Fix handling of signatures on draft edit (#1488798) - Fix so compacting of non-empty folder is possible also when messages list is empty (#1488858) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index b4dbd8d9c..d07cf587f 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -20,10 +20,10 @@ */ // define constants for message compose mode -define('RCUBE_COMPOSE_REPLY', 0x0106); -define('RCUBE_COMPOSE_FORWARD', 0x0107); -define('RCUBE_COMPOSE_DRAFT', 0x0108); -define('RCUBE_COMPOSE_EDIT', 0x0109); +define('RCUBE_COMPOSE_REPLY', 'reply'); +define('RCUBE_COMPOSE_FORWARD', 'forward'); +define('RCUBE_COMPOSE_DRAFT', 'draft'); +define('RCUBE_COMPOSE_EDIT', 'edit'); $MESSAGE_FORM = null; $COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GET); @@ -156,17 +156,16 @@ if ($msg_uid = $COMPOSE['param']['draft_uid']) { } else if ($msg_uid = $COMPOSE['param']['reply_uid']) { $compose_mode = RCUBE_COMPOSE_REPLY; - $OUTPUT->set_env('compose_mode', 'reply'); } else if ($msg_uid = $COMPOSE['param']['forward_uid']) { $compose_mode = RCUBE_COMPOSE_FORWARD; - $OUTPUT->set_env('compose_mode', 'forward'); $COMPOSE['forward_uid'] = $msg_uid; $COMPOSE['as_attachment'] = !empty($COMPOSE['param']['attachment']); } else if ($msg_uid = $COMPOSE['param']['uid']) { $compose_mode = RCUBE_COMPOSE_EDIT; } +$OUTPUT->set_env('compose_mode', $compose_mode); $config_show_sig = $RCMAIL->config->get('show_sig', 1); if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) { @@ -374,102 +373,6 @@ $MESSAGE_BODY = rcmail_prepare_message_body(); /****** compose mode functions ********/ -function rcmail_identity_select($MESSAGE, $identities, $compose_mode) -{ - $a_recipients = array(); - $a_names = array(); - - // extract all recipients of the reply-message - if (is_object($MESSAGE->headers) && in_array($compose_mode, array(RCUBE_COMPOSE_REPLY, RCUBE_COMPOSE_FORWARD))) { - $a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset); - foreach ($a_to as $addr) { - if (!empty($addr['mailto'])) { - $a_recipients[] = format_email($addr['mailto']); - $a_names[] = $addr['name']; - } - } - - if (!empty($MESSAGE->headers->cc)) { - $a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset); - foreach ($a_cc as $addr) { - if (!empty($addr['mailto'])) { - $a_recipients[] = format_email($addr['mailto']); - $a_names[] = $addr['name']; - } - } - } - } - - $from_idx = null; - $found_idx = null; - $default_identity = 0; // default identity is always first on the list - - // Select identity - foreach ($identities as $idx => $ident) { - // use From header - if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { - if ($MESSAGE->headers->from == $ident['ident']) { - $from_idx = $idx; - break; - } - } - // reply to yourself - else if ($compose_mode == RCUBE_COMPOSE_REPLY && $MESSAGE->headers->from == $ident['ident']) { - $from_idx = $idx; - break; - } - // use replied message recipients - else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) { - if ($found_idx === null) { - $found_idx = $idx; - } - // match identity name - if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) { - $from_idx = $idx; - break; - } - } - } - - // If matching by name+address doesn't found any amtches, get first found address (identity) - if ($from_idx === null) { - $from_idx = $found_idx; - } - - // Try Return-Path - if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { - foreach ($identities as $idx => $ident) { - if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) { - $from_idx = $idx; - break; - } - } - } - - // Fallback using Delivered-To - if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { - foreach ($identities as $idx => $ident) { - if (in_array($ident['email_ascii'], (array)$delivered_to)) { - $from_idx = $idx; - break; - } - } - } - - // Fallback using Envelope-To - if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) { - foreach ($identities as $idx => $ident) { - if (in_array($ident['email_ascii'], (array)$envelope_to)) { - $from_idx = $idx; - break; - } - } - } - - return $identities[$from_idx !== null ? $from_idx : $default_identity]; -} - - function rcmail_compose_headers($attrib) { global $MESSAGE; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 7d6a51751..bd381d5c0 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1720,11 +1720,11 @@ function rcmail_send_mdn($message, &$smtp_error) if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) && ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*'))) { - $identity = $RCMAIL->user->get_identity(); - $sender = format_email_recipient($identity['email'], $identity['name']); + $identity = rcmail_identity_select($message); + $sender = format_email_recipient($identity['email'], $identity['name']); $recipient = array_shift(rcube_mime::decode_address_list( $message->headers->mdn_to, 1, true, $message->headers->charset)); - $mailto = $recipient['mailto']; + $mailto = $recipient['mailto']; $compose = new Mail_mime("\r\n"); @@ -1782,6 +1782,107 @@ function rcmail_send_mdn($message, &$smtp_error) return false; } +/** + * Detect recipient identity from specified message + */ +function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'reply') +{ + $a_recipients = array(); + $a_names = array(); + + if ($identities === null) { + $identities = rcmail::get_instance()->user->list_identities(null, true); + } + + // extract all recipients of the reply-message + if (is_object($MESSAGE->headers) && in_array($compose_mode, array('reply', 'forward'))) { + $a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset); + foreach ($a_to as $addr) { + if (!empty($addr['mailto'])) { + $a_recipients[] = format_email($addr['mailto']); + $a_names[] = $addr['name']; + } + } + + if (!empty($MESSAGE->headers->cc)) { + $a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset); + foreach ($a_cc as $addr) { + if (!empty($addr['mailto'])) { + $a_recipients[] = format_email($addr['mailto']); + $a_names[] = $addr['name']; + } + } + } + } + + $from_idx = null; + $found_idx = null; + $default_identity = 0; // default identity is always first on the list + + // Select identity + foreach ($identities as $idx => $ident) { + // use From header + if (in_array($compose_mode, array('draft', 'edit'))) { + if ($MESSAGE->headers->from == $ident['ident']) { + $from_idx = $idx; + break; + } + } + // reply to yourself + else if ($compose_mode == 'reply' && $MESSAGE->headers->from == $ident['ident']) { + $from_idx = $idx; + break; + } + // use replied message recipients + else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) { + if ($found_idx === null) { + $found_idx = $idx; + } + // match identity name + if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) { + $from_idx = $idx; + break; + } + } + } + + // If matching by name+address doesn't found any matches, get first found address (identity) + if ($from_idx === null) { + $from_idx = $found_idx; + } + + // Try Return-Path + if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { + foreach ($identities as $idx => $ident) { + if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) { + $from_idx = $idx; + break; + } + } + } + + // Fallback using Delivered-To + if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], (array)$delivered_to)) { + $from_idx = $idx; + break; + } + } + } + + // Fallback using Envelope-To + if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], (array)$envelope_to)) { + $from_idx = $idx; + break; + } + } + } + + return $identities[$from_idx !== null ? $from_idx : $default_identity]; +} // Fixes some content-type names function rcmail_fix_mimetype($name) -- cgit v1.2.3 From 5c421d9927c973049bfaea69609cdf760f8f7332 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 14 Dec 2012 13:50:39 +0100 Subject: Fix delete button regression in message view (#1488867) --- program/js/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index b5bf1840a..00a47f4b8 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -2600,7 +2600,7 @@ function rcube_webmail() { var uid, i, len, trash = this.env.trash_mailbox, list = this.message_list, - selection = list.get_selection(); + selection = list ? list.get_selection() : []; // exit if no mailbox specified or if selection is empty if (!this.env.uid && !selection.length) @@ -2710,7 +2710,7 @@ function rcube_webmail() data._mbox = this.env.mailbox; if (!data._uid) { - var uids = this.env.uid ? this.env.uid : this.message_list.get_selection(); + var uids = this.env.uid ? [this.env.uid] : this.message_list.get_selection(); data._uid = this.uids_to_list(uids); } -- cgit v1.2.3 From ff4a92c8e2f11711975f9697a057cd96ce370bc5 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 14 Dec 2012 19:41:07 +0100 Subject: Fix contact copy/add-to-group operations on search result (#1488862) --- CHANGELOG | 1 + program/js/app.js | 88 +++++++++++++++++++++++------------- program/steps/addressbook/func.inc | 28 ++++++------ program/steps/addressbook/groups.inc | 13 +++--- 4 files changed, 79 insertions(+), 51 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 039d833c3..2deecd233 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix contact copy/add-to-group operations on search result (#1488862) - Use matching identity in MDN response (#1488864) - Fix unwanted horizontal scrollbar in message preview header (#1488866) - Fix handling of signatures on draft edit (#1488798) diff --git a/program/js/app.js b/program/js/app.js index 00a47f4b8..a0cf5f834 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1386,8 +1386,8 @@ function rcube_webmail() // over the folders for (k in this.env.folder_coords) { pos = this.env.folder_coords[k]; - if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2){ - if ((check = this.check_droptarget(k))) { + if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2) { + if (check = this.check_droptarget(k)) { li = this.get_folder_li(k); div = $(li.getElementsByTagName('div')[0]); @@ -1401,7 +1401,8 @@ function rcube_webmail() rcmail.command('collapse-folder', rcmail.folder_auto_expand); rcmail.drag_start(null); }, 1000); - } else if (this.folder_auto_timer) { + } + else if (this.folder_auto_timer) { clearTimeout(this.folder_auto_timer); this.folder_auto_timer = null; this.folder_auto_expand = null; @@ -1411,9 +1412,10 @@ function rcube_webmail() this.env.folder_coords[k].on = 1; this.env.last_folder_target = k; layerclass = 'draglayer' + (check > 1 ? 'copy' : 'normal'); - } else { // Clear target, otherwise drag end will trigger move into last valid droptarget - this.env.last_folder_target = null; } + // Clear target, otherwise drag end will trigger move into last valid droptarget + else + this.env.last_folder_target = null; } else if (pos.on) { $(this.get_folder_li(k)).removeClass('droptarget'); @@ -1640,27 +1642,31 @@ function rcube_webmail() this.check_droptarget = function(id) { - var allow = false, copy = false; - if (this.task == 'mail') - allow = (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual); - else if (this.task == 'settings') - allow = (id != this.env.mailbox); - else if (this.task == 'addressbook') { + return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual) ? 1 : 0; + + if (this.task == 'settings') + return id != this.env.mailbox ? 1 : 0; + + if (this.task == 'addressbook') { if (id != this.env.source && this.env.contactfolders[id]) { + // droptarget is a group - contact add to group action if (this.env.contactfolders[id].type == 'group') { var target_abook = this.env.contactfolders[id].source; - allow = this.env.contactfolders[id].id != this.env.group && !this.env.contactfolders[target_abook].readonly; - copy = target_abook != this.env.source; + if (this.env.contactfolders[id].id != this.env.group && !this.env.contactfolders[target_abook].readonly) { + // search result may contain contacts from many sources + return (this.env.selection_sources.length > 1 || $.inArray(target_abook, this.env.selection_sources) == -1) ? 2 : 1; + } } - else { - allow = !this.env.contactfolders[id].readonly; - copy = true; + // droptarget is a (writable) addressbook - contact copy action + else if (!this.env.contactfolders[id].readonly) { + // search result may contain contacts from many sources + return (this.env.selection_sources.length > 1 || $.inArray(id, this.env.selection_sources) == -1) ? 2 : 0; } } } - return allow ? (copy ? 2 : 1) : 0; + return 0; }; this.open_window = function(url, width, height) @@ -4082,19 +4088,24 @@ function rcube_webmail() else if (this.env.contentframe) this.show_contentframe(false); - // no source = search result, we'll need to detect if any of - // selected contacts are in writable addressbook to enable edit/delete if (list.selection.length) { + // no source = search result, we'll need to detect if any of + // selected contacts are in writable addressbook to enable edit/delete + // we'll also need to know sources used in selection for copy + // and group-addmember operations (drag&drop) + this.env.selection_sources = []; if (!source) { for (n in list.selection) { sid = String(list.selection[n]).replace(/^[^-]+-/, ''); - if (sid && this.env.address_sources[sid] && !this.env.address_sources[sid].readonly) { - writable = true; - break; + if (sid && this.env.address_sources[sid]) { + writable = writable || !this.env.address_sources[sid].readonly; + this.env.selection_sources.push(sid); } } + this.env.selection_sources = $.unique(this.env.selection_sources); } else { + this.env.selection_sources.push(this.env.source); writable = !source.readonly; } } @@ -4245,22 +4256,35 @@ function rcube_webmail() // copy a contact to the specified target (group or directory) this.copy_contact = function(cid, to) { + var n, dest = to.type == 'group' ? to.source : to.id, + source = this.env.source, + group = this.env.group ? this.env.group : ''; + if (!cid) cid = this.contact_list.get_selection().join(','); - if (to.type == 'group' && to.source == this.env.source) - this.group_member_change('add', cid, to.source, to.id); - else if (to.type == 'group' && !this.env.address_sources[to.source].readonly) { - var lock = this.display_message(this.get_label('copyingcontact'), 'loading'), - post_data = {_cid: cid, _source: this.env.source, _to: to.source, _togid: to.id, - _gid: (this.env.group ? this.env.group : '')}; + if (!cid || !this.env.address_sources[dest] || this.env.address_sources[dest].readonly) + return; - this.http_post('copy', post_data, lock); + // search result may contain contacts from many sources, but if there is only one... + if (source == '' && this.env.selection_sources.length == 1) + source = this.env.selection_sources[0]; + + // tagret is a group + if (to.type == 'group') { + if (dest == source) + this.group_member_change('add', cid, dest, to.id); + else { + var lock = this.display_message(this.get_label('copyingcontact'), 'loading'), + post_data = {_cid: cid, _source: source, _to: dest, _togid: to.id, _gid: group}; + + this.http_post('copy', post_data, lock); + } } - else if (to.id != this.env.source && cid && this.env.address_sources[to.id] && !this.env.address_sources[to.id].readonly) { + // target is an addressbook + else if (to.id != source) { var lock = this.display_message(this.get_label('copyingcontact'), 'loading'), - post_data = {_cid: cid, _source: this.env.source, _to: to.id, - _gid: (this.env.group ? this.env.group : '')}; + post_data = {_cid: cid, _source: source, _to: to.id, _gid: group}; this.http_post('copy', post_data, lock); } diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index fded9a819..2f47483de 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -756,7 +756,7 @@ function rcmail_contact_key($row, $sort_col) * * @return array List of contact IDs per-source */ -function rcmail_get_cids() +function rcmail_get_cids($filter = null) { // contact ID (or comma-separated list of IDs) is provided in two // forms. If _source is an empty string then the ID is a string @@ -765,24 +765,25 @@ function rcmail_get_cids() $cid = get_input_value('_cid', RCUBE_INPUT_GPC); $source = (string) get_input_value('_source', RCUBE_INPUT_GPC); + if (is_array($cid)) { + return $cid; + } + if (!preg_match('/^[a-zA-Z0-9\+\/=_-]+(,[a-zA-Z0-9\+\/=_-]+)*$/', $cid)) { return array(); } - $cid = explode(',', $cid); - $got_source = strlen($source); - $result = array(); + $cid = explode(',', $cid); + $result = array(); // create per-source contact IDs array foreach ($cid as $id) { - // if _source is not specified we'll find it from decoded ID - if (!$got_source) { - if ($sep = strrpos($id, '-')) { - $contact_id = substr($id, 0, $sep); - $source_id = substr($id, $sep+1); - if (strlen($source_id)) { - $result[(string)$source_id][] = $contact_id; - } + // get source from decoded ID + if ($sep = strrpos($id, '-')) { + $contact_id = substr($id, 0, $sep); + $source_id = substr($id, $sep+1); + if (strlen($source_id)) { + $result[(string)$source_id][] = $contact_id; } } else { @@ -790,9 +791,10 @@ function rcmail_get_cids() } } - return $result; + return $filter !== null ? $result[$filter] : $result; } + // register UI objects $OUTPUT->add_handlers(array( 'directorylist' => 'rcmail_directory_list', diff --git a/program/steps/addressbook/groups.inc b/program/steps/addressbook/groups.inc index b70453889..3b9288a2b 100644 --- a/program/steps/addressbook/groups.inc +++ b/program/steps/addressbook/groups.inc @@ -20,7 +20,7 @@ */ $source = get_input_value('_source', RCUBE_INPUT_GPC); -$CONTACTS = rcmail_contact_source($source, true); +$CONTACTS = rcmail_contact_source($source); if ($CONTACTS->readonly || !$CONTACTS->groups) { $OUTPUT->show_message('sourceisreadonly', 'warning'); @@ -28,11 +28,11 @@ if ($CONTACTS->readonly || !$CONTACTS->groups) { } if ($RCMAIL->action == 'group-addmembers') { - if (($gid = get_input_value('_gid', RCUBE_INPUT_POST)) && ($ids = get_input_value('_cid', RCUBE_INPUT_POST))) { + if (($gid = get_input_value('_gid', RCUBE_INPUT_POST)) && ($ids = rcmail_get_cids($source))) { $plugin = $RCMAIL->plugins->exec_hook('group_addmembers', array('group_id' => $gid, 'ids' => $ids, 'source' => $source)); $CONTACTS->set_group($gid); - $num2add = count(explode(',', $plugin['ids'])); + $num2add = count($plugin['ids']); if (!$plugin['abort']) { if (($maxnum = $RCMAIL->config->get('max_group_members', 0)) && ($CONTACTS->count()->count + $num2add > $maxnum)) { @@ -55,7 +55,7 @@ if ($RCMAIL->action == 'group-addmembers') { } else if ($RCMAIL->action == 'group-delmembers') { - if (($gid = get_input_value('_gid', RCUBE_INPUT_POST)) && ($ids = get_input_value('_cid', RCUBE_INPUT_POST))) { + if (($gid = get_input_value('_gid', RCUBE_INPUT_POST)) && ($ids = rcmail_get_cids($source))) { $plugin = $RCMAIL->plugins->exec_hook('group_delmembers', array('group_id' => $gid, 'ids' => $ids, 'source' => $source)); if (!$plugin['abort']) @@ -63,10 +63,11 @@ else if ($RCMAIL->action == 'group-delmembers') { else $result = $plugin['result']; - if ($result){ + if ($result) { $OUTPUT->show_message('contactremovedfromgroup'); $OUTPUT->command('remove_group_contacts',array('source' => $source, 'gid' => $gid)); - }else{ + } + else { $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error'); } } -- cgit v1.2.3 From c0208002a804aa36cf6891e9875e2f8adc0deb2d Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 15 Dec 2012 18:32:42 +0100 Subject: Fix escaping of add-contact arguments - fixes JS error in IE --- program/steps/mail/func.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index bd381d5c0..88391b102 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1528,7 +1528,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, if ($addicon && $_SESSION['writeable_abook']) { $address .= html::a(array( 'href' => "#add", - 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, $string), + 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, JQ($string)), 'title' => rcube_label('addtoaddressbook'), 'class' => 'rcmaddcontact', ), -- cgit v1.2.3 From a072247dde60497f879b2a00790a6ec0a64fab4c Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sun, 16 Dec 2012 17:03:01 +0100 Subject: Fix package definitions and include framework classes in phpdoc --- bin/makedoc.sh | 5 +++-- program/include/bc.php | 1 + program/lib/Roundcube/rcube.php | 3 ++- program/lib/Roundcube/rcube_db.php | 2 +- program/lib/Roundcube/rcube_message_header.php | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) (limited to 'program') diff --git a/bin/makedoc.sh b/bin/makedoc.sh index 40c75bf47..2a34254cb 100755 --- a/bin/makedoc.sh +++ b/bin/makedoc.sh @@ -1,10 +1,11 @@ #!/bin/sh -TITLE="Roundcube Classes" +TITLE="Roundcube Webmail" PACKAGES="Core" INSTALL_PATH="`dirname $0`/.." PATH_PROJECT=$INSTALL_PATH/program/include +PATH_FRAMEWORK=$INSTALL_PATH/program/lib/Roundcube PATH_DOCS=$INSTALL_PATH/doc/phpdoc BIN_PHPDOC="`/usr/bin/which phpdoc`" @@ -20,6 +21,6 @@ TEMPLATE=earthli PRIVATE=off # make documentation -$BIN_PHPDOC -d $PATH_PROJECT -t $PATH_DOCS -ti "$TITLE" -dn $PACKAGES \ +$BIN_PHPDOC -d $PATH_PROJECT,$PATH_FRAMEWORK -t $PATH_DOCS -ti "$TITLE" -dn $PACKAGES \ -o $OUTPUTFORMAT:$CONVERTER:$TEMPLATE -pp $PRIVATE diff --git a/program/include/bc.php b/program/include/bc.php index 12110c0ad..dc4d54fd7 100644 --- a/program/include/bc.php +++ b/program/include/bc.php @@ -23,6 +23,7 @@ * Roundcube Webmail deprecated functions * * @package Core + * @subpackage Legacy * @author Thomas Bruederli */ diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php index cc4905a14..a127eeb4f 100644 --- a/program/lib/Roundcube/rcube.php +++ b/program/lib/Roundcube/rcube.php @@ -1266,7 +1266,8 @@ class rcube /** * Lightweight plugin API class serving as a dummy if plugins are not enabled * - * @package Core + * @package Framework + * @subpackage Core */ class rcube_dummy_plugin_api { diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index 2c471e74d..e6e8c2ede 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -25,7 +25,7 @@ * This is a wrapper for the PHP PDO. * * @package Framework - * @sbpackage Database + * @subpackage Database */ class rcube_db { diff --git a/program/lib/Roundcube/rcube_message_header.php b/program/lib/Roundcube/rcube_message_header.php index 7009a00af..16a0aaac9 100644 --- a/program/lib/Roundcube/rcube_message_header.php +++ b/program/lib/Roundcube/rcube_message_header.php @@ -257,7 +257,8 @@ class rcube_message_header /** * Class for sorting an array of rcube_message_header objects in a predetermined order. * - * @package Mail + * @package Framework + * @subpackage Storage * @author Aleksander Machniak */ class rcube_message_header_sorter -- cgit v1.2.3 From a2b638320425309dd9af9ec8d53b925890628783 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 17 Dec 2012 08:13:28 +0100 Subject: Fix keep-alive interval reset on AJAX request --- program/js/app.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index a0cf5f834..f1df73cee 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -6128,14 +6128,14 @@ function rcube_webmail() // send request this.log('HTTP GET: ' + url); + // reset keep-alive interval + this.start_keepalive(); + return $.ajax({ type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json', success: function(data){ ref.http_response(data); }, error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } }); - - // reset keep-alive interval - this.start_keepalive(); }; // send a http POST request to the server @@ -6163,14 +6163,14 @@ function rcube_webmail() // send request this.log('HTTP POST: ' + url); + // reset keep-alive interval + this.start_keepalive(); + return $.ajax({ type: 'POST', url: url, data: postdata, dataType: 'json', success: function(data){ ref.http_response(data); }, error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } }); - - // reset keep-alive interval - this.start_keepalive(); }; // aborts ajax request -- cgit v1.2.3 From 9945f24274d84f6fe2124bdf23bc3bd2f128a6c9 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 18 Dec 2012 09:01:19 +0100 Subject: CS fixes --- program/lib/Roundcube/rcube_smtp.php | 764 +++++++++++++++++------------------ 1 file changed, 373 insertions(+), 391 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_smtp.php b/program/lib/Roundcube/rcube_smtp.php index 96534c0b8..1a4958e2b 100644 --- a/program/lib/Roundcube/rcube_smtp.php +++ b/program/lib/Roundcube/rcube_smtp.php @@ -5,7 +5,7 @@ | program/include/rcube_smtp.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -19,9 +19,6 @@ +-----------------------------------------------------------------------+ */ -// define headers delimiter -define('SMTP_MIME_CRLF', "\r\n"); - /** * Class to provide SMTP functionality using PEAR Net_SMTP * @@ -32,439 +29,424 @@ define('SMTP_MIME_CRLF', "\r\n"); */ class rcube_smtp { - - private $conn = null; - private $response; - private $error; - - - /** - * SMTP Connection and authentication - * - * @param string Server host - * @param string Server port - * @param string User name - * @param string Password - * - * @return bool Returns true on success, or false on error - */ - public function connect($host=null, $port=null, $user=null, $pass=null) - { - $rcube = rcube::get_instance(); - - // disconnect/destroy $this->conn - $this->disconnect(); - - // reset error/response var - $this->error = $this->response = null; - - // let plugins alter smtp connection config - $CONFIG = $rcube->plugins->exec_hook('smtp_connect', array( - 'smtp_server' => $host ? $host : $rcube->config->get('smtp_server'), - 'smtp_port' => $port ? $port : $rcube->config->get('smtp_port', 25), - 'smtp_user' => $user ? $user : $rcube->config->get('smtp_user'), - 'smtp_pass' => $pass ? $pass : $rcube->config->get('smtp_pass'), - 'smtp_auth_cid' => $rcube->config->get('smtp_auth_cid'), - 'smtp_auth_pw' => $rcube->config->get('smtp_auth_pw'), - 'smtp_auth_type' => $rcube->config->get('smtp_auth_type'), - 'smtp_helo_host' => $rcube->config->get('smtp_helo_host'), - 'smtp_timeout' => $rcube->config->get('smtp_timeout'), - 'smtp_auth_callbacks' => array(), - )); - - $smtp_host = rcube_utils::parse_host($CONFIG['smtp_server']); - // when called from Installer it's possible to have empty $smtp_host here - if (!$smtp_host) $smtp_host = 'localhost'; - $smtp_port = is_numeric($CONFIG['smtp_port']) ? $CONFIG['smtp_port'] : 25; - $smtp_host_url = parse_url($smtp_host); - - // overwrite port - if (isset($smtp_host_url['host']) && isset($smtp_host_url['port'])) + private $conn = null; + private $response; + private $error; + + // define headers delimiter + const SMTP_MIME_CRLF = "\r\n"; + + + /** + * SMTP Connection and authentication + * + * @param string Server host + * @param string Server port + * @param string User name + * @param string Password + * + * @return bool Returns true on success, or false on error + */ + public function connect($host=null, $port=null, $user=null, $pass=null) { - $smtp_host = $smtp_host_url['host']; - $smtp_port = $smtp_host_url['port']; - } + $rcube = rcube::get_instance(); - // re-write smtp host - if (isset($smtp_host_url['host']) && isset($smtp_host_url['scheme'])) - $smtp_host = sprintf('%s://%s', $smtp_host_url['scheme'], $smtp_host_url['host']); + // disconnect/destroy $this->conn + $this->disconnect(); - // remove TLS prefix and set flag for use in Net_SMTP::auth() - if (preg_match('#^tls://#i', $smtp_host)) { - $smtp_host = preg_replace('#^tls://#i', '', $smtp_host); - $use_tls = true; - } + // reset error/response var + $this->error = $this->response = null; + + // let plugins alter smtp connection config + $CONFIG = $rcube->plugins->exec_hook('smtp_connect', array( + 'smtp_server' => $host ? $host : $rcube->config->get('smtp_server'), + 'smtp_port' => $port ? $port : $rcube->config->get('smtp_port', 25), + 'smtp_user' => $user ? $user : $rcube->config->get('smtp_user'), + 'smtp_pass' => $pass ? $pass : $rcube->config->get('smtp_pass'), + 'smtp_auth_cid' => $rcube->config->get('smtp_auth_cid'), + 'smtp_auth_pw' => $rcube->config->get('smtp_auth_pw'), + 'smtp_auth_type' => $rcube->config->get('smtp_auth_type'), + 'smtp_helo_host' => $rcube->config->get('smtp_helo_host'), + 'smtp_timeout' => $rcube->config->get('smtp_timeout'), + 'smtp_auth_callbacks' => array(), + )); + + $smtp_host = rcube_utils::parse_host($CONFIG['smtp_server']); + // when called from Installer it's possible to have empty $smtp_host here + if (!$smtp_host) $smtp_host = 'localhost'; + $smtp_port = is_numeric($CONFIG['smtp_port']) ? $CONFIG['smtp_port'] : 25; + $smtp_host_url = parse_url($smtp_host); + + // overwrite port + if (isset($smtp_host_url['host']) && isset($smtp_host_url['port'])) { + $smtp_host = $smtp_host_url['host']; + $smtp_port = $smtp_host_url['port']; + } - if (!empty($CONFIG['smtp_helo_host'])) - $helo_host = $CONFIG['smtp_helo_host']; - else if (!empty($_SERVER['SERVER_NAME'])) - $helo_host = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); - else - $helo_host = 'localhost'; + // re-write smtp host + if (isset($smtp_host_url['host']) && isset($smtp_host_url['scheme'])) { + $smtp_host = sprintf('%s://%s', $smtp_host_url['scheme'], $smtp_host_url['host']); + } - // IDNA Support - $smtp_host = rcube_utils::idn_to_ascii($smtp_host); + // remove TLS prefix and set flag for use in Net_SMTP::auth() + if (preg_match('#^tls://#i', $smtp_host)) { + $smtp_host = preg_replace('#^tls://#i', '', $smtp_host); + $use_tls = true; + } - $this->conn = new Net_SMTP($smtp_host, $smtp_port, $helo_host); + if (!empty($CONFIG['smtp_helo_host'])) { + $helo_host = $CONFIG['smtp_helo_host']; + } + else if (!empty($_SERVER['SERVER_NAME'])) { + $helo_host = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); + } + else { + $helo_host = 'localhost'; + } - if ($rcube->config->get('smtp_debug')) - $this->conn->setDebug(true, array($this, 'debug_handler')); + // IDNA Support + $smtp_host = rcube_utils::idn_to_ascii($smtp_host); - // register authentication methods - if (!empty($CONFIG['smtp_auth_callbacks']) && method_exists($this->conn, 'setAuthMethod')) { - foreach ($CONFIG['smtp_auth_callbacks'] as $callback) { - $this->conn->setAuthMethod($callback['name'], $callback['function'], - isset($callback['prepend']) ? $callback['prepend'] : true); - } - } + $this->conn = new Net_SMTP($smtp_host, $smtp_port, $helo_host); - // try to connect to server and exit on failure - $result = $this->conn->connect($smtp_timeout); + if ($rcube->config->get('smtp_debug')) { + $this->conn->setDebug(true, array($this, 'debug_handler')); + } - if (PEAR::isError($result)) { - $this->response[] = "Connection failed: ".$result->getMessage(); - $this->error = array('label' => 'smtpconnerror', 'vars' => array('code' => $this->conn->_code)); - $this->conn = null; - return false; - } + // register authentication methods + if (!empty($CONFIG['smtp_auth_callbacks']) && method_exists($this->conn, 'setAuthMethod')) { + foreach ($CONFIG['smtp_auth_callbacks'] as $callback) { + $this->conn->setAuthMethod($callback['name'], $callback['function'], + isset($callback['prepend']) ? $callback['prepend'] : true); + } + } - // workaround for timeout bug in Net_SMTP 1.5.[0-1] (#1487843) - if (method_exists($this->conn, 'setTimeout') - && ($timeout = ini_get('default_socket_timeout')) - ) { - $this->conn->setTimeout($timeout); - } + // try to connect to server and exit on failure + $result = $this->conn->connect($smtp_timeout); - $smtp_user = str_replace('%u', $rcube->get_user_name(), $CONFIG['smtp_user']); - $smtp_pass = str_replace('%p', $rcube->get_user_password(), $CONFIG['smtp_pass']); - $smtp_auth_type = empty($CONFIG['smtp_auth_type']) ? NULL : $CONFIG['smtp_auth_type']; + if (PEAR::isError($result)) { + $this->response[] = "Connection failed: ".$result->getMessage(); + $this->error = array('label' => 'smtpconnerror', 'vars' => array('code' => $this->conn->_code)); + $this->conn = null; + return false; + } - if (!empty($CONFIG['smtp_auth_cid'])) { - $smtp_authz = $smtp_user; - $smtp_user = $CONFIG['smtp_auth_cid']; - $smtp_pass = $CONFIG['smtp_auth_pw']; - } + // workaround for timeout bug in Net_SMTP 1.5.[0-1] (#1487843) + if (method_exists($this->conn, 'setTimeout') + && ($timeout = ini_get('default_socket_timeout')) + ) { + $this->conn->setTimeout($timeout); + } - // attempt to authenticate to the SMTP server - if ($smtp_user && $smtp_pass) - { - // IDNA Support - if (strpos($smtp_user, '@')) { - $smtp_user = rcube_utils::idn_to_ascii($smtp_user); - } - - $result = $this->conn->auth($smtp_user, $smtp_pass, $smtp_auth_type, $use_tls, $smtp_authz); - - if (PEAR::isError($result)) - { - $this->error = array('label' => 'smtpautherror', 'vars' => array('code' => $this->conn->_code)); - $this->response[] .= 'Authentication failure: ' . $result->getMessage() . ' (Code: ' . $result->getCode() . ')'; - $this->reset(); - $this->disconnect(); - return false; - } - } + $smtp_user = str_replace('%u', $rcube->get_user_name(), $CONFIG['smtp_user']); + $smtp_pass = str_replace('%p', $rcube->get_user_password(), $CONFIG['smtp_pass']); + $smtp_auth_type = empty($CONFIG['smtp_auth_type']) ? NULL : $CONFIG['smtp_auth_type']; - return true; - } - - - /** - * Function for sending mail - * - * @param string Sender e-Mail address - * - * @param mixed Either a comma-seperated list of recipients - * (RFC822 compliant), or an array of recipients, - * each RFC822 valid. This may contain recipients not - * specified in the headers, for Bcc:, resending - * messages, etc. - * @param mixed The message headers to send with the mail - * Either as an associative array or a finally - * formatted string - * @param mixed The full text of the message body, including any Mime parts - * or file handle - * @param array Delivery options (e.g. DSN request) - * - * @return bool Returns true on success, or false on error - */ - public function send_mail($from, $recipients, &$headers, &$body, $opts=null) - { - if (!is_object($this->conn)) - return false; - - // prepare message headers as string - if (is_array($headers)) - { - if (!($headerElements = $this->_prepare_headers($headers))) { - $this->reset(); - return false; - } + if (!empty($CONFIG['smtp_auth_cid'])) { + $smtp_authz = $smtp_user; + $smtp_user = $CONFIG['smtp_auth_cid']; + $smtp_pass = $CONFIG['smtp_auth_pw']; + } - list($from, $text_headers) = $headerElements; - } - else if (is_string($headers)) - $text_headers = $headers; - else - { - $this->reset(); - $this->response[] = "Invalid message headers"; - return false; + // attempt to authenticate to the SMTP server + if ($smtp_user && $smtp_pass) { + // IDNA Support + if (strpos($smtp_user, '@')) { + $smtp_user = rcube_utils::idn_to_ascii($smtp_user); + } + + $result = $this->conn->auth($smtp_user, $smtp_pass, $smtp_auth_type, $use_tls, $smtp_authz); + + if (PEAR::isError($result)) { + $this->error = array('label' => 'smtpautherror', 'vars' => array('code' => $this->conn->_code)); + $this->response[] .= 'Authentication failure: ' . $result->getMessage() . ' (Code: ' . $result->getCode() . ')'; + $this->reset(); + $this->disconnect(); + return false; + } + } + + return true; } - // exit if no from address is given - if (!isset($from)) + /** + * Function for sending mail + * + * @param string Sender e-Mail address + * + * @param mixed Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * @param mixed The message headers to send with the mail + * Either as an associative array or a finally + * formatted string + * @param mixed The full text of the message body, including any Mime parts + * or file handle + * @param array Delivery options (e.g. DSN request) + * + * @return bool Returns true on success, or false on error + */ + public function send_mail($from, $recipients, &$headers, &$body, $opts=null) { - $this->reset(); - $this->response[] = "No From address has been provided"; - return false; - } + if (!is_object($this->conn)) { + return false; + } - // RFC3461: Delivery Status Notification - if ($opts['dsn']) { - $exts = $this->conn->getServiceExtensions(); + // prepare message headers as string + if (is_array($headers)) { + if (!($headerElements = $this->_prepare_headers($headers))) { + $this->reset(); + return false; + } - if (isset($exts['DSN'])) { - $from_params = 'RET=HDRS'; - $recipient_params = 'NOTIFY=SUCCESS,FAILURE'; - } - } + list($from, $text_headers) = $headerElements; + } + else if (is_string($headers)) { + $text_headers = $headers; + } + else { + $this->reset(); + $this->response[] = "Invalid message headers"; + return false; + } + + // exit if no from address is given + if (!isset($from)) { + $this->reset(); + $this->response[] = "No From address has been provided"; + return false; + } + + // RFC3461: Delivery Status Notification + if ($opts['dsn']) { + $exts = $this->conn->getServiceExtensions(); + + if (isset($exts['DSN'])) { + $from_params = 'RET=HDRS'; + $recipient_params = 'NOTIFY=SUCCESS,FAILURE'; + } + } + + // RFC2298.3: remove envelope sender address + if (preg_match('/Content-Type: multipart\/report/', $text_headers) + && preg_match('/report-type=disposition-notification/', $text_headers) + ) { + $from = ''; + } + + // set From: address + if (PEAR::isError($this->conn->mailFrom($from, $from_params))) { + $err = $this->conn->getResponse(); + $this->error = array('label' => 'smtpfromerror', 'vars' => array( + 'from' => $from, 'code' => $this->conn->_code, 'msg' => $err[1])); + $this->response[] = "Failed to set sender '$from'"; + $this->reset(); + return false; + } + + // prepare list of recipients + $recipients = $this->_parse_rfc822($recipients); + if (PEAR::isError($recipients)) { + $this->error = array('label' => 'smtprecipientserror'); + $this->reset(); + return false; + } - // RFC2298.3: remove envelope sender address - if (preg_match('/Content-Type: multipart\/report/', $text_headers) - && preg_match('/report-type=disposition-notification/', $text_headers) - ) { - $from = ''; + // set mail recipients + foreach ($recipients as $recipient) { + if (PEAR::isError($this->conn->rcptTo($recipient, $recipient_params))) { + $err = $this->conn->getResponse(); + $this->error = array('label' => 'smtptoerror', 'vars' => array( + 'to' => $recipient, 'code' => $this->conn->_code, 'msg' => $err[1])); + $this->response[] = "Failed to add recipient '$recipient'"; + $this->reset(); + return false; + } + } + + if (is_resource($body)) { + // file handle + $data = $body; + $text_headers = preg_replace('/[\r\n]+$/', '', $text_headers); + } + else { + // Concatenate headers and body so it can be passed by reference to SMTP_CONN->data + // so preg_replace in SMTP_CONN->quotedata will store a reference instead of a copy. + // We are still forced to make another copy here for a couple ticks so we don't really + // get to save a copy in the method call. + $data = $text_headers . "\r\n" . $body; + + // unset old vars to save data and so we can pass into SMTP_CONN->data by reference. + unset($text_headers, $body); + } + + // Send the message's headers and the body as SMTP data. + if (PEAR::isError($result = $this->conn->data($data, $text_headers))) { + $err = $this->conn->getResponse(); + if (!in_array($err[0], array(354, 250, 221))) { + $msg = sprintf('[%d] %s', $err[0], $err[1]); + } + else { + $msg = $result->getMessage(); + } + + $this->error = array('label' => 'smtperror', 'vars' => array('msg' => $msg)); + $this->response[] = "Failed to send data"; + $this->reset(); + return false; + } + + $this->response[] = join(': ', $this->conn->getResponse()); + return true; } - // set From: address - if (PEAR::isError($this->conn->mailFrom($from, $from_params))) + /** + * Reset the global SMTP connection + */ + public function reset() { - $err = $this->conn->getResponse(); - $this->error = array('label' => 'smtpfromerror', 'vars' => array( - 'from' => $from, 'code' => $this->conn->_code, 'msg' => $err[1])); - $this->response[] = "Failed to set sender '$from'"; - $this->reset(); - return false; + if (is_object($this->conn)) { + $this->conn->rset(); + } } - // prepare list of recipients - $recipients = $this->_parse_rfc822($recipients); - if (PEAR::isError($recipients)) + /** + * Disconnect the global SMTP connection + */ + public function disconnect() { - $this->error = array('label' => 'smtprecipientserror'); - $this->reset(); - return false; + if (is_object($this->conn)) { + $this->conn->disconnect(); + $this->conn = null; + } } - // set mail recipients - foreach ($recipients as $recipient) + + /** + * This is our own debug handler for the SMTP connection + */ + public function debug_handler(&$smtp, $message) { - if (PEAR::isError($this->conn->rcptTo($recipient, $recipient_params))) { - $err = $this->conn->getResponse(); - $this->error = array('label' => 'smtptoerror', 'vars' => array( - 'to' => $recipient, 'code' => $this->conn->_code, 'msg' => $err[1])); - $this->response[] = "Failed to add recipient '$recipient'"; - $this->reset(); - return false; - } + rcube::write_log('smtp', preg_replace('/\r\n$/', '', $message)); } - if (is_resource($body)) + /** + * Get error message + */ + public function get_error() { - // file handle - $data = $body; - $text_headers = preg_replace('/[\r\n]+$/', '', $text_headers); - } else { - // Concatenate headers and body so it can be passed by reference to SMTP_CONN->data - // so preg_replace in SMTP_CONN->quotedata will store a reference instead of a copy. - // We are still forced to make another copy here for a couple ticks so we don't really - // get to save a copy in the method call. - $data = $text_headers . "\r\n" . $body; - - // unset old vars to save data and so we can pass into SMTP_CONN->data by reference. - unset($text_headers, $body); + return $this->error; } - // Send the message's headers and the body as SMTP data. - if (PEAR::isError($result = $this->conn->data($data, $text_headers))) + /** + * Get server response messages array + */ + public function get_response() { - $err = $this->conn->getResponse(); - if (!in_array($err[0], array(354, 250, 221))) - $msg = sprintf('[%d] %s', $err[0], $err[1]); - else - $msg = $result->getMessage(); - - $this->error = array('label' => 'smtperror', 'vars' => array('msg' => $msg)); - $this->response[] = "Failed to send data"; - $this->reset(); - return false; + return $this->response; } - $this->response[] = join(': ', $this->conn->getResponse()); - return true; - } - - - /** - * Reset the global SMTP connection - * @access public - */ - public function reset() - { - if (is_object($this->conn)) - $this->conn->rset(); - } - - - /** - * Disconnect the global SMTP connection - * @access public - */ - public function disconnect() - { - if (is_object($this->conn)) { - $this->conn->disconnect(); - $this->conn = null; - } - } - - - /** - * This is our own debug handler for the SMTP connection - * @access public - */ - public function debug_handler(&$smtp, $message) - { - rcube::write_log('smtp', preg_replace('/\r\n$/', '', $message)); - } - - - /** - * Get error message - * @access public - */ - public function get_error() - { - return $this->error; - } - - - /** - * Get server response messages array - * @access public - */ - public function get_response() - { - return $this->response; - } - - - /** - * Take an array of mail headers and return a string containing - * text usable in sending a message. - * - * @param array $headers The array of headers to prepare, in an associative - * array, where the array key is the header name (ie, - * 'Subject'), and the array value is the header - * value (ie, 'test'). The header produced from those - * values would be 'Subject: test'. - * - * @return mixed Returns false if it encounters a bad address, - * otherwise returns an array containing two - * elements: Any From: address found in the headers, - * and the plain text version of the headers. - * @access private - */ - private function _prepare_headers($headers) - { - $lines = array(); - $from = null; - - foreach ($headers as $key => $value) + /** + * Take an array of mail headers and return a string containing + * text usable in sending a message. + * + * @param array $headers The array of headers to prepare, in an associative + * array, where the array key is the header name (ie, + * 'Subject'), and the array value is the header + * value (ie, 'test'). The header produced from those + * values would be 'Subject: test'. + * + * @return mixed Returns false if it encounters a bad address, + * otherwise returns an array containing two + * elements: Any From: address found in the headers, + * and the plain text version of the headers. + */ + private function _prepare_headers($headers) { - if (strcasecmp($key, 'From') === 0) - { - $addresses = $this->_parse_rfc822($value); - - if (is_array($addresses)) - $from = $addresses[0]; - - // Reject envelope From: addresses with spaces. - if (strpos($from, ' ') !== false) - return false; - - $lines[] = $key . ': ' . $value; - } - else if (strcasecmp($key, 'Received') === 0) - { - $received = array(); - if (is_array($value)) - { - foreach ($value as $line) - $received[] = $key . ': ' . $line; - } - else - { - $received[] = $key . ': ' . $value; + $lines = array(); + $from = null; + + foreach ($headers as $key => $value) { + if (strcasecmp($key, 'From') === 0) { + $addresses = $this->_parse_rfc822($value); + + if (is_array($addresses)) { + $from = $addresses[0]; + } + + // Reject envelope From: addresses with spaces. + if (strpos($from, ' ') !== false) { + return false; + } + + $lines[] = $key . ': ' . $value; + } + else if (strcasecmp($key, 'Received') === 0) { + $received = array(); + if (is_array($value)) { + foreach ($value as $line) { + $received[] = $key . ': ' . $line; + } + } + else { + $received[] = $key . ': ' . $value; + } + + // Put Received: headers at the top. Spam detectors often + // flag messages with Received: headers after the Subject: + // as spam. + $lines = array_merge($received, $lines); + } + else { + // If $value is an array (i.e., a list of addresses), convert + // it to a comma-delimited string of its elements (addresses). + if (is_array($value)) { + $value = implode(', ', $value); + } + + $lines[] = $key . ': ' . $value; + } } - // Put Received: headers at the top. Spam detectors often - // flag messages with Received: headers after the Subject: - // as spam. - $lines = array_merge($received, $lines); - } - else - { - // If $value is an array (i.e., a list of addresses), convert - // it to a comma-delimited string of its elements (addresses). - if (is_array($value)) - $value = implode(', ', $value); - - $lines[] = $key . ': ' . $value; - } + return array($from, join(self::SMTP_MIME_CRLF, $lines) . self::SMTP_MIME_CRLF); } - return array($from, join(SMTP_MIME_CRLF, $lines) . SMTP_MIME_CRLF); - } - - /** - * Take a set of recipients and parse them, returning an array of - * bare addresses (forward paths) that can be passed to sendmail - * or an smtp server with the rcpt to: command. - * - * @param mixed Either a comma-seperated list of recipients - * (RFC822 compliant), or an array of recipients, - * each RFC822 valid. - * - * @return array An array of forward paths (bare addresses). - * @access private - */ - private function _parse_rfc822($recipients) - { - // if we're passed an array, assume addresses are valid and implode them before parsing. - if (is_array($recipients)) - $recipients = implode(', ', $recipients); - - $addresses = array(); - $recipients = rcube_utils::explode_quoted_string(',', $recipients); - - reset($recipients); - while (list($k, $recipient) = each($recipients)) + /** + * Take a set of recipients and parse them, returning an array of + * bare addresses (forward paths) that can be passed to sendmail + * or an smtp server with the rcpt to: command. + * + * @param mixed Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. + * + * @return array An array of forward paths (bare addresses). + */ + private function _parse_rfc822($recipients) { - $a = rcube_utils::explode_quoted_string(' ', $recipient); - while (list($k2, $word) = each($a)) - { - if (strpos($word, "@") > 0 && $word[strlen($word)-1] != '"') - { - $word = preg_replace('/^<|>$/', '', trim($word)); - if (in_array($word, $addresses)===false) - array_push($addresses, $word); + // if we're passed an array, assume addresses are valid and implode them before parsing. + if (is_array($recipients)) { + $recipients = implode(', ', $recipients); } - } - } - return $addresses; - } + $addresses = array(); + $recipients = rcube_utils::explode_quoted_string(',', $recipients); + + reset($recipients); + while (list($k, $recipient) = each($recipients)) { + $a = rcube_utils::explode_quoted_string(' ', $recipient); + while (list($k2, $word) = each($a)) { + if (strpos($word, "@") > 0 && $word[strlen($word)-1] != '"') { + $word = preg_replace('/^<|>$/', '', trim($word)); + if (in_array($word, $addresses) === false) { + array_push($addresses, $word); + } + } + } + } + return $addresses; + } } -- cgit v1.2.3 From d2534c63f2c0b640a39fce2a71b14a5dcda6e7fd Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 18 Dec 2012 09:07:00 +0100 Subject: Cleanup, remove file paths from doc --- program/lib/Roundcube/bootstrap.php | 3 --- program/lib/Roundcube/html.php | 3 --- program/lib/Roundcube/rcube.php | 2 -- program/lib/Roundcube/rcube_addressbook.php | 3 --- program/lib/Roundcube/rcube_base_replacer.php | 3 --- program/lib/Roundcube/rcube_browser.php | 3 --- program/lib/Roundcube/rcube_cache.php | 3 --- program/lib/Roundcube/rcube_charset.php | 3 --- program/lib/Roundcube/rcube_config.php | 3 --- program/lib/Roundcube/rcube_contacts.php | 3 --- program/lib/Roundcube/rcube_content_filter.php | 3 --- program/lib/Roundcube/rcube_csv2vcard.php | 2 -- program/lib/Roundcube/rcube_db.php | 4 ---- program/lib/Roundcube/rcube_db_mssql.php | 4 ---- program/lib/Roundcube/rcube_db_mysql.php | 4 ---- program/lib/Roundcube/rcube_db_pgsql.php | 4 ---- program/lib/Roundcube/rcube_db_sqlite.php | 4 ---- program/lib/Roundcube/rcube_db_sqlsrv.php | 4 ---- program/lib/Roundcube/rcube_enriched.php | 4 ---- program/lib/Roundcube/rcube_image.php | 3 --- program/lib/Roundcube/rcube_imap.php | 4 ---- program/lib/Roundcube/rcube_imap_cache.php | 4 ---- program/lib/Roundcube/rcube_imap_generic.php | 4 ---- program/lib/Roundcube/rcube_ldap.php | 4 ---- program/lib/Roundcube/rcube_message.php | 3 --- program/lib/Roundcube/rcube_message_header.php | 3 --- program/lib/Roundcube/rcube_message_part.php | 4 ---- program/lib/Roundcube/rcube_mime.php | 4 ---- program/lib/Roundcube/rcube_output.php | 4 +--- program/lib/Roundcube/rcube_plugin.php | 2 -- program/lib/Roundcube/rcube_plugin_api.php | 3 --- program/lib/Roundcube/rcube_result_index.php | 4 ---- program/lib/Roundcube/rcube_result_set.php | 4 ---- program/lib/Roundcube/rcube_result_thread.php | 4 ---- program/lib/Roundcube/rcube_session.php | 3 --- program/lib/Roundcube/rcube_smtp.php | 3 --- program/lib/Roundcube/rcube_spellchecker.php | 4 ---- program/lib/Roundcube/rcube_storage.php | 4 ---- program/lib/Roundcube/rcube_string_replacer.php | 4 ---- program/lib/Roundcube/rcube_user.php | 4 ---- program/lib/Roundcube/rcube_utils.php | 3 --- program/lib/Roundcube/rcube_vcard.php | 3 --- 42 files changed, 1 insertion(+), 143 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/bootstrap.php b/program/lib/Roundcube/bootstrap.php index eed7db8c1..18c07ddab 100644 --- a/program/lib/Roundcube/bootstrap.php +++ b/program/lib/Roundcube/bootstrap.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/bootstrap.php | - | | | This file is part of the Roundcube PHP suite | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | CONTENTS: | | Roundcube Framework Initialization | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php index 5fb574b97..33b766c44 100644 --- a/program/lib/Roundcube/html.php +++ b/program/lib/Roundcube/html.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/html.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2011, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Helper class to create valid XHTML code | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php index a127eeb4f..cde549052 100644 --- a/program/lib/Roundcube/rcube.php +++ b/program/lib/Roundcube/rcube.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index ea8df700c..a8f274a8f 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_addressbook.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2006-2012, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Interface to the local address book database | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_base_replacer.php b/program/lib/Roundcube/rcube_base_replacer.php index b2a0fc13c..fcd85c2c8 100644 --- a/program/lib/Roundcube/rcube_base_replacer.php +++ b/program/lib/Roundcube/rcube_base_replacer.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_base_replacer.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Provide basic functions for base URL replacement | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_browser.php b/program/lib/Roundcube/rcube_browser.php index 154e7ef4e..d10fe2a2c 100644 --- a/program/lib/Roundcube/rcube_browser.php +++ b/program/lib/Roundcube/rcube_browser.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_browser.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2007-2009, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Class representing the client browser's properties | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_cache.php b/program/lib/Roundcube/rcube_cache.php index 3e1ce4fc8..92f12a8bf 100644 --- a/program/lib/Roundcube/rcube_cache.php +++ b/program/lib/Roundcube/rcube_cache.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_cache.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2011, The Roundcube Dev Team | | Copyright (C) 2011, Kolab Systems AG | @@ -14,7 +12,6 @@ | | | PURPOSE: | | Caching engine | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | diff --git a/program/lib/Roundcube/rcube_charset.php b/program/lib/Roundcube/rcube_charset.php index 6135a5711..968d1c4b8 100644 --- a/program/lib/Roundcube/rcube_charset.php +++ b/program/lib/Roundcube/rcube_charset.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_charset.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -15,7 +13,6 @@ | | | PURPOSE: | | Provide charset conversion functionality | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | diff --git a/program/lib/Roundcube/rcube_config.php b/program/lib/Roundcube/rcube_config.php index 615faf3ad..2190dc4c2 100644 --- a/program/lib/Roundcube/rcube_config.php +++ b/program/lib/Roundcube/rcube_config.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_config.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2012, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Class to read configuration settings | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php index 5b4292a4c..a98b13865 100644 --- a/program/lib/Roundcube/rcube_contacts.php +++ b/program/lib/Roundcube/rcube_contacts.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_contacts.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2006-2012, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Interface to the local address book database | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_content_filter.php b/program/lib/Roundcube/rcube_content_filter.php index 99916a300..b814bb71d 100644 --- a/program/lib/Roundcube/rcube_content_filter.php +++ b/program/lib/Roundcube/rcube_content_filter.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_content_filter.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2011, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | PHP stream filter to detect evil content in mail attachments | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php index 850c0c4c3..9c28a3b49 100644 --- a/program/lib/Roundcube/rcube_csv2vcard.php +++ b/program/lib/Roundcube/rcube_csv2vcard.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_csv2vcard.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2012, The Roundcube Dev Team | | | diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index e6e8c2ede..47ddc81a6 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_db.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -13,13 +11,11 @@ | | | PURPOSE: | | Database wrapper class that implements PHP PDO functions | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Database independent query interface. * This is a wrapper for the PHP PDO. diff --git a/program/lib/Roundcube/rcube_db_mssql.php b/program/lib/Roundcube/rcube_db_mssql.php index c95663c74..84fe22bbc 100644 --- a/program/lib/Roundcube/rcube_db_mssql.php +++ b/program/lib/Roundcube/rcube_db_mssql.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_db_mssql.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -14,13 +12,11 @@ | PURPOSE: | | Database wrapper class that implements PHP PDO functions | | for MS SQL Server database | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Database independent query interface * This is a wrapper for the PHP PDO diff --git a/program/lib/Roundcube/rcube_db_mysql.php b/program/lib/Roundcube/rcube_db_mysql.php index 1c5ba1de7..c32cc259c 100644 --- a/program/lib/Roundcube/rcube_db_mysql.php +++ b/program/lib/Roundcube/rcube_db_mysql.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_db_mysql.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -14,13 +12,11 @@ | PURPOSE: | | Database wrapper class that implements PHP PDO functions | | for MySQL database | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Database independent query interface * diff --git a/program/lib/Roundcube/rcube_db_pgsql.php b/program/lib/Roundcube/rcube_db_pgsql.php index 797860a84..cf23c5e48 100644 --- a/program/lib/Roundcube/rcube_db_pgsql.php +++ b/program/lib/Roundcube/rcube_db_pgsql.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_db_pgsql.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -14,13 +12,11 @@ | PURPOSE: | | Database wrapper class that implements PHP PDO functions | | for PostgreSQL database | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Database independent query interface * This is a wrapper for the PHP PDO diff --git a/program/lib/Roundcube/rcube_db_sqlite.php b/program/lib/Roundcube/rcube_db_sqlite.php index 65dcb6d6e..326c6a710 100644 --- a/program/lib/Roundcube/rcube_db_sqlite.php +++ b/program/lib/Roundcube/rcube_db_sqlite.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_db_sqlite.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -14,13 +12,11 @@ | PURPOSE: | | Database wrapper class that implements PHP PDO functions | | for SQLite database | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Database independent query interface * This is a wrapper for the PHP PDO diff --git a/program/lib/Roundcube/rcube_db_sqlsrv.php b/program/lib/Roundcube/rcube_db_sqlsrv.php index 8b6ffe807..e69678025 100644 --- a/program/lib/Roundcube/rcube_db_sqlsrv.php +++ b/program/lib/Roundcube/rcube_db_sqlsrv.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_db_sqlsrv.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -14,13 +12,11 @@ | PURPOSE: | | Database wrapper class that implements PHP PDO functions | | for MS SQL Server database | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Database independent query interface * This is a wrapper for the PHP PDO diff --git a/program/lib/Roundcube/rcube_enriched.php b/program/lib/Roundcube/rcube_enriched.php index 8b64fe054..8c628c912 100644 --- a/program/lib/Roundcube/rcube_enriched.php +++ b/program/lib/Roundcube/rcube_enriched.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_enriched.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -13,14 +11,12 @@ | | | PURPOSE: | | Helper class to convert Enriched to HTML format (RFC 1523, 1896) | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | | Author: Ryo Chijiiwa (IlohaMail) | +-----------------------------------------------------------------------+ */ - /** * Class for Enriched to HTML conversion * diff --git a/program/lib/Roundcube/rcube_image.php b/program/lib/Roundcube/rcube_image.php index b72a24c51..ad96842d2 100644 --- a/program/lib/Roundcube/rcube_image.php +++ b/program/lib/Roundcube/rcube_image.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_image.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -14,7 +12,6 @@ | | | PURPOSE: | | Image resizer and converter | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index ea3743d02..74c1f5324 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_imap.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -14,14 +12,12 @@ | | | PURPOSE: | | IMAP Storage Engine | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Interface class for accessing an IMAP server * diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php index 31214cfbf..f33ac076c 100644 --- a/program/lib/Roundcube/rcube_imap_cache.php +++ b/program/lib/Roundcube/rcube_imap_cache.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_imap_cache.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -13,14 +11,12 @@ | | | PURPOSE: | | Caching of IMAP folder contents (messages and index) | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Interface class for accessing Roundcube messages cache * diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 28d56c16f..112e91350 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_imap_generic.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -19,14 +17,12 @@ | functionality built-in. | | | | Based on Iloha IMAP Library. See http://ilohamail.org/ for details | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | | Author: Ryo Chijiiwa | +-----------------------------------------------------------------------+ */ - /** * PHP based wrapper class to connect to an IMAP server * diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index c32cea728..d4bc669fd 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_ldap.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2006-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -14,7 +12,6 @@ | | | PURPOSE: | | Interface to an LDAP address directory | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Andreas Dick | @@ -22,7 +19,6 @@ +-----------------------------------------------------------------------+ */ - /** * Model class to access an LDAP address directory * diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index c626af08a..f41493d12 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_message.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2010, The Roundcube Dev Team | | | @@ -19,7 +17,6 @@ +-----------------------------------------------------------------------+ */ - /** * Logical representation of a mail message with all its data * and related functions diff --git a/program/lib/Roundcube/rcube_message_header.php b/program/lib/Roundcube/rcube_message_header.php index 16a0aaac9..274ae7f9f 100644 --- a/program/lib/Roundcube/rcube_message_header.php +++ b/program/lib/Roundcube/rcube_message_header.php @@ -2,8 +2,6 @@ /** +-----------------------------------------------------------------------+ - | program/include/rcube_message_header.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -14,7 +12,6 @@ | | | PURPOSE: | | E-mail message headers representation | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_message_part.php b/program/lib/Roundcube/rcube_message_part.php index c9c9257eb..4222ba390 100644 --- a/program/lib/Roundcube/rcube_message_part.php +++ b/program/lib/Roundcube/rcube_message_part.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_message_part.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -14,14 +12,12 @@ | | | PURPOSE: | | Class representing a message part | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Class representing a message part * diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 4bb5b483f..eef8ca17c 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_mime.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -14,14 +12,12 @@ | | | PURPOSE: | | MIME message parsing utilities | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Class for parsing MIME messages * diff --git a/program/lib/Roundcube/rcube_output.php b/program/lib/Roundcube/rcube_output.php index 4ef42f598..b8ae86cf6 100644 --- a/program/lib/Roundcube/rcube_output.php +++ b/program/lib/Roundcube/rcube_output.php @@ -2,17 +2,15 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_output.php | - | | | This file is part of the Roundcube PHP suite | | Copyright (C) 2005-2012 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. | + | | | CONTENTS: | | Abstract class for output generation | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | diff --git a/program/lib/Roundcube/rcube_plugin.php b/program/lib/Roundcube/rcube_plugin.php index 5db85025d..06247d456 100644 --- a/program/lib/Roundcube/rcube_plugin.php +++ b/program/lib/Roundcube/rcube_plugin.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_plugin.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2009, The Roundcube Dev Team | | | diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php index 47508a2ef..b4626441d 100644 --- a/program/lib/Roundcube/rcube_plugin_api.php +++ b/program/lib/Roundcube/rcube_plugin_api.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_plugin_api.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2011, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Plugins repository | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_result_index.php b/program/lib/Roundcube/rcube_result_index.php index 4d1ae13b6..5f592c54f 100644 --- a/program/lib/Roundcube/rcube_result_index.php +++ b/program/lib/Roundcube/rcube_result_index.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_result_index.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2011, The Roundcube Dev Team | | Copyright (C) 2011, Kolab Systems AG | @@ -14,14 +12,12 @@ | | | PURPOSE: | | SORT/SEARCH/ESEARCH response handler | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Class for accessing IMAP's SORT/SEARCH/ESEARCH result * diff --git a/program/lib/Roundcube/rcube_result_set.php b/program/lib/Roundcube/rcube_result_set.php index 456d1c9d6..1391e5e4b 100644 --- a/program/lib/Roundcube/rcube_result_set.php +++ b/program/lib/Roundcube/rcube_result_set.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_result_set.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2006-2011, The Roundcube Dev Team | | | @@ -13,13 +11,11 @@ | | | PURPOSE: | | Class representing an address directory result set | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ */ - /** * Roundcube result set class. * Representing an address directory result set. diff --git a/program/lib/Roundcube/rcube_result_thread.php b/program/lib/Roundcube/rcube_result_thread.php index c609bdc39..7657550be 100644 --- a/program/lib/Roundcube/rcube_result_thread.php +++ b/program/lib/Roundcube/rcube_result_thread.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_result_thread.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2011, The Roundcube Dev Team | | Copyright (C) 2011, Kolab Systems AG | @@ -14,14 +12,12 @@ | | | PURPOSE: | | THREAD response handler | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Class for accessing IMAP's THREAD result * diff --git a/program/lib/Roundcube/rcube_session.php b/program/lib/Roundcube/rcube_session.php index fdbf668ca..69eaabedc 100644 --- a/program/lib/Roundcube/rcube_session.php +++ b/program/lib/Roundcube/rcube_session.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_session.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2011, Kolab Systems AG | @@ -14,7 +12,6 @@ | | | PURPOSE: | | Provide database supported session management | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | diff --git a/program/lib/Roundcube/rcube_smtp.php b/program/lib/Roundcube/rcube_smtp.php index 1a4958e2b..79ffcfbf8 100644 --- a/program/lib/Roundcube/rcube_smtp.php +++ b/program/lib/Roundcube/rcube_smtp.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_smtp.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -13,7 +11,6 @@ | | | PURPOSE: | | Provide SMTP functionality using socket connections | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ diff --git a/program/lib/Roundcube/rcube_spellchecker.php b/program/lib/Roundcube/rcube_spellchecker.php index fce2cac75..e9e1ceb0f 100644 --- a/program/lib/Roundcube/rcube_spellchecker.php +++ b/program/lib/Roundcube/rcube_spellchecker.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_spellchecker.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2011, Kolab Systems AG | | Copyright (C) 2008-2011, The Roundcube Dev Team | @@ -14,14 +12,12 @@ | | | PURPOSE: | | Spellchecking using different backends | - | | +-----------------------------------------------------------------------+ | Author: Aleksander Machniak | | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ */ - /** * Helper class for spellchecking with Googielspell and PSpell support. * diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index 763b9155e..65de2660c 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_storage.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | Copyright (C) 2012, Kolab Systems AG | @@ -14,14 +12,12 @@ | | | PURPOSE: | | Mail Storage Engine | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Abstract class for accessing mail messages storage server * diff --git a/program/lib/Roundcube/rcube_string_replacer.php b/program/lib/Roundcube/rcube_string_replacer.php index 584b9f68c..68288f54c 100644 --- a/program/lib/Roundcube/rcube_string_replacer.php +++ b/program/lib/Roundcube/rcube_string_replacer.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_string_replacer.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2009-2012, The Roundcube Dev Team | | | @@ -13,13 +11,11 @@ | | | PURPOSE: | | Handle string replacements based on preg_replace_callback | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ */ - /** * Helper class for string replacements based on preg_replace_callback * diff --git a/program/lib/Roundcube/rcube_user.php b/program/lib/Roundcube/rcube_user.php index f6b77f5e1..505b190d1 100644 --- a/program/lib/Roundcube/rcube_user.php +++ b/program/lib/Roundcube/rcube_user.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_user.inc | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | | | @@ -14,14 +12,12 @@ | PURPOSE: | | This class represents a system user linked and provides access | | to the related database records. | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ - /** * Class representing a system user * diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php index 500f2c371..4b687111e 100644 --- a/program/lib/Roundcube/rcube_utils.php +++ b/program/lib/Roundcube/rcube_utils.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_utils.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -20,7 +18,6 @@ +-----------------------------------------------------------------------+ */ - /** * Utility class providing common functions * diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php index 45ee601e5..a5c5ccec8 100644 --- a/program/lib/Roundcube/rcube_vcard.php +++ b/program/lib/Roundcube/rcube_vcard.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_vcard.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2012, The Roundcube Dev Team | | | @@ -19,7 +17,6 @@ +-----------------------------------------------------------------------+ */ - /** * Logical representation of a vcard-based address record * Provides functions to parse and export vCard data format -- cgit v1.2.3 From 8cacecb2ff8b2c819f573bbd47f6bc8171d26ee8 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 18 Dec 2012 09:30:15 +0100 Subject: CS fixes --- program/lib/Roundcube/rcube_vcard.php | 1463 +++++++++++++++++---------------- 1 file changed, 758 insertions(+), 705 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php index a5c5ccec8..e6fa5b248 100644 --- a/program/lib/Roundcube/rcube_vcard.php +++ b/program/lib/Roundcube/rcube_vcard.php @@ -26,765 +26,818 @@ */ class rcube_vcard { - private static $values_decoded = false; - private $raw = array( - 'FN' => array(), - 'N' => array(array('','','','','')), - ); - private static $fieldmap = array( - 'phone' => 'TEL', - 'birthday' => 'BDAY', - 'website' => 'URL', - 'notes' => 'NOTE', - 'email' => 'EMAIL', - 'address' => 'ADR', - 'jobtitle' => 'TITLE', - 'department' => 'X-DEPARTMENT', - 'gender' => 'X-GENDER', - 'maidenname' => 'X-MAIDENNAME', - 'anniversary' => 'X-ANNIVERSARY', - 'assistant' => 'X-ASSISTANT', - 'manager' => 'X-MANAGER', - 'spouse' => 'X-SPOUSE', - 'edit' => 'X-AB-EDIT', - ); - private $typemap = array('IPHONE' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax'); - private $phonetypemap = array('HOME1' => 'HOME', 'BUSINESS1' => 'WORK', 'BUSINESS2' => 'WORK2', 'BUSINESSFAX' => 'WORK,FAX', 'MOBILE' => 'CELL'); - private $addresstypemap = array('BUSINESS' => 'WORK'); - private $immap = array('X-JABBER' => 'jabber', 'X-ICQ' => 'icq', 'X-MSN' => 'msn', 'X-AIM' => 'aim', 'X-YAHOO' => 'yahoo', 'X-SKYPE' => 'skype', 'X-SKYPE-USERNAME' => 'skype'); - - public $business = false; - public $displayname; - public $surname; - public $firstname; - public $middlename; - public $nickname; - public $organization; - public $email = array(); - - public static $eol = "\r\n"; - - /** - * Constructor - */ - public function __construct($vcard = null, $charset = RCUBE_CHARSET, $detect = false, $fieldmap = array()) - { - if (!empty($fielmap)) - $this->extend_fieldmap($fieldmap); - - if (!empty($vcard)) - $this->load($vcard, $charset, $detect); - } - - - /** - * Load record from (internal, unfolded) vcard 3.0 format - * - * @param string vCard string to parse - * @param string Charset of string values - * @param boolean True if loading a 'foreign' vcard and extra heuristics for charset detection is required - */ - public function load($vcard, $charset = RCUBE_CHARSET, $detect = false) - { - self::$values_decoded = false; - $this->raw = self::vcard_decode($vcard); - - // resolve charset parameters - if ($charset == null) { - $this->raw = self::charset_convert($this->raw); + private static $values_decoded = false; + private $raw = array( + 'FN' => array(), + 'N' => array(array('','','','','')), + ); + private static $fieldmap = array( + 'phone' => 'TEL', + 'birthday' => 'BDAY', + 'website' => 'URL', + 'notes' => 'NOTE', + 'email' => 'EMAIL', + 'address' => 'ADR', + 'jobtitle' => 'TITLE', + 'department' => 'X-DEPARTMENT', + 'gender' => 'X-GENDER', + 'maidenname' => 'X-MAIDENNAME', + 'anniversary' => 'X-ANNIVERSARY', + 'assistant' => 'X-ASSISTANT', + 'manager' => 'X-MANAGER', + 'spouse' => 'X-SPOUSE', + 'edit' => 'X-AB-EDIT', + ); + private $typemap = array( + 'IPHONE' => 'mobile', + 'CELL' => 'mobile', + 'WORK,FAX' => 'workfax', + ); + private $phonetypemap = array( + 'HOME1' => 'HOME', + 'BUSINESS1' => 'WORK', + 'BUSINESS2' => 'WORK2', + 'BUSINESSFAX' => 'WORK,FAX', + 'MOBILE' => 'CELL', + ); + private $addresstypemap = array( + 'BUSINESS' => 'WORK', + ); + private $immap = array( + 'X-JABBER' => 'jabber', + 'X-ICQ' => 'icq', + 'X-MSN' => 'msn', + 'X-AIM' => 'aim', + 'X-YAHOO' => 'yahoo', + 'X-SKYPE' => 'skype', + 'X-SKYPE-USERNAME' => 'skype', + ); + + public $business = false; + public $displayname; + public $surname; + public $firstname; + public $middlename; + public $nickname; + public $organization; + public $email = array(); + + public static $eol = "\r\n"; + + + /** + * Constructor + */ + public function __construct($vcard = null, $charset = RCUBE_CHARSET, $detect = false, $fieldmap = array()) + { + if (!empty($fielmap)) { + $this->extend_fieldmap($fieldmap); + } + + if (!empty($vcard)) { + $this->load($vcard, $charset, $detect); + } } - // vcard has encoded values and charset should be detected - else if ($detect && self::$values_decoded && - ($detected_charset = self::detect_encoding(self::vcard_encode($this->raw))) && $detected_charset != RCUBE_CHARSET) { - $this->raw = self::charset_convert($this->raw, $detected_charset); + + /** + * Load record from (internal, unfolded) vcard 3.0 format + * + * @param string vCard string to parse + * @param string Charset of string values + * @param boolean True if loading a 'foreign' vcard and extra heuristics for charset detection is required + */ + public function load($vcard, $charset = RCUBE_CHARSET, $detect = false) + { + self::$values_decoded = false; + $this->raw = self::vcard_decode($vcard); + + // resolve charset parameters + if ($charset == null) { + $this->raw = self::charset_convert($this->raw); + } + // vcard has encoded values and charset should be detected + else if ($detect && self::$values_decoded + && ($detected_charset = self::detect_encoding(self::vcard_encode($this->raw))) + && $detected_charset != RCUBE_CHARSET + ) { + $this->raw = self::charset_convert($this->raw, $detected_charset); + } + + // consider FN empty if the same as the primary e-mail address + if ($this->raw['FN'][0][0] == $this->raw['EMAIL'][0][0]) { + $this->raw['FN'][0][0] = ''; + } + + // find well-known address fields + $this->displayname = $this->raw['FN'][0][0]; + $this->surname = $this->raw['N'][0][0]; + $this->firstname = $this->raw['N'][0][1]; + $this->middlename = $this->raw['N'][0][2]; + $this->nickname = $this->raw['NICKNAME'][0][0]; + $this->organization = $this->raw['ORG'][0][0]; + $this->business = ($this->raw['X-ABSHOWAS'][0][0] == 'COMPANY') || (join('', (array)$this->raw['N'][0]) == '' && !empty($this->organization)); + + foreach ((array)$this->raw['EMAIL'] as $i => $raw_email) { + $this->email[$i] = is_array($raw_email) ? $raw_email[0] : $raw_email; + } + + // make the pref e-mail address the first entry in $this->email + $pref_index = $this->get_type_index('EMAIL', 'pref'); + if ($pref_index > 0) { + $tmp = $this->email[0]; + $this->email[0] = $this->email[$pref_index]; + $this->email[$pref_index] = $tmp; + } } - // consider FN empty if the same as the primary e-mail address - if ($this->raw['FN'][0][0] == $this->raw['EMAIL'][0][0]) - $this->raw['FN'][0][0] = ''; - - // find well-known address fields - $this->displayname = $this->raw['FN'][0][0]; - $this->surname = $this->raw['N'][0][0]; - $this->firstname = $this->raw['N'][0][1]; - $this->middlename = $this->raw['N'][0][2]; - $this->nickname = $this->raw['NICKNAME'][0][0]; - $this->organization = $this->raw['ORG'][0][0]; - $this->business = ($this->raw['X-ABSHOWAS'][0][0] == 'COMPANY') || (join('', (array)$this->raw['N'][0]) == '' && !empty($this->organization)); - - foreach ((array)$this->raw['EMAIL'] as $i => $raw_email) - $this->email[$i] = is_array($raw_email) ? $raw_email[0] : $raw_email; - - // make the pref e-mail address the first entry in $this->email - $pref_index = $this->get_type_index('EMAIL', 'pref'); - if ($pref_index > 0) { - $tmp = $this->email[0]; - $this->email[0] = $this->email[$pref_index]; - $this->email[$pref_index] = $tmp; + /** + * Return vCard data as associative array to be unsed in Roundcube address books + * + * @return array Hash array with key-value pairs + */ + public function get_assoc() + { + $out = array('name' => $this->displayname); + $typemap = $this->typemap; + + // copy name fields to output array + foreach (array('firstname','surname','middlename','nickname','organization') as $col) { + if (strlen($this->$col)) { + $out[$col] = $this->$col; + } + } + + if ($this->raw['N'][0][3]) + $out['prefix'] = $this->raw['N'][0][3]; + if ($this->raw['N'][0][4]) + $out['suffix'] = $this->raw['N'][0][4]; + + // convert from raw vcard data into associative data for Roundcube + foreach (array_flip(self::$fieldmap) as $tag => $col) { + foreach ((array)$this->raw[$tag] as $i => $raw) { + if (is_array($raw)) { + $k = -1; + $key = $col; + $subtype = ''; + + if (!empty($raw['type'])) { + $combined = join(',', self::array_filter((array)$raw['type'], 'internet,pref', true)); + $combined = strtoupper($combined); + + if ($typemap[$combined]) { + $subtype = $typemap[$combined]; + } + else if ($typemap[$raw['type'][++$k]]) { + $subtype = $typemap[$raw['type'][$k]]; + } + else { + $subtype = strtolower($raw['type'][$k]); + } + + while ($k < count($raw['type']) && ($subtype == 'internet' || $subtype == 'pref')) { + $subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]); + } + } + + // read vcard 2.1 subtype + if (!$subtype) { + foreach ($raw as $k => $v) { + if (!is_numeric($k) && $v === true && ($k = strtolower($k)) + && !in_array($k, array('pref','internet','voice','base64')) + ) { + $k_uc = strtoupper($k); + $subtype = $typemap[$k_uc] ? $typemap[$k_uc] : $k; + break; + } + } + } + + // force subtype if none set + if (!$subtype && preg_match('/^(email|phone|address|website)/', $key)) { + $subtype = 'other'; + } + + if ($subtype) { + $key .= ':' . $subtype; + } + + // split ADR values into assoc array + if ($tag == 'ADR') { + list(,, $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']) = $raw; + $out[$key][] = $value; + } + else { + $out[$key][] = $raw[0]; + } + } + else { + $out[$col][] = $raw; + } + } + } + + // handle special IM fields as used by Apple + foreach ($this->immap as $tag => $type) { + foreach ((array)$this->raw[$tag] as $i => $raw) { + $out['im:'.$type][] = $raw[0]; + } + } + + // copy photo data + if ($this->raw['PHOTO']) { + $out['photo'] = $this->raw['PHOTO'][0][0]; + } + + return $out; } - } - - - /** - * Return vCard data as associative array to be unsed in Roundcube address books - * - * @return array Hash array with key-value pairs - */ - public function get_assoc() - { - $out = array('name' => $this->displayname); - $typemap = $this->typemap; - - // copy name fields to output array - foreach (array('firstname','surname','middlename','nickname','organization') as $col) { - if (strlen($this->$col)) - $out[$col] = $this->$col; + + /** + * Convert the data structure into a vcard 3.0 string + */ + public function export($folded = true) + { + $vcard = self::vcard_encode($this->raw); + return $folded ? self::rfc2425_fold($vcard) : $vcard; } - if ($this->raw['N'][0][3]) - $out['prefix'] = $this->raw['N'][0][3]; - if ($this->raw['N'][0][4]) - $out['suffix'] = $this->raw['N'][0][4]; - - // convert from raw vcard data into associative data for Roundcube - foreach (array_flip(self::$fieldmap) as $tag => $col) { - foreach ((array)$this->raw[$tag] as $i => $raw) { - if (is_array($raw)) { - $k = -1; - $key = $col; - $subtype = ''; - - if (!empty($raw['type'])) { - $combined = join(',', self::array_filter((array)$raw['type'], 'internet,pref', true)); - $combined = strtoupper($combined); - - if ($typemap[$combined]) { - $subtype = $typemap[$combined]; - } - else if ($typemap[$raw['type'][++$k]]) { - $subtype = $typemap[$raw['type'][$k]]; + /** + * Clear the given fields in the loaded vcard data + * + * @param array List of field names to be reset + */ + public function reset($fields = null) + { + if (!$fields) { + $fields = array_merge(array_values(self::$fieldmap), array_keys($this->immap), + array('FN','N','ORG','NICKNAME','EMAIL','ADR','BDAY')); + } + + foreach ($fields as $f) { + unset($this->raw[$f]); + } + + if (!$this->raw['N']) { + $this->raw['N'] = array(array('','','','','')); + } + if (!$this->raw['FN']) { + $this->raw['FN'] = array(); + } + + $this->email = array(); + } + + /** + * Setter for address record fields + * + * @param string Field name + * @param string Field value + * @param string Type/section name + */ + public function set($field, $value, $type = 'HOME') + { + $field = strtolower($field); + $type_uc = strtoupper($type); + + switch ($field) { + case 'name': + case 'displayname': + $this->raw['FN'][0][0] = $this->displayname = $value; + break; + + case 'surname': + $this->raw['N'][0][0] = $this->surname = $value; + break; + + case 'firstname': + $this->raw['N'][0][1] = $this->firstname = $value; + break; + + case 'middlename': + $this->raw['N'][0][2] = $this->middlename = $value; + break; + + case 'prefix': + $this->raw['N'][0][3] = $value; + break; + + case 'suffix': + $this->raw['N'][0][4] = $value; + break; + + case 'nickname': + $this->raw['NICKNAME'][0][0] = $this->nickname = $value; + break; + + case 'organization': + $this->raw['ORG'][0][0] = $this->organization = $value; + break; + + case 'photo': + if (strpos($value, 'http:') === 0) { + // TODO: fetch file from URL and save it locally? + $this->raw['PHOTO'][0] = array(0 => $value, 'url' => true); } else { - $subtype = strtolower($raw['type'][$k]); + $this->raw['PHOTO'][0] = array(0 => $value, 'base64' => (bool) preg_match('![^a-z0-9/=+-]!i', $value)); + } + break; + + case 'email': + $this->raw['EMAIL'][] = array(0 => $value, 'type' => array_filter(array('INTERNET', $type_uc))); + $this->email[] = $value; + break; + + case 'im': + // save IM subtypes into extension fields + $typemap = array_flip($this->immap); + if ($field = $typemap[strtolower($type)]) { + $this->raw[$field][] = array(0 => $value); } + break; - while ($k < count($raw['type']) && ($subtype == 'internet' || $subtype == 'pref')) - $subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]); - } - - // read vcard 2.1 subtype - if (!$subtype) { - foreach ($raw as $k => $v) { - if (!is_numeric($k) && $v === true && ($k = strtolower($k)) - && !in_array($k, array('pref','internet','voice','base64')) - ) { - $k_uc = strtoupper($k); - $subtype = $typemap[$k_uc] ? $typemap[$k_uc] : $k; - break; - } + case 'birthday': + case 'anniversary': + if (($val = rcube_utils::strtotime($value)) && ($fn = self::$fieldmap[$field])) { + $this->raw[$fn][] = array(0 => date('Y-m-d', $val), 'value' => array('date')); } - } + break; - // force subtype if none set - if (!$subtype && preg_match('/^(email|phone|address|website)/', $key)) - $subtype = 'other'; + case 'address': + if ($this->addresstypemap[$type_uc]) { + $type = $this->addresstypemap[$type_uc]; + } - if ($subtype) - $key .= ':' . $subtype; + $value = $value[0] ? $value : array('', '', $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']); - // split ADR values into assoc array - if ($tag == 'ADR') { - list(,, $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']) = $raw; - $out[$key][] = $value; - } - else - $out[$key][] = $raw[0]; - } - else { - $out[$col][] = $raw; + // fall through if not empty + if (!strlen(join('', $value))) { + break; + } + + default: + if ($field == 'phone' && $this->phonetypemap[$type_uc]) { + $type = $this->phonetypemap[$type_uc]; + } + + if (($tag = self::$fieldmap[$field]) && (is_array($value) || strlen($value))) { + $index = count($this->raw[$tag]); + $this->raw[$tag][$index] = (array)$value; + if ($type) { + $typemap = array_flip($this->typemap); + $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type)); + } + } + break; } - } } - // handle special IM fields as used by Apple - foreach ($this->immap as $tag => $type) { - foreach ((array)$this->raw[$tag] as $i => $raw) { - $out['im:'.$type][] = $raw[0]; - } + /** + * Setter for individual vcard properties + * + * @param string VCard tag name + * @param array Value-set of this vcard property + * @param boolean Set to true if the value-set should be appended instead of replacing any existing value-set + */ + public function set_raw($tag, $value, $append = false) + { + $index = $append ? count($this->raw[$tag]) : 0; + $this->raw[$tag][$index] = (array)$value; } - // copy photo data - if ($this->raw['PHOTO']) - $out['photo'] = $this->raw['PHOTO'][0][0]; - - return $out; - } - - - /** - * Convert the data structure into a vcard 3.0 string - */ - public function export($folded = true) - { - $vcard = self::vcard_encode($this->raw); - return $folded ? self::rfc2425_fold($vcard) : $vcard; - } - - - /** - * Clear the given fields in the loaded vcard data - * - * @param array List of field names to be reset - */ - public function reset($fields = null) - { - if (!$fields) - $fields = array_merge(array_values(self::$fieldmap), array_keys($this->immap), array('FN','N','ORG','NICKNAME','EMAIL','ADR','BDAY')); - - foreach ($fields as $f) - unset($this->raw[$f]); - - if (!$this->raw['N']) - $this->raw['N'] = array(array('','','','','')); - if (!$this->raw['FN']) - $this->raw['FN'] = array(); - - $this->email = array(); - } - - - /** - * Setter for address record fields - * - * @param string Field name - * @param string Field value - * @param string Type/section name - */ - public function set($field, $value, $type = 'HOME') - { - $field = strtolower($field); - $type_uc = strtoupper($type); - - switch ($field) { - case 'name': - case 'displayname': - $this->raw['FN'][0][0] = $this->displayname = $value; - break; - - case 'surname': - $this->raw['N'][0][0] = $this->surname = $value; - break; - - case 'firstname': - $this->raw['N'][0][1] = $this->firstname = $value; - break; - - case 'middlename': - $this->raw['N'][0][2] = $this->middlename = $value; - break; - - case 'prefix': - $this->raw['N'][0][3] = $value; - break; - - case 'suffix': - $this->raw['N'][0][4] = $value; - break; - - case 'nickname': - $this->raw['NICKNAME'][0][0] = $this->nickname = $value; - break; - - case 'organization': - $this->raw['ORG'][0][0] = $this->organization = $value; - break; - - case 'photo': - if (strpos($value, 'http:') === 0) { - // TODO: fetch file from URL and save it locally? - $this->raw['PHOTO'][0] = array(0 => $value, 'url' => true); - } - else { - $this->raw['PHOTO'][0] = array(0 => $value, 'base64' => (bool) preg_match('![^a-z0-9/=+-]!i', $value)); - } - break; - - case 'email': - $this->raw['EMAIL'][] = array(0 => $value, 'type' => array_filter(array('INTERNET', $type_uc))); - $this->email[] = $value; - break; - - case 'im': - // save IM subtypes into extension fields - $typemap = array_flip($this->immap); - if ($field = $typemap[strtolower($type)]) - $this->raw[$field][] = array(0 => $value); - break; - - case 'birthday': - case 'anniversary': - if (($val = rcube_utils::strtotime($value)) && ($fn = self::$fieldmap[$field])) - $this->raw[$fn][] = array(0 => date('Y-m-d', $val), 'value' => array('date')); - break; - - case 'address': - if ($this->addresstypemap[$type_uc]) - $type = $this->addresstypemap[$type_uc]; - - $value = $value[0] ? $value : array('', '', $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']); - - // fall through if not empty - if (!strlen(join('', $value))) - break; - - default: - if ($field == 'phone' && $this->phonetypemap[$type_uc]) - $type = $this->phonetypemap[$type_uc]; - - if (($tag = self::$fieldmap[$field]) && (is_array($value) || strlen($value))) { - $index = count($this->raw[$tag]); - $this->raw[$tag][$index] = (array)$value; - if ($type) { - $typemap = array_flip($this->typemap); - $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type)); - } - } - break; - } - } - - /** - * Setter for individual vcard properties - * - * @param string VCard tag name - * @param array Value-set of this vcard property - * @param boolean Set to true if the value-set should be appended instead of replacing any existing value-set - */ - public function set_raw($tag, $value, $append = false) - { - $index = $append ? count($this->raw[$tag]) : 0; - $this->raw[$tag][$index] = (array)$value; - } - - - /** - * Find index with the '$type' attribute - * - * @param string Field name - * @return int Field index having $type set - */ - private function get_type_index($field, $type = 'pref') - { - $result = 0; - if ($this->raw[$field]) { - foreach ($this->raw[$field] as $i => $data) { - if (is_array($data['type']) && in_array_nocase('pref', $data['type'])) - $result = $i; - } + /** + * Find index with the '$type' attribute + * + * @param string Field name + * @return int Field index having $type set + */ + private function get_type_index($field, $type = 'pref') + { + $result = 0; + if ($this->raw[$field]) { + foreach ($this->raw[$field] as $i => $data) { + if (is_array($data['type']) && in_array_nocase('pref', $data['type'])) { + $result = $i; + } + } + } + + return $result; } - return $result; - } - - - /** - * Convert a whole vcard (array) to UTF-8. - * If $force_charset is null, each member value that has a charset parameter will be converted - */ - private static function charset_convert($card, $force_charset = null) - { - foreach ($card as $key => $node) { - foreach ($node as $i => $subnode) { - if (is_array($subnode) && (($charset = $force_charset) || ($subnode['charset'] && ($charset = $subnode['charset'][0])))) { - foreach ($subnode as $j => $value) { - if (is_numeric($j) && is_string($value)) - $card[$key][$i][$j] = rcube_charset::convert($value, $charset); - } - unset($card[$key][$i]['charset']); - } - } + /** + * Convert a whole vcard (array) to UTF-8. + * If $force_charset is null, each member value that has a charset parameter will be converted + */ + private static function charset_convert($card, $force_charset = null) + { + foreach ($card as $key => $node) { + foreach ($node as $i => $subnode) { + if (is_array($subnode) && (($charset = $force_charset) || ($subnode['charset'] && ($charset = $subnode['charset'][0])))) { + foreach ($subnode as $j => $value) { + if (is_numeric($j) && is_string($value)) { + $card[$key][$i][$j] = rcube_charset::convert($value, $charset); + } + } + unset($card[$key][$i]['charset']); + } + } + } + + return $card; } - return $card; - } - - - /** - * Extends fieldmap definition - */ - public function extend_fieldmap($map) - { - if (is_array($map)) - self::$fieldmap = array_merge($map, self::$fieldmap); - } - - - /** - * Factory method to import a vcard file - * - * @param string vCard file content - * @return array List of rcube_vcard objects - */ - public static function import($data) - { - $out = array(); - - // check if charsets are specified (usually vcard version < 3.0 but this is not reliable) - if (preg_match('/charset=/i', substr($data, 0, 2048))) - $charset = null; - // detect charset and convert to utf-8 - else if (($charset = self::detect_encoding($data)) && $charset != RCUBE_CHARSET) { - $data = rcube_charset::convert($data, $charset); - $data = preg_replace(array('/^[\xFE\xFF]{2}/', '/^\xEF\xBB\xBF/', '/^\x00+/'), '', $data); // also remove BOM - $charset = RCUBE_CHARSET; + /** + * Extends fieldmap definition + */ + public function extend_fieldmap($map) + { + if (is_array($map)) { + self::$fieldmap = array_merge($map, self::$fieldmap); + } } - $vcard_block = ''; - $in_vcard_block = false; + /** + * Factory method to import a vcard file + * + * @param string vCard file content + * + * @return array List of rcube_vcard objects + */ + public static function import($data) + { + $out = array(); + + // check if charsets are specified (usually vcard version < 3.0 but this is not reliable) + if (preg_match('/charset=/i', substr($data, 0, 2048))) { + $charset = null; + } + // detect charset and convert to utf-8 + else if (($charset = self::detect_encoding($data)) && $charset != RCUBE_CHARSET) { + $data = rcube_charset::convert($data, $charset); + $data = preg_replace(array('/^[\xFE\xFF]{2}/', '/^\xEF\xBB\xBF/', '/^\x00+/'), '', $data); // also remove BOM + $charset = RCUBE_CHARSET; + } - foreach (preg_split("/[\r\n]+/", $data) as $i => $line) { - if ($in_vcard_block && !empty($line)) - $vcard_block .= $line . "\n"; + $vcard_block = ''; + $in_vcard_block = false; - $line = trim($line); + foreach (preg_split("/[\r\n]+/", $data) as $i => $line) { + if ($in_vcard_block && !empty($line)) { + $vcard_block .= $line . "\n"; + } - if (preg_match('/^END:VCARD$/i', $line)) { - // parse vcard - $obj = new rcube_vcard(self::cleanup($vcard_block), $charset, true, self::$fieldmap); - if (!empty($obj->displayname) || !empty($obj->email)) - $out[] = $obj; + $line = trim($line); - $in_vcard_block = false; - } - else if (preg_match('/^BEGIN:VCARD$/i', $line)) { - $vcard_block = $line . "\n"; - $in_vcard_block = true; - } + if (preg_match('/^END:VCARD$/i', $line)) { + // parse vcard + $obj = new rcube_vcard(self::cleanup($vcard_block), $charset, true, self::$fieldmap); + if (!empty($obj->displayname) || !empty($obj->email)) { + $out[] = $obj; + } + + $in_vcard_block = false; + } + else if (preg_match('/^BEGIN:VCARD$/i', $line)) { + $vcard_block = $line . "\n"; + $in_vcard_block = true; + } + } + + return $out; } - return $out; - } - - - /** - * Normalize vcard data for better parsing - * - * @param string vCard block - * @return string Cleaned vcard block - */ - private static function cleanup($vcard) - { - // Convert special types (like Skype) to normal type='skype' classes with this simple regex ;) - $vcard = preg_replace( - '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s', - '\2;type=\5\3:\4', - $vcard); - - // convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility - $vcard = preg_replace_callback( - '/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s', - array('self', 'x_abrelatednames_callback'), - $vcard); - - // Remove cruft like item1.X-AB*, item1.ADR instead of ADR, and empty lines - $vcard = preg_replace(array('/^item\d*\.X-AB.*$/m', '/^item\d*\./m', "/\n+/"), array('', '', "\n"), $vcard); - - // convert X-WAB-GENDER to X-GENDER - if (preg_match('/X-WAB-GENDER:(\d)/', $vcard, $matches)) { - $value = $matches[1] == '2' ? 'male' : 'female'; - $vcard = preg_replace('/X-WAB-GENDER:\d/', 'X-GENDER:' . $value, $vcard); + /** + * Normalize vcard data for better parsing + * + * @param string vCard block + * + * @return string Cleaned vcard block + */ + private static function cleanup($vcard) + { + // Convert special types (like Skype) to normal type='skype' classes with this simple regex ;) + $vcard = preg_replace( + '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s', + '\2;type=\5\3:\4', + $vcard); + + // convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility + $vcard = preg_replace_callback( + '/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s', + array('self', 'x_abrelatednames_callback'), + $vcard); + + // Remove cruft like item1.X-AB*, item1.ADR instead of ADR, and empty lines + $vcard = preg_replace(array('/^item\d*\.X-AB.*$/m', '/^item\d*\./m', "/\n+/"), array('', '', "\n"), $vcard); + + // convert X-WAB-GENDER to X-GENDER + if (preg_match('/X-WAB-GENDER:(\d)/', $vcard, $matches)) { + $value = $matches[1] == '2' ? 'male' : 'female'; + $vcard = preg_replace('/X-WAB-GENDER:\d/', 'X-GENDER:' . $value, $vcard); + } + + // if N doesn't have any semicolons, add some + $vcard = preg_replace('/^(N:[^;\R]*)$/m', '\1;;;;', $vcard); + + return $vcard; } - // if N doesn't have any semicolons, add some - $vcard = preg_replace('/^(N:[^;\R]*)$/m', '\1;;;;', $vcard); - - return $vcard; - } - - private static function x_abrelatednames_callback($matches) - { - return 'X-' . strtoupper($matches[5]) . $matches[3] . ':'. $matches[4]; - } - - private static function rfc2425_fold_callback($matches) - { - // chunk_split string and avoid lines breaking multibyte characters - $c = 71; - $out .= substr($matches[1], 0, $c); - for ($n = $c; $c < strlen($matches[1]); $c++) { - // break if length > 75 or mutlibyte character starts after position 71 - if ($n > 75 || ($n > 71 && ord($matches[1][$c]) >> 6 == 3)) { - $out .= "\r\n "; - $n = 0; - } - $out .= $matches[1][$c]; - $n++; + private static function x_abrelatednames_callback($matches) + { + return 'X-' . strtoupper($matches[5]) . $matches[3] . ':'. $matches[4]; } - return $out; - } - - public static function rfc2425_fold($val) - { - return preg_replace_callback('/([^\n]{72,})/', array('self', 'rfc2425_fold_callback'), $val); - } - - - /** - * Decodes a vcard block (vcard 3.0 format, unfolded) - * into an array structure - * - * @param string vCard block to parse - * @return array Raw data structure - */ - private static function vcard_decode($vcard) - { - // Perform RFC2425 line unfolding and split lines - $vcard = preg_replace(array("/\r/", "/\n\s+/"), '', $vcard); - $lines = explode("\n", $vcard); - $data = array(); - - for ($i=0; $i < count($lines); $i++) { - if (!preg_match('/^([^:]+):(.+)$/', $lines[$i], $line)) - continue; - - if (preg_match('/^(BEGIN|END)$/i', $line[1])) - continue; - - // convert 2.1-style "EMAIL;internet;home:" to 3.0-style "EMAIL;TYPE=internet;TYPE=home:" - if (($data['VERSION'][0] == "2.1") && preg_match('/^([^;]+);([^:]+)/', $line[1], $regs2) && !preg_match('/^TYPE=/i', $regs2[2])) { - $line[1] = $regs2[1]; - foreach (explode(';', $regs2[2]) as $prop) - $line[1] .= ';' . (strpos($prop, '=') ? $prop : 'TYPE='.$prop); - } - - if (preg_match_all('/([^\\;]+);?/', $line[1], $regs2)) { - $entry = array(); - $field = strtoupper($regs2[1][0]); - $enc = null; - - foreach($regs2[1] as $attrid => $attr) { - if ((list($key, $value) = explode('=', $attr)) && $value) { - $value = trim($value); - if ($key == 'ENCODING') { - $value = strtoupper($value); - // add next line(s) to value string if QP line end detected - if ($value == 'QUOTED-PRINTABLE') { - while (preg_match('/=$/', $lines[$i])) - $line[2] .= "\n" . $lines[++$i]; - } - $enc = $value; + private static function rfc2425_fold_callback($matches) + { + // chunk_split string and avoid lines breaking multibyte characters + $c = 71; + $out .= substr($matches[1], 0, $c); + for ($n = $c; $c < strlen($matches[1]); $c++) { + // break if length > 75 or mutlibyte character starts after position 71 + if ($n > 75 || ($n > 71 && ord($matches[1][$c]) >> 6 == 3)) { + $out .= "\r\n "; + $n = 0; } - else { - $lc_key = strtolower($key); - $entry[$lc_key] = array_merge((array)$entry[$lc_key], (array)self::vcard_unquote($value, ',')); - } - } - else if ($attrid > 0) { - $entry[strtolower($key)] = true; // true means attr without =value - } + $out .= $matches[1][$c]; + $n++; } - // decode value - if ($enc || !empty($entry['base64'])) { - // save encoding type (#1488432) - if ($enc == 'B') { - $entry['encoding'] = 'B'; - // should we use vCard 3.0 instead? - // $entry['base64'] = true; - } - $line[2] = self::decode_value($line[2], $enc ? $enc : 'base64'); - } + return $out; + } + + public static function rfc2425_fold($val) + { + return preg_replace_callback('/([^\n]{72,})/', array('self', 'rfc2425_fold_callback'), $val); + } - if ($enc != 'B' && empty($entry['base64'])) { - $line[2] = self::vcard_unquote($line[2]); + /** + * Decodes a vcard block (vcard 3.0 format, unfolded) + * into an array structure + * + * @param string vCard block to parse + * + * @return array Raw data structure + */ + private static function vcard_decode($vcard) + { + // Perform RFC2425 line unfolding and split lines + $vcard = preg_replace(array("/\r/", "/\n\s+/"), '', $vcard); + $lines = explode("\n", $vcard); + $data = array(); + + for ($i=0; $i < count($lines); $i++) { + if (!preg_match('/^([^:]+):(.+)$/', $lines[$i], $line)) + continue; + + if (preg_match('/^(BEGIN|END)$/i', $line[1])) + continue; + + // convert 2.1-style "EMAIL;internet;home:" to 3.0-style "EMAIL;TYPE=internet;TYPE=home:" + if ($data['VERSION'][0] == "2.1" + && preg_match('/^([^;]+);([^:]+)/', $line[1], $regs2) + && !preg_match('/^TYPE=/i', $regs2[2]) + ) { + $line[1] = $regs2[1]; + foreach (explode(';', $regs2[2]) as $prop) { + $line[1] .= ';' . (strpos($prop, '=') ? $prop : 'TYPE='.$prop); + } + } + + if (preg_match_all('/([^\\;]+);?/', $line[1], $regs2)) { + $entry = array(); + $field = strtoupper($regs2[1][0]); + $enc = null; + + foreach($regs2[1] as $attrid => $attr) { + if ((list($key, $value) = explode('=', $attr)) && $value) { + $value = trim($value); + if ($key == 'ENCODING') { + $value = strtoupper($value); + // add next line(s) to value string if QP line end detected + if ($value == 'QUOTED-PRINTABLE') { + while (preg_match('/=$/', $lines[$i])) { + $line[2] .= "\n" . $lines[++$i]; + } + } + $enc = $value; + } + else { + $lc_key = strtolower($key); + $entry[$lc_key] = array_merge((array)$entry[$lc_key], (array)self::vcard_unquote($value, ',')); + } + } + else if ($attrid > 0) { + $entry[strtolower($key)] = true; // true means attr without =value + } + } + + // decode value + if ($enc || !empty($entry['base64'])) { + // save encoding type (#1488432) + if ($enc == 'B') { + $entry['encoding'] = 'B'; + // should we use vCard 3.0 instead? + // $entry['base64'] = true; + } + $line[2] = self::decode_value($line[2], $enc ? $enc : 'base64'); + } + + if ($enc != 'B' && empty($entry['base64'])) { + $line[2] = self::vcard_unquote($line[2]); + } + + $entry = array_merge($entry, (array) $line[2]); + $data[$field][] = $entry; + } } - $entry = array_merge($entry, (array) $line[2]); - $data[$field][] = $entry; - } + unset($data['VERSION']); + return $data; } - unset($data['VERSION']); - return $data; - } - - - /** - * Decode a given string with the encoding rule from ENCODING attributes - * - * @param string String to decode - * @param string Encoding type (quoted-printable and base64 supported) - * @return string Decoded 8bit value - */ - private static function decode_value($value, $encoding) - { - switch (strtolower($encoding)) { - case 'quoted-printable': - self::$values_decoded = true; - return quoted_printable_decode($value); - - case 'base64': - case 'b': - self::$values_decoded = true; - return base64_decode($value); - - default: - return $value; + /** + * Decode a given string with the encoding rule from ENCODING attributes + * + * @param string String to decode + * @param string Encoding type (quoted-printable and base64 supported) + * + * @return string Decoded 8bit value + */ + private static function decode_value($value, $encoding) + { + switch (strtolower($encoding)) { + case 'quoted-printable': + self::$values_decoded = true; + return quoted_printable_decode($value); + + case 'base64': + case 'b': + self::$values_decoded = true; + return base64_decode($value); + + default: + return $value; + } } - } - - - /** - * Encodes an entry for storage in our database (vcard 3.0 format, unfolded) - * - * @param array Raw data structure to encode - * @return string vCard encoded string - */ - static function vcard_encode($data) - { - foreach((array)$data as $type => $entries) { - /* valid N has 5 properties */ - while ($type == "N" && is_array($entries[0]) && count($entries[0]) < 5) - $entries[0][] = ""; - - // make sure FN is not empty (required by RFC2426) - if ($type == "FN" && empty($entries)) - $entries[0] = $data['EMAIL'][0][0]; - - foreach((array)$entries as $entry) { - $attr = ''; - if (is_array($entry)) { - $value = array(); - foreach($entry as $attrname => $attrvalues) { - if (is_int($attrname)) { - if (!empty($entry['base64']) || $entry['encoding'] == 'B') { - $attrvalues = base64_encode($attrvalues); - } - $value[] = $attrvalues; + + /** + * Encodes an entry for storage in our database (vcard 3.0 format, unfolded) + * + * @param array Raw data structure to encode + * + * @return string vCard encoded string + */ + static function vcard_encode($data) + { + foreach ((array)$data as $type => $entries) { + // valid N has 5 properties + while ($type == "N" && is_array($entries[0]) && count($entries[0]) < 5) { + $entries[0][] = ""; } - else if (is_bool($attrvalues)) { - if ($attrvalues) { - $attr .= strtoupper(";$attrname"); // true means just tag, not tag=value, as in PHOTO;BASE64:... - } + + // make sure FN is not empty (required by RFC2426) + if ($type == "FN" && empty($entries)) { + $entries[0] = $data['EMAIL'][0][0]; } - else { - foreach((array)$attrvalues as $attrvalue) - $attr .= strtoupper(";$attrname=") . self::vcard_quote($attrvalue, ','); + + foreach ((array)$entries as $entry) { + $attr = ''; + if (is_array($entry)) { + $value = array(); + foreach ($entry as $attrname => $attrvalues) { + if (is_int($attrname)) { + if (!empty($entry['base64']) || $entry['encoding'] == 'B') { + $attrvalues = base64_encode($attrvalues); + } + $value[] = $attrvalues; + } + else if (is_bool($attrvalues)) { + // true means just tag, not tag=value, as in PHOTO;BASE64:... + if ($attrvalues) { + $attr .= strtoupper(";$attrname"); + } + } + else { + foreach((array)$attrvalues as $attrvalue) { + $attr .= strtoupper(";$attrname=") . self::vcard_quote($attrvalue, ','); + } + } + } + } + else { + $value = $entry; + } + + // skip empty entries + if (self::is_empty($value)) { + continue; + } + + $vcard .= self::vcard_quote($type) . $attr . ':' . self::vcard_quote($value) . self::$eol; } - } } - else { - $value = $entry; - } - - // skip empty entries - if (self::is_empty($value)) - continue; - $vcard .= self::vcard_quote($type) . $attr . ':' . self::vcard_quote($value) . self::$eol; - } + return 'BEGIN:VCARD' . self::$eol . 'VERSION:3.0' . self::$eol . $vcard . 'END:VCARD'; } - return 'BEGIN:VCARD' . self::$eol . 'VERSION:3.0' . self::$eol . $vcard . 'END:VCARD'; - } - - - /** - * Join indexed data array to a vcard quoted string - * - * @param array Field data - * @param string Separator - * @return string Joined and quoted string - */ - private static function vcard_quote($s, $sep = ';') - { - if (is_array($s)) { - foreach($s as $part) { - $r[] = self::vcard_quote($part, $sep); - } - return(implode($sep, (array)$r)); - } - else { - return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', ',' => '\,', ';' => '\;')); - } - } - - - /** - * Split quoted string - * - * @param string vCard string to split - * @param string Separator char/string - * @return array List with splited values - */ - private static function vcard_unquote($s, $sep = ';') - { - // break string into parts separated by $sep, but leave escaped $sep alone - if (count($parts = explode($sep, strtr($s, array("\\$sep" => "\007")))) > 1) { - foreach($parts as $s) { - $result[] = self::vcard_unquote(strtr($s, array("\007" => "\\$sep")), $sep); - } - return $result; + /** + * Join indexed data array to a vcard quoted string + * + * @param array Field data + * @param string Separator + * + * @return string Joined and quoted string + */ + private static function vcard_quote($s, $sep = ';') + { + if (is_array($s)) { + foreach($s as $part) { + $r[] = self::vcard_quote($part, $sep); + } + return(implode($sep, (array)$r)); + } + + return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', ',' => '\,', ';' => '\;')); } - else { - return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';', '\:' => ':')); + + /** + * Split quoted string + * + * @param string vCard string to split + * @param string Separator char/string + * + * @return array List with splited values + */ + private static function vcard_unquote($s, $sep = ';') + { + // break string into parts separated by $sep, but leave escaped $sep alone + if (count($parts = explode($sep, strtr($s, array("\\$sep" => "\007")))) > 1) { + foreach($parts as $s) { + $result[] = self::vcard_unquote(strtr($s, array("\007" => "\\$sep")), $sep); + } + return $result; + } + + return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';', '\:' => ':')); } - } - - - /** - * Check if vCard entry is empty: empty string or an array with - * all entries empty. - * - * @param mixed $value Attribute value (string or array) - * - * @return bool True if the value is empty, False otherwise - */ - private static function is_empty($value) - { - foreach ((array)$value as $v) { - if (((string)$v) !== '') { - return false; - } + + /** + * Check if vCard entry is empty: empty string or an array with + * all entries empty. + * + * @param mixed $value Attribute value (string or array) + * + * @return bool True if the value is empty, False otherwise + */ + private static function is_empty($value) + { + foreach ((array)$value as $v) { + if (((string)$v) !== '') { + return false; + } + } + + return true; } - return true; - } - - /** - * Extract array values by a filter - * - * @param array Array to filter - * @param keys Array or comma separated list of values to keep - * @param boolean Invert key selection: remove the listed values - * @return array The filtered array - */ - private static function array_filter($arr, $values, $inverse = false) - { - if (!is_array($values)) - $values = explode(',', $values); - - $result = array(); - $keep = array_flip((array)$values); - foreach ($arr as $key => $val) - if ($inverse != isset($keep[strtolower($val)])) - $result[$key] = $val; - - return $result; - } - - /** - * Returns UNICODE type based on BOM (Byte Order Mark) - * - * @param string Input string to test - * @return string Detected encoding - */ - private static function detect_encoding($string) - { - $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1 - - return rcube_charset::detect($string, $fallback); - } + /** + * Extract array values by a filter + * + * @param array Array to filter + * @param keys Array or comma separated list of values to keep + * @param boolean Invert key selection: remove the listed values + * + * @return array The filtered array + */ + private static function array_filter($arr, $values, $inverse = false) + { + if (!is_array($values)) { + $values = explode(',', $values); + } + + $result = array(); + $keep = array_flip((array)$values); + foreach ($arr as $key => $val) { + if ($inverse != isset($keep[strtolower($val)])) { + $result[$key] = $val; + } + } + + return $result; + } + + /** + * Returns UNICODE type based on BOM (Byte Order Mark) + * + * @param string Input string to test + * + * @return string Detected encoding + */ + private static function detect_encoding($string) + { + $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1 + + return rcube_charset::detect($string, $fallback); + } } -- cgit v1.2.3 From dfc57863d1b054534f8e0ce8e3babb38d4fe89cb Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 18 Dec 2012 09:45:20 +0100 Subject: Plugin API: Added message_before_send hook --- CHANGELOG | 1 + program/include/rcmail.php | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 2deecd233..a89e02930 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Plugin API: Added message_before_send hook - Fix contact copy/add-to-group operations on search result (#1488862) - Use matching identity in MDN response (#1488864) - Fix unwanted horizontal scrollbar in message preview header (#1488866) diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 8e01a2155..249bd0559 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -934,15 +934,26 @@ class rcmail extends rcube * @param object $message Reference to Mail_MIME object * @param string $from Sender address string * @param array $mailto Array of recipient address strings - * @param array $smtp_error SMTP error array (reference) + * @param array $error SMTP error array (reference) * @param string $body_file Location of file with saved message body (reference), * used when delay_file_io is enabled - * @param array $smtp_opts SMTP options (e.g. DSN request) + * @param array $options SMTP options (e.g. DSN request) * * @return boolean Send status. */ - public function deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file = null, $smtp_opts = null) + public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null) { + $plugin = $this->plugins->exec_hook('message_before_send', array( + 'message' => $message, + 'from' => $from, + 'mailto' => $mailto, + 'options' => $options, + )); + + $from = $plugin['from']; + $mailto = $plugin['mailto']; + $options = $plugin['options']; + $message = $plugin['message']; $headers = $message->headers(); // send thru SMTP server using custom SMTP library @@ -985,15 +996,15 @@ class rcmail extends rcube $this->smtp_init(true); } - $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts); - $smtp_response = $this->smtp->get_response(); - $smtp_error = $this->smtp->get_error(); + $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options); + $response = $this->smtp->get_response(); + $error = $this->smtp->get_error(); // log error if (!$sent) { self::raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__, - 'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE); + 'message' => "SMTP error: ".join("\n", $response)), TRUE, FALSE); } } // send mail using PHP's mail() function @@ -1061,7 +1072,7 @@ class rcmail extends rcube $this->user->get_username(), $_SERVER['REMOTE_ADDR'], $mailto, - !empty($smtp_response) ? join('; ', $smtp_response) : '')); + !empty($response) ? join('; ', $response) : '')); } } -- cgit v1.2.3 From 83370e5ff14f55f6af435807713956160f91abfa Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 18 Dec 2012 12:54:38 +0100 Subject: Display 'Sender' header in message preview --- CHANGELOG | 1 + program/lib/Roundcube/rcube_storage.php | 1 + program/localization/en_US/labels.inc | 1 + program/steps/mail/func.inc | 10 +++++++++- 4 files changed, 12 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index a89e02930..8cfeaf89d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Display 'Sender' header in message preview - Plugin API: Added message_before_send hook - Fix contact copy/add-to-group operations on search result (#1488862) - Use matching identity in MDN response (#1488864) diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index 65de2660c..8a36f1f9d 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -53,6 +53,7 @@ abstract class rcube_storage protected $all_headers = array( 'IN-REPLY-TO', 'BCC', + 'SENDER', 'MESSAGE-ID', 'CONTENT-TRANSFER-ENCODING', 'REFERENCES', diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index abb0dca5d..730e6af09 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -41,6 +41,7 @@ $labels['junk'] = 'Junk'; // message listing $labels['subject'] = 'Subject'; $labels['from'] = 'From'; +$labels['sender'] = 'Sender'; $labels['to'] = 'To'; $labels['cc'] = 'Cc'; $labels['bcc'] = 'Bcc'; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 88391b102..f5165399b 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -967,7 +967,7 @@ function rcmail_message_headers($attrib, $headers=null) } // show these headers - $standard_headers = array('subject', 'from', 'to', 'cc', 'bcc', 'replyto', + $standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto', 'mail-reply-to', 'mail-followup-to', 'date', 'priority'); $exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array(); $output_headers = array(); @@ -1018,6 +1018,14 @@ function rcmail_message_headers($attrib, $headers=null) else continue; } + else if ($hkey == 'sender') { + if ($headers['sender'] != $headers['from']) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else + continue; + } else if ($hkey == 'mail-followup-to') { $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); $ishtml = true; -- cgit v1.2.3 From 0d214498d04439c29c9764fa291dcfde49701467 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 18 Dec 2012 19:02:53 +0100 Subject: CS fixes --- program/lib/Roundcube/html.php | 19 +- program/lib/Roundcube/rcube_addressbook.php | 4 +- program/lib/Roundcube/rcube_session.php | 1159 ++++++++++++----------- program/lib/Roundcube/rcube_string_replacer.php | 298 +++--- 4 files changed, 754 insertions(+), 726 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php index 33b766c44..522a82305 100644 --- a/program/lib/Roundcube/html.php +++ b/program/lib/Roundcube/html.php @@ -169,7 +169,7 @@ class html $attr = array('href' => $attr); } return self::tag('a', $attr, $cont, array_merge(self::$common_attrib, - array('href','target','name','rel','onclick','onmouseover','onmouseout','onmousedown','onmouseup'))); + array('href','target','name','rel','onclick','onmouseover','onmouseout','onmousedown','onmouseup'))); } /** @@ -675,7 +675,7 @@ class html_table extends html } $cell = new stdClass; - $cell->attrib = $attr; + $cell->attrib = $attr; $cell->content = $cont; $this->rows[$this->rowindex]->cells[$this->colindex] = $cell; @@ -699,16 +699,16 @@ class html_table extends html } $cell = new stdClass; - $cell->attrib = $attr; - $cell->content = $cont; + $cell->attrib = $attr; + $cell->content = $cont; $this->header[] = $cell; } - /** + /** * Remove a column from a table * Useful for plugins making alterations - * - * @param string $class + * + * @param string $class */ public function remove_column($class) { @@ -788,8 +788,9 @@ class html_table extends html */ public function show($attrib = null) { - if (is_array($attrib)) + if (is_array($attrib)) { $this->attrib = array_merge($this->attrib, $attrib); + } $thead = $tbody = ""; @@ -831,7 +832,7 @@ class html_table extends html */ public function size() { - return count($this->rows); + return count($this->rows); } /** diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index a8f274a8f..98d8f98ee 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -138,7 +138,7 @@ abstract class rcube_addressbook */ function get_error() { - return $this->error; + return $this->error; } /** @@ -149,7 +149,7 @@ abstract class rcube_addressbook */ protected function set_error($type, $message) { - $this->error = array('type' => $type, 'message' => $message); + $this->error = array('type' => $type, 'message' => $message); } /** diff --git a/program/lib/Roundcube/rcube_session.php b/program/lib/Roundcube/rcube_session.php index 69eaabedc..1aa5d5856 100644 --- a/program/lib/Roundcube/rcube_session.php +++ b/program/lib/Roundcube/rcube_session.php @@ -28,602 +28,629 @@ */ class rcube_session { - private $db; - private $ip; - private $start; - private $changed; - private $unsets = array(); - private $gc_handlers = array(); - private $cookiename = 'roundcube_sessauth'; - private $vars; - private $key; - private $now; - private $secret = ''; - private $ip_check = false; - private $logging = false; - private $memcache; - - /** - * Default constructor - */ - public function __construct($db, $config) - { - $this->db = $db; - $this->start = microtime(true); - $this->ip = $_SERVER['REMOTE_ADDR']; - $this->logging = $config->get('log_session', false); - - $lifetime = $config->get('session_lifetime', 1) * 60; - $this->set_lifetime($lifetime); - - // use memcache backend - if ($config->get('session_storage', 'db') == 'memcache') { - $this->memcache = rcube::get_instance()->get_memcache(); - - // set custom functions for PHP session management if memcache is available - if ($this->memcache) { - session_set_save_handler( - array($this, 'open'), - array($this, 'close'), - array($this, 'mc_read'), - array($this, 'mc_write'), - array($this, 'mc_destroy'), - array($this, 'gc')); - } - else { - rcube::raise_error(array('code' => 604, 'type' => 'db', - 'line' => __LINE__, 'file' => __FILE__, - 'message' => "Failed to connect to memcached. Please check configuration"), - true, true); - } + private $db; + private $ip; + private $start; + private $changed; + private $unsets = array(); + private $gc_handlers = array(); + private $cookiename = 'roundcube_sessauth'; + private $vars; + private $key; + private $now; + private $secret = ''; + private $ip_check = false; + private $logging = false; + private $memcache; + + + /** + * Default constructor + */ + public function __construct($db, $config) + { + $this->db = $db; + $this->start = microtime(true); + $this->ip = $_SERVER['REMOTE_ADDR']; + $this->logging = $config->get('log_session', false); + + $lifetime = $config->get('session_lifetime', 1) * 60; + $this->set_lifetime($lifetime); + + // use memcache backend + if ($config->get('session_storage', 'db') == 'memcache') { + $this->memcache = rcube::get_instance()->get_memcache(); + + // set custom functions for PHP session management if memcache is available + if ($this->memcache) { + session_set_save_handler( + array($this, 'open'), + array($this, 'close'), + array($this, 'mc_read'), + array($this, 'mc_write'), + array($this, 'mc_destroy'), + array($this, 'gc')); + } + else { + rcube::raise_error(array('code' => 604, 'type' => 'db', + 'line' => __LINE__, 'file' => __FILE__, + 'message' => "Failed to connect to memcached. Please check configuration"), + true, true); + } + } + else { + // set custom functions for PHP session management + session_set_save_handler( + array($this, 'open'), + array($this, 'close'), + array($this, 'db_read'), + array($this, 'db_write'), + array($this, 'db_destroy'), + array($this, 'db_gc')); + } } - else { - // set custom functions for PHP session management - session_set_save_handler( - array($this, 'open'), - array($this, 'close'), - array($this, 'db_read'), - array($this, 'db_write'), - array($this, 'db_destroy'), - array($this, 'db_gc')); - } - } - - - public function open($save_path, $session_name) - { - return true; - } - - - public function close() - { - return true; - } - - - /** - * Delete session data for the given key - * - * @param string Session ID - */ - public function destroy($key) - { - return $this->memcache ? $this->mc_destroy($key) : $this->db_destroy($key); - } - - - /** - * Read session data from database - * - * @param string Session ID - * @return string Session vars - */ - public function db_read($key) - { - $sql_result = $this->db->query( - "SELECT vars, ip, changed FROM ".$this->db->table_name('session') - ." WHERE sess_id = ?", $key); - - if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { - $this->changed = strtotime($sql_arr['changed']); - $this->ip = $sql_arr['ip']; - $this->vars = base64_decode($sql_arr['vars']); - $this->key = $key; - - return !empty($this->vars) ? (string) $this->vars : ''; + + + public function open($save_path, $session_name) + { + return true; + } + + + public function close() + { + return true; } - return null; - } - - - /** - * Save session data. - * handler for session_read() - * - * @param string Session ID - * @param string Serialized session vars - * @return boolean True on success - */ - public function db_write($key, $vars) - { - $ts = microtime(true); - $now = $this->db->fromunixtime((int)$ts); - - // no session row in DB (db_read() returns false) - if (!$this->key) { - $oldvars = null; + + /** + * Delete session data for the given key + * + * @param string Session ID + */ + public function destroy($key) + { + return $this->memcache ? $this->mc_destroy($key) : $this->db_destroy($key); + } + + + /** + * Read session data from database + * + * @param string Session ID + * + * @return string Session vars + */ + public function db_read($key) + { + $sql_result = $this->db->query( + "SELECT vars, ip, changed FROM ".$this->db->table_name('session') + ." WHERE sess_id = ?", $key); + + if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { + $this->changed = strtotime($sql_arr['changed']); + $this->ip = $sql_arr['ip']; + $this->vars = base64_decode($sql_arr['vars']); + $this->key = $key; + + return !empty($this->vars) ? (string) $this->vars : ''; + } + + return null; } - // use internal data from read() for fast requests (up to 0.5 sec.) - else if ($key == $this->key && (!$this->vars || $ts - $this->start < 0.5)) { - $oldvars = $this->vars; + + + /** + * Save session data. + * handler for session_read() + * + * @param string Session ID + * @param string Serialized session vars + * + * @return boolean True on success + */ + public function db_write($key, $vars) + { + $ts = microtime(true); + $now = $this->db->fromunixtime((int)$ts); + + // no session row in DB (db_read() returns false) + if (!$this->key) { + $oldvars = null; + } + // use internal data from read() for fast requests (up to 0.5 sec.) + else if ($key == $this->key && (!$this->vars || $ts - $this->start < 0.5)) { + $oldvars = $this->vars; + } + else { // else read data again from DB + $oldvars = $this->db_read($key); + } + + if ($oldvars !== null) { + $newvars = $this->_fixvars($vars, $oldvars); + + if ($newvars !== $oldvars) { + $this->db->query( + sprintf("UPDATE %s SET vars=?, changed=%s WHERE sess_id=?", + $this->db->table_name('session'), $now), + base64_encode($newvars), $key); + } + else if ($ts - $this->changed > $this->lifetime / 2) { + $this->db->query("UPDATE ".$this->db->table_name('session') + ." SET changed=$now WHERE sess_id=?", $key); + } + } + else { + $this->db->query( + sprintf("INSERT INTO %s (sess_id, vars, ip, created, changed) ". + "VALUES (?, ?, ?, %s, %s)", + $this->db->table_name('session'), $now, $now), + $key, base64_encode($vars), (string)$this->ip); + } + + return true; + } + + + /** + * Merge vars with old vars and apply unsets + */ + private function _fixvars($vars, $oldvars) + { + if ($oldvars !== null) { + $a_oldvars = $this->unserialize($oldvars); + if (is_array($a_oldvars)) { + foreach ((array)$this->unsets as $k) + unset($a_oldvars[$k]); + + $newvars = $this->serialize(array_merge( + (array)$a_oldvars, (array)$this->unserialize($vars))); + } + else { + $newvars = $vars; + } + } + + $this->unsets = array(); + return $newvars; } - else { // else read data again from DB - $oldvars = $this->db_read($key); + + + /** + * Handler for session_destroy() + * + * @param string Session ID + * + * @return boolean True on success + */ + public function db_destroy($key) + { + if ($key) { + $this->db->query(sprintf("DELETE FROM %s WHERE sess_id = ?", + $this->db->table_name('session')), $key); + } + + return true; } - if ($oldvars !== null) { - $newvars = $this->_fixvars($vars, $oldvars); - if ($newvars !== $oldvars) { + /** + * Garbage collecting function + * + * @param string Session lifetime in seconds + * @return boolean True on success + */ + public function db_gc($maxlifetime) + { + // just delete all expired sessions $this->db->query( - sprintf("UPDATE %s SET vars=?, changed=%s WHERE sess_id=?", - $this->db->table_name('session'), $now), - base64_encode($newvars), $key); - } - else if ($ts - $this->changed > $this->lifetime / 2) { - $this->db->query("UPDATE ".$this->db->table_name('session')." SET changed=$now WHERE sess_id=?", $key); - } + sprintf("DELETE FROM %s WHERE changed < %s", + $this->db->table_name('session'), $this->db->fromunixtime(time() - $maxlifetime))); + + $this->gc(); + + return true; + } + + + /** + * Read session data from memcache + * + * @param string Session ID + * @return string Session vars + */ + public function mc_read($key) + { + if ($value = $this->memcache->get($key)) { + $arr = unserialize($value); + $this->changed = $arr['changed']; + $this->ip = $arr['ip']; + $this->vars = $arr['vars']; + $this->key = $key; + + return !empty($this->vars) ? (string) $this->vars : ''; + } + + return null; + } + + + /** + * Save session data. + * handler for session_read() + * + * @param string Session ID + * @param string Serialized session vars + * + * @return boolean True on success + */ + public function mc_write($key, $vars) + { + $ts = microtime(true); + + // no session data in cache (mc_read() returns false) + if (!$this->key) + $oldvars = null; + // use internal data for fast requests (up to 0.5 sec.) + else if ($key == $this->key && (!$this->vars || $ts - $this->start < 0.5)) + $oldvars = $this->vars; + else // else read data again + $oldvars = $this->mc_read($key); + + $newvars = $oldvars !== null ? $this->_fixvars($vars, $oldvars) : $vars; + + if ($newvars !== $oldvars || $ts - $this->changed > $this->lifetime / 2) { + return $this->memcache->set($key, serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $newvars)), + MEMCACHE_COMPRESSED, $this->lifetime); + } + + return true; + } + + + /** + * Handler for session_destroy() with memcache backend + * + * @param string Session ID + * + * @return boolean True on success + */ + public function mc_destroy($key) + { + if ($key) { + // #1488592: use 2nd argument + $this->memcache->delete($key, 0); + } + + return true; + } + + + /** + * Execute registered garbage collector routines + */ + public function gc() + { + foreach ($this->gc_handlers as $fct) { + call_user_func($fct); + } } - else { - $this->db->query( - sprintf("INSERT INTO %s (sess_id, vars, ip, created, changed) ". - "VALUES (?, ?, ?, %s, %s)", - $this->db->table_name('session'), $now, $now), - $key, base64_encode($vars), (string)$this->ip); + + + /** + * Register additional garbage collector functions + * + * @param mixed Callback function + */ + public function register_gc_handler($func) + { + foreach ($this->gc_handlers as $handler) { + if ($handler == $func) { + return; + } + } + + $this->gc_handlers[] = $func; } - return true; - } - - - /** - * Merge vars with old vars and apply unsets - */ - private function _fixvars($vars, $oldvars) - { - if ($oldvars !== null) { - $a_oldvars = $this->unserialize($oldvars); - if (is_array($a_oldvars)) { - foreach ((array)$this->unsets as $k) - unset($a_oldvars[$k]); - - $newvars = $this->serialize(array_merge( - (array)$a_oldvars, (array)$this->unserialize($vars))); - } - else - $newvars = $vars; + + /** + * Generate and set new session id + * + * @param boolean $destroy If enabled the current session will be destroyed + */ + public function regenerate_id($destroy=true) + { + session_regenerate_id($destroy); + + $this->vars = null; + $this->key = session_id(); + + return true; } - $this->unsets = array(); - return $newvars; - } - - - /** - * Handler for session_destroy() - * - * @param string Session ID - * - * @return boolean True on success - */ - public function db_destroy($key) - { - if ($key) { - $this->db->query(sprintf("DELETE FROM %s WHERE sess_id = ?", $this->db->table_name('session')), $key); + + /** + * Unset a session variable + * + * @param string Varibale name + * @return boolean True on success + */ + public function remove($var=null) + { + if (empty($var)) { + return $this->destroy(session_id()); + } + + $this->unsets[] = $var; + unset($_SESSION[$var]); + + return true; + } + + + /** + * Kill this session + */ + public function kill() + { + $this->vars = null; + $this->ip = $_SERVER['REMOTE_ADDR']; // update IP (might have changed) + $this->destroy(session_id()); + rcube_utils::setcookie($this->cookiename, '-del-', time() - 60); + } + + + /** + * Re-read session data from storage backend + */ + public function reload() + { + if ($this->key && $this->memcache) + $data = $this->mc_read($this->key); + else if ($this->key) + $data = $this->db_read($this->key); + + if ($data) + session_decode($data); + } + + + /** + * Serialize session data + */ + private function serialize($vars) + { + $data = ''; + if (is_array($vars)) { + foreach ($vars as $var=>$value) + $data .= $var.'|'.serialize($value); + } + else { + $data = 'b:0;'; + } + + return $data; } - return true; - } - - - /** - * Garbage collecting function - * - * @param string Session lifetime in seconds - * @return boolean True on success - */ - public function db_gc($maxlifetime) - { - // just delete all expired sessions - $this->db->query( - sprintf("DELETE FROM %s WHERE changed < %s", - $this->db->table_name('session'), $this->db->fromunixtime(time() - $maxlifetime))); - - $this->gc(); - - return true; - } - - - /** - * Read session data from memcache - * - * @param string Session ID - * @return string Session vars - */ - public function mc_read($key) - { - if ($value = $this->memcache->get($key)) { - $arr = unserialize($value); - $this->changed = $arr['changed']; - $this->ip = $arr['ip']; - $this->vars = $arr['vars']; - $this->key = $key; - - return !empty($this->vars) ? (string) $this->vars : ''; + + /** + * Unserialize session data + * http://www.php.net/manual/en/function.session-decode.php#56106 + */ + private function unserialize($str) + { + $str = (string)$str; + $endptr = strlen($str); + $p = 0; + + $serialized = ''; + $items = 0; + $level = 0; + + while ($p < $endptr) { + $q = $p; + while ($str[$q] != '|') + if (++$q >= $endptr) + break 2; + + if ($str[$p] == '!') { + $p++; + $has_value = false; + } + else { + $has_value = true; + } + + $name = substr($str, $p, $q - $p); + $q++; + + $serialized .= 's:' . strlen($name) . ':"' . $name . '";'; + + if ($has_value) { + for (;;) { + $p = $q; + switch (strtolower($str[$q])) { + case 'n': // null + case 'b': // boolean + case 'i': // integer + case 'd': // decimal + do $q++; + while ( ($q < $endptr) && ($str[$q] != ';') ); + $q++; + $serialized .= substr($str, $p, $q - $p); + if ($level == 0) + break 2; + break; + case 'r': // reference + $q+= 2; + for ($id = ''; ($q < $endptr) && ($str[$q] != ';'); $q++) + $id .= $str[$q]; + $q++; + // increment pointer because of outer array + $serialized .= 'R:' . ($id + 1) . ';'; + if ($level == 0) + break 2; + break; + case 's': // string + $q+=2; + for ($length=''; ($q < $endptr) && ($str[$q] != ':'); $q++) + $length .= $str[$q]; + $q+=2; + $q+= (int)$length + 2; + $serialized .= substr($str, $p, $q - $p); + if ($level == 0) + break 2; + break; + case 'a': // array + case 'o': // object + do $q++; + while ($q < $endptr && $str[$q] != '{'); + $q++; + $level++; + $serialized .= substr($str, $p, $q - $p); + break; + case '}': // end of array|object + $q++; + $serialized .= substr($str, $p, $q - $p); + if (--$level == 0) + break 2; + break; + default: + return false; + } + } + } + else { + $serialized .= 'N;'; + $q += 2; + } + $items++; + $p = $q; + } + + return unserialize( 'a:' . $items . ':{' . $serialized . '}' ); } - return null; - } - - - /** - * Save session data. - * handler for session_read() - * - * @param string Session ID - * @param string Serialized session vars - * @return boolean True on success - */ - public function mc_write($key, $vars) - { - $ts = microtime(true); - - // no session data in cache (mc_read() returns false) - if (!$this->key) - $oldvars = null; - // use internal data for fast requests (up to 0.5 sec.) - else if ($key == $this->key && (!$this->vars || $ts - $this->start < 0.5)) - $oldvars = $this->vars; - else // else read data again - $oldvars = $this->mc_read($key); - - $newvars = $oldvars !== null ? $this->_fixvars($vars, $oldvars) : $vars; - - if ($newvars !== $oldvars || $ts - $this->changed > $this->lifetime / 2) - return $this->memcache->set($key, serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $newvars)), MEMCACHE_COMPRESSED, $this->lifetime); - - return true; - } - - - /** - * Handler for session_destroy() with memcache backend - * - * @param string Session ID - * - * @return boolean True on success - */ - public function mc_destroy($key) - { - if ($key) { - // #1488592: use 2nd argument - $this->memcache->delete($key, 0); + + /** + * Setter for session lifetime + */ + public function set_lifetime($lifetime) + { + $this->lifetime = max(120, $lifetime); + + // valid time range is now - 1/2 lifetime to now + 1/2 lifetime + $now = time(); + $this->now = $now - ($now % ($this->lifetime / 2)); } - return true; - } + /** + * Getter for remote IP saved with this session + */ + public function get_ip() + { + return $this->ip; + } - /** - * Execute registered garbage collector routines - */ - public function gc() - { - foreach ($this->gc_handlers as $fct) { - call_user_func($fct); + + /** + * Setter for cookie encryption secret + */ + function set_secret($secret) + { + $this->secret = $secret; } - } - - - /** - * Register additional garbage collector functions - * - * @param mixed Callback function - */ - public function register_gc_handler($func) - { - foreach ($this->gc_handlers as $handler) { - if ($handler == $func) { - return; - } + + + /** + * Enable/disable IP check + */ + function set_ip_check($check) + { + $this->ip_check = $check; } - $this->gc_handlers[] = $func; - } - - - /** - * Generate and set new session id - * - * @param boolean $destroy If enabled the current session will be destroyed - */ - public function regenerate_id($destroy=true) - { - session_regenerate_id($destroy); - - $this->vars = null; - $this->key = session_id(); - - return true; - } - - - /** - * Unset a session variable - * - * @param string Varibale name - * @return boolean True on success - */ - public function remove($var=null) - { - if (empty($var)) - return $this->destroy(session_id()); - - $this->unsets[] = $var; - unset($_SESSION[$var]); - - return true; - } - - - /** - * Kill this session - */ - public function kill() - { - $this->vars = null; - $this->ip = $_SERVER['REMOTE_ADDR']; // update IP (might have changed) - $this->destroy(session_id()); - rcube_utils::setcookie($this->cookiename, '-del-', time() - 60); - } - - - /** - * Re-read session data from storage backend - */ - public function reload() - { - if ($this->key && $this->memcache) - $data = $this->mc_read($this->key); - else if ($this->key) - $data = $this->db_read($this->key); - - if ($data) - session_decode($data); - } - - - /** - * Serialize session data - */ - private function serialize($vars) - { - $data = ''; - if (is_array($vars)) - foreach ($vars as $var=>$value) - $data .= $var.'|'.serialize($value); - else - $data = 'b:0;'; - return $data; - } - - - /** - * Unserialize session data - * http://www.php.net/manual/en/function.session-decode.php#56106 - */ - private function unserialize($str) - { - $str = (string)$str; - $endptr = strlen($str); - $p = 0; - - $serialized = ''; - $items = 0; - $level = 0; - - while ($p < $endptr) { - $q = $p; - while ($str[$q] != '|') - if (++$q >= $endptr) break 2; - - if ($str[$p] == '!') { - $p++; - $has_value = false; - } else { - $has_value = true; - } - - $name = substr($str, $p, $q - $p); - $q++; - - $serialized .= 's:' . strlen($name) . ':"' . $name . '";'; - - if ($has_value) { - for (;;) { - $p = $q; - switch (strtolower($str[$q])) { - case 'n': /* null */ - case 'b': /* boolean */ - case 'i': /* integer */ - case 'd': /* decimal */ - do $q++; - while ( ($q < $endptr) && ($str[$q] != ';') ); - $q++; - $serialized .= substr($str, $p, $q - $p); - if ($level == 0) break 2; - break; - case 'r': /* reference */ - $q+= 2; - for ($id = ''; ($q < $endptr) && ($str[$q] != ';'); $q++) $id .= $str[$q]; - $q++; - $serialized .= 'R:' . ($id + 1) . ';'; /* increment pointer because of outer array */ - if ($level == 0) break 2; - break; - case 's': /* string */ - $q+=2; - for ($length=''; ($q < $endptr) && ($str[$q] != ':'); $q++) $length .= $str[$q]; - $q+=2; - $q+= (int)$length + 2; - $serialized .= substr($str, $p, $q - $p); - if ($level == 0) break 2; - break; - case 'a': /* array */ - case 'o': /* object */ - do $q++; - while ( ($q < $endptr) && ($str[$q] != '{') ); - $q++; - $level++; - $serialized .= substr($str, $p, $q - $p); - break; - case '}': /* end of array|object */ - $q++; - $serialized .= substr($str, $p, $q - $p); - if (--$level == 0) break 2; - break; - default: - return false; - } + + /** + * Setter for the cookie name used for session cookie + */ + function set_cookiename($cookiename) + { + if ($cookiename) { + $this->cookiename = $cookiename; } - } else { - $serialized .= 'N;'; - $q += 2; - } - $items++; - $p = $q; } - return unserialize( 'a:' . $items . ':{' . $serialized . '}' ); - } - - - /** - * Setter for session lifetime - */ - public function set_lifetime($lifetime) - { - $this->lifetime = max(120, $lifetime); - - // valid time range is now - 1/2 lifetime to now + 1/2 lifetime - $now = time(); - $this->now = $now - ($now % ($this->lifetime / 2)); - } - - - /** - * Getter for remote IP saved with this session - */ - public function get_ip() - { - return $this->ip; - } - - - /** - * Setter for cookie encryption secret - */ - function set_secret($secret) - { - $this->secret = $secret; - } - - - /** - * Enable/disable IP check - */ - function set_ip_check($check) - { - $this->ip_check = $check; - } - - - /** - * Setter for the cookie name used for session cookie - */ - function set_cookiename($cookiename) - { - if ($cookiename) - $this->cookiename = $cookiename; - } - - - /** - * Check session authentication cookie - * - * @return boolean True if valid, False if not - */ - function check_auth() - { - $this->cookie = $_COOKIE[$this->cookiename]; - $result = $this->ip_check ? $_SERVER['REMOTE_ADDR'] == $this->ip : true; - - if (!$result) - $this->log("IP check failed for " . $this->key . "; expected " . $this->ip . "; got " . $_SERVER['REMOTE_ADDR']); - - if ($result && $this->_mkcookie($this->now) != $this->cookie) { - $this->log("Session auth check failed for " . $this->key . "; timeslot = " . date('Y-m-d H:i:s', $this->now)); - $result = false; - - // Check if using id from a previous time slot - for ($i = 1; $i <= 2; $i++) { - $prev = $this->now - ($this->lifetime / 2) * $i; - if ($this->_mkcookie($prev) == $this->cookie) { - $this->log("Send new auth cookie for " . $this->key . ": " . $this->cookie); - $this->set_auth_cookie(); - $result = true; + + /** + * Check session authentication cookie + * + * @return boolean True if valid, False if not + */ + function check_auth() + { + $this->cookie = $_COOKIE[$this->cookiename]; + $result = $this->ip_check ? $_SERVER['REMOTE_ADDR'] == $this->ip : true; + + if (!$result) { + $this->log("IP check failed for " . $this->key . "; expected " . $this->ip . "; got " . $_SERVER['REMOTE_ADDR']); } - } + + if ($result && $this->_mkcookie($this->now) != $this->cookie) { + $this->log("Session auth check failed for " . $this->key . "; timeslot = " . date('Y-m-d H:i:s', $this->now)); + $result = false; + + // Check if using id from a previous time slot + for ($i = 1; $i <= 2; $i++) { + $prev = $this->now - ($this->lifetime / 2) * $i; + if ($this->_mkcookie($prev) == $this->cookie) { + $this->log("Send new auth cookie for " . $this->key . ": " . $this->cookie); + $this->set_auth_cookie(); + $result = true; + } + } + } + + if (!$result) { + $this->log("Session authentication failed for " . $this->key + . "; invalid auth cookie sent; timeslot = " . date('Y-m-d H:i:s', $prev)); + } + + return $result; + } + + + /** + * Set session authentication cookie + */ + function set_auth_cookie() + { + $this->cookie = $this->_mkcookie($this->now); + rcube_utils::setcookie($this->cookiename, $this->cookie, 0); + $_COOKIE[$this->cookiename] = $this->cookie; } - if (!$result) - $this->log("Session authentication failed for " . $this->key . "; invalid auth cookie sent; timeslot = " . date('Y-m-d H:i:s', $prev)); - - return $result; - } - - - /** - * Set session authentication cookie - */ - function set_auth_cookie() - { - $this->cookie = $this->_mkcookie($this->now); - rcube_utils::setcookie($this->cookiename, $this->cookie, 0); - $_COOKIE[$this->cookiename] = $this->cookie; - } - - - /** - * Create session cookie from session data - * - * @param int Time slot to use - */ - function _mkcookie($timeslot) - { - $auth_string = "$this->key,$this->secret,$timeslot"; - return "S" . (function_exists('sha1') ? sha1($auth_string) : md5($auth_string)); - } - - /** - * Writes debug information to the log - */ - function log($line) - { - if ($this->logging) - rcube::write_log('session', $line); - } + /** + * Create session cookie from session data + * + * @param int Time slot to use + */ + function _mkcookie($timeslot) + { + $auth_string = "$this->key,$this->secret,$timeslot"; + return "S" . (function_exists('sha1') ? sha1($auth_string) : md5($auth_string)); + } + + /** + * Writes debug information to the log + */ + function log($line) + { + if ($this->logging) { + rcube::write_log('session', $line); + } + } } diff --git a/program/lib/Roundcube/rcube_string_replacer.php b/program/lib/Roundcube/rcube_string_replacer.php index 68288f54c..0fe982b26 100644 --- a/program/lib/Roundcube/rcube_string_replacer.php +++ b/program/lib/Roundcube/rcube_string_replacer.php @@ -24,164 +24,164 @@ */ class rcube_string_replacer { - public static $pattern = '/##str_replacement\[([0-9]+)\]##/'; - public $mailto_pattern; - public $link_pattern; - private $values = array(); - - - function __construct() - { - // Simplified domain expression for UTF8 characters handling - // Support unicode/punycode in top-level domain part - $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.?([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-zA-Z0-9]{2,})'; - $url1 = '.:;,'; - $url2 = 'a-zA-Z0-9%=#$@+?!&\\/_~\\[\\]{}\*-'; - - $this->link_pattern = "/([\w]+:\/\/|\W[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)($utf_domain([$url1]?[$url2]+)*)/"; - $this->mailto_pattern = "/(" - ."[-\w!\#\$%&\'*+~\/^`|{}=]+(?:\.[-\w!\#\$%&\'*+~\/^`|{}=]+)*" // local-part - ."@$utf_domain" // domain-part - ."(\?[$url1$url2]+)?" // e.g. ?subject=test... - .")/"; - } - - /** - * Add a string to the internal list - * - * @param string String value - * @return int Index of value for retrieval - */ - public function add($str) - { - $i = count($this->values); - $this->values[$i] = $str; - return $i; - } - - /** - * Build replacement string - */ - public function get_replacement($i) - { - return '##str_replacement['.$i.']##'; - } - - /** - * Callback function used to build HTML links around URL strings - * - * @param array Matches result from preg_replace_callback - * @return int Index of saved string value - */ - public function link_callback($matches) - { - $i = -1; - $scheme = strtolower($matches[1]); - - if (preg_match('!^(http|ftp|file)s?://!i', $scheme)) { - $url = $matches[1] . $matches[2]; + public static $pattern = '/##str_replacement\[([0-9]+)\]##/'; + public $mailto_pattern; + public $link_pattern; + private $values = array(); + + + function __construct() + { + // Simplified domain expression for UTF8 characters handling + // Support unicode/punycode in top-level domain part + $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.?([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-zA-Z0-9]{2,})'; + $url1 = '.:;,'; + $url2 = 'a-zA-Z0-9%=#$@+?!&\\/_~\\[\\]{}\*-'; + + $this->link_pattern = "/([\w]+:\/\/|\W[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)($utf_domain([$url1]?[$url2]+)*)/"; + $this->mailto_pattern = "/(" + ."[-\w!\#\$%&\'*+~\/^`|{}=]+(?:\.[-\w!\#\$%&\'*+~\/^`|{}=]+)*" // local-part + ."@$utf_domain" // domain-part + ."(\?[$url1$url2]+)?" // e.g. ?subject=test... + .")/"; } - else if (preg_match('/^(\W*)(www\.)$/i', $matches[1], $m)) { - $url = $m[2] . $matches[2]; - $url_prefix = 'http://'; - $prefix = $m[1]; + + /** + * Add a string to the internal list + * + * @param string String value + * @return int Index of value for retrieval + */ + public function add($str) + { + $i = count($this->values); + $this->values[$i] = $str; + return $i; } - if ($url) { - $suffix = $this->parse_url_brackets($url); - $i = $this->add($prefix . html::a(array( - 'href' => $url_prefix . $url, - 'target' => '_blank' - ), rcube::Q($url)) . $suffix); + /** + * Build replacement string + */ + public function get_replacement($i) + { + return '##str_replacement['.$i.']##'; } - // Return valid link for recognized schemes, otherwise, return the unmodified string for unrecognized schemes. - return $i >= 0 ? $this->get_replacement($i) : $matches[0]; - } - - /** - * Callback function used to build mailto: links around e-mail strings - * - * @param array Matches result from preg_replace_callback - * @return int Index of saved string value - */ - public function mailto_callback($matches) - { - $href = $matches[1]; - $suffix = $this->parse_url_brackets($href); - $i = $this->add(html::a('mailto:' . $href, rcube::Q($href)) . $suffix); - - return $i >= 0 ? $this->get_replacement($i) : ''; - } - - /** - * Look up the index from the preg_replace matches array - * and return the substitution value. - * - * @param array Matches result from preg_replace_callback - * @return string Value at index $matches[1] - */ - public function replace_callback($matches) - { - return $this->values[$matches[1]]; - } - - /** - * Replace all defined (link|mailto) patterns with replacement string - * - * @param string $str Text - * - * @return string Text - */ - public function replace($str) - { - // search for patterns like links and e-mail addresses - $str = preg_replace_callback($this->link_pattern, array($this, 'link_callback'), $str); - $str = preg_replace_callback($this->mailto_pattern, array($this, 'mailto_callback'), $str); - - return $str; - } - - /** - * Replace substituted strings with original values - */ - public function resolve($str) - { - return preg_replace_callback(self::$pattern, array($this, 'replace_callback'), $str); - } - - /** - * Fixes bracket characters in URL handling - */ - public static function parse_url_brackets(&$url) - { - // #1487672: special handling of square brackets, - // URL regexp allows [] characters in URL, for example: - // "http://example.com/?a[b]=c". However we need to handle - // properly situation when a bracket is placed at the end - // of the link e.g. "[http://example.com]" - if (preg_match('/(\\[|\\])/', $url)) { - $in = false; - for ($i=0, $len=strlen($url); $i<$len; $i++) { - if ($url[$i] == '[') { - if ($in) - break; - $in = true; + /** + * Callback function used to build HTML links around URL strings + * + * @param array Matches result from preg_replace_callback + * @return int Index of saved string value + */ + public function link_callback($matches) + { + $i = -1; + $scheme = strtolower($matches[1]); + + if (preg_match('!^(http|ftp|file)s?://!i', $scheme)) { + $url = $matches[1] . $matches[2]; + } + else if (preg_match('/^(\W*)(www\.)$/i', $matches[1], $m)) { + $url = $m[2] . $matches[2]; + $url_prefix = 'http://'; + $prefix = $m[1]; } - else if ($url[$i] == ']') { - if (!$in) - break; - $in = false; + + if ($url) { + $suffix = $this->parse_url_brackets($url); + $i = $this->add($prefix . html::a(array( + 'href' => $url_prefix . $url, + 'target' => '_blank' + ), rcube::Q($url)) . $suffix); } - } - if ($i<$len) { - $suffix = substr($url, $i); - $url = substr($url, 0, $i); - } + // Return valid link for recognized schemes, otherwise + // return the unmodified string for unrecognized schemes. + return $i >= 0 ? $this->get_replacement($i) : $matches[0]; } - return $suffix; - } + /** + * Callback function used to build mailto: links around e-mail strings + * + * @param array Matches result from preg_replace_callback + * @return int Index of saved string value + */ + public function mailto_callback($matches) + { + $href = $matches[1]; + $suffix = $this->parse_url_brackets($href); + $i = $this->add(html::a('mailto:' . $href, rcube::Q($href)) . $suffix); + + return $i >= 0 ? $this->get_replacement($i) : ''; + } + /** + * Look up the index from the preg_replace matches array + * and return the substitution value. + * + * @param array Matches result from preg_replace_callback + * @return string Value at index $matches[1] + */ + public function replace_callback($matches) + { + return $this->values[$matches[1]]; + } + + /** + * Replace all defined (link|mailto) patterns with replacement string + * + * @param string $str Text + * + * @return string Text + */ + public function replace($str) + { + // search for patterns like links and e-mail addresses + $str = preg_replace_callback($this->link_pattern, array($this, 'link_callback'), $str); + $str = preg_replace_callback($this->mailto_pattern, array($this, 'mailto_callback'), $str); + + return $str; + } + + /** + * Replace substituted strings with original values + */ + public function resolve($str) + { + return preg_replace_callback(self::$pattern, array($this, 'replace_callback'), $str); + } + + /** + * Fixes bracket characters in URL handling + */ + public static function parse_url_brackets(&$url) + { + // #1487672: special handling of square brackets, + // URL regexp allows [] characters in URL, for example: + // "http://example.com/?a[b]=c". However we need to handle + // properly situation when a bracket is placed at the end + // of the link e.g. "[http://example.com]" + if (preg_match('/(\\[|\\])/', $url)) { + $in = false; + for ($i=0, $len=strlen($url); $i<$len; $i++) { + if ($url[$i] == '[') { + if ($in) + break; + $in = true; + } + else if ($url[$i] == ']') { + if (!$in) + break; + $in = false; + } + } + + if ($i < $len) { + $suffix = substr($url, $i); + $url = substr($url, 0, $i); + } + } + + return $suffix; + } } -- cgit v1.2.3 From c5d7c941aa16b5bd98cfd56f12bbe7c39bddc608 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 19 Dec 2012 11:43:52 +0100 Subject: Add unsupported alternative parts to attachments list (#1488870) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_message.php | 63 ++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 17 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 41e266d0c..c4e63aaeb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add unsupported alternative parts to attachments list (#1488870) - Add Compose button on message view page (#1488747) - Display 'Sender' header in message preview - Plugin API: Added message_before_send hook diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index f41493d12..08b94d8d9 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -106,6 +106,7 @@ class rcube_message if (!empty($this->headers->structure)) { $this->get_mime_numbers($this->headers->structure); $this->parse_structure($this->headers->structure); + $this->parse_attachments(); } else { $this->body = $this->storage->get_body($uid); @@ -333,7 +334,7 @@ class rcube_message if ($recursive && is_array($structure->headers) && isset($structure->headers['subject'])) { $c = new stdClass; $c->type = 'headers'; - $c->headers = &$structure->headers; + $c->headers = $structure->headers; $this->parts[] = $c; } @@ -351,7 +352,7 @@ class rcube_message // print body if message doesn't have multiple parts if ($message_ctype_primary == 'text' && !$recursive) { $structure->type = 'content'; - $this->parts[] = &$structure; + $this->parts[] = $structure; // Parse simple (plain text) message body if ($message_ctype_secondary == 'plain') @@ -363,32 +364,39 @@ class rcube_message // the same for pgp signed messages else if ($mimetype == 'application/pgp' && !$recursive) { $structure->type = 'content'; - $this->parts[] = &$structure; + $this->parts[] = $structure; } // message contains (more than one!) alternative parts else if ($mimetype == 'multipart/alternative' && is_array($structure->parts) && count($structure->parts) > 1 ) { - // get html/plaintext parts - $plain_part = $html_part = $print_part = $related_part = null; + $plain_part = null; + $html_part = null; + $print_part = null; + $related_part = null; + $attach_part = null; + // get html/plaintext parts, other add to attachments list foreach ($structure->parts as $p => $sub_part) { $sub_mimetype = $sub_part->mimetype; + $is_multipart = in_array($sub_mimetype, array('multipart/related', 'multipart/mixed', 'multipart/alternative')); // skip empty text parts - if (!$sub_part->size && preg_match('#^text/(plain|html|enriched)$#', $sub_mimetype)) { + if (!$sub_part->size && !$is_multipart) { continue; } // check if sub part is - if ($sub_mimetype == 'text/plain') + if ($is_multipart) + $related_part = $p; + else if ($sub_mimetype == 'text/plain') $plain_part = $p; else if ($sub_mimetype == 'text/html') $html_part = $p; else if ($sub_mimetype == 'text/enriched') $enriched_part = $p; - else if (in_array($sub_mimetype, array('multipart/related', 'multipart/mixed', 'multipart/alternative'))) - $related_part = $p; + else + $attach_part = $p; } // parse related part (alternative part could be in here) @@ -404,13 +412,13 @@ class rcube_message // choose html/plain part to print if ($html_part !== null && $this->opt['prefer_html']) { - $print_part = &$structure->parts[$html_part]; + $print_part = $structure->parts[$html_part]; } else if ($enriched_part !== null) { - $print_part = &$structure->parts[$enriched_part]; + $print_part = $structure->parts[$enriched_part]; } else if ($plain_part !== null) { - $print_part = &$structure->parts[$plain_part]; + $print_part = $structure->parts[$plain_part]; } // add the right message body @@ -432,11 +440,16 @@ class rcube_message // add html part as attachment if ($html_part !== null && $structure->parts[$html_part] !== $print_part) { - $html_part = &$structure->parts[$html_part]; + $html_part = $structure->parts[$html_part]; $html_part->mimetype = 'text/html'; $this->attachments[] = $html_part; } + + // add unsupported/unrecognized parts to attachments list + if ($attach_part) { + $this->attachments[] = $structure->parts[$attach_part]; + } } // this is an ecrypted message -> create a plaintext body with the according message else if ($mimetype == 'multipart/encrypted') { @@ -561,9 +574,6 @@ class rcube_message // regular attachment with valid content type // (content-type name regexp according to RFC4288.4.2) else if (preg_match('/^[a-z0-9!#$&.+^_-]+\/[a-z0-9!#$&.+^_-]+$/i', $part_mimetype)) { - if (!$mail_part->filename) - $mail_part->filename = 'Part '.$mail_part->mime_id; - $this->attachments[] = $mail_part; } // attachment with invalid content type @@ -628,12 +638,31 @@ class rcube_message } // message is a single part non-text (without filename) else if (preg_match('/application\//i', $mimetype)) { - $structure->filename = 'Part '.$structure->mime_id; $this->attachments[] = $structure; } } + /** + * Parse attachment parts + */ + private function parse_attachments() + { + // Attachment must have a name + foreach ($this->attachments as $attachment) { + if (!$attachment->filename) { + $ext = rcube_mime::get_mime_extensions($attachment->mimetype); + $ext = array_shift($ext); + + $attachment->filename = 'Part_' . $attachment->mime_id; + if ($ext) { + $attachment->filename .= '.' . $ext; + } + } + } + } + + /** * Fill aflat array with references to all parts, indexed by part numbers * -- cgit v1.2.3 From 9ac96015f274b9451377d05001097d0bb7526a27 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 19 Dec 2012 12:27:52 +0100 Subject: Better GD module functions detection, should fix "Call to undefined function imagecreatefromjpeg()" error --- program/lib/Roundcube/rcube_image.php | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_image.php b/program/lib/Roundcube/rcube_image.php index ad96842d2..9695022da 100644 --- a/program/lib/Roundcube/rcube_image.php +++ b/program/lib/Roundcube/rcube_image.php @@ -128,17 +128,20 @@ class rcube_image } // use GD extension - $gd_types = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); - if ($props['gd_type'] && in_array($props['gd_type'], $gd_types)) { - if ($props['gd_type'] == IMAGETYPE_JPEG) { + if ($props['gd_type']) { + if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) { $image = imagecreatefromjpeg($this->image_file); } - elseif($props['gd_type'] == IMAGETYPE_GIF) { + else if($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) { $image = imagecreatefromgif($this->image_file); } - elseif($props['gd_type'] == IMAGETYPE_PNG) { + else if($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) { $image = imagecreatefrompng($this->image_file); } + else { + // @TODO: print error to the log? + return false; + } $scale = $size / max($props['width'], $props['height']); $width = $props['width'] * $scale; @@ -216,19 +219,22 @@ class rcube_image } // use GD extension (TIFF isn't supported) - $props = $this->props(); - $gd_types = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); + $props = $this->props(); - if ($props['gd_type'] && in_array($props['gd_type'], $gd_types)) { - if ($props['gd_type'] == IMAGETYPE_JPEG) { + if ($props['gd_type']) { + if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) { $image = imagecreatefromjpeg($this->image_file); } - else if ($props['gd_type'] == IMAGETYPE_GIF) { + else if ($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) { $image = imagecreatefromgif($this->image_file); } - else if ($props['gd_type'] == IMAGETYPE_PNG) { + else if ($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) { $image = imagecreatefrompng($this->image_file); } + else { + // @TODO: print error to the log? + return false; + } if ($type == self::TYPE_JPG) { $result = imagejpeg($image, $filename, 75); -- cgit v1.2.3 From c23dc87f2b76ac76968c73bc9f31920b316282c6 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 19 Dec 2012 13:01:45 +0100 Subject: Don't display message parts with unsupported text type, e.g. text/calendar --- program/lib/Roundcube/rcube_message.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index 08b94d8d9..c45dbfcd0 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -351,15 +351,22 @@ class rcube_message // print body if message doesn't have multiple parts if ($message_ctype_primary == 'text' && !$recursive) { + // parts with unsupported type add to attachments list + if (!in_array($message_ctype_secondary, array('plain', 'html', 'enriched'))) { + $this->attachments[] = $structure; + return; + } + $structure->type = 'content'; $this->parts[] = $structure; // Parse simple (plain text) message body - if ($message_ctype_secondary == 'plain') + if ($message_ctype_secondary == 'plain') { foreach ((array)$this->uu_decode($structure) as $uupart) { $this->mime_parts[$uupart->mime_id] = $uupart; $this->attachments[] = $uupart; } + } } // the same for pgp signed messages else if ($mimetype == 'application/pgp' && !$recursive) { -- cgit v1.2.3 From a8ffab3f4ff54af41c9041a30eb989954d6ffc17 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 19 Dec 2012 14:15:11 +0100 Subject: Fix Call to undefined method rcube_db_sqlite::_get_result() --- program/lib/Roundcube/rcube_db_sqlite.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_db_sqlite.php b/program/lib/Roundcube/rcube_db_sqlite.php index 326c6a710..145b8a371 100644 --- a/program/lib/Roundcube/rcube_db_sqlite.php +++ b/program/lib/Roundcube/rcube_db_sqlite.php @@ -120,12 +120,7 @@ class rcube_db_sqlite extends rcube_db $q = $this->query('SELECT name FROM sqlite_master' .' WHERE type = \'table\' ORDER BY name'); - if ($res = $this->_get_result($q)) { - $this->tables = $res->fetchAll(PDO::FETCH_COLUMN, 0); - } - else { - $this->tables = array(); - } + $this->tables = $q ? $q->fetchAll(PDO::FETCH_COLUMN, 0) : array(); } return $this->tables; -- cgit v1.2.3 From a079269166d120bcbcb33d34f4b1c8f60d102e32 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 20 Dec 2012 08:53:48 +0100 Subject: Fix version comparisons with -stable suffix (#1488876) --- CHANGELOG | 1 + bin/installto.sh | 2 +- bin/update.sh | 4 ++-- installer/rcube_install.php | 6 +++--- program/lib/Roundcube/bootstrap.php | 16 ++++++++++++++++ tests/Framework/Bootstrap.php | 8 ++++++++ 6 files changed, 31 insertions(+), 6 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index c4e63aaeb..02e20455c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix version comparisons with -stable suffix (#1488876) - Add unsupported alternative parts to attachments list (#1488870) - Add Compose button on message view page (#1488747) - Display 'Sender' header in message preview diff --git a/bin/installto.sh b/bin/installto.sh index de96bf004..e6cf79d7d 100755 --- a/bin/installto.sh +++ b/bin/installto.sh @@ -35,7 +35,7 @@ if (!preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z-]*)/', $iniset, $m)) $oldversion = $m[1]; -if (version_compare($oldversion, RCMAIL_VERSION, '>=')) +if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '>=')) die("Installation at target location is up-to-date!\n"); echo "Upgrading from $oldversion. Do you want to continue? (y/N)\n"; diff --git a/bin/update.sh b/bin/update.sh index 59aa596dd..2015aa904 100755 --- a/bin/update.sh +++ b/bin/update.sh @@ -34,7 +34,7 @@ if (!$opts['version']) { $opts['version'] = $input; } -if ($opts['version'] && version_compare($opts['version'], RCMAIL_VERSION, '>')) +if ($opts['version'] && version_compare(version_parse($opts['version']), version_parse(RCMAIL_VERSION), '>')) die("Nothing to be done here. Bye!\n"); @@ -169,7 +169,7 @@ if ($RCI->configured) { } // index contacts for fulltext searching - if (version_compare($opts['version'], '0.6', '<')) { + if (version_compare(version_parse($opts['version']), '0.6.0', '<')) { system(INSTALL_PATH . 'bin/indexcontacts.sh'); } diff --git a/installer/rcube_install.php b/installer/rcube_install.php index dfd63562d..530be3ebe 100644 --- a/installer/rcube_install.php +++ b/installer/rcube_install.php @@ -633,8 +633,8 @@ class rcube_install */ function update_db($DB, $version) { - $version = strtolower($version); - $engine = isset($this->db_map[$DB->db_provider]) ? $this->db_map[$DB->db_provider] : $DB->db_provider; + $version = version_parse(strtolower($version)); + $engine = isset($this->db_map[$DB->db_provider]) ? $this->db_map[$DB->db_provider] : $DB->db_provider; // read schema file from /SQL/* $fname = INSTALL_PATH . "SQL/$engine.update.sql"; @@ -643,7 +643,7 @@ class rcube_install foreach ($lines as $line) { $is_comment = preg_match('/^--/', $line); if (!$from && $is_comment && preg_match('/from version\s([0-9.]+[a-z-]*)/', $line, $m)) { - $v = strtolower($m[1]); + $v = version_parse(strtolower($m[1])); if ($v == $version || version_compare($version, $v, '<=')) $from = true; } diff --git a/program/lib/Roundcube/bootstrap.php b/program/lib/Roundcube/bootstrap.php index 18c07ddab..530a7f855 100644 --- a/program/lib/Roundcube/bootstrap.php +++ b/program/lib/Roundcube/bootstrap.php @@ -357,6 +357,22 @@ function format_email($email) } +/** + * Fix version number so it can be used correctly in version_compare() + * + * @param string $version Version number string + * + * @param return Version number string + */ +function version_parse($version) +{ + return str_replace( + array('-stable', '-git'), + array('.0', '.99'), + $version); +} + + /** * mbstring replacement functions */ diff --git a/tests/Framework/Bootstrap.php b/tests/Framework/Bootstrap.php index d18fd371b..904be7e3b 100644 --- a/tests/Framework/Bootstrap.php +++ b/tests/Framework/Bootstrap.php @@ -207,4 +207,12 @@ class Framework_Bootstrap extends PHPUnit_Framework_TestCase $this->assertFalse($result, "Invalid ASCII (UTF-8 character [2])"); } + /** + * bootstrap.php: version_parse() + */ + function test_version_parse() + { + $this->assertEquals('0.9.0', version_parse('0.9-stable')); + $this->assertEquals('0.9.99', version_parse('0.9-git')); + } } -- cgit v1.2.3 From a61326c141816b5365613c206ef9ac350bfd9935 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 20 Dec 2012 19:51:37 +0100 Subject: Fix locking issue in SQLite driver (#1488874) --- program/lib/Roundcube/rcube_db.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index 47ddc81a6..9283bb0d4 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -400,6 +400,10 @@ class rcube_db $this->debug($query); + // destroy reference to previous result, required for SQLite driver (#1488874) + $this->last_result = null; + + // send query $query = $this->dbh->query($query); if ($query === false) { -- cgit v1.2.3 From c4781306a54006727b05a5b8a5414e09c51b8bef Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 21 Dec 2012 09:13:11 +0100 Subject: CS fixes --- program/lib/Roundcube/rcube_plugin.php | 647 +++++++++++---------- program/lib/Roundcube/rcube_plugin_api.php | 891 +++++++++++++++-------------- 2 files changed, 782 insertions(+), 756 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_plugin.php b/program/lib/Roundcube/rcube_plugin.php index 06247d456..66e77cce2 100644 --- a/program/lib/Roundcube/rcube_plugin.php +++ b/program/lib/Roundcube/rcube_plugin.php @@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2009, The Roundcube Dev Team | + | Copyright (C) 2008-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -25,334 +25,353 @@ */ abstract class rcube_plugin { - /** - * Class name of the plugin instance - * - * @var string - */ - public $ID; - - /** - * Instance of Plugin API - * - * @var rcube_plugin_api - */ - public $api; - - /** - * Regular expression defining task(s) to bind with - * - * @var string - */ - public $task; - - /** - * Disables plugin in AJAX requests - * - * @var boolean - */ - public $noajax = false; - - /** - * Disables plugin in framed mode - * - * @var boolean - */ - public $noframe = false; - - protected $home; - protected $urlbase; - private $mytask; - - - /** - * Default constructor. - * - * @param rcube_plugin_api $api Plugin API - */ - public function __construct($api) - { - $this->ID = get_class($this); - $this->api = $api; - $this->home = $api->dir . $this->ID; - $this->urlbase = $api->url . $this->ID . '/'; - } - - /** - * Initialization method, needs to be implemented by the plugin itself - */ - abstract function init(); - - - /** - * Attempt to load the given plugin which is required for the current plugin - * - * @param string Plugin name - * @return boolean True on success, false on failure - */ - public function require_plugin($plugin_name) - { - return $this->api->load_plugin($plugin_name); - } - - - /** - * Load local config file from plugins directory. - * The loaded values are patched over the global configuration. - * - * @param string $fname Config file name relative to the plugin's folder - * @return boolean True on success, false on failure - */ - public function load_config($fname = 'config.inc.php') - { - $fpath = $this->home.'/'.$fname; - $rcube = rcube::get_instance(); - if (is_file($fpath) && !$rcube->config->load_from_file($fpath)) { - rcube::raise_error(array( - 'code' => 527, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Failed to load config from $fpath"), true, false); - return false; + /** + * Class name of the plugin instance + * + * @var string + */ + public $ID; + + /** + * Instance of Plugin API + * + * @var rcube_plugin_api + */ + public $api; + + /** + * Regular expression defining task(s) to bind with + * + * @var string + */ + public $task; + + /** + * Disables plugin in AJAX requests + * + * @var boolean + */ + public $noajax = false; + + /** + * Disables plugin in framed mode + * + * @var boolean + */ + public $noframe = false; + + protected $home; + protected $urlbase; + private $mytask; + + + /** + * Default constructor. + * + * @param rcube_plugin_api $api Plugin API + */ + public function __construct($api) + { + $this->ID = get_class($this); + $this->api = $api; + $this->home = $api->dir . $this->ID; + $this->urlbase = $api->url . $this->ID . '/'; } - return true; - } - - /** - * Register a callback function for a specific (server-side) hook - * - * @param string $hook Hook name - * @param mixed $callback Callback function as string or array with object reference and method name - */ - public function add_hook($hook, $callback) - { - $this->api->register_hook($hook, $callback); - } - - /** - * Unregister a callback function for a specific (server-side) hook. - * - * @param string $hook Hook name - * @param mixed $callback Callback function as string or array with object reference and method name - */ - public function remove_hook($hook, $callback) - { - $this->api->unregister_hook($hook, $callback); - } - - /** - * Load localized texts from the plugins dir - * - * @param string $dir Directory to search in - * @param mixed $add2client Make texts also available on the client (array with list or true for all) - */ - public function add_texts($dir, $add2client = false) - { - $domain = $this->ID; - $lang = $_SESSION['language']; - $langs = array_unique(array('en_US', $lang)); - $locdir = slashify(realpath(slashify($this->home) . $dir)); - $texts = array(); - - // Language aliases used to find localization in similar lang, see below - $aliases = array( - 'de_CH' => 'de_DE', - 'es_AR' => 'es_ES', - 'fa_AF' => 'fa_IR', - 'nl_BE' => 'nl_NL', - 'pt_BR' => 'pt_PT', - 'zh_CN' => 'zh_TW', - ); - - // use buffering to handle empty lines/spaces after closing PHP tag - ob_start(); - - foreach ($langs as $lng) { - $fpath = $locdir . $lng . '.inc'; - if (is_file($fpath) && is_readable($fpath)) { - include $fpath; - $texts = (array)$labels + (array)$messages + (array)$texts; - } - else if ($lng != 'en_US') { - // Find localization in similar language (#1488401) - $alias = null; - if (!empty($aliases[$lng])) { - $alias = $aliases[$lng]; + /** + * Initialization method, needs to be implemented by the plugin itself + */ + abstract function init(); + + /** + * Attempt to load the given plugin which is required for the current plugin + * + * @param string Plugin name + * @return boolean True on success, false on failure + */ + public function require_plugin($plugin_name) + { + return $this->api->load_plugin($plugin_name); + } + + /** + * Load local config file from plugins directory. + * The loaded values are patched over the global configuration. + * + * @param string $fname Config file name relative to the plugin's folder + * + * @return boolean True on success, false on failure + */ + public function load_config($fname = 'config.inc.php') + { + $fpath = $this->home.'/'.$fname; + $rcube = rcube::get_instance(); + + if (is_file($fpath) && !$rcube->config->load_from_file($fpath)) { + rcube::raise_error(array( + 'code' => 527, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Failed to load config from $fpath"), true, false); + return false; } - else if ($key = array_search($lng, $aliases)) { - $alias = $key; + + return true; + } + + /** + * Register a callback function for a specific (server-side) hook + * + * @param string $hook Hook name + * @param mixed $callback Callback function as string or array + * with object reference and method name + */ + public function add_hook($hook, $callback) + { + $this->api->register_hook($hook, $callback); + } + + /** + * Unregister a callback function for a specific (server-side) hook. + * + * @param string $hook Hook name + * @param mixed $callback Callback function as string or array + * with object reference and method name + */ + public function remove_hook($hook, $callback) + { + $this->api->unregister_hook($hook, $callback); + } + + /** + * Load localized texts from the plugins dir + * + * @param string $dir Directory to search in + * @param mixed $add2client Make texts also available on the client + * (array with list or true for all) + */ + public function add_texts($dir, $add2client = false) + { + $domain = $this->ID; + $lang = $_SESSION['language']; + $langs = array_unique(array('en_US', $lang)); + $locdir = slashify(realpath(slashify($this->home) . $dir)); + $texts = array(); + + // Language aliases used to find localization in similar lang, see below + $aliases = array( + 'de_CH' => 'de_DE', + 'es_AR' => 'es_ES', + 'fa_AF' => 'fa_IR', + 'nl_BE' => 'nl_NL', + 'pt_BR' => 'pt_PT', + 'zh_CN' => 'zh_TW', + ); + + // use buffering to handle empty lines/spaces after closing PHP tag + ob_start(); + + foreach ($langs as $lng) { + $fpath = $locdir . $lng . '.inc'; + if (is_file($fpath) && is_readable($fpath)) { + include $fpath; + $texts = (array)$labels + (array)$messages + (array)$texts; + } + else if ($lng != 'en_US') { + // Find localization in similar language (#1488401) + $alias = null; + if (!empty($aliases[$lng])) { + $alias = $aliases[$lng]; + } + else if ($key = array_search($lng, $aliases)) { + $alias = $key; + } + + if (!empty($alias)) { + $fpath = $locdir . $alias . '.inc'; + if (is_file($fpath) && is_readable($fpath)) { + include $fpath; + $texts = (array)$labels + (array)$messages + (array)$texts; + } + } + } } - if (!empty($alias)) { - $fpath = $locdir . $alias . '.inc'; - if (is_file($fpath) && is_readable($fpath)) { - include $fpath; - $texts = (array)$labels + (array)$messages + (array)$texts; - } + ob_end_clean(); + + // prepend domain to text keys and add to the application texts repository + if (!empty($texts)) { + $add = array(); + foreach ($texts as $key => $value) { + $add[$domain.'.'.$key] = $value; + } + + $rcube = rcube::get_instance(); + $rcube->load_language($lang, $add); + + // add labels to client + if ($add2client) { + if (is_array($add2client)) { + $js_labels = array_map(array($this, 'label_map_callback'), $add2client); + } + else { + $js_labels = array_keys($add); + } + $rcube->output->add_label($js_labels); + } } - } } - ob_end_clean(); + /** + * Wrapper for rcube::gettext() adding the plugin ID as domain + * + * @param string $p Message identifier + * + * @return string Localized text + * @see rcube::gettext() + */ + public function gettext($p) + { + return rcube::get_instance()->gettext($p, $this->ID); + } - // prepend domain to text keys and add to the application texts repository - if (!empty($texts)) { - $add = array(); - foreach ($texts as $key => $value) - $add[$domain.'.'.$key] = $value; + /** + * Register this plugin to be responsible for a specific task + * + * @param string $task Task name (only characters [a-z0-9_.-] are allowed) + */ + public function register_task($task) + { + if ($this->api->register_task($task, $this->ID)) { + $this->mytask = $task; + } + } - $rcube = rcube::get_instance(); - $rcube->load_language($lang, $add); + /** + * Register a handler for a specific client-request action + * + * The callback will be executed upon a request like /?_task=mail&_action=plugin.myaction + * + * @param string $action Action name (should be unique) + * @param mixed $callback Callback function as string + * or array with object reference and method name + */ + public function register_action($action, $callback) + { + $this->api->register_action($action, $this->ID, $callback, $this->mytask); + } - // add labels to client - if ($add2client) { - $js_labels = is_array($add2client) ? array_map(array($this, 'label_map_callback'), $add2client) : array_keys($add); - $rcube->output->add_label($js_labels); - } + /** + * Register a handler function for a template object + * + * When parsing a template for display, tags like + * will be replaced by the return value if the registered callback function. + * + * @param string $name Object name (should be unique and start with 'plugin.') + * @param mixed $callback Callback function as string or array with object reference + * and method name + */ + public function register_handler($name, $callback) + { + $this->api->register_handler($name, $this->ID, $callback); } - } - - /** - * Wrapper for rcube::gettext() adding the plugin ID as domain - * - * @param string $p Message identifier - * @return string Localized text - * @see rcube::gettext() - */ - public function gettext($p) - { - return rcube::get_instance()->gettext($p, $this->ID); - } - - /** - * Register this plugin to be responsible for a specific task - * - * @param string $task Task name (only characters [a-z0-9_.-] are allowed) - */ - public function register_task($task) - { - if ($this->api->register_task($task, $this->ID)) - $this->mytask = $task; - } - - /** - * Register a handler for a specific client-request action - * - * The callback will be executed upon a request like /?_task=mail&_action=plugin.myaction - * - * @param string $action Action name (should be unique) - * @param mixed $callback Callback function as string or array with object reference and method name - */ - public function register_action($action, $callback) - { - $this->api->register_action($action, $this->ID, $callback, $this->mytask); - } - - /** - * Register a handler function for a template object - * - * When parsing a template for display, tags like - * will be replaced by the return value if the registered callback function. - * - * @param string $name Object name (should be unique and start with 'plugin.') - * @param mixed $callback Callback function as string or array with object reference and method name - */ - public function register_handler($name, $callback) - { - $this->api->register_handler($name, $this->ID, $callback); - } - - /** - * Make this javascipt file available on the client - * - * @param string $fn File path; absolute or relative to the plugin directory - */ - public function include_script($fn) - { - $this->api->include_script($this->resource_url($fn)); - } - - /** - * Make this stylesheet available on the client - * - * @param string $fn File path; absolute or relative to the plugin directory - */ - public function include_stylesheet($fn) - { - $this->api->include_stylesheet($this->resource_url($fn)); - } - - /** - * Append a button to a certain container - * - * @param array $p Hash array with named parameters (as used in skin templates) - * @param string $container Container name where the buttons should be added to - * @see rcube_remplate::button() - */ - public function add_button($p, $container) - { - if ($this->api->output->type == 'html') { - // fix relative paths - foreach (array('imagepas', 'imageact', 'imagesel') as $key) - if ($p[$key]) - $p[$key] = $this->api->url . $this->resource_url($p[$key]); - - $this->api->add_content($this->api->output->button($p), $container); + + /** + * Make this javascipt file available on the client + * + * @param string $fn File path; absolute or relative to the plugin directory + */ + public function include_script($fn) + { + $this->api->include_script($this->resource_url($fn)); } - } - - /** - * Generate an absolute URL to the given resource within the current - * plugin directory - * - * @param string $fn The file name - * @return string Absolute URL to the given resource - */ - public function url($fn) - { - return $this->api->url . $this->resource_url($fn); - } - - /** - * Make the given file name link into the plugin directory - * - * @param string $fn Filename - */ - private function resource_url($fn) - { - if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn)) - return $this->ID . '/' . $fn; - else - return $fn; - } - - /** - * Provide path to the currently selected skin folder within the plugin directory - * with a fallback to the default skin folder. - * - * @return string Skin path relative to plugins directory - */ - public function local_skin_path() - { - $rcube = rcube::get_instance(); - foreach (array($rcube->config->get('skin'), 'larry') as $skin) { - $skin_path = 'skins/' . $skin; - if (is_dir(realpath(slashify($this->home) . $skin_path))) - break; + + /** + * Make this stylesheet available on the client + * + * @param string $fn File path; absolute or relative to the plugin directory + */ + public function include_stylesheet($fn) + { + $this->api->include_stylesheet($this->resource_url($fn)); } - return $skin_path; - } + /** + * Append a button to a certain container + * + * @param array $p Hash array with named parameters (as used in skin templates) + * @param string $container Container name where the buttons should be added to + * + * @see rcube_remplate::button() + */ + public function add_button($p, $container) + { + if ($this->api->output->type == 'html') { + // fix relative paths + foreach (array('imagepas', 'imageact', 'imagesel') as $key) { + if ($p[$key]) { + $p[$key] = $this->api->url . $this->resource_url($p[$key]); + } + } + + $this->api->add_content($this->api->output->button($p), $container); + } + } - /** - * Callback function for array_map - * - * @param string $key Array key. - * @return string - */ - private function label_map_callback($key) - { - return $this->ID.'.'.$key; - } + /** + * Generate an absolute URL to the given resource within the current + * plugin directory + * + * @param string $fn The file name + * + * @return string Absolute URL to the given resource + */ + public function url($fn) + { + return $this->api->url . $this->resource_url($fn); + } + /** + * Make the given file name link into the plugin directory + * + * @param string $fn Filename + */ + private function resource_url($fn) + { + if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn)) { + return $this->ID . '/' . $fn; + } + else { + return $fn; + } + } + + /** + * Provide path to the currently selected skin folder within the plugin directory + * with a fallback to the default skin folder. + * + * @return string Skin path relative to plugins directory + */ + public function local_skin_path() + { + $rcube = rcube::get_instance(); + foreach (array($rcube->config->get('skin'), 'larry') as $skin) { + $skin_path = 'skins/' . $skin; + if (is_dir(realpath(slashify($this->home) . $skin_path))) { + break; + } + } + + return $skin_path; + } + + /** + * Callback function for array_map + * + * @param string $key Array key. + * @return string + */ + private function label_map_callback($key) + { + return $this->ID.'.'.$key; + } } diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php index b4626441d..8a4cce215 100644 --- a/program/lib/Roundcube/rcube_plugin_api.php +++ b/program/lib/Roundcube/rcube_plugin_api.php @@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2011, The Roundcube Dev Team | + | Copyright (C) 2008-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -17,9 +17,9 @@ */ // location where plugins are loade from -if (!defined('RCUBE_PLUGINS_DIR')) - define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'plugins/'); - +if (!defined('RCUBE_PLUGINS_DIR')) { + define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'plugins/'); +} /** * The plugin loader and global API @@ -29,469 +29,476 @@ if (!defined('RCUBE_PLUGINS_DIR')) */ class rcube_plugin_api { - static protected $instance; - - public $dir; - public $url = 'plugins/'; - public $task = ''; - public $output; - - public $handlers = array(); - protected $plugins = array(); - protected $tasks = array(); - protected $actions = array(); - protected $actionmap = array(); - protected $objectsmap = array(); - protected $template_contents = array(); - protected $active_hook = false; - - // Deprecated names of hooks, will be removed after 0.5-stable release - protected $deprecated_hooks = array( - 'create_user' => 'user_create', - 'kill_session' => 'session_destroy', - 'upload_attachment' => 'attachment_upload', - 'save_attachment' => 'attachment_save', - 'get_attachment' => 'attachment_get', - 'cleanup_attachments' => 'attachments_cleanup', - 'display_attachment' => 'attachment_display', - 'remove_attachment' => 'attachment_delete', - 'outgoing_message_headers' => 'message_outgoing_headers', - 'outgoing_message_body' => 'message_outgoing_body', - 'address_sources' => 'addressbooks_list', - 'get_address_book' => 'addressbook_get', - 'create_contact' => 'contact_create', - 'save_contact' => 'contact_update', - 'contact_save' => 'contact_update', - 'delete_contact' => 'contact_delete', - 'manage_folders' => 'folders_list', - 'list_mailboxes' => 'mailboxes_list', - 'save_preferences' => 'preferences_save', - 'user_preferences' => 'preferences_list', - 'list_prefs_sections' => 'preferences_sections_list', - 'list_identities' => 'identities_list', - 'create_identity' => 'identity_create', - 'delete_identity' => 'identity_delete', - 'save_identity' => 'identity_update', - 'identity_save' => 'identity_update', - // to be removed after 0.8 - 'imap_init' => 'storage_init', - 'mailboxes_list' => 'storage_folders', - 'imap_connect' => 'storage_connect', - ); - - /** - * This implements the 'singleton' design pattern - * - * @return rcube_plugin_api The one and only instance if this class - */ - static function get_instance() - { - if (!self::$instance) { - self::$instance = new rcube_plugin_api(); - } + static protected $instance; + + public $dir; + public $url = 'plugins/'; + public $task = ''; + public $output; + public $handlers = array(); + + protected $plugins = array(); + protected $tasks = array(); + protected $actions = array(); + protected $actionmap = array(); + protected $objectsmap = array(); + protected $template_contents = array(); + protected $active_hook = false; + + // Deprecated names of hooks, will be removed after 0.5-stable release + protected $deprecated_hooks = array( + 'create_user' => 'user_create', + 'kill_session' => 'session_destroy', + 'upload_attachment' => 'attachment_upload', + 'save_attachment' => 'attachment_save', + 'get_attachment' => 'attachment_get', + 'cleanup_attachments' => 'attachments_cleanup', + 'display_attachment' => 'attachment_display', + 'remove_attachment' => 'attachment_delete', + 'outgoing_message_headers' => 'message_outgoing_headers', + 'outgoing_message_body' => 'message_outgoing_body', + 'address_sources' => 'addressbooks_list', + 'get_address_book' => 'addressbook_get', + 'create_contact' => 'contact_create', + 'save_contact' => 'contact_update', + 'contact_save' => 'contact_update', + 'delete_contact' => 'contact_delete', + 'manage_folders' => 'folders_list', + 'list_mailboxes' => 'mailboxes_list', + 'save_preferences' => 'preferences_save', + 'user_preferences' => 'preferences_list', + 'list_prefs_sections' => 'preferences_sections_list', + 'list_identities' => 'identities_list', + 'create_identity' => 'identity_create', + 'delete_identity' => 'identity_delete', + 'save_identity' => 'identity_update', + 'identity_save' => 'identity_update', + // to be removed after 0.8 + 'imap_init' => 'storage_init', + 'mailboxes_list' => 'storage_folders', + 'imap_connect' => 'storage_connect', + ); + + /** + * This implements the 'singleton' design pattern + * + * @return rcube_plugin_api The one and only instance if this class + */ + static function get_instance() + { + if (!self::$instance) { + self::$instance = new rcube_plugin_api(); + } - return self::$instance; - } - - - /** - * Private constructor - */ - protected function __construct() - { - $this->dir = slashify(RCUBE_PLUGINS_DIR); - } - - - /** - * Initialize plugin engine - * - * This has to be done after rcmail::load_gui() or rcmail::json_init() - * was called because plugins need to have access to rcmail->output - * - * @param object rcube Instance of the rcube base class - * @param string Current application task (used for conditional plugin loading) - */ - public function init($app, $task = '') - { - $this->task = $task; - $this->output = $app->output; - - // register an internal hook - $this->register_hook('template_container', array($this, 'template_container_hook')); - - // maybe also register a shudown function which triggers shutdown functions of all plugin objects - } - - - /** - * Load and init all enabled plugins - * - * This has to be done after rcmail::load_gui() or rcmail::json_init() - * was called because plugins need to have access to rcmail->output - * - * @param array List of configured plugins to load - * @param array List of plugins required by the application - */ - public function load_plugins($plugins_enabled, $required_plugins = array()) - { - foreach ($plugins_enabled as $plugin_name) { - $this->load_plugin($plugin_name); + return self::$instance; } - // check existance of all required core plugins - foreach ($required_plugins as $plugin_name) { - $loaded = false; - foreach ($this->plugins as $plugin) { - if ($plugin instanceof $plugin_name) { - $loaded = true; - break; - } - } - - // load required core plugin if no derivate was found - if (!$loaded) - $loaded = $this->load_plugin($plugin_name); - - // trigger fatal error if still not loaded - if (!$loaded) { - rcube::raise_error(array('code' => 520, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Requried plugin $plugin_name was not loaded"), true, true); - } + /** + * Private constructor + */ + protected function __construct() + { + $this->dir = slashify(RCUBE_PLUGINS_DIR); } - } - - /** - * Load the specified plugin - * - * @param string Plugin name - * @return boolean True on success, false if not loaded or failure - */ - public function load_plugin($plugin_name) - { - static $plugins_dir; - - if (!$plugins_dir) { - $dir = dir($this->dir); - $plugins_dir = unslashify($dir->path); + + /** + * Initialize plugin engine + * + * This has to be done after rcmail::load_gui() or rcmail::json_init() + * was called because plugins need to have access to rcmail->output + * + * @param object rcube Instance of the rcube base class + * @param string Current application task (used for conditional plugin loading) + */ + public function init($app, $task = '') + { + $this->task = $task; + $this->output = $app->output; + + // register an internal hook + $this->register_hook('template_container', array($this, 'template_container_hook')); + + // maybe also register a shudown function which triggers + // shutdown functions of all plugin objects } - // plugin already loaded - if ($this->plugins[$plugin_name] || class_exists($plugin_name, false)) - return true; - - $fn = $plugins_dir . DIRECTORY_SEPARATOR . $plugin_name . DIRECTORY_SEPARATOR . $plugin_name . '.php'; - - if (file_exists($fn)) { - include($fn); - - // instantiate class if exists - if (class_exists($plugin_name, false)) { - $plugin = new $plugin_name($this); - // check inheritance... - if (is_subclass_of($plugin, 'rcube_plugin')) { - // ... task, request type and framed mode - if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $this->task)) - && (!$plugin->noajax || (is_object($this->output) && $this->output->type == 'html')) - && (!$plugin->noframe || empty($_REQUEST['_framed'])) - ) { - $plugin->init(); - $this->plugins[$plugin_name] = $plugin; - } - return true; + /** + * Load and init all enabled plugins + * + * This has to be done after rcmail::load_gui() or rcmail::json_init() + * was called because plugins need to have access to rcmail->output + * + * @param array List of configured plugins to load + * @param array List of plugins required by the application + */ + public function load_plugins($plugins_enabled, $required_plugins = array()) + { + foreach ($plugins_enabled as $plugin_name) { + $this->load_plugin($plugin_name); + } + + // check existance of all required core plugins + foreach ($required_plugins as $plugin_name) { + $loaded = false; + foreach ($this->plugins as $plugin) { + if ($plugin instanceof $plugin_name) { + $loaded = true; + break; + } + } + + // load required core plugin if no derivate was found + if (!$loaded) { + $loaded = $this->load_plugin($plugin_name); + } + + // trigger fatal error if still not loaded + if (!$loaded) { + rcube::raise_error(array( + 'code' => 520, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Requried plugin $plugin_name was not loaded"), true, true); + } } - } - else { - rcube::raise_error(array('code' => 520, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "No plugin class $plugin_name found in $fn"), true, false); - } } - else { - rcube::raise_error(array('code' => 520, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Failed to load plugin file $fn"), true, false); + + /** + * Load the specified plugin + * + * @param string Plugin name + * + * @return boolean True on success, false if not loaded or failure + */ + public function load_plugin($plugin_name) + { + static $plugins_dir; + + if (!$plugins_dir) { + $dir = dir($this->dir); + $plugins_dir = unslashify($dir->path); + } + + // plugin already loaded + if ($this->plugins[$plugin_name] || class_exists($plugin_name, false)) { + return true; + } + + $fn = $plugins_dir . DIRECTORY_SEPARATOR . $plugin_name + . DIRECTORY_SEPARATOR . $plugin_name . '.php'; + + if (file_exists($fn)) { + include $fn; + + // instantiate class if exists + if (class_exists($plugin_name, false)) { + $plugin = new $plugin_name($this); + // check inheritance... + if (is_subclass_of($plugin, 'rcube_plugin')) { + // ... task, request type and framed mode + if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $this->task)) + && (!$plugin->noajax || (is_object($this->output) && $this->output->type == 'html')) + && (!$plugin->noframe || empty($_REQUEST['_framed'])) + ) { + $plugin->init(); + $this->plugins[$plugin_name] = $plugin; + } + return true; + } + } + else { + rcube::raise_error(array('code' => 520, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "No plugin class $plugin_name found in $fn"), + true, false); + } + } + else { + rcube::raise_error(array('code' => 520, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Failed to load plugin file $fn"), true, false); + } + + return false; } - return false; - } - - - /** - * Allows a plugin object to register a callback for a certain hook - * - * @param string $hook Hook name - * @param mixed $callback String with global function name or array($obj, 'methodname') - */ - public function register_hook($hook, $callback) - { - if (is_callable($callback)) { - if (isset($this->deprecated_hooks[$hook])) { - rcube::raise_error(array('code' => 522, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Deprecated hook name. ".$hook.' -> '.$this->deprecated_hooks[$hook]), true, false); - $hook = $this->deprecated_hooks[$hook]; - } - $this->handlers[$hook][] = $callback; + /** + * Allows a plugin object to register a callback for a certain hook + * + * @param string $hook Hook name + * @param mixed $callback String with global function name or array($obj, 'methodname') + */ + public function register_hook($hook, $callback) + { + if (is_callable($callback)) { + if (isset($this->deprecated_hooks[$hook])) { + rcube::raise_error(array('code' => 522, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Deprecated hook name. " + . $hook . ' -> ' . $this->deprecated_hooks[$hook]), true, false); + $hook = $this->deprecated_hooks[$hook]; + } + $this->handlers[$hook][] = $callback; + } + else { + rcube::raise_error(array('code' => 521, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Invalid callback function for $hook"), true, false); + } } - else - rcube::raise_error(array('code' => 521, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Invalid callback function for $hook"), true, false); - } - - /** - * Allow a plugin object to unregister a callback. - * - * @param string $hook Hook name - * @param mixed $callback String with global function name or array($obj, 'methodname') - */ - public function unregister_hook($hook, $callback) - { - $callback_id = array_search($callback, $this->handlers[$hook]); - if ($callback_id !== false) { - unset($this->handlers[$hook][$callback_id]); + + /** + * Allow a plugin object to unregister a callback. + * + * @param string $hook Hook name + * @param mixed $callback String with global function name or array($obj, 'methodname') + */ + public function unregister_hook($hook, $callback) + { + $callback_id = array_search($callback, $this->handlers[$hook]); + if ($callback_id !== false) { + unset($this->handlers[$hook][$callback_id]); + } } - } - - - /** - * Triggers a plugin hook. - * This is called from the application and executes all registered handlers - * - * @param string $hook Hook name - * @param array $args Named arguments (key->value pairs) - * @return array The (probably) altered hook arguments - */ - public function exec_hook($hook, $args = array()) - { - if (!is_array($args)) - $args = array('arg' => $args); - - $args += array('abort' => false); - $this->active_hook = $hook; - - foreach ((array)$this->handlers[$hook] as $callback) { - $ret = call_user_func($callback, $args); - if ($ret && is_array($ret)) - $args = $ret + $args; - - if ($args['abort']) - break; + + /** + * Triggers a plugin hook. + * This is called from the application and executes all registered handlers + * + * @param string $hook Hook name + * @param array $args Named arguments (key->value pairs) + * + * @return array The (probably) altered hook arguments + */ + public function exec_hook($hook, $args = array()) + { + if (!is_array($args)) { + $args = array('arg' => $args); + } + + $args += array('abort' => false); + $this->active_hook = $hook; + + foreach ((array)$this->handlers[$hook] as $callback) { + $ret = call_user_func($callback, $args); + if ($ret && is_array($ret)) { + $args = $ret + $args; + } + + if ($args['abort']) { + break; + } + } + + $this->active_hook = false; + return $args; } - $this->active_hook = false; - return $args; - } - - - /** - * Let a plugin register a handler for a specific request - * - * @param string $action Action name (_task=mail&_action=plugin.foo) - * @param string $owner Plugin name that registers this action - * @param mixed $callback Callback: string with global function name or array($obj, 'methodname') - * @param string $task Task name registered by this plugin - */ - public function register_action($action, $owner, $callback, $task = null) - { - // check action name - if ($task) - $action = $task.'.'.$action; - else if (strpos($action, 'plugin.') !== 0) - $action = 'plugin.'.$action; - - // can register action only if it's not taken or registered by myself - if (!isset($this->actionmap[$action]) || $this->actionmap[$action] == $owner) { - $this->actions[$action] = $callback; - $this->actionmap[$action] = $owner; + /** + * Let a plugin register a handler for a specific request + * + * @param string $action Action name (_task=mail&_action=plugin.foo) + * @param string $owner Plugin name that registers this action + * @param mixed $callback Callback: string with global function name or array($obj, 'methodname') + * @param string $task Task name registered by this plugin + */ + public function register_action($action, $owner, $callback, $task = null) + { + // check action name + if ($task) + $action = $task.'.'.$action; + else if (strpos($action, 'plugin.') !== 0) + $action = 'plugin.'.$action; + + // can register action only if it's not taken or registered by myself + if (!isset($this->actionmap[$action]) || $this->actionmap[$action] == $owner) { + $this->actions[$action] = $callback; + $this->actionmap[$action] = $owner; + } + else { + rcube::raise_error(array('code' => 523, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Cannot register action $action;" + ." already taken by another plugin"), true, false); + } } - else { - rcube::raise_error(array('code' => 523, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Cannot register action $action; already taken by another plugin"), true, false); + + /** + * This method handles requests like _task=mail&_action=plugin.foo + * It executes the callback function that was registered with the given action. + * + * @param string $action Action name + */ + public function exec_action($action) + { + if (isset($this->actions[$action])) { + call_user_func($this->actions[$action]); + } + else if (rcube::get_instance()->action != 'refresh') { + rcube::raise_error(array('code' => 524, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "No handler found for action $action"), true, true); + } } - } - - - /** - * This method handles requests like _task=mail&_action=plugin.foo - * It executes the callback function that was registered with the given action. - * - * @param string $action Action name - */ - public function exec_action($action) - { - if (isset($this->actions[$action])) { - call_user_func($this->actions[$action]); + + /** + * Register a handler function for template objects + * + * @param string $name Object name + * @param string $owner Plugin name that registers this action + * @param mixed $callback Callback: string with global function name or array($obj, 'methodname') + */ + public function register_handler($name, $owner, $callback) + { + // check name + if (strpos($name, 'plugin.') !== 0) { + $name = 'plugin.' . $name; + } + + // can register handler only if it's not taken or registered by myself + if (is_object($this->output) + && (!isset($this->objectsmap[$name]) || $this->objectsmap[$name] == $owner) + ) { + $this->output->add_handler($name, $callback); + $this->objectsmap[$name] = $owner; + } + else { + rcube::raise_error(array('code' => 525, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Cannot register template handler $name;" + ." already taken by another plugin or no output object available"), true, false); + } } - else if (rcube::get_instance()->action != 'refresh') { - rcube::raise_error(array('code' => 524, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "No handler found for action $action"), true, true); + + /** + * Register this plugin to be responsible for a specific task + * + * @param string $task Task name (only characters [a-z0-9_.-] are allowed) + * @param string $owner Plugin name that registers this action + */ + public function register_task($task, $owner) + { + // tasks are irrelevant in framework mode + if (!class_exists('rcmail', false)) { + return true; + } + + if ($task != asciiwords($task)) { + rcube::raise_error(array('code' => 526, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Invalid task name: $task." + ." Only characters [a-z0-9_.-] are allowed"), true, false); + } + else if (in_array($task, rcmail::$main_tasks)) { + rcube::raise_error(array('code' => 526, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Cannot register taks $task;" + ." already taken by another plugin or the application itself"), true, false); + } + else { + $this->tasks[$task] = $owner; + rcmail::$main_tasks[] = $task; + return true; + } + + return false; } - } - - - /** - * Register a handler function for template objects - * - * @param string $name Object name - * @param string $owner Plugin name that registers this action - * @param mixed $callback Callback: string with global function name or array($obj, 'methodname') - */ - public function register_handler($name, $owner, $callback) - { - // check name - if (strpos($name, 'plugin.') !== 0) - $name = 'plugin.'.$name; - - // can register handler only if it's not taken or registered by myself - if (is_object($this->output) && (!isset($this->objectsmap[$name]) || $this->objectsmap[$name] == $owner)) { - $this->output->add_handler($name, $callback); - $this->objectsmap[$name] = $owner; + + /** + * Checks whether the given task is registered by a plugin + * + * @param string $task Task name + * + * @return boolean True if registered, otherwise false + */ + public function is_plugin_task($task) + { + return $this->tasks[$task] ? true : false; } - else { - rcube::raise_error(array('code' => 525, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Cannot register template handler $name; already taken by another plugin or no output object available"), true, false); + + /** + * Check if a plugin hook is currently processing. + * Mainly used to prevent loops and recursion. + * + * @param string $hook Hook to check (optional) + * + * @return boolean True if any/the given hook is currently processed, otherwise false + */ + public function is_processing($hook = null) + { + return $this->active_hook && (!$hook || $this->active_hook == $hook); } - } - - - /** - * Register this plugin to be responsible for a specific task - * - * @param string $task Task name (only characters [a-z0-9_.-] are allowed) - * @param string $owner Plugin name that registers this action - */ - public function register_task($task, $owner) - { - // tasks are irrelevant in framework mode - if (!class_exists('rcmail', false)) - return true; - - if ($task != asciiwords($task)) { - rcube::raise_error(array('code' => 526, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Invalid task name: $task. Only characters [a-z0-9_.-] are allowed"), true, false); + + /** + * Include a plugin script file in the current HTML page + * + * @param string $fn Path to script + */ + public function include_script($fn) + { + if (is_object($this->output) && $this->output->type == 'html') { + $src = $this->resource_url($fn); + $this->output->add_header(html::tag('script', + array('type' => "text/javascript", 'src' => $src))); + } } - else if (in_array($task, rcmail::$main_tasks)) { - rcube::raise_error(array('code' => 526, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Cannot register taks $task; already taken by another plugin or the application itself"), true, false); + + /** + * Include a plugin stylesheet in the current HTML page + * + * @param string $fn Path to stylesheet + */ + public function include_stylesheet($fn) + { + if (is_object($this->output) && $this->output->type == 'html') { + $src = $this->resource_url($fn); + $this->output->include_css($src); + } } - else { - $this->tasks[$task] = $owner; - rcmail::$main_tasks[] = $task; - return true; + + /** + * Save the given HTML content to be added to a template container + * + * @param string $html HTML content + * @param string $container Template container identifier + */ + public function add_content($html, $container) + { + $this->template_contents[$container] .= $html . "\n"; } - return false; - } - - - /** - * Checks whether the given task is registered by a plugin - * - * @param string $task Task name - * @return boolean True if registered, otherwise false - */ - public function is_plugin_task($task) - { - return $this->tasks[$task] ? true : false; - } - - - /** - * Check if a plugin hook is currently processing. - * Mainly used to prevent loops and recursion. - * - * @param string $hook Hook to check (optional) - * @return boolean True if any/the given hook is currently processed, otherwise false - */ - public function is_processing($hook = null) - { - return $this->active_hook && (!$hook || $this->active_hook == $hook); - } - - /** - * Include a plugin script file in the current HTML page - * - * @param string $fn Path to script - */ - public function include_script($fn) - { - if (is_object($this->output) && $this->output->type == 'html') { - $src = $this->resource_url($fn); - $this->output->add_header(html::tag('script', array('type' => "text/javascript", 'src' => $src))); + /** + * Returns list of loaded plugins names + * + * @return array List of plugin names + */ + public function loaded_plugins() + { + return array_keys($this->plugins); } - } - - - /** - * Include a plugin stylesheet in the current HTML page - * - * @param string $fn Path to stylesheet - */ - public function include_stylesheet($fn) - { - if (is_object($this->output) && $this->output->type == 'html') { - $src = $this->resource_url($fn); - $this->output->include_css($src); + + /** + * Callback for template_container hooks + * + * @param array $attrib + * @return array + */ + protected function template_container_hook($attrib) + { + $container = $attrib['name']; + return array('content' => $attrib['content'] . $this->template_contents[$container]); } - } - - - /** - * Save the given HTML content to be added to a template container - * - * @param string $html HTML content - * @param string $container Template container identifier - */ - public function add_content($html, $container) - { - $this->template_contents[$container] .= $html . "\n"; - } - - - /** - * Returns list of loaded plugins names - * - * @return array List of plugin names - */ - public function loaded_plugins() - { - return array_keys($this->plugins); - } - - - /** - * Callback for template_container hooks - * - * @param array $attrib - * @return array - */ - protected function template_container_hook($attrib) - { - $container = $attrib['name']; - return array('content' => $attrib['content'] . $this->template_contents[$container]); - } - - - /** - * Make the given file name link into the plugins directory - * - * @param string $fn Filename - * @return string - */ - protected function resource_url($fn) - { - if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn)) - return $this->url . $fn; - else - return $fn; - } + /** + * Make the given file name link into the plugins directory + * + * @param string $fn Filename + * @return string + */ + protected function resource_url($fn) + { + if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn)) + return $this->url . $fn; + else + return $fn; + } } -- cgit v1.2.3 From 679b375a4685ad84456860accdd6d719531c81cf Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 21 Dec 2012 09:50:08 +0100 Subject: Fix comment --- program/lib/Roundcube/rcube_db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index 9283bb0d4..3e4617948 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -426,7 +426,7 @@ class rcube_db * * @param mixed $result Optional query handle * - * @return int Number of rows or false on failure + * @return int Number of (matching) rows */ public function affected_rows($result = null) { -- cgit v1.2.3 From 4fe8f923a99b1c1b26e83e3f4b1e557deb131a34 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 21 Dec 2012 13:50:18 +0100 Subject: Small optimization --- program/js/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index f1df73cee..6295aee06 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1525,16 +1525,16 @@ function rcube_webmail() if (this.preview_read_timer) clearTimeout(this.preview_read_timer); - var selected = list.get_single_selection() != null; + var selected = list.get_single_selection(); - this.enable_command(this.env.message_commands, selected); + this.enable_command(this.env.message_commands, selected != null); if (selected) { // Hide certain command buttons when Drafts folder is selected if (this.env.mailbox == this.env.drafts_mailbox) this.enable_command('reply', 'reply-all', 'reply-list', 'forward', 'forward-attachment', 'forward-inline', false); // Disable reply-list when List-Post header is not set else { - var msg = this.env.messages[list.get_single_selection()]; + var msg = this.env.messages[selected]; if (!msg.ml) this.enable_command('reply-list', false); } -- cgit v1.2.3 From 0a9d414084b5c0bef3b319afeddf7e634333a9b1 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 21 Dec 2012 14:31:35 +0100 Subject: Update changelog, set version to 6.1 --- plugins/managesieve/Changelog | 3 +++ plugins/managesieve/managesieve.php | 2 +- plugins/managesieve/package.xml | 4 ++-- program/js/app.js | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) (limited to 'program') diff --git a/plugins/managesieve/Changelog b/plugins/managesieve/Changelog index aa89e69a3..50e51a6c2 100644 --- a/plugins/managesieve/Changelog +++ b/plugins/managesieve/Changelog @@ -1,7 +1,10 @@ +* version 6.1 [2012-12-21] +----------------------------------------------------------- - Fixed filter activation/deactivation confirmation message (#1488765) - Moved rcube_* classes to /lib/Roundcube for compat. with Roundcube Framework autoloader - Fixed filter selection after filter deletion (#1488832) - Fixed compatibility with jQueryUI-1.9 +- Don't force 'stop' action on last rule in a script * version 6.0 [2012-10-03] ----------------------------------------------------------- diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php index 1d8248ed2..1579d6243 100644 --- a/plugins/managesieve/managesieve.php +++ b/plugins/managesieve/managesieve.php @@ -62,7 +62,7 @@ class managesieve extends rcube_plugin "x-beenthere", ); - const VERSION = '6.0'; + const VERSION = '6.1'; const PROGNAME = 'Roundcube (Managesieve)'; const PORT = 4190; diff --git a/plugins/managesieve/package.xml b/plugins/managesieve/package.xml index e8e8102b0..d4a7af6b8 100644 --- a/plugins/managesieve/package.xml +++ b/plugins/managesieve/package.xml @@ -17,9 +17,9 @@ alec@alec.pl yes - 2012-10-03 + 2012-12-21 - 6.0 + 6.1 6.0 diff --git a/program/js/app.js b/program/js/app.js index 6295aee06..4935dce24 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -990,7 +990,7 @@ function rcube_webmail() if (uid = this.get_single_uid()) { url = {_reply_uid: uid, _mbox: this.env.mailbox}; if (command == 'reply-all') - // do reply-list, when list is detected and popup menu wasn't used + // do reply-list, when list is detected and popup menu wasn't used url._all = (!props && this.commands['reply-list'] ? 'list' : 'all'); else if (command == 'reply-list') url._all = 'list'; -- cgit v1.2.3 From 7d88e614aec9d6dd3bfb6b85c774e2a53b741948 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 22 Dec 2012 15:42:14 +0100 Subject: Add hint about possible disabled fsockopen() function on connection error --- program/lib/Roundcube/rcube_imap_generic.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 112e91350..59a444da7 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -753,12 +753,16 @@ class rcube_imap_generic $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); if (!$this->fp) { + if (!$errstr) { + $errstr = "Unknown reason (fsockopen() function disabled?)"; + } $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr)); return false; } - if ($this->prefs['timeout'] > 0) + if ($this->prefs['timeout'] > 0) { stream_set_timeout($this->fp, $this->prefs['timeout']); + } $line = trim(fgets($this->fp, 8192)); -- cgit v1.2.3 From 090c49d4a3343d346677ed1687ae28697f5b1c6e Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sat, 22 Dec 2012 16:39:47 +0100 Subject: Treat image/pjpeg as image/jpeg --- program/steps/mail/func.inc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index f5165399b..70493766b 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1290,7 +1290,7 @@ function rcmail_part_image_type($part) // Content-Type: image/*... if (preg_match($mime_regex, $part->mimetype)) { - return $part->mimetype; + return rcmail_fix_mimetype($part->mimetype); } // Many clients use application/octet-stream, we'll detect mimetype @@ -1900,6 +1900,10 @@ function rcmail_fix_mimetype($name) if (preg_match('/^application\/pdf.+/', $name)) $name = 'application/pdf'; + // treat image/pjpeg as image/jpeg + else if (preg_match('/^image\/p?jpe?g$/', $name)) + $name = 'image/jpeg'; + return $name; } -- cgit v1.2.3 From 5f0bd1fcb40eae92e747e0e855b77639fd17fc4a Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sat, 22 Dec 2012 16:40:20 +0100 Subject: Make html button-links work in IE --- program/steps/mail/get.inc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'program') diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index 314a437e7..803716d61 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -166,12 +166,11 @@ else if (strlen($pid = get_input_value('_part', RCUBE_INPUT_GET))) { 'vars' => array('expected' => "$mimetype (.$file_extension)", 'detected' => "$real_mimetype (.$extensions[0])") )) . html::p('buttons', - html::tag('button', null, - html::a(array( - 'href' => $RCMAIL->url(array_merge($_GET, array('_nocheck' => 1))), - 'style' => 'text-decoration:none;color:#000', - ), rcube_label('showanyway'))) - )) + html::a(array( + 'href' => $RCMAIL->url(array_merge($_GET, array('_nocheck' => 1))), + 'style' => 'text-decoration:none;color:#000', + ), html::tag('button', null, rcube_label('showanyway')))) + ) ))); exit; } -- cgit v1.2.3 From 0931a97c5fc7231df99fdf4cdeebb525392886ed Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 23 Dec 2012 15:09:56 +0100 Subject: Fix handling of parentheses in URLs --- program/lib/Roundcube/rcube_string_replacer.php | 27 ++++++++++++++++++++++++- tests/Framework/StringReplacer.php | 6 ++++++ 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_string_replacer.php b/program/lib/Roundcube/rcube_string_replacer.php index 0fe982b26..6b289886b 100644 --- a/program/lib/Roundcube/rcube_string_replacer.php +++ b/program/lib/Roundcube/rcube_string_replacer.php @@ -36,7 +36,7 @@ class rcube_string_replacer // Support unicode/punycode in top-level domain part $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.?([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-zA-Z0-9]{2,})'; $url1 = '.:;,'; - $url2 = 'a-zA-Z0-9%=#$@+?!&\\/_~\\[\\]{}\*-'; + $url2 = 'a-zA-Z0-9%=#$@+?!&\\/_~\\[\\]\\(\\){}\*-'; $this->link_pattern = "/([\w]+:\/\/|\W[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)($utf_domain([$url1]?[$url2]+)*)/"; $this->mailto_pattern = "/(" @@ -161,6 +161,9 @@ class rcube_string_replacer // "http://example.com/?a[b]=c". However we need to handle // properly situation when a bracket is placed at the end // of the link e.g. "[http://example.com]" + // Yes, this is not perfect handles correctly only paired characters + // but it should work for common cases + if (preg_match('/(\\[|\\])/', $url)) { $in = false; for ($i=0, $len=strlen($url); $i<$len; $i++) { @@ -182,6 +185,28 @@ class rcube_string_replacer } } + // Do the same for parentheses + if (preg_match('/(\\(|\\))/', $url)) { + $in = false; + for ($i=0, $len=strlen($url); $i<$len; $i++) { + if ($url[$i] == '(') { + if ($in) + break; + $in = true; + } + else if ($url[$i] == ')') { + if (!$in) + break; + $in = false; + } + } + + if ($i < $len) { + $suffix = substr($url, $i); + $url = substr($url, 0, $i); + } + } + return $suffix; } } diff --git a/tests/Framework/StringReplacer.php b/tests/Framework/StringReplacer.php index a76ba00ee..60399cf6b 100644 --- a/tests/Framework/StringReplacer.php +++ b/tests/Framework/StringReplacer.php @@ -29,6 +29,12 @@ class Framework_StringReplacer extends PHPUnit_Framework_TestCase array('Start http://localhost/?foo End', 'Start http://localhost/?foo End'), array('www.domain.tld', 'www.domain.tld'), array('WWW.DOMAIN.TLD', 'WWW.DOMAIN.TLD'), + array('[http://link.com]', '[http://link.com]'), + array('http://link.com?a[]=1', 'http://link.com?a[]=1'), + array('http://link.com?a[]', 'http://link.com?a[]'), + array('(http://link.com)', '(http://link.com)'), + array('http://link.com?a(b)c', 'http://link.com?a(b)c'), + array('http://link.com?(link)', 'http://link.com?(link)'), ); } -- cgit v1.2.3 From 7ac94421bf85eb04c00c5ed05390e1ea0c6bcb0b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 25 Dec 2012 18:06:17 +0100 Subject: Move washtml class into Roundcube Framework (rcube_washtml), add some improvements --- program/include/bc.php | 4 + program/lib/Roundcube/rcube_washtml.php | 451 ++++++++++++++++++++++++++++++++ program/lib/washtml.php | 330 ----------------------- program/steps/mail/func.inc | 68 +---- tests/Framework/Washtml.php | 28 ++ tests/MailFunc.php | 2 +- tests/phpunit.xml | 1 + 7 files changed, 486 insertions(+), 398 deletions(-) create mode 100644 program/lib/Roundcube/rcube_washtml.php delete mode 100644 program/lib/washtml.php create mode 100644 tests/Framework/Washtml.php (limited to 'program') diff --git a/program/include/bc.php b/program/include/bc.php index dc4d54fd7..05d15b9e3 100644 --- a/program/include/bc.php +++ b/program/include/bc.php @@ -408,3 +408,7 @@ function enriched_to_html($data) class rcube_html_page extends rcmail_html_page { } + +class washtml extends rcube_washtml +{ +} diff --git a/program/lib/Roundcube/rcube_washtml.php b/program/lib/Roundcube/rcube_washtml.php new file mode 100644 index 000000000..715c46047 --- /dev/null +++ b/program/lib/Roundcube/rcube_washtml.php @@ -0,0 +1,451 @@ + | + | Author: Aleksander Machniak | + | Author: Frederic Motte | + +-----------------------------------------------------------------------+ + */ + +/** + * Washtml, a HTML sanityzer. + * + * Copyright (c) 2007 Frederic Motte + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * OVERVIEW: + * + * Wahstml take an untrusted HTML and return a safe html string. + * + * SYNOPSIS: + * + * $washer = new washtml($config); + * $washer->wash($html); + * It return a sanityzed string of the $html parameter without html and head tags. + * $html is a string containing the html code to wash. + * $config is an array containing options: + * $config['allow_remote'] is a boolean to allow link to remote images. + * $config['blocked_src'] string with image-src to be used for blocked remote images + * $config['show_washed'] is a boolean to include washed out attributes as x-washed + * $config['cid_map'] is an array where cid urls index urls to replace them. + * $config['charset'] is a string containing the charset of the HTML document if it is not defined in it. + * $washer->extlinks is a reference to a boolean that is set to true if remote images were removed. (FE: show remote images link) + * + * INTERNALS: + * + * Only tags and attributes in the static lists $html_elements and $html_attributes + * are kept, inline styles are also filtered: all style identifiers matching + * /[a-z\-]/i are allowed. Values matching colors, sizes, /[a-z\-]/i and safe + * urls if allowed and cid urls if mapped are kept. + * + * Roundcube Changes: + * - added $block_elements + * - changed $ignore_elements behaviour + * - added RFC2397 support + * - base URL support + * - invalid HTML comments removal before parsing + * - "fixing" unitless CSS values for XHTML output + * - base url resolving + */ + +/** + * Utility class providing HTML sanityzer + * + * @package Framework + * @subpackage Utils + */ +class rcube_washtml +{ + /* Allowed HTML elements (default) */ + static $html_elements = array('a', 'abbr', 'acronym', 'address', 'area', 'b', + 'basefont', 'bdo', 'big', 'blockquote', 'br', 'caption', 'center', + 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', + 'dt', 'em', 'fieldset', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', + 'ins', 'label', 'legend', 'li', 'map', 'menu', 'nobr', 'ol', 'p', 'pre', 'q', + 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', + 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'wbr', 'img', + // form elements + 'button', 'input', 'textarea', 'select', 'option', 'optgroup' + ); + + /* Ignore these HTML tags and their content */ + static $ignore_elements = array('script', 'applet', 'embed', 'object', 'style'); + + /* Allowed HTML attributes */ + static $html_attribs = array('name', 'class', 'title', 'alt', 'width', 'height', + 'align', 'nowrap', 'col', 'row', 'id', 'rowspan', 'colspan', 'cellspacing', + 'cellpadding', 'valign', 'bgcolor', 'color', 'border', 'bordercolorlight', + 'bordercolordark', 'face', 'marginwidth', 'marginheight', 'axis', 'border', + 'abbr', 'char', 'charoff', 'clear', 'compact', 'coords', 'vspace', 'hspace', + 'cellborder', 'size', 'lang', 'dir', 'usemap', 'shape', 'media', + // attributes of form elements + 'type', 'rows', 'cols', 'disabled', 'readonly', 'checked', 'multiple', 'value' + ); + + /* Block elements which could be empty but cannot be returned in short form () */ + static $block_elements = array('div', 'p', 'pre', 'blockquote', 'a', 'font', 'center', + 'table', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'dl', 'strong', + 'i', 'b', 'u', 'span', + ); + + /* State for linked objects in HTML */ + public $extlinks = false; + + /* Current settings */ + private $config = array(); + + /* Registered callback functions for tags */ + private $handlers = array(); + + /* Allowed HTML elements */ + private $_html_elements = array(); + + /* Ignore these HTML tags but process their content */ + private $_ignore_elements = array(); + + /* Block elements which could be empty but cannot be returned in short form () */ + private $_block_elements = array(); + + /* Allowed HTML attributes */ + private $_html_attribs = array(); + + + /** + * Class constructor + */ + public function __construct($p = array()) + { + $this->_html_elements = array_flip((array)$p['html_elements']) + array_flip(self::$html_elements) ; + $this->_html_attribs = array_flip((array)$p['html_attribs']) + array_flip(self::$html_attribs); + $this->_ignore_elements = array_flip((array)$p['ignore_elements']) + array_flip(self::$ignore_elements); + $this->_block_elements = array_flip((array)$p['block_elements']) + array_flip(self::$block_elements); + + unset($p['html_elements'], $p['html_attribs'], $p['ignore_elements'], $p['block_elements']); + + $this->config = $p + array('show_washed' => true, 'allow_remote' => false, 'cid_map' => array()); + } + + /** + * Register a callback function for a certain tag + */ + public function add_callback($tagName, $callback) + { + $this->handlers[$tagName] = $callback; + } + + /** + * Check CSS style + */ + private function wash_style($style) + { + $s = ''; + + foreach (explode(';', $style) as $declaration) { + if (preg_match('/^\s*([a-z\-]+)\s*:\s*(.*)\s*$/i', $declaration, $match)) { + $cssid = $match[1]; + $str = $match[2]; + $value = ''; + + while (sizeof($str) > 0 && + preg_match('/^(url\(\s*[\'"]?([^\'"\)]*)[\'"]?\s*\)'./*1,2*/ + '|rgb\(\s*[0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*\)'. + '|-?[0-9.]+\s*(em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)?'. + '|#[0-9a-f]{3,6}'. + '|[a-z0-9", -]+'. + ')\s*/i', $str, $match) + ) { + if ($match[2]) { + if (($src = $this->config['cid_map'][$match[2]]) + || ($src = $this->config['cid_map'][$this->config['base_url'].$match[2]]) + ) { + $value .= ' url('.htmlspecialchars($src, ENT_QUOTES) . ')'; + } + else if (preg_match('!^(https?:)?//[a-z0-9/._+-]+$!i', $match[2], $url)) { + if ($this->config['allow_remote']) { + $value .= ' url('.htmlspecialchars($url[0], ENT_QUOTES).')'; + } + else { + $this->extlinks = true; + } + } + else if (preg_match('/^data:.+/i', $match[2])) { // RFC2397 + $value .= ' url('.htmlspecialchars($match[2], ENT_QUOTES).')'; + } + } + else { + // whitelist ? + $value .= ' ' . $match[0]; + + // #1488535: Fix size units, so width:800 would be changed to width:800px + if (preg_match('/(left|right|top|bottom|width|height)/i', $cssid) + && preg_match('/^[0-9]+$/', $match[0]) + ) { + $value .= 'px'; + } + } + + $str = substr($str, strlen($match[0])); + } + + if (isset($value[0])) { + $s .= ($s?' ':'') . $cssid . ':' . $value . ';'; + } + } + } + + return $s; + } + + /** + * Take a node and return allowed attributes and check values + */ + private function wash_attribs($node) + { + $t = ''; + $washed = ''; + + foreach ($node->attributes as $key => $plop) { + $key = strtolower($key); + $value = $node->getAttribute($key); + + if (isset($this->_html_attribs[$key]) || + ($key == 'href' && !preg_match('!^(javascript|vbscript|data:text)!i', $value) + && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value)) + ) { + $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"'; + } + else if ($key == 'style' && ($style = $this->wash_style($value))) { + $quot = strpos($style, '"') !== false ? "'" : '"'; + $t .= ' style=' . $quot . $style . $quot; + } + else if ($key == 'background' || ($key == 'src' && strtolower($node->tagName) == 'img')) { //check tagName anyway + if (($src = $this->config['cid_map'][$value]) + || ($src = $this->config['cid_map'][$this->config['base_url'].$value]) + ) { + $t .= ' ' . $key . '="' . htmlspecialchars($src, ENT_QUOTES) . '"'; + } + else if (preg_match('/^(http|https|ftp):.+/i', $value)) { + if ($this->config['allow_remote']) { + $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"'; + } + else { + $this->extlinks = true; + if ($this->config['blocked_src']) { + $t .= ' ' . $key . '="' . htmlspecialchars($this->config['blocked_src'], ENT_QUOTES) . '"'; + } + } + } + else if (preg_match('/^data:.+/i', $value)) { // RFC2397 + $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"'; + } + } + else { + $washed .= ($washed ? ' ' : '') . $key; + } + } + + return $t . ($washed && $this->config['show_washed'] ? ' x-washed="'.$washed.'"' : ''); + } + + /** + * The main loop that recurse on a node tree. + * It output only allowed tags with allowed attributes + * and allowed inline styles + */ + private function dumpHtml($node) + { + if (!$node->hasChildNodes()) { + return ''; + } + + $node = $node->firstChild; + $dump = ''; + + do { + switch($node->nodeType) { + case XML_ELEMENT_NODE: //Check element + $tagName = strtolower($node->tagName); + if ($callback = $this->handlers[$tagName]) { + $dump .= call_user_func($callback, $tagName, + $this->wash_attribs($node), $this->dumpHtml($node), $this); + } + else if (isset($this->_html_elements[$tagName])) { + $content = $this->dumpHtml($node); + $dump .= '<' . $tagName . $this->wash_attribs($node) . + ($content != '' || isset($this->_block_elements[$tagName]) ? ">$content" : ' />'); + } + else if (isset($this->_ignore_elements[$tagName])) { + $dump .= ''; + } + else { + $dump .= ''; + $dump .= $this->dumpHtml($node); // ignore tags not its content + } + break; + + case XML_CDATA_SECTION_NODE: + $dump .= $node->nodeValue; + break; + + case XML_TEXT_NODE: + $dump .= htmlspecialchars($node->nodeValue); + break; + + case XML_HTML_DOCUMENT_NODE: + $dump .= $this->dumpHtml($node); + break; + + case XML_DOCUMENT_TYPE_NODE: + break; + + default: + $dump . ''; + } + } while($node = $node->nextSibling); + + return $dump; + } + + /** + * Main function, give it untrusted HTML, tell it if you allow loading + * remote images and give it a map to convert "cid:" urls. + */ + public function wash($html) + { + // Charset seems to be ignored (probably if defined in the HTML document) + $node = new DOMDocument('1.0', $this->config['charset']); + $this->extlinks = false; + + $html = $this->cleanup($html); + + // Find base URL for images + if (preg_match('/config['base_url'] = $matches[1]; + } + else { + $this->config['base_url'] = ''; + } + + @$node->loadHTML($html); + return $this->dumpHtml($node); + } + + /** + * Getter for config parameters + */ + public function get_config($prop) + { + return $this->config[$prop]; + } + + /** + * Clean HTML input + */ + private function cleanup($html) + { + // special replacements (not properly handled by washtml class) + $html_search = array( + '/(<\/nobr>)(\s+)()/i', // space(s) between + '/]*>[^<]*<\/title>/i', // PHP bug #32547 workaround: remove title tag + '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', // byte-order mark (only outlook?) + '/]+>/i', // washtml/DOMDocument cannot handle xml namespaces + ); + + $html_replace = array( + '\\1'.'   '.'\\3', + '', + '', + '', + ); + $html = preg_replace($html_search, $html_replace, trim($html)); + + // PCRE errors handling (#1486856), should we use something like for every preg_* use? + if ($html === null && ($preg_error = preg_last_error()) != PREG_NO_ERROR) { + $errstr = "Could not clean up HTML message! PCRE Error: $preg_error."; + + if ($preg_error == PREG_BACKTRACK_LIMIT_ERROR) { + $errstr .= " Consider raising pcre.backtrack_limit!"; + } + if ($preg_error == PREG_RECURSION_LIMIT_ERROR) { + $errstr .= " Consider raising pcre.recursion_limit!"; + } + + rcube::raise_error(array('code' => 620, 'type' => 'php', + 'line' => __LINE__, 'file' => __FILE__, + 'message' => $errstr), true, false); + return ''; + } + + // fix (unknown/malformed) HTML tags before "wash" + $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', array($this, 'html_tag_callback'), $html); + + // Remove invalid HTML comments (#1487759) + // Don't remove valid conditional comments + $html = preg_replace('/'; - } - else { - $dump .= ''; - $dump .= $this->dumpHtml($node); // ignore tags not its content - } - break; - case XML_CDATA_SECTION_NODE: - $dump .= $node->nodeValue; - break; - case XML_TEXT_NODE: - $dump .= htmlspecialchars($node->nodeValue); - break; - case XML_HTML_DOCUMENT_NODE: - $dump .= $this->dumpHtml($node); - break; - case XML_DOCUMENT_TYPE_NODE: - break; - default: - $dump . ''; - } - } while($node = $node->nextSibling); - - return $dump; - } - - /* Main function, give it untrusted HTML, tell it if you allow loading - * remote images and give it a map to convert "cid:" urls. */ - public function wash($html) - { - // Charset seems to be ignored (probably if defined in the HTML document) - $node = new DOMDocument('1.0', $this->config['charset']); - $this->extlinks = false; - - // Find base URL for images - if (preg_match('/config['base_url'] = $matches[1]; - else - $this->config['base_url'] = ''; - - // Remove invalid HTML comments (#1487759) - // Don't remove valid conditional comments - $html = preg_replace('/
- + + + + + @@ -75,6 +79,12 @@
+
+
    +
  • +
  • +
+
    -- cgit v1.2.3 From 64afb530a2c80ef54ff6495e427e86c7098df41a Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 11 Jan 2013 15:12:33 +0100 Subject: Fix opener check in extwin (avoid JS errors in IE when opener is gone); always close extwin, even if opener isn't available anymore --- program/js/app.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 2804e88df..de0d2b71a 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -3043,7 +3043,7 @@ function rcube_webmail() ac_props; // close compose step in opener - if (window.opener && opener.rcmail && opener.rcmail.env.action == 'compose') { + if (window.opener && !window.opener.closed && opener.rcmail && opener.rcmail.env.action == 'compose') { setTimeout(function(){ opener.history.back(); }, 100); this.env.opened_extwin = true; } @@ -3713,9 +3713,10 @@ function rcube_webmail() { this.display_message(msg, type); - if (this.env.extwin && window.opener && opener.rcmail) { + if (this.env.extwin) { this.lock_form(this.gui_objects.messageform); - opener.rcmail.display_message(msg, type); + if (window.opener && !window.opener.closed && opener.rcmail) + opener.rcmail.display_message(msg, type); setTimeout(function(){ window.close() }, 1000); } else { -- cgit v1.2.3 From 38b71e78790f5ee80af8f65298f5408998f1769d Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 11 Jan 2013 15:30:43 +0100 Subject: Better check for 'real' links on shift/ctrl clicks --- program/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index de0d2b71a..b1714843b 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -509,7 +509,7 @@ function rcube_webmail() return false; // let the browser handle this click (shift/ctrl usually opens the link in a new window/tab) - if ((obj && obj.href && String(obj.href).indexOf(location.href) < 0) && rcube_event.get_modifier(event)) { + if ((obj && obj.href && String(obj.href).indexOf('#') < 0) && rcube_event.get_modifier(event)) { return true; } -- cgit v1.2.3 From 0b3b66ab127fb534a6941ce89739a7a53be8d9ad Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 11 Jan 2013 19:01:43 +0100 Subject: Fix "Export selected" is inactive after contact delete (#1488906) --- program/js/app.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index b1714843b..686868697 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -4227,12 +4227,10 @@ function rcube_webmail() target = win; this.show_contentframe(true); - // load dummy content - if (!cid) { - // unselect selected row(s) + // load dummy content, unselect selected row(s) + if (!cid) this.contact_list.clear_selection(); - this.enable_command('delete', 'compose', false); - } + this.enable_command('delete', 'compose', 'export-selected', cid); } else if (framed) return false; -- cgit v1.2.3 From 4f9edbd79936c2139d6a20b1121bfc6d8e46a2fa Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Mon, 14 Jan 2013 21:41:02 +0100 Subject: Select 8 KB of message part for headers (to make sure we get them all) --- program/lib/Roundcube/rcube_message.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index 51b2242df..b52b79b25 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -322,7 +322,7 @@ class rcube_message // parse headers from message/rfc822 part if (!isset($structure->headers['subject'])) { - list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 4096)); + list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 8192)); $structure->headers = rcube_mime::parse_headers($headers); } } -- cgit v1.2.3 From b5b76d2ccb8e28183c078d242e1530508b2686ae Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 15 Jan 2013 18:18:11 +0100 Subject: Make sure mimetypes is an array not object in a better way --- program/js/app.js | 2 +- program/steps/mail/show.inc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 686868697..71976096c 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -820,7 +820,7 @@ function rcube_webmail() var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part; // open attachment in frame if it's of a supported mimetype - if (this.env.uid && props.mimetype && this.env.mimetypes && $.inArray(props.mimetype, $.map(this.env.mimetypes, function(v,k){ return v })) >= 0) { + if (this.env.uid && props.mimetype && this.env.mimetypes && $.inArray(props.mimetype, this.env.mimetypes) >= 0) { if (props.mimetype == 'text/html') qstring += '&_safe=1'; this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment'); diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index 64e628880..3495df9c0 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -79,7 +79,7 @@ if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) { } } - $OUTPUT->set_env('mimetypes', $mimetypes); + $OUTPUT->set_env('mimetypes', array_values($mimetypes)); if ($CONFIG['drafts_mbox']) $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']); -- cgit v1.2.3 From 8e8f3b96b51fde1df953de7398b15e0f01e10777 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 17 Jan 2013 18:47:01 +0100 Subject: Fix export of selected contacts from search result (#1488905) --- program/steps/addressbook/export.inc | 70 ++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 14 deletions(-) (limited to 'program') diff --git a/program/steps/addressbook/export.inc b/program/steps/addressbook/export.inc index bf0657b74..fc9f23fa1 100644 --- a/program/steps/addressbook/export.inc +++ b/program/steps/addressbook/export.inc @@ -40,11 +40,31 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search // get records $result = $source->list_records(); - while ($row = $result->next()) { - $row['sourceid'] = $s; - $key = rcmail_contact_key($row, $sort_col); - $records[$key] = $row; + while ($record = $result->next()) { + // because vcard_map is per-source we need to create vcard here + if (empty($record['vcard']) || empty($record['name'])) { + $vcard = new rcube_vcard(); + $vcard->extend_fieldmap($source->vcard_map); + $vcard->load($record['vcard']); + $vcard->reset(); + + foreach ($record as $key => $values) { + list($field, $section) = explode(':', $key); + foreach ((array)$values as $value) { + if (is_array($value) || @strlen($value)) { + $vcard->set($field, $value, strtoupper($section)); + } + } + } + + $record['vcard'] = $vcard->export(true); + } + + $record['sourceid'] = $s; + $key = rcmail_contact_key($record, $sort_col); + $records[$key] = $record; } + unset($result); } @@ -59,17 +79,39 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search // selected contacts else if (!empty($_REQUEST['_cid'])) { $sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name'); - $records = array(); + $records = array(); - $cids = explode(',', get_input_value('_cid', RCUBE_INPUT_GET)); - $CONTACTS = rcmail_contact_source(null, true); + // Selected contact IDs (with multi-source support) + $cids = rcmail_get_cids(); - // Get records from all sources - foreach ($cids as $cid) { - $record = $CONTACTS->get_record($cid, true); - $key = rcmail_contact_key($record, $sort_col); - $records[$key] = $record; - unset($record); + foreach ($cids as $s => $ids) { + $source = $RCMAIL->get_address_book($s); + $result = $source->search('ID', $ids, 1, true, true); + + while ($record = $result->next()) { + // because vcard_map is per-source we need to create vcard here + if (empty($record['vcard']) || empty($record['name'])) { + $vcard = new rcube_vcard(); + $vcard->extend_fieldmap($source->vcard_map); + $vcard->load($record['vcard']); + $vcard->reset(); + + foreach ($record as $key => $values) { + list($field, $section) = explode(':', $key); + foreach ((array)$values as $value) { + if (is_array($value) || @strlen($value)) { + $vcard->set($field, $value, strtoupper($section)); + } + } + } + + $record['vcard'] = $vcard->export(true); + } + + $record['sourceid'] = $s; + $key = rcmail_contact_key($record, $sort_col); + $records[$key] = $record; + } } ksort($records, SORT_LOCALE_STRING); @@ -91,7 +133,7 @@ else { // send downlaod headers header('Content-Type: text/x-vcard; charset='.RCMAIL_CHARSET); -header('Content-Disposition: attachment; filename="rcube_contacts.vcf"'); +header('Content-Disposition: attachment; filename="contacts.vcf"'); while ($result && ($row = $result->next())) { // we already have a vcard record -- cgit v1.2.3 From 4d7964d9101d08b5e7533cea50e52e07bf3f783a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 18 Jan 2013 13:24:52 +0100 Subject: Improved folder path presentation in page title (use unified delimiter, localize path). E.g. folder "INBOX.test" will be displayed as "Inbox >> test" --- program/include/rcmail.php | 23 +++++++++++++++++++++-- program/steps/mail/func.inc | 8 ++++++-- program/steps/mail/list.inc | 1 - 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'program') diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 249bd0559..c734216ac 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1677,12 +1677,31 @@ class rcmail extends rcube * Try to localize the given IMAP folder name. * UTF-7 decode it in case no localized text was found * - * @param string $name Folder name + * @param string $name Folder name + * @param bool $with_path Enable path localization * * @return string Localized folder name in UTF-8 encoding */ - public function localize_foldername($name) + public function localize_foldername($name, $with_path = true) { + // try to localize path of the folder + if ($with_path) { + $storage = $this->get_storage(); + $delimiter = $storage->get_hierarchy_delimiter(); + $path = explode($delimiter, $name); + $count = count($path); + + if ($count > 1) { + for ($i = 1; $i < $count; $i++) { + $folder = implode($delimiter, array_slice($path, 0, -$i)); + if ($folder_class = $this->folder_classname($folder)) { + $name = implode($delimiter, array_slice($path, $count - $i)); + return $this->gettext($folder_class) . $delimiter . rcube_charset::convert($name, 'UTF7-IMAP'); + } + } + } + } + if ($folder_class = $this->folder_classname($name)) { return $this->gettext($folder_class); } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index f82e60a36..6b8879dcf 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -89,11 +89,12 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { } $threading = (bool) $RCMAIL->storage->get_threading(); + $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); // set current mailbox and some other vars in client environment $OUTPUT->set_env('mailbox', $mbox_name); $OUTPUT->set_env('pagesize', $RCMAIL->storage->get_pagesize()); - $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter()); + $OUTPUT->set_env('delimiter', $delimiter); $OUTPUT->set_env('threading', $threading); $OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD')); $OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0)); @@ -121,7 +122,10 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { 'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage', 'copy', 'move', 'quota'); - $OUTPUT->set_pagetitle(rcmail_localize_foldername($RCMAIL->storage->mod_folder($mbox_name))); + $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true); + $pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle); + + $OUTPUT->set_pagetitle($pagetitle); } /** diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index b8c3ee021..a2380131a 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -97,7 +97,6 @@ $OUTPUT->set_env('threading', $threading); $OUTPUT->set_env('current_page', $count ? $RCMAIL->storage->get_page() : 1); $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); -$OUTPUT->command('set_mailboxname', rcmail_get_mailbox_name_text()); // add message rows rcmail_js_message_list($a_headers, FALSE, $cols); -- cgit v1.2.3 From 61be822d62ea245b7f54ad313f49a956ab49076d Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 18 Jan 2013 15:24:49 +0100 Subject: Remove deprecated functions (from bc.php file) usage in plugins --- plugins/acl/acl.php | 42 +-- plugins/archive/archive.php | 4 +- .../database_attachments/database_attachments.php | 10 +- plugins/enigma/enigma.php | 26 +- plugins/enigma/lib/enigma_engine.php | 24 +- plugins/enigma/lib/enigma_ui.php | 26 +- plugins/hide_blockquote/hide_blockquote.php | 2 +- .../http_authentication/http_authentication.php | 2 +- plugins/managesieve/Changelog | 1 + plugins/managesieve/lib/Roundcube/rcube_sieve.php | 2 +- plugins/managesieve/managesieve.php | 354 ++++++++++----------- plugins/markasjunk/markasjunk.php | 4 +- plugins/new_user_dialog/new_user_dialog.php | 16 +- plugins/new_user_identity/new_user_identity.php | 2 +- plugins/newmail_notifier/newmail_notifier.php | 4 +- plugins/password/drivers/chpasswd.php | 2 +- plugins/password/drivers/dbmail.php | 2 +- plugins/password/drivers/directadmin.php | 2 +- plugins/password/drivers/expect.php | 2 +- plugins/password/drivers/hmail.php | 12 +- plugins/password/drivers/ldap.php | 2 +- plugins/password/drivers/ldap_simple.php | 2 +- plugins/password/drivers/pam.php | 4 +- plugins/password/drivers/pw_usermod.php | 2 +- plugins/password/drivers/sasl.php | 2 +- plugins/password/drivers/smb.php | 2 +- plugins/password/drivers/sql.php | 14 +- plugins/password/drivers/virtualmin.php | 2 +- plugins/password/drivers/xmail.php | 4 +- plugins/password/password.php | 32 +- .../squirrelmail_usercopy.php | 16 +- .../subscriptions_option/subscriptions_option.php | 2 +- plugins/userinfo/userinfo.php | 24 +- plugins/vcard_attachments/vcard_attachments.php | 12 +- plugins/virtuser_file/virtuser_file.php | 2 +- plugins/virtuser_query/virtuser_query.php | 62 ++-- plugins/zipdownload/zipdownload.php | 29 +- program/include/rcmail.php | 2 +- 38 files changed, 380 insertions(+), 374 deletions(-) (limited to 'program') diff --git a/plugins/acl/acl.php b/plugins/acl/acl.php index 1952dad49..5ae9e4e0a 100644 --- a/plugins/acl/acl.php +++ b/plugins/acl/acl.php @@ -55,7 +55,7 @@ class acl extends rcube_plugin */ function acl_actions() { - $action = trim(get_input_value('_act', RCUBE_INPUT_GPC)); + $action = trim(rcube_utils::get_input_value('_act', rcube_utils::INPUT_GPC)); // Connect to IMAP $this->rc->storage_init(); @@ -85,8 +85,8 @@ class acl extends rcube_plugin { $this->load_config(); - $search = get_input_value('_search', RCUBE_INPUT_GPC, true); - $sid = get_input_value('_id', RCUBE_INPUT_GPC); + $search = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC, true); + $sid = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC); $users = array(); if ($this->init_ldap()) { @@ -157,12 +157,12 @@ class acl extends rcube_plugin // add Info fieldset if it doesn't exist if (!isset($args['form']['props']['fieldsets']['info'])) $args['form']['props']['fieldsets']['info'] = array( - 'name' => rcube_label('info'), + 'name' => $this->rc->gettext('info'), 'content' => array()); // Display folder rights to 'Info' fieldset $args['form']['props']['fieldsets']['info']['content']['myrights'] = array( - 'label' => Q($this->gettext('myrights')), + 'label' => rcube::Q($this->gettext('myrights')), 'value' => $this->acl2text($myrights) ); @@ -186,7 +186,7 @@ class acl extends rcube_plugin $this->rc->output->add_label('autocompletechars', 'autocompletemore'); $args['form']['sharing'] = array( - 'name' => Q($this->gettext('sharing')), + 'name' => rcube::Q($this->gettext('sharing')), 'content' => $this->rc->output->parse('acl.table', false, false), ); @@ -392,14 +392,14 @@ class acl extends rcube_plugin // filter out virtual rights (c or d) the server may return $userrights = array_intersect($rights, $supported); - $userid = html_identifier($user); + $userid = rcube_utils::html_identifier($user); if (!empty($this->specials) && in_array($user, $this->specials)) { $user = $this->gettext($user); } $table->add_row(array('id' => 'rcmrow'.$userid)); - $table->add('user', Q($user)); + $table->add('user', rcube::Q($user)); foreach ($items as $key => $right) { $in = $this->acl_compare($userrights, $right); @@ -427,10 +427,10 @@ class acl extends rcube_plugin */ private function action_save() { - $mbox = trim(get_input_value('_mbox', RCUBE_INPUT_GPC, true)); // UTF7-IMAP - $user = trim(get_input_value('_user', RCUBE_INPUT_GPC)); - $acl = trim(get_input_value('_acl', RCUBE_INPUT_GPC)); - $oldid = trim(get_input_value('_old', RCUBE_INPUT_GPC)); + $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP + $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC)); + $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); @@ -443,7 +443,7 @@ class acl extends rcube_plugin } else { if (!strpos($user, '@') && ($realm = $this->get_realm())) { - $user .= '@' . rcube_idn_to_ascii(preg_replace('/^@/', '', $realm)); + $user .= '@' . rcube_utils::idn_to_ascii(preg_replace('/^@/', '', $realm)); } $username = $user; } @@ -454,7 +454,7 @@ class acl extends rcube_plugin if ($user != $_SESSION['username'] && $username != $_SESSION['username']) { if ($this->rc->storage->set_acl($mbox, $user, $acl)) { - $ret = array('id' => html_identifier($user), + $ret = array('id' => rcube_utils::html_identifier($user), 'username' => $username, 'acl' => implode($acl), 'old' => $oldid); $this->rc->output->command('acl_update', $ret); $result++; @@ -475,15 +475,15 @@ class acl extends rcube_plugin */ private function action_delete() { - $mbox = trim(get_input_value('_mbox', RCUBE_INPUT_GPC, true)); //UTF7-IMAP - $user = trim(get_input_value('_user', RCUBE_INPUT_GPC)); + $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); //UTF7-IMAP + $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC)); $user = explode(',', $user); foreach ($user as $u) { $u = trim($u); if ($this->rc->storage->delete_acl($mbox, $u)) { - $this->rc->output->command('acl_remove_row', html_identifier($u)); + $this->rc->output->command('acl_remove_row', rcube_utils::html_identifier($u)); } else { $error = true; @@ -507,8 +507,8 @@ class acl extends rcube_plugin return; } - $this->mbox = trim(get_input_value('_mbox', RCUBE_INPUT_GPC, true)); // UTF7-IMAP - $advanced = trim(get_input_value('_mode', RCUBE_INPUT_GPC)); + $this->mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP + $advanced = trim(rcube_utils::get_input_value('_mode', rcube_utils::INPUT_GPC)); $advanced = $advanced == 'advanced' ? true : false; // Save state in user preferences @@ -543,12 +543,12 @@ class acl extends rcube_plugin foreach ($supported as $right) { if (in_array($right, $rights)) { - $list[] = html::tag('li', null, Q($this->gettext('acl' . $right))); + $list[] = html::tag('li', null, rcube::Q($this->gettext('acl' . $right))); } } if (count($list) == count($supported)) - return Q($this->gettext('aclfull')); + return rcube::Q($this->gettext('aclfull')); return html::tag('ul', $attrib, implode("\n", $list)); } diff --git a/plugins/archive/archive.php b/plugins/archive/archive.php index 0a298cbe3..9b03cb186 100644 --- a/plugins/archive/archive.php +++ b/plugins/archive/archive.php @@ -104,7 +104,7 @@ class archive extends rcube_plugin // load folders list when needed if ($CURR_SECTION) - $select = rcmail_mailbox_select(array('noselection' => '---', 'realnames' => true, + $select = $rcmail->folder_selector(array('noselection' => '---', 'realnames' => true, 'maxlength' => 30, 'exceptions' => array('INBOX'), 'folder_filter' => 'mail', 'folder_rights' => 'w')); else $select = new html_select(); @@ -121,7 +121,7 @@ class archive extends rcube_plugin function save_prefs($args) { if ($args['section'] == 'folders') { - $args['prefs']['archive_mbox'] = get_input_value('_archive_mbox', RCUBE_INPUT_POST); + $args['prefs']['archive_mbox'] = rcube_utils::get_input_value('_archive_mbox', rcube_utils::INPUT_POST); return $args; } } diff --git a/plugins/database_attachments/database_attachments.php b/plugins/database_attachments/database_attachments.php index 079f4e567..2511dbbb2 100644 --- a/plugins/database_attachments/database_attachments.php +++ b/plugins/database_attachments/database_attachments.php @@ -46,7 +46,7 @@ class database_attachments extends filesystem_attachments $data = base64_encode($data); $status = $rcmail->db->query( - "INSERT INTO ".get_table_name('cache') + "INSERT INTO ".$rcmail->db->table_name('cache') ." (created, user_id, cache_key, data)" ." VALUES (".$rcmail->db->now().", ?, ?, ?)", $_SESSION['user_id'], @@ -82,7 +82,7 @@ class database_attachments extends filesystem_attachments $data = base64_encode($args['data']); $status = $rcmail->db->query( - "INSERT INTO ".get_table_name('cache') + "INSERT INTO ".$rcmail->db->table_name('cache') ." (created, user_id, cache_key, data)" ." VALUES (".$rcmail->db->now().", ?, ?, ?)", $_SESSION['user_id'], @@ -106,7 +106,7 @@ class database_attachments extends filesystem_attachments $args['status'] = false; $rcmail = rcmail::get_instance(); $status = $rcmail->db->query( - "DELETE FROM ".get_table_name('cache') + "DELETE FROM ".$rcmail->db->table_name('cache') ." WHERE user_id = ?" ." AND cache_key = ?", $_SESSION['user_id'], @@ -139,7 +139,7 @@ class database_attachments extends filesystem_attachments $sql_result = $rcmail->db->query( "SELECT data" - ." FROM ".get_table_name('cache') + ." FROM ".$rcmail->db->table_name('cache') ." WHERE user_id=?" ." AND cache_key=?", $_SESSION['user_id'], @@ -161,7 +161,7 @@ class database_attachments extends filesystem_attachments $prefix = $this->cache_prefix . $args['group']; $rcmail = rcmail::get_instance(); $rcmail->db->query( - "DELETE FROM ".get_table_name('cache') + "DELETE FROM ".$rcmail->db->table_name('cache') ." WHERE user_id = ?" ." AND cache_key LIKE '{$prefix}%'", $_SESSION['user_id']); diff --git a/plugins/enigma/enigma.php b/plugins/enigma/enigma.php index a4009ce26..c96b94620 100644 --- a/plugins/enigma/enigma.php +++ b/plugins/enigma/enigma.php @@ -79,7 +79,7 @@ class enigma extends rcube_plugin $this->register_action('plugin.enigma', array($this, 'preferences_ui')); // grab keys/certs management iframe requests - $section = get_input_value('_section', RCUBE_INPUT_GET); + $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); @@ -230,7 +230,7 @@ class enigma extends rcube_plugin { if ($p['section'] == 'enigmasettings') { $a['prefs'] = array( -// 'dummy' => get_input_value('_dummy', RCUBE_INPUT_POST), +// 'dummy' => rcube_utils::get_input_value('_dummy', rcube_utils::INPUT_POST), ); } @@ -285,16 +285,16 @@ class enigma extends rcube_plugin $attrib['class'] = 'enigmaerror'; $code = $status->getCode(); if ($code == enigma_error::E_KEYNOTFOUND) - $msg = Q(str_replace('$keyid', enigma_key::format_id($status->getData('id')), + $msg = rcube::Q(str_replace('$keyid', enigma_key::format_id($status->getData('id')), $this->gettext('decryptnokey'))); else if ($code == enigma_error::E_BADPASS) - $msg = Q($this->gettext('decryptbadpass')); + $msg = rcube::Q($this->gettext('decryptbadpass')); else - $msg = Q($this->gettext('decrypterror')); + $msg = rcube::Q($this->gettext('decrypterror')); } else { $attrib['class'] = 'enigmanotice'; - $msg = Q($this->gettext('decryptok')); + $msg = rcube::Q($this->gettext('decryptok')); } $p['prefix'] .= html::div($attrib, $msg); @@ -315,27 +315,27 @@ class enigma extends rcube_plugin if ($sig->valid) { $attrib['class'] = 'enigmanotice'; $sender = ($sig->name ? $sig->name . ' ' : '') . '<' . $sig->email . '>'; - $msg = Q(str_replace('$sender', $sender, $this->gettext('sigvalid'))); + $msg = rcube::Q(str_replace('$sender', $sender, $this->gettext('sigvalid'))); } else { $attrib['class'] = 'enigmawarning'; $sender = ($sig->name ? $sig->name . ' ' : '') . '<' . $sig->email . '>'; - $msg = Q(str_replace('$sender', $sender, $this->gettext('siginvalid'))); + $msg = rcube::Q(str_replace('$sender', $sender, $this->gettext('siginvalid'))); } } else if ($sig->getCode() == enigma_error::E_KEYNOTFOUND) { $attrib['class'] = 'enigmawarning'; - $msg = Q(str_replace('$keyid', enigma_key::format_id($sig->getData('id')), + $msg = rcube::Q(str_replace('$keyid', enigma_key::format_id($sig->getData('id')), $this->gettext('signokey'))); } else { $attrib['class'] = 'enigmaerror'; - $msg = Q($this->gettext('sigerror')); + $msg = rcube::Q($this->gettext('sigerror')); } /* $msg .= ' ' . html::a(array('href' => "#sigdetails", - 'onclick' => JS_OBJECT_NAME.".command('enigma-sig-details')"), - Q($this->gettext('showdetails'))); + 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('enigma-sig-details')"), + rcube::Q($this->gettext('showdetails'))); */ // test // $msg .= '
    '.$sig->body.'
    '; @@ -433,7 +433,7 @@ class enigma extends rcube_plugin $p['content'] .= html::p(array('style' => $style), html::a(array( 'href' => "#", - 'onclick' => "return ".JS_OBJECT_NAME.".enigma_import_attachment('".JQ($part)."')", + 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".enigma_import_attachment('".rcube::JQ($part)."')", 'title' => $this->gettext('keyattimport')), html::img(array('src' => $this->url('skins/classic/key_add.png'), 'style' => "vertical-align:middle"))) . ' ' . html::span(null, $this->gettext('keyattfound'))); diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php index 89cb4b796..220d6c0b3 100644 --- a/plugins/enigma/lib/enigma_engine.php +++ b/plugins/enigma/lib/enigma_engine.php @@ -65,7 +65,7 @@ class enigma_engine $this->pgp_driver = new $driver($username); if (!$this->pgp_driver) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: Unable to load PGP driver: $driver" @@ -76,7 +76,7 @@ class enigma_engine $result = $this->pgp_driver->init(); if ($result instanceof enigma_error) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: ".$result->getMessage() @@ -102,7 +102,7 @@ class enigma_engine $this->smime_driver = new $driver($username); if (!$this->smime_driver) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: Unable to load S/MIME driver: $driver" @@ -113,7 +113,7 @@ class enigma_engine $result = $this->smime_driver->init(); if ($result instanceof enigma_error) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: ".$result->getMessage() @@ -378,7 +378,7 @@ class enigma_engine $sig = $this->pgp_driver->verify($msg_body, $sig_body); if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND) - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: " . $error->getMessage() @@ -407,7 +407,7 @@ class enigma_engine if ($result instanceof enigma_error) { $err_code = $result->getCode(); if (!in_array($err_code, array(enigma_error::E_KEYNOTFOUND, enigma_error::E_BADPASS))) - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: " . $result->getMessage() @@ -432,7 +432,7 @@ class enigma_engine $result = $this->pgp_driver->list_keys($pattern); if ($result instanceof enigma_error) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: " . $result->getMessage() @@ -455,7 +455,7 @@ class enigma_engine $result = $this->pgp_driver->get_key($keyid); if ($result instanceof enigma_error) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: " . $result->getMessage() @@ -479,7 +479,7 @@ class enigma_engine $result = $this->pgp_driver->import($content, $isfile); if ($result instanceof enigma_error) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Enigma plugin: " . $result->getMessage() @@ -498,9 +498,9 @@ class enigma_engine */ function import_file() { - $uid = get_input_value('_uid', RCUBE_INPUT_POST); - $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); - $mime_id = get_input_value('_part', RCUBE_INPUT_POST); + $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); if ($uid && $mime_id) { $part = $this->rc->storage->get_message_part($uid, $mime_id); diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index dc3580872..47366b7e8 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -49,7 +49,7 @@ class enigma_ui // Enigma actions if ($this->rc->action == 'plugin.enigma') { - $action = get_input_value('_a', RCUBE_INPUT_GPC); + $action = rcube_utils::get_input_value('_a', rcube_utils::INPUT_GPC); switch ($action) { case 'keyedit': @@ -152,7 +152,7 @@ class enigma_ui $a_show_cols = array('name'); // create XHTML table - $out = rcube_table_output($attrib, array(), $a_show_cols, 'id'); + $out = $this->rc->table_output($attrib, array(), $a_show_cols, 'id'); // set client env $this->rc->output->add_gui_object('keyslist', $attrib['id']); @@ -172,8 +172,8 @@ class enigma_ui $this->enigma->load_engine(); $pagesize = $this->rc->config->get('pagesize', 100); - $page = max(intval(get_input_value('_p', RCUBE_INPUT_GPC)), 1); - $search = get_input_value('_q', RCUBE_INPUT_GPC); + $page = max(intval(rcube_utils::get_input_value('_p', rcube_utils::INPUT_GPC)), 1); + $search = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GPC); // define list of cols to be displayed $a_show_cols = array('name'); @@ -202,7 +202,7 @@ class enigma_ui // Add rows foreach($list as $idx => $key) { $this->rc->output->command('enigma_add_list_row', - array('name' => Q($key->name), 'id' => $key->id)); + array('name' => rcube::Q($key->name), 'id' => $key->id)); } } } @@ -261,7 +261,7 @@ class enigma_ui */ private function key_info() { - $id = get_input_value('_id', RCUBE_INPUT_GET); + $id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GET); $this->enigma->load_engine(); $res = $this->enigma->engine->get_key($id); @@ -288,7 +288,7 @@ class enigma_ui */ function tpl_key_name($attrib) { - return Q($this->data->name); + return rcube::Q($this->data->name); } /** @@ -301,7 +301,7 @@ class enigma_ui // Key user ID $table->add('title', $this->enigma->gettext('keyuserid')); - $table->add(null, Q($this->data->name)); + $table->add(null, rcube::Q($this->data->name)); // Key ID $table->add('title', $this->enigma->gettext('keyid')); $table->add(null, $this->data->subkeys[0]->get_short_id()); @@ -369,7 +369,7 @@ class enigma_ui else if ($err = $_FILES['_file']['error']) { if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) { $this->rc->output->show_message('filesizeerror', 'error', - array('size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))); + array('size' => $this->rc->show_bytes(parse_bytes(ini_get('upload_max_filesize'))))); } else { $this->rc->output->show_message('fileuploaderror', 'error'); } @@ -394,7 +394,7 @@ class enigma_ui 'id' => 'rcmimportfile', 'size' => 30)); $form = html::p(null, - Q($this->enigma->gettext('keyimporttext'), 'show') + rcube::Q($this->enigma->gettext('keyimporttext'), 'show') . html::br() . html::br() . $upload->show() ); @@ -433,15 +433,15 @@ class enigma_ui $chbox = new html_checkbox(array('value' => 1)); $menu->add(null, html::label(array('for' => 'enigmadefaultopt'), - Q($this->enigma->gettext('identdefault')))); + rcube::Q($this->enigma->gettext('identdefault')))); $menu->add(null, $chbox->show(1, array('name' => '_enigma_default', 'id' => 'enigmadefaultopt'))); $menu->add(null, html::label(array('for' => 'enigmasignopt'), - Q($this->enigma->gettext('signmsg')))); + rcube::Q($this->enigma->gettext('signmsg')))); $menu->add(null, $chbox->show(1, array('name' => '_enigma_sign', 'id' => 'enigmasignopt'))); $menu->add(null, html::label(array('for' => 'enigmacryptopt'), - Q($this->enigma->gettext('encryptmsg')))); + rcube::Q($this->enigma->gettext('encryptmsg')))); $menu->add(null, $chbox->show(1, array('name' => '_enigma_crypt', 'id' => 'enigmacryptopt'))); $menu = html::div(array('id' => 'enigmamenu', 'class' => 'popupmenu'), diff --git a/plugins/hide_blockquote/hide_blockquote.php b/plugins/hide_blockquote/hide_blockquote.php index 7af163dcd..1168656fd 100644 --- a/plugins/hide_blockquote/hide_blockquote.php +++ b/plugins/hide_blockquote/hide_blockquote.php @@ -69,7 +69,7 @@ class hide_blockquote extends rcube_plugin function save_prefs($args) { if ($args['section'] == 'mailview') { - $args['prefs']['hide_blockquote_limit'] = (int) get_input_value('_hide_blockquote_limit', RCUBE_INPUT_POST); + $args['prefs']['hide_blockquote_limit'] = (int) rcube_utils::get_input_value('_hide_blockquote_limit', rcube_utils::INPUT_POST); } return $args; diff --git a/plugins/http_authentication/http_authentication.php b/plugins/http_authentication/http_authentication.php index a94b6121a..57227cb03 100644 --- a/plugins/http_authentication/http_authentication.php +++ b/plugins/http_authentication/http_authentication.php @@ -53,7 +53,7 @@ class http_authentication extends rcube_plugin $host = rcmail::get_instance()->config->get('http_authentication_host'); if (is_string($host) && trim($host) !== '') - $args['host'] = rcube_idn_to_ascii(rcube_parse_host($host)); + $args['host'] = rcube_utils::idn_to_ascii(rcube_utils::parse_host($host)); // Allow entering other user data in login form, // e.g. after log out (#1487953) diff --git a/plugins/managesieve/Changelog b/plugins/managesieve/Changelog index 19799a302..d8baf63ef 100644 --- a/plugins/managesieve/Changelog +++ b/plugins/managesieve/Changelog @@ -1,4 +1,5 @@ - Support tls:// prefix in managesieve_host option +- Removed depracated functions usage * version 6.1 [2012-12-21] ----------------------------------------------------------- diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve.php b/plugins/managesieve/lib/Roundcube/rcube_sieve.php index 4f66bf029..736f73146 100644 --- a/plugins/managesieve/lib/Roundcube/rcube_sieve.php +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve.php @@ -379,6 +379,6 @@ class rcube_sieve */ public function debug_handler(&$sieve, $message) { - write_log('sieve', preg_replace('/\r\n$/', '', $message)); + rcube::write_log('sieve', preg_replace('/\r\n$/', '', $message)); } } diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php index d30404ac7..8f50cd5a2 100644 --- a/plugins/managesieve/managesieve.php +++ b/plugins/managesieve/managesieve.php @@ -205,8 +205,8 @@ class managesieve extends rcube_plugin $port = $this->rc->config->get('managesieve_port'); $tls = $this->rc->config->get('managesieve_usetls', false); - $host = rcube_parse_host($host); - $host = rcube_idn_to_ascii($host); + $host = rcube_utils::parse_host($host); + $host = rcube_utils::idn_to_ascii($host); // remove tls:// prefix, set TLS flag if (($host = preg_replace('|^tls://|i', '', $host, 1, $cnt)) && $cnt) { @@ -252,7 +252,7 @@ class managesieve extends rcube_plugin $list = $this->list_scripts(); if (!empty($_GET['_set']) || !empty($_POST['_set'])) { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true); } else if (!empty($_SESSION['managesieve_current'])) { $script_name = $_SESSION['managesieve_current']; @@ -304,7 +304,7 @@ class managesieve extends rcube_plugin break; } - raise_error(array('code' => 403, 'type' => 'php', + rcube::raise_error(array('code' => 403, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Unable to connect to managesieve on $host:$port"), true, false); @@ -329,8 +329,8 @@ class managesieve extends rcube_plugin $error = $this->managesieve_start(); // Handle user requests - if ($action = get_input_value('_act', RCUBE_INPUT_GPC)) { - $fid = (int) get_input_value('_fid', RCUBE_INPUT_POST); + if ($action = rcube_utils::get_input_value('_act', rcube_utils::INPUT_GPC)) { + $fid = (int) rcube_utils::get_input_value('_fid', rcube_utils::INPUT_POST); if ($action == 'delete' && !$error) { if (isset($this->script[$fid])) { @@ -347,7 +347,7 @@ class managesieve extends rcube_plugin } else if ($action == 'move' && !$error) { if (isset($this->script[$fid])) { - $to = (int) get_input_value('_to', RCUBE_INPUT_POST); + $to = (int) rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST); $rule = $this->script[$fid]; // remove rule @@ -408,7 +408,7 @@ class managesieve extends rcube_plugin } } else if ($action == 'setact' && !$error) { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true); $result = $this->activate_script($script_name); $kep14 = $this->rc->config->get('managesieve_kolab_master'); @@ -422,7 +422,7 @@ class managesieve extends rcube_plugin } } else if ($action == 'deact' && !$error) { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true); $result = $this->deactivate_script($script_name); if ($result === true) { @@ -435,7 +435,7 @@ class managesieve extends rcube_plugin } } else if ($action == 'setdel' && !$error) { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true); $result = $this->remove_script($script_name); if ($result === true) { @@ -448,7 +448,7 @@ class managesieve extends rcube_plugin } } else if ($action == 'setget') { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true); $script = $this->sieve->get_script($script_name); if (PEAR::isError($script)) @@ -479,14 +479,14 @@ class managesieve extends rcube_plugin $this->rc->output->command('managesieve_updatelist', 'list', array('list' => $result)); } else if ($action == 'ruleadd') { - $rid = get_input_value('_rid', RCUBE_INPUT_GPC); + $rid = rcube_utils::get_input_value('_rid', rcube_utils::INPUT_GPC); $id = $this->genid(); $content = $this->rule_div($fid, $id, false); $this->rc->output->command('managesieve_rulefill', $content, $id, $rid); } else if ($action == 'actionadd') { - $aid = get_input_value('_aid', RCUBE_INPUT_GPC); + $aid = rcube_utils::get_input_value('_aid', rcube_utils::INPUT_GPC); $id = $this->genid(); $content = $this->action_div($fid, $id, false); @@ -497,7 +497,7 @@ class managesieve extends rcube_plugin } else if ($this->rc->task == 'mail') { // Initialize the form - $rules = get_input_value('r', RCUBE_INPUT_GET); + $rules = rcube_utils::get_input_value('r', rcube_utils::INPUT_GET); if (!empty($rules)) { $i = 0; foreach ($rules as $rule) { @@ -570,9 +570,9 @@ class managesieve extends rcube_plugin } // filters set add action else if (!empty($_POST['_newset'])) { - $name = get_input_value('_name', RCUBE_INPUT_POST, true); - $copy = get_input_value('_copy', RCUBE_INPUT_POST, true); - $from = get_input_value('_from', RCUBE_INPUT_POST); + $name = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true); + $copy = rcube_utils::get_input_value('_copy', rcube_utils::INPUT_POST, true); + $from = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST); $exceptions = $this->rc->config->get('managesieve_filename_exceptions'); $kolab = $this->rc->config->get('managesieve_kolab_master'); $name_uc = mb_strtolower($name); @@ -609,9 +609,9 @@ class managesieve extends rcube_plugin $err = $_FILES['_file']['error']; if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) { - $msg = rcube_label(array('name' => 'filesizeerror', + $msg = $this->rc->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => - show_bytes(parse_bytes(ini_get('upload_max_filesize')))))); + $this->rc->show_bytes(parse_bytes(ini_get('upload_max_filesize')))))); } else { $this->errors['file'] = $this->gettext('fileuploaderror'); @@ -640,40 +640,40 @@ class managesieve extends rcube_plugin } // filter add/edit action else if (isset($_POST['_name'])) { - $name = trim(get_input_value('_name', RCUBE_INPUT_POST, true)); - $fid = trim(get_input_value('_fid', RCUBE_INPUT_POST)); - $join = trim(get_input_value('_join', RCUBE_INPUT_POST)); + $name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true)); + $fid = trim(rcube_utils::get_input_value('_fid', rcube_utils::INPUT_POST)); + $join = trim(rcube_utils::get_input_value('_join', rcube_utils::INPUT_POST)); // and arrays - $headers = get_input_value('_header', RCUBE_INPUT_POST); - $cust_headers = get_input_value('_custom_header', RCUBE_INPUT_POST); - $ops = get_input_value('_rule_op', RCUBE_INPUT_POST); - $sizeops = get_input_value('_rule_size_op', RCUBE_INPUT_POST); - $sizeitems = get_input_value('_rule_size_item', RCUBE_INPUT_POST); - $sizetargets = get_input_value('_rule_size_target', RCUBE_INPUT_POST); - $targets = get_input_value('_rule_target', RCUBE_INPUT_POST, true); - $mods = get_input_value('_rule_mod', RCUBE_INPUT_POST); - $mod_types = get_input_value('_rule_mod_type', RCUBE_INPUT_POST); - $body_trans = get_input_value('_rule_trans', RCUBE_INPUT_POST); - $body_types = get_input_value('_rule_trans_type', RCUBE_INPUT_POST, true); - $comparators = get_input_value('_rule_comp', RCUBE_INPUT_POST); - $act_types = get_input_value('_action_type', RCUBE_INPUT_POST, true); - $mailboxes = get_input_value('_action_mailbox', RCUBE_INPUT_POST, true); - $act_targets = get_input_value('_action_target', RCUBE_INPUT_POST, true); - $area_targets = get_input_value('_action_target_area', RCUBE_INPUT_POST, true); - $reasons = get_input_value('_action_reason', RCUBE_INPUT_POST, true); - $addresses = get_input_value('_action_addresses', RCUBE_INPUT_POST, true); - $days = get_input_value('_action_days', RCUBE_INPUT_POST); - $subject = get_input_value('_action_subject', RCUBE_INPUT_POST, true); - $flags = get_input_value('_action_flags', RCUBE_INPUT_POST); - $varnames = get_input_value('_action_varname', RCUBE_INPUT_POST); - $varvalues = get_input_value('_action_varvalue', RCUBE_INPUT_POST); - $varmods = get_input_value('_action_varmods', RCUBE_INPUT_POST); - $notifyaddrs = get_input_value('_action_notifyaddress', RCUBE_INPUT_POST); - $notifybodies = get_input_value('_action_notifybody', RCUBE_INPUT_POST); - $notifymessages = get_input_value('_action_notifymessage', RCUBE_INPUT_POST); - $notifyfrom = get_input_value('_action_notifyfrom', RCUBE_INPUT_POST); - $notifyimp = get_input_value('_action_notifyimportance', RCUBE_INPUT_POST); + $headers = rcube_utils::get_input_value('_header', rcube_utils::INPUT_POST); + $cust_headers = rcube_utils::get_input_value('_custom_header', rcube_utils::INPUT_POST); + $ops = rcube_utils::get_input_value('_rule_op', rcube_utils::INPUT_POST); + $sizeops = rcube_utils::get_input_value('_rule_size_op', rcube_utils::INPUT_POST); + $sizeitems = rcube_utils::get_input_value('_rule_size_item', rcube_utils::INPUT_POST); + $sizetargets = rcube_utils::get_input_value('_rule_size_target', rcube_utils::INPUT_POST); + $targets = rcube_utils::get_input_value('_rule_target', rcube_utils::INPUT_POST, true); + $mods = rcube_utils::get_input_value('_rule_mod', rcube_utils::INPUT_POST); + $mod_types = rcube_utils::get_input_value('_rule_mod_type', rcube_utils::INPUT_POST); + $body_trans = rcube_utils::get_input_value('_rule_trans', rcube_utils::INPUT_POST); + $body_types = rcube_utils::get_input_value('_rule_trans_type', rcube_utils::INPUT_POST, true); + $comparators = rcube_utils::get_input_value('_rule_comp', rcube_utils::INPUT_POST); + $act_types = rcube_utils::get_input_value('_action_type', rcube_utils::INPUT_POST, true); + $mailboxes = rcube_utils::get_input_value('_action_mailbox', rcube_utils::INPUT_POST, true); + $act_targets = rcube_utils::get_input_value('_action_target', rcube_utils::INPUT_POST, true); + $area_targets = rcube_utils::get_input_value('_action_target_area', rcube_utils::INPUT_POST, true); + $reasons = rcube_utils::get_input_value('_action_reason', rcube_utils::INPUT_POST, true); + $addresses = rcube_utils::get_input_value('_action_addresses', rcube_utils::INPUT_POST, true); + $days = rcube_utils::get_input_value('_action_days', rcube_utils::INPUT_POST); + $subject = rcube_utils::get_input_value('_action_subject', rcube_utils::INPUT_POST, true); + $flags = rcube_utils::get_input_value('_action_flags', rcube_utils::INPUT_POST); + $varnames = rcube_utils::get_input_value('_action_varname', rcube_utils::INPUT_POST); + $varvalues = rcube_utils::get_input_value('_action_varvalue', rcube_utils::INPUT_POST); + $varmods = rcube_utils::get_input_value('_action_varmods', rcube_utils::INPUT_POST); + $notifyaddrs = rcube_utils::get_input_value('_action_notifyaddress', rcube_utils::INPUT_POST); + $notifybodies = rcube_utils::get_input_value('_action_notifybody', rcube_utils::INPUT_POST); + $notifymessages = rcube_utils::get_input_value('_action_notifymessage', rcube_utils::INPUT_POST); + $notifyfrom = rcube_utils::get_input_value('_action_notifyfrom', rcube_utils::INPUT_POST); + $notifyimp = rcube_utils::get_input_value('_action_notifyimportance', rcube_utils::INPUT_POST); // we need a "hack" for radiobuttons foreach ($sizeitems as $item) @@ -858,7 +858,7 @@ class managesieve extends rcube_plugin if ($this->form['actions'][$i]['target'] == '') $this->errors['actions'][$i]['target'] = $this->gettext('cannotbeempty'); - else if (!check_email($this->form['actions'][$i]['target'])) + else if (!rcube_utils::check_email($this->form['actions'][$i]['target'])) $this->errors['actions'][$i]['target'] = $this->gettext('noemailwarning'); if ($type == 'redirect_copy') { @@ -895,7 +895,7 @@ class managesieve extends rcube_plugin $address = trim($address); if (!$address) unset($this->form['actions'][$i]['addresses'][$aidx]); - else if(!check_email($address)) { + else if(!rcube_utils::check_email($address)) { $this->errors['actions'][$i]['addresses'] = $this->gettext('noemailwarning'); break; } else @@ -932,10 +932,10 @@ class managesieve extends rcube_plugin if (empty($notifyaddrs[$idx])) { $this->errors['actions'][$i]['address'] = $this->gettext('cannotbeempty'); } - else if (!check_email($notifyaddrs[$idx])) { + else if (!rcube_utils::check_email($notifyaddrs[$idx])) { $this->errors['actions'][$i]['address'] = $this->gettext('noemailwarning'); } - if (!empty($notifyfrom[$idx]) && !check_email($notifyfrom[$idx])) { + if (!empty($notifyfrom[$idx]) && !rcube_utils::check_email($notifyfrom[$idx])) { $this->errors['actions'][$i]['from'] = $this->gettext('noemailwarning'); } $this->form['actions'][$i]['address'] = $notifyaddrs[$idx]; @@ -967,7 +967,7 @@ class managesieve extends rcube_plugin $this->rc->output->command('parent.managesieve_updatelist', isset($new) ? 'add' : 'update', array( - 'name' => Q($this->form['name']), + 'name' => rcube::Q($this->form['name']), 'id' => $fid, 'disabled' => $this->form['disabled'] )); @@ -1016,7 +1016,7 @@ class managesieve extends rcube_plugin $result = $this->list_rules(); // create XHTML table - $out = rcube_table_output($attrib, $result, $a_show_cols, 'id'); + $out = $this->rc->table_output($attrib, $result, $a_show_cols, 'id'); // set client env $this->rc->output->add_gui_object('filterslist', $attrib['id']); @@ -1049,7 +1049,7 @@ class managesieve extends rcube_plugin foreach ($list as $idx => $set) { $scripts['S'.$idx] = $set; $result[] = array( - 'name' => Q($set), + 'name' => rcube::Q($set), 'id' => 'S'.$idx, 'class' => !in_array($set, $this->active) ? 'disabled' : '', ); @@ -1057,7 +1057,7 @@ class managesieve extends rcube_plugin } // create XHTML table - $out = rcube_table_output($attrib, $result, $a_show_cols, 'id'); + $out = $this->rc->table_output($attrib, $result, $a_show_cols, 'id'); $this->rc->output->set_env('filtersets', $scripts); $this->rc->output->include_script('list.js'); @@ -1111,21 +1111,21 @@ class managesieve extends rcube_plugin $out .= $hiddenfields->show(); - $name = get_input_value('_name', RCUBE_INPUT_POST); - $copy = get_input_value('_copy', RCUBE_INPUT_POST); - $selected = get_input_value('_from', RCUBE_INPUT_POST); + $name = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST); + $copy = rcube_utils::get_input_value('_copy', rcube_utils::INPUT_POST); + $selected = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST); // filter set name input $input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30, 'class' => ($this->errors['name'] ? 'error' : ''))); $out .= sprintf(' %s

    ', - '_name', Q($this->gettext('filtersetname')), $input_name->show($name)); + '_name', rcube::Q($this->gettext('filtersetname')), $input_name->show($name)); $out .="\n
    " . $this->gettext('filters') . ":\n"; $out .= ''; - $out .= sprintf(' ', 'from_none', Q($this->gettext('none'))); + $out .= sprintf(' ', 'from_none', rcube::Q($this->gettext('none'))); // filters set list $list = $this->list_scripts(); @@ -1143,7 +1143,7 @@ class managesieve extends rcube_plugin $out .= '
    '; - $out .= sprintf(' ', 'from_set', Q($this->gettext('fromset'))); + $out .= sprintf(' ', 'from_set', rcube::Q($this->gettext('fromset'))); $out .= $select->show($copy); } @@ -1153,7 +1153,7 @@ class managesieve extends rcube_plugin $out .= '
    '; - $out .= sprintf(' ', 'from_file', Q($this->gettext('fromfile'))); + $out .= sprintf(' ', 'from_file', rcube::Q($this->gettext('fromfile'))); $out .= $upload->show(); $out .= '
    '; @@ -1175,7 +1175,7 @@ class managesieve extends rcube_plugin if (!$attrib['id']) $attrib['id'] = 'rcmfilterform'; - $fid = get_input_value('_fid', RCUBE_INPUT_GPC); + $fid = rcube_utils::get_input_value('_fid', rcube_utils::INPUT_GPC); $scr = isset($this->form) ? $this->form : $this->script[$fid]; $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task)); @@ -1204,16 +1204,16 @@ class managesieve extends rcube_plugin $input_name = $input_name->show(); $out .= sprintf("\n %s\n", - $field_id, Q($this->gettext('filtername')), $input_name); + $field_id, rcube::Q($this->gettext('filtername')), $input_name); // filter set selector if ($this->rc->task == 'mail') { $out .= sprintf("\n  %s\n", - $field_id, Q($this->gettext('filterset')), + $field_id, rcube::Q($this->gettext('filterset')), $this->filtersets_list(array('id' => 'sievescriptname'), true)); } - $out .= '

    ' . Q($this->gettext('messagesrules')) . "\n"; + $out .= '

    ' . rcube::Q($this->gettext('messagesrules')) . "\n"; // any, allof, anyof radio buttons $field_id = '_allof'; @@ -1226,7 +1226,7 @@ class managesieve extends rcube_plugin $input_join = $input_join->show(); $out .= sprintf("%s \n", - $input_join, $field_id, Q($this->gettext('filterallof'))); + $input_join, $field_id, rcube::Q($this->gettext('filterallof'))); $field_id = '_anyof'; $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'anyof', @@ -1238,7 +1238,7 @@ class managesieve extends rcube_plugin $input_join = $input_join->show('anyof'); // default $out .= sprintf("%s\n", - $input_join, $field_id, Q($this->gettext('filteranyof'))); + $input_join, $field_id, rcube::Q($this->gettext('filteranyof'))); $field_id = '_any'; $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'any', @@ -1247,7 +1247,7 @@ class managesieve extends rcube_plugin $input_join = $input_join->show($any ? 'any' : ''); $out .= sprintf("%s\n", - $input_join, $field_id, Q($this->gettext('filterany'))); + $input_join, $field_id, rcube::Q($this->gettext('filterany'))); $rows_num = isset($scr) ? sizeof($scr['tests']) : 1; @@ -1259,7 +1259,7 @@ class managesieve extends rcube_plugin $out .= "
    \n"; // actions - $out .= '
    ' . Q($this->gettext('messagesactions')) . "\n"; + $out .= '
    ' . rcube::Q($this->gettext('messagesactions')) . "\n"; $rows_num = isset($scr) ? sizeof($scr['actions']) : 1; @@ -1293,11 +1293,11 @@ class managesieve extends rcube_plugin $select_header = new html_select(array('name' => "_header[]", 'id' => 'header'.$id, 'onchange' => 'rule_header_select(' .$id .')')); foreach($this->headers as $name => $val) - $select_header->add(Q($this->gettext($name)), Q($val)); + $select_header->add(rcube::Q($this->gettext($name)), Q($val)); if (in_array('body', $this->exts)) - $select_header->add(Q($this->gettext('body')), 'body'); - $select_header->add(Q($this->gettext('size')), 'size'); - $select_header->add(Q($this->gettext('...')), '...'); + $select_header->add(rcube::Q($this->gettext('body')), 'body'); + $select_header->add(rcube::Q($this->gettext('size')), 'size'); + $select_header->add(rcube::Q($this->gettext('...')), '...'); // TODO: list arguments $aout = ''; @@ -1337,38 +1337,38 @@ class managesieve extends rcube_plugin $tout = '
    error_class($id, 'test', 'header', 'custom_header_i') - .' value="' .Q($custom). '" size="15" /> 
    ' . "\n"; + .' value="' .rcube::Q($custom). '" size="15" /> 
' . "\n"; // matching type select (operator) $select_op = new html_select(array('name' => "_rule_op[]", 'id' => 'rule_op'.$id, 'style' => 'display:' .($rule['test']!='size' ? 'inline' : 'none'), 'class' => 'operator_selector', 'onchange' => 'rule_op_select('.$id.')')); - $select_op->add(Q($this->gettext('filtercontains')), 'contains'); - $select_op->add(Q($this->gettext('filternotcontains')), 'notcontains'); - $select_op->add(Q($this->gettext('filteris')), 'is'); - $select_op->add(Q($this->gettext('filterisnot')), 'notis'); - $select_op->add(Q($this->gettext('filterexists')), 'exists'); - $select_op->add(Q($this->gettext('filternotexists')), 'notexists'); - $select_op->add(Q($this->gettext('filtermatches')), 'matches'); - $select_op->add(Q($this->gettext('filternotmatches')), 'notmatches'); + $select_op->add(rcube::Q($this->gettext('filtercontains')), 'contains'); + $select_op->add(rcube::Q($this->gettext('filternotcontains')), 'notcontains'); + $select_op->add(rcube::Q($this->gettext('filteris')), 'is'); + $select_op->add(rcube::Q($this->gettext('filterisnot')), 'notis'); + $select_op->add(rcube::Q($this->gettext('filterexists')), 'exists'); + $select_op->add(rcube::Q($this->gettext('filternotexists')), 'notexists'); + $select_op->add(rcube::Q($this->gettext('filtermatches')), 'matches'); + $select_op->add(rcube::Q($this->gettext('filternotmatches')), 'notmatches'); if (in_array('regex', $this->exts)) { - $select_op->add(Q($this->gettext('filterregex')), 'regex'); - $select_op->add(Q($this->gettext('filternotregex')), 'notregex'); + $select_op->add(rcube::Q($this->gettext('filterregex')), 'regex'); + $select_op->add(rcube::Q($this->gettext('filternotregex')), 'notregex'); } if (in_array('relational', $this->exts)) { - $select_op->add(Q($this->gettext('countisgreaterthan')), 'count-gt'); - $select_op->add(Q($this->gettext('countisgreaterthanequal')), 'count-ge'); - $select_op->add(Q($this->gettext('countislessthan')), 'count-lt'); - $select_op->add(Q($this->gettext('countislessthanequal')), 'count-le'); - $select_op->add(Q($this->gettext('countequals')), 'count-eq'); - $select_op->add(Q($this->gettext('countnotequals')), 'count-ne'); - $select_op->add(Q($this->gettext('valueisgreaterthan')), 'value-gt'); - $select_op->add(Q($this->gettext('valueisgreaterthanequal')), 'value-ge'); - $select_op->add(Q($this->gettext('valueislessthan')), 'value-lt'); - $select_op->add(Q($this->gettext('valueislessthanequal')), 'value-le'); - $select_op->add(Q($this->gettext('valueequals')), 'value-eq'); - $select_op->add(Q($this->gettext('valuenotequals')), 'value-ne'); + $select_op->add(rcube::Q($this->gettext('countisgreaterthan')), 'count-gt'); + $select_op->add(rcube::Q($this->gettext('countisgreaterthanequal')), 'count-ge'); + $select_op->add(rcube::Q($this->gettext('countislessthan')), 'count-lt'); + $select_op->add(rcube::Q($this->gettext('countislessthanequal')), 'count-le'); + $select_op->add(rcube::Q($this->gettext('countequals')), 'count-eq'); + $select_op->add(rcube::Q($this->gettext('countnotequals')), 'count-ne'); + $select_op->add(rcube::Q($this->gettext('valueisgreaterthan')), 'value-gt'); + $select_op->add(rcube::Q($this->gettext('valueisgreaterthanequal')), 'value-ge'); + $select_op->add(rcube::Q($this->gettext('valueislessthan')), 'value-lt'); + $select_op->add(rcube::Q($this->gettext('valueislessthanequal')), 'value-le'); + $select_op->add(rcube::Q($this->gettext('valueequals')), 'value-eq'); + $select_op->add(rcube::Q($this->gettext('valuenotequals')), 'value-ne'); } // target input (TODO: lists) @@ -1400,53 +1400,53 @@ class managesieve extends rcube_plugin $tout .= $select_op->show($test); $tout .= 'error_class($id, 'test', 'target', 'rule_target') + value="' .rcube::Q($target). '" size="20" ' . $this->error_class($id, 'test', 'target', 'rule_target') . ' style="display:' . ($rule['test']!='size' && $rule['test'] != 'exists' ? 'inline' : 'none') . '" />'."\n"; $select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id)); - $select_size_op->add(Q($this->gettext('filterover')), 'over'); - $select_size_op->add(Q($this->gettext('filterunder')), 'under'); + $select_size_op->add(rcube::Q($this->gettext('filterover')), 'over'); + $select_size_op->add(rcube::Q($this->gettext('filterunder')), 'under'); $tout .= '
'; $tout .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : ''); $tout .= 'error_class($id, 'test', 'sizetarget', 'rule_size_i') .' /> '.rcube_label('B').' + . (!$sizeitem ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('B').' '.rcube_label('KB').' + . ($sizeitem=='K' ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('KB').' '.rcube_label('MB').' + . ($sizeitem=='M' ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('MB').' '.rcube_label('GB'); + . ($sizeitem=='G' ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('GB'); $tout .= '
'; // Advanced modifiers (address, envelope) $select_mod = new html_select(array('name' => "_rule_mod[]", 'id' => 'rule_mod_op'.$id, 'onchange' => 'rule_mod_select(' .$id .')')); - $select_mod->add(Q($this->gettext('none')), ''); - $select_mod->add(Q($this->gettext('address')), 'address'); + $select_mod->add(rcube::Q($this->gettext('none')), ''); + $select_mod->add(rcube::Q($this->gettext('address')), 'address'); if (in_array('envelope', $this->exts)) - $select_mod->add(Q($this->gettext('envelope')), 'envelope'); + $select_mod->add(rcube::Q($this->gettext('envelope')), 'envelope'); $select_type = new html_select(array('name' => "_rule_mod_type[]", 'id' => 'rule_mod_type'.$id)); - $select_type->add(Q($this->gettext('allparts')), 'all'); - $select_type->add(Q($this->gettext('domain')), 'domain'); - $select_type->add(Q($this->gettext('localpart')), 'localpart'); + $select_type->add(rcube::Q($this->gettext('allparts')), 'all'); + $select_type->add(rcube::Q($this->gettext('domain')), 'domain'); + $select_type->add(rcube::Q($this->gettext('localpart')), 'localpart'); if (in_array('subaddress', $this->exts)) { - $select_type->add(Q($this->gettext('user')), 'user'); - $select_type->add(Q($this->gettext('detail')), 'detail'); + $select_type->add(rcube::Q($this->gettext('user')), 'user'); + $select_type->add(rcube::Q($this->gettext('detail')), 'detail'); } $need_mod = $rule['test'] != 'size' && $rule['test'] != 'body'; $mout = '
'; $mout .= ' '; - $mout .= Q($this->gettext('modifier')) . ' '; + $mout .= rcube::Q($this->gettext('modifier')) . ' '; $mout .= $select_mod->show($rule['test']); $mout .= ''; $mout .= ' '; - $mout .= Q($this->gettext('modtype')) . ' '; + $mout .= rcube::Q($this->gettext('modtype')) . ' '; $mout .= $select_type->show($rule['part']); $mout .= ''; $mout .= '
'; @@ -1454,13 +1454,13 @@ class managesieve extends rcube_plugin // Advanced modifiers (body transformations) $select_mod = new html_select(array('name' => "_rule_trans[]", 'id' => 'rule_trans_op'.$id, 'onchange' => 'rule_trans_select(' .$id .')')); - $select_mod->add(Q($this->gettext('text')), 'text'); - $select_mod->add(Q($this->gettext('undecoded')), 'raw'); - $select_mod->add(Q($this->gettext('contenttype')), 'content'); + $select_mod->add(rcube::Q($this->gettext('text')), 'text'); + $select_mod->add(rcube::Q($this->gettext('undecoded')), 'raw'); + $select_mod->add(rcube::Q($this->gettext('contenttype')), 'content'); $mout .= '
'; $mout .= ' '; - $mout .= Q($this->gettext('modifier')) . ' '; + $mout .= rcube::Q($this->gettext('modifier')) . ' '; $mout .= $select_mod->show($rule['part']); $mout .= ' 'rule_comp_op'.$id)); - $select_comp->add(Q($this->gettext('default')), ''); - $select_comp->add(Q($this->gettext('octet')), 'i;octet'); - $select_comp->add(Q($this->gettext('asciicasemap')), 'i;ascii-casemap'); + $select_comp->add(rcube::Q($this->gettext('default')), ''); + $select_comp->add(rcube::Q($this->gettext('octet')), 'i;octet'); + $select_comp->add(rcube::Q($this->gettext('asciicasemap')), 'i;ascii-casemap'); if (in_array('comparator-i;ascii-numeric', $this->exts)) { - $select_comp->add(Q($this->gettext('asciinumeric')), 'i;ascii-numeric'); + $select_comp->add(rcube::Q($this->gettext('asciinumeric')), 'i;ascii-numeric'); } $mout .= '
'; $mout .= ' '; - $mout .= Q($this->gettext('comparator')) . ' '; + $mout .= rcube::Q($this->gettext('comparator')) . ' '; $mout .= $select_comp->show($rule['comparator']); $mout .= ''; $mout .= '
'; @@ -1489,7 +1489,7 @@ class managesieve extends rcube_plugin $out = $div ? '
'."\n" : ''; $out .= ''; $out .= ''; $out .= ''; @@ -1499,9 +1499,9 @@ class managesieve extends rcube_plugin // add/del buttons $out .= ''; $out .= '
'; - $out .= '  '; $out .= '' . $aout . ''; - $out .= ''; - $out .= ''; $out .= '
'; @@ -1524,31 +1524,31 @@ class managesieve extends rcube_plugin $select_action = new html_select(array('name' => "_action_type[$id]", 'id' => 'action_type'.$id, 'onchange' => 'action_type_select(' .$id .')')); if (in_array('fileinto', $this->exts)) - $select_action->add(Q($this->gettext('messagemoveto')), 'fileinto'); + $select_action->add(rcube::Q($this->gettext('messagemoveto')), 'fileinto'); if (in_array('fileinto', $this->exts) && in_array('copy', $this->exts)) - $select_action->add(Q($this->gettext('messagecopyto')), 'fileinto_copy'); - $select_action->add(Q($this->gettext('messageredirect')), 'redirect'); + $select_action->add(rcube::Q($this->gettext('messagecopyto')), 'fileinto_copy'); + $select_action->add(rcube::Q($this->gettext('messageredirect')), 'redirect'); if (in_array('copy', $this->exts)) - $select_action->add(Q($this->gettext('messagesendcopy')), 'redirect_copy'); + $select_action->add(rcube::Q($this->gettext('messagesendcopy')), 'redirect_copy'); if (in_array('reject', $this->exts)) - $select_action->add(Q($this->gettext('messagediscard')), 'reject'); + $select_action->add(rcube::Q($this->gettext('messagediscard')), 'reject'); else if (in_array('ereject', $this->exts)) - $select_action->add(Q($this->gettext('messagediscard')), 'ereject'); + $select_action->add(rcube::Q($this->gettext('messagediscard')), 'ereject'); if (in_array('vacation', $this->exts)) - $select_action->add(Q($this->gettext('messagereply')), 'vacation'); - $select_action->add(Q($this->gettext('messagedelete')), 'discard'); + $select_action->add(rcube::Q($this->gettext('messagereply')), 'vacation'); + $select_action->add(rcube::Q($this->gettext('messagedelete')), 'discard'); if (in_array('imapflags', $this->exts) || in_array('imap4flags', $this->exts)) { - $select_action->add(Q($this->gettext('setflags')), 'setflag'); - $select_action->add(Q($this->gettext('addflags')), 'addflag'); - $select_action->add(Q($this->gettext('removeflags')), 'removeflag'); + $select_action->add(rcube::Q($this->gettext('setflags')), 'setflag'); + $select_action->add(rcube::Q($this->gettext('addflags')), 'addflag'); + $select_action->add(rcube::Q($this->gettext('removeflags')), 'removeflag'); } if (in_array('variables', $this->exts)) { - $select_action->add(Q($this->gettext('setvariable')), 'set'); + $select_action->add(rcube::Q($this->gettext('setvariable')), 'set'); } if (in_array('enotify', $this->exts) || in_array('notify', $this->exts)) { - $select_action->add(Q($this->gettext('notify')), 'notify'); + $select_action->add(rcube::Q($this->gettext('notify')), 'notify'); } - $select_action->add(Q($this->gettext('rulestop')), 'stop'); + $select_action->add(rcube::Q($this->gettext('rulestop')), 'stop'); $select_type = $action['type']; if (in_array($action['type'], array('fileinto', 'redirect')) && $action['copy']) { @@ -1562,32 +1562,32 @@ class managesieve extends rcube_plugin $out .= ''; // shared targets $out .= 'error_class($id, 'action', 'target', 'action_target') .' />'; $out .= '\n"; // vacation $out .= '
'; - $out .= ''. Q($this->gettext('vacationreason')) .'
' + $out .= ''. rcube::Q($this->gettext('vacationreason')) .'
' .'\n"; - $out .= '
' .Q($this->gettext('vacationsubject')) . '
' + $out .= '
' .rcube::Q($this->gettext('vacationsubject')) . '
' .'error_class($id, 'action', 'subject', 'action_subject') .' />'; - $out .= '
' .Q($this->gettext('vacationaddresses')) . '
' + $out .= '
' .rcube::Q($this->gettext('vacationaddresses')) . '
' .'error_class($id, 'action', 'addresses', 'action_addr') .' />'; - $out .= '
' . Q($this->gettext('vacationdays')) . '
' + $out .= '
' . rcube::Q($this->gettext('vacationdays')) . '
' .'error_class($id, 'action', 'days', 'action_days') .' />'; $out .= '
'; @@ -1607,7 +1607,7 @@ class managesieve extends rcube_plugin foreach ($flags as $fidx => $flag) { $out .= '' - . Q($this->gettext('flag'.$fidx)) .'
'; + . rcube::Q($this->gettext('flag'.$fidx)) .'
'; } $out .= '
'; @@ -1622,42 +1622,42 @@ class managesieve extends rcube_plugin ); $out .= '
'; - $out .= '' .Q($this->gettext('setvarname')) . '
' + $out .= '' .rcube::Q($this->gettext('setvarname')) . '
' .'error_class($id, 'action', 'name', 'action_varname') .' />'; - $out .= '
' .Q($this->gettext('setvarvalue')) . '
' + $out .= '
' .rcube::Q($this->gettext('setvarvalue')) . '
' .'error_class($id, 'action', 'value', 'action_varvalue') .' />'; - $out .= '
' .Q($this->gettext('setvarmodifiers')) . '
'; + $out .= '
' .rcube::Q($this->gettext('setvarmodifiers')) . '
'; foreach ($set_modifiers as $j => $s_m) { $s_m_id = 'action_varmods' . $id . $s_m; $out .= sprintf('%s
', $id, $s_m, $s_m_id, (array_key_exists($s_m, (array)$action) && $action[$s_m] ? ' checked="checked"' : ''), - Q($this->gettext('var' . $s_m))); + rcube::Q($this->gettext('var' . $s_m))); } $out .= '
'; // notify // skip :options tag - not used by the mailto method $out .= '
'; - $out .= '' .Q($this->gettext('notifyaddress')) . '
' + $out .= '' .rcube::Q($this->gettext('notifyaddress')) . '
' .'error_class($id, 'action', 'address', 'action_notifyaddress') .' />'; - $out .= '
'. Q($this->gettext('notifybody')) .'
' + $out .= '
'. rcube::Q($this->gettext('notifybody')) .'
' .'\n"; - $out .= '
' .Q($this->gettext('notifysubject')) . '
' + . rcube::Q($action['body'], 'strict', false) . "\n"; + $out .= '
' .rcube::Q($this->gettext('notifysubject')) . '
' .'error_class($id, 'action', 'message', 'action_notifymessage') .' />'; - $out .= '
' .Q($this->gettext('notifyfrom')) . '
' + $out .= '
' .rcube::Q($this->gettext('notifyfrom')) . '
' .'error_class($id, 'action', 'from', 'action_notifyfrom') .' />'; $importance_options = array( 3 => 'notifyimportancelow', @@ -1669,9 +1669,9 @@ class managesieve extends rcube_plugin 'id' => '_action_notifyimportance' . $id, 'class' => $this->error_class($id, 'action', 'importance', 'action_notifyimportance'))); foreach ($importance_options as $io_v => $io_n) { - $select_importance->add(Q($this->gettext($io_n)), $io_v); + $select_importance->add(rcube::Q($this->gettext($io_n)), $io_v); } - $out .= '
' . Q($this->gettext('notifyimportance')) . '
'; + $out .= '
' . rcube::Q($this->gettext('notifyimportance')) . '
'; $out .= $select_importance->show($action['importance'] ? $action['importance'] : 2); $out .= '
'; @@ -1681,7 +1681,7 @@ class managesieve extends rcube_plugin else $mailbox = ''; - $select = rcmail_mailbox_select(array( + $select = $this->rc->folder_selector(array( 'realnames' => false, 'maxlength' => 100, 'id' => 'action_mailbox' . $id, @@ -1693,9 +1693,9 @@ class managesieve extends rcube_plugin // add/del buttons $out .= ''; - $out .= ''; - $out .= ''; $out .= ''; @@ -1746,7 +1746,7 @@ class managesieve extends rcube_plugin if (empty($this->tips)) return; - $script = JS_OBJECT_NAME.'.managesieve_tip_register('.json_encode($this->tips).');'; + $script = rcmail_output::JS_OBJECT_NAME.'.managesieve_tip_register('.json_encode($this->tips).');'; $this->rc->output->add_script($script, 'foot'); } @@ -1766,12 +1766,12 @@ class managesieve extends rcube_plugin $mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP'); if ($mode == 'out') { - $mailbox = rcube_charset_convert($mailbox, $mbox_encoding, 'UTF7-IMAP'); + $mailbox = rcube_charset::convert($mailbox, $mbox_encoding, 'UTF7-IMAP'); if ($replace_delimiter && $replace_delimiter != $delimiter) $mailbox = str_replace($replace_delimiter, $delimiter, $mailbox); } else { - $mailbox = rcube_charset_convert($mailbox, 'UTF7-IMAP', $mbox_encoding); + $mailbox = rcube_charset::convert($mailbox, 'UTF7-IMAP', $mbox_encoding); if ($replace_delimiter && $replace_delimiter != $delimiter) $mailbox = str_replace($delimiter, $replace_delimiter, $mailbox); } @@ -2039,7 +2039,7 @@ class managesieve extends rcube_plugin $fname = $filter['name'] ? $filter['name'] : "#$i"; $result[] = array( 'id' => $idx, - 'name' => Q($fname), + 'name' => rcube::Q($fname), 'class' => $filter['disabled'] ? 'disabled' : '', ); $i++; diff --git a/plugins/markasjunk/markasjunk.php b/plugins/markasjunk/markasjunk.php index 4db90c1bc..76b14c140 100644 --- a/plugins/markasjunk/markasjunk.php +++ b/plugins/markasjunk/markasjunk.php @@ -45,8 +45,8 @@ class markasjunk extends rcube_plugin $GLOBALS['IMAP_FLAGS']['JUNK'] = 'Junk'; $GLOBALS['IMAP_FLAGS']['NONJUNK'] = 'NonJunk'; - $uids = get_input_value('_uid', RCUBE_INPUT_POST); - $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); + $uids = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST); + $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST); $rcmail = rcmail::get_instance(); $rcmail->storage->unset_flag($uids, 'NONJUNK'); diff --git a/plugins/new_user_dialog/new_user_dialog.php b/plugins/new_user_dialog/new_user_dialog.php index 9c9dcce1c..871384e47 100644 --- a/plugins/new_user_dialog/new_user_dialog.php +++ b/plugins/new_user_dialog/new_user_dialog.php @@ -63,7 +63,7 @@ class new_user_dialog extends rcube_plugin $table->add(null, html::tag('input', array( 'type' => 'text', 'name' => '_email', - 'value' => rcube_idn_to_utf8($identity['email']), + 'value' => rcube_utils::idn_to_utf8($identity['email']), 'disabled' => ($identities_level == 1 || $identities_level == 3) ))); @@ -86,8 +86,8 @@ class new_user_dialog extends rcube_plugin 'id' => 'newuserdialog', 'action' => $rcmail->url('plugin.newusersave'), 'method' => 'post'), - html::tag('h3', null, Q($this->gettext('identitydialogtitle'))) . - html::p('hint', Q($this->gettext('identitydialoghint'))) . + html::tag('h3', null, rcube::Q($this->gettext('identitydialogtitle'))) . + html::p('hint', rcube::Q($this->gettext('identitydialoghint'))) . $table->show() . html::p(array('class' => 'formbuttons'), html::tag('input', array('type' => 'submit', @@ -119,17 +119,17 @@ class new_user_dialog extends rcube_plugin $identities_level = intval($rcmail->config->get('identities_level', 0)); $save_data = array( - 'name' => get_input_value('_name', RCUBE_INPUT_POST), - 'email' => get_input_value('_email', RCUBE_INPUT_POST), - 'organization' => get_input_value('_organization', RCUBE_INPUT_POST), - 'signature' => get_input_value('_signature', RCUBE_INPUT_POST), + 'name' => rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST), + 'email' => rcube_utils::get_input_value('_email', rcube_utils::INPUT_POST), + 'organization' => rcube_utils::get_input_value('_organization', rcube_utils::INPUT_POST), + 'signature' => rcube_utils::get_input_value('_signature', rcube_utils::INPUT_POST), ); // don't let the user alter the e-mail address if disabled by config if ($identities_level == 1 || $identities_level == 3) $save_data['email'] = $identity['email']; else - $save_data['email'] = rcube_idn_to_ascii($save_data['email']); + $save_data['email'] = rcube_utils::idn_to_ascii($save_data['email']); // save data if not empty if (!empty($save_data['name']) && !empty($save_data['email'])) { diff --git a/plugins/new_user_identity/new_user_identity.php b/plugins/new_user_identity/new_user_identity.php index 200d9accd..f98145b6c 100644 --- a/plugins/new_user_identity/new_user_identity.php +++ b/plugins/new_user_identity/new_user_identity.php @@ -43,7 +43,7 @@ class new_user_identity extends rcube_plugin $args['user_name'] = $user_name; if (!$args['user_email'] && strpos($user_email, '@')) { - $args['user_email'] = rcube_idn_to_ascii($user_email); + $args['user_email'] = rcube_utils::idn_to_ascii($user_email); } } } diff --git a/plugins/newmail_notifier/newmail_notifier.php b/plugins/newmail_notifier/newmail_notifier.php index 942421166..a45eeaedb 100644 --- a/plugins/newmail_notifier/newmail_notifier.php +++ b/plugins/newmail_notifier/newmail_notifier.php @@ -93,7 +93,7 @@ class newmail_notifier extends rcube_plugin $this->gettext('test')); $args['blocks']['new_message']['options'][$key] = array( - 'title' => html::label($field_id, Q($this->gettext($type))), + 'title' => html::label($field_id, rcube::Q($this->gettext($type))), 'content' => $content ); } @@ -120,7 +120,7 @@ class newmail_notifier extends rcube_plugin foreach (array('basic', 'desktop', 'sound') as $type) { $key = 'newmail_notifier_' . $type; if (!in_array($key, $dont_override)) { - $args['prefs'][$key] = get_input_value('_'.$key, RCUBE_INPUT_POST) ? true : false; + $args['prefs'][$key] = rcube_utils::get_input_value('_'.$key, rcube_utils::INPUT_POST) ? true : false; } } diff --git a/plugins/password/drivers/chpasswd.php b/plugins/password/drivers/chpasswd.php index 3ea10159c..137275e69 100644 --- a/plugins/password/drivers/chpasswd.php +++ b/plugins/password/drivers/chpasswd.php @@ -26,7 +26,7 @@ class rcube_chpasswd_password return PASSWORD_SUCCESS; } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/dbmail.php b/plugins/password/drivers/dbmail.php index e4c0d52e3..529027b8d 100644 --- a/plugins/password/drivers/dbmail.php +++ b/plugins/password/drivers/dbmail.php @@ -29,7 +29,7 @@ class rcube_dbmail_password return PASSWORD_SUCCESS; } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/directadmin.php b/plugins/password/drivers/directadmin.php index fb156cea9..8bf0dc613 100644 --- a/plugins/password/drivers/directadmin.php +++ b/plugins/password/drivers/directadmin.php @@ -43,7 +43,7 @@ class rcube_directadmin_password $response = $Socket->fetch_parsed_body(); //DEBUG - //console("Password Plugin: [USER: $da_user] [HOST: $da_host] - Response: [SOCKET: ".$Socket->result_status_code."] [DA ERROR: ".strip_tags($response['error'])."] [TEXT: ".$response[text]."]"); + //rcube::console("Password Plugin: [USER: $da_user] [HOST: $da_host] - Response: [SOCKET: ".$Socket->result_status_code."] [DA ERROR: ".strip_tags($response['error'])."] [TEXT: ".$response[text]."]"); if($Socket->result_status_code != 200) return array('code' => PASSWORD_CONNECT_ERROR, 'message' => $Socket->error[0]); diff --git a/plugins/password/drivers/expect.php b/plugins/password/drivers/expect.php index 7a191e254..1f68924df 100644 --- a/plugins/password/drivers/expect.php +++ b/plugins/password/drivers/expect.php @@ -45,7 +45,7 @@ class rcube_expect_password return PASSWORD_SUCCESS; } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/hmail.php b/plugins/password/drivers/hmail.php index 104c851ae..a8f07a23b 100644 --- a/plugins/password/drivers/hmail.php +++ b/plugins/password/drivers/hmail.php @@ -26,8 +26,8 @@ class rcube_hmail_password $obApp = new COM("hMailServer.Application"); } catch (Exception $e) { - write_log('errors', "Plugin password (hmail driver): " . trim(strip_tags($e->getMessage()))); - write_log('errors', "Plugin password (hmail driver): This problem is often caused by DCOM permissions not being set."); + rcube::write_log('errors', "Plugin password (hmail driver): " . trim(strip_tags($e->getMessage()))); + rcube::write_log('errors', "Plugin password (hmail driver): This problem is often caused by DCOM permissions not being set."); return PASSWORD_ERROR; } @@ -39,8 +39,8 @@ class rcube_hmail_password else { $domain = $rcmail->config->get('username_domain',false); if (!$domain) { - write_log('errors','Plugin password (hmail driver): $rcmail_config[\'username_domain\'] is not defined.'); - write_log('errors','Plugin password (hmail driver): Hint: Use hmail_login plugin (http://myroundcube.googlecode.com'); + rcube::write_log('errors','Plugin password (hmail driver): $rcmail_config[\'username_domain\'] is not defined.'); + rcube::write_log('errors','Plugin password (hmail driver): Hint: Use hmail_login plugin (http://myroundcube.googlecode.com'); return PASSWORD_ERROR; } $username = $username . "@" . $domain; @@ -55,8 +55,8 @@ class rcube_hmail_password return PASSWORD_SUCCESS; } catch (Exception $e) { - write_log('errors', "Plugin password (hmail driver): " . trim(strip_tags($e->getMessage()))); - write_log('errors', "Plugin password (hmail driver): This problem is often caused by DCOM permissions not being set."); + rcube::write_log('errors', "Plugin password (hmail driver): " . trim(strip_tags($e->getMessage()))); + rcube::write_log('errors', "Plugin password (hmail driver): This problem is often caused by DCOM permissions not being set."); return PASSWORD_ERROR; } } diff --git a/plugins/password/drivers/ldap.php b/plugins/password/drivers/ldap.php index f773335ac..548d327e1 100644 --- a/plugins/password/drivers/ldap.php +++ b/plugins/password/drivers/ldap.php @@ -271,7 +271,7 @@ class rcube_ldap_password case 'samba': if (function_exists('hash')) { - $cryptedPassword = hash('md4', rcube_charset_convert($passwordClear, RCMAIL_CHARSET, 'UTF-16LE')); + $cryptedPassword = hash('md4', rcube_charset::convert($passwordClear, RCUBE_CHARSET, 'UTF-16LE')); $cryptedPassword = strtoupper($cryptedPassword); } else { /* Your PHP install does not have the hash() function */ diff --git a/plugins/password/drivers/ldap_simple.php b/plugins/password/drivers/ldap_simple.php index 01385f2d0..d47e14492 100644 --- a/plugins/password/drivers/ldap_simple.php +++ b/plugins/password/drivers/ldap_simple.php @@ -240,7 +240,7 @@ class rcube_ldap_simple_password break; case 'samba': if (function_exists('hash')) { - $crypted_password = hash('md4', rcube_charset_convert($password_clear, RCMAIL_CHARSET, 'UTF-16LE')); + $crypted_password = hash('md4', rcube_charset::convert($password_clear, RCUBE_CHARSET, 'UTF-16LE')); $crypted_password = strtoupper($crypted_password); } else { /* Your PHP install does not have the hash() function */ diff --git a/plugins/password/drivers/pam.php b/plugins/password/drivers/pam.php index 20524d9f1..8cd94c737 100644 --- a/plugins/password/drivers/pam.php +++ b/plugins/password/drivers/pam.php @@ -20,7 +20,7 @@ class rcube_pam_password } } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, @@ -29,7 +29,7 @@ class rcube_pam_password } } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/pw_usermod.php b/plugins/password/drivers/pw_usermod.php index 5b92fcbfb..237e275a7 100644 --- a/plugins/password/drivers/pw_usermod.php +++ b/plugins/password/drivers/pw_usermod.php @@ -28,7 +28,7 @@ class rcube_pw_usermod_password return PASSWORD_SUCCESS; } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/sasl.php b/plugins/password/drivers/sasl.php index 9380cf838..8776eff2e 100644 --- a/plugins/password/drivers/sasl.php +++ b/plugins/password/drivers/sasl.php @@ -32,7 +32,7 @@ class rcube_sasl_password return PASSWORD_SUCCESS; } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/smb.php b/plugins/password/drivers/smb.php index 88021156f..d56924eee 100644 --- a/plugins/password/drivers/smb.php +++ b/plugins/password/drivers/smb.php @@ -44,7 +44,7 @@ class rcube_smb_password return PASSWORD_SUCCESS; } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php index b08833dbf..e02bff146 100644 --- a/plugins/password/drivers/sql.php +++ b/plugins/password/drivers/sql.php @@ -117,7 +117,7 @@ class rcube_sql_password // hashed passwords if (preg_match('/%[n|q]/', $sql)) { if (!extension_loaded('hash')) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, @@ -164,14 +164,14 @@ class rcube_sql_password // convert domains to/from punnycode if ($rcmail->config->get('password_idn_ascii')) { - $domain_part = rcube_idn_to_ascii($domain_part); - $username = rcube_idn_to_ascii($username); - $host = rcube_idn_to_ascii($host); + $domain_part = rcube_utils::idn_to_ascii($domain_part); + $username = rcube_utils::idn_to_ascii($username); + $host = rcube_utils::idn_to_ascii($host); } else { - $domain_part = rcube_idn_to_utf8($domain_part); - $username = rcube_idn_to_utf8($username); - $host = rcube_idn_to_utf8($host); + $domain_part = rcube_utils::idn_to_utf8($domain_part); + $username = rcube_utils::idn_to_utf8($username); + $host = rcube_utils::idn_to_utf8($host); } // at least we should always have the local part diff --git a/plugins/password/drivers/virtualmin.php b/plugins/password/drivers/virtualmin.php index d2b765a9e..2c7aee617 100644 --- a/plugins/password/drivers/virtualmin.php +++ b/plugins/password/drivers/virtualmin.php @@ -67,7 +67,7 @@ class rcube_virtualmin_password return PASSWORD_SUCCESS; } else { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/drivers/xmail.php b/plugins/password/drivers/xmail.php index 33a49ffe3..37abc3001 100644 --- a/plugins/password/drivers/xmail.php +++ b/plugins/password/drivers/xmail.php @@ -32,7 +32,7 @@ class rcube_xmail_password $xmail->port = $rcmail->config->get('xmail_port'); if (!$xmail->connect()) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, @@ -42,7 +42,7 @@ class rcube_xmail_password } else if (!$xmail->send("userpasswd\t".$domain."\t".$user."\t".$newpass."\n")) { $xmail->close(); - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/password/password.php b/plugins/password/password.php index 806db0586..39020a0bf 100644 --- a/plugins/password/password.php +++ b/plugins/password/password.php @@ -112,22 +112,22 @@ class password extends rcube_plugin $rc_charset = strtoupper($rcmail->output->get_charset()); $sespwd = $rcmail->decrypt($_SESSION['password']); - $curpwd = $confirm ? get_input_value('_curpasswd', RCUBE_INPUT_POST, true, $charset) : $sespwd; - $newpwd = get_input_value('_newpasswd', RCUBE_INPUT_POST, true); - $conpwd = get_input_value('_confpasswd', RCUBE_INPUT_POST, true); + $curpwd = $confirm ? rcube_utils::get_input_value('_curpasswd', rcube_utils::INPUT_POST, true, $charset) : $sespwd; + $newpwd = rcube_utils::get_input_value('_newpasswd', rcube_utils::INPUT_POST, true); + $conpwd = rcube_utils::get_input_value('_confpasswd', rcube_utils::INPUT_POST, true); // check allowed characters according to the configured 'password_charset' option // by converting the password entered by the user to this charset and back to UTF-8 $orig_pwd = $newpwd; - $chk_pwd = rcube_charset_convert($orig_pwd, $rc_charset, $charset); - $chk_pwd = rcube_charset_convert($chk_pwd, $charset, $rc_charset); + $chk_pwd = rcube_charset::convert($orig_pwd, $rc_charset, $charset); + $chk_pwd = rcube_charset::convert($chk_pwd, $charset, $rc_charset); // WARNING: Default password_charset is ISO-8859-1, so conversion will // change national characters. This may disable possibility of using // the same password in other MUA's. // We're doing this for consistence with Roundcube core - $newpwd = rcube_charset_convert($newpwd, $rc_charset, $charset); - $conpwd = rcube_charset_convert($conpwd, $rc_charset, $charset); + $newpwd = rcube_charset::convert($newpwd, $rc_charset, $charset); + $conpwd = rcube_charset::convert($conpwd, $rc_charset, $charset); if ($chk_pwd != $orig_pwd) { $rcmail->output->command('display_message', $this->gettext('passwordforbidden'), 'error'); @@ -141,7 +141,7 @@ class password extends rcube_plugin } else if ($required_length && strlen($newpwd) < $required_length) { $rcmail->output->command('display_message', $this->gettext( - array('name' => 'passwordshort', 'vars' => array('length' => $required_length))), 'error'); + array('name' => 'passwordshort', 'vars' => array('length' => $required_length))), 'error'); } else if ($check_strength && (!preg_match("/[0-9]/", $newpwd) || !preg_match("/[^A-Za-z0-9]/", $newpwd))) { $rcmail->output->command('display_message', $this->gettext('passwordweak'), 'error'); @@ -163,8 +163,8 @@ class password extends rcube_plugin // Log password change if ($rcmail->config->get('password_log')) { - write_log('password', sprintf('Password changed for user %s (ID: %d) from %s', - $rcmail->get_user_name(), $rcmail->user->ID, rcmail_remote_ip())); + rcube::write_log('password', sprintf('Password changed for user %s (ID: %d) from %s', + $rcmail->get_user_name(), $rcmail->user->ID, rcube_utils::remote_ip())); } } else { @@ -172,7 +172,7 @@ class password extends rcube_plugin } } - rcmail_overwrite_action('plugin.password'); + $rcmail->overwrite_action('plugin.password'); $rcmail->output->send('plugin'); } @@ -197,7 +197,7 @@ class password extends rcube_plugin $input_curpasswd = new html_passwordfield(array('name' => '_curpasswd', 'id' => $field_id, 'size' => 20, 'autocomplete' => 'off')); - $table->add('title', html::label($field_id, Q($this->gettext('curpasswd')))); + $table->add('title', html::label($field_id, rcube::Q($this->gettext('curpasswd')))); $table->add(null, $input_curpasswd->show()); } @@ -206,7 +206,7 @@ class password extends rcube_plugin $input_newpasswd = new html_passwordfield(array('name' => '_newpasswd', 'id' => $field_id, 'size' => 20, 'autocomplete' => 'off')); - $table->add('title', html::label($field_id, Q($this->gettext('newpasswd')))); + $table->add('title', html::label($field_id, rcube::Q($this->gettext('newpasswd')))); $table->add(null, $input_newpasswd->show()); // show confirm password selection @@ -214,7 +214,7 @@ class password extends rcube_plugin $input_confpasswd = new html_passwordfield(array('name' => '_confpasswd', 'id' => $field_id, 'size' => 20, 'autocomplete' => 'off')); - $table->add('title', html::label($field_id, Q($this->gettext('confpasswd')))); + $table->add('title', html::label($field_id, rcube::Q($this->gettext('confpasswd')))); $table->add(null, $input_confpasswd->show()); $out = html::div(array('class' => 'box'), @@ -246,7 +246,7 @@ class password extends rcube_plugin $file = $this->home . "/drivers/$driver.php"; if (!file_exists($file)) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, @@ -258,7 +258,7 @@ class password extends rcube_plugin include_once $file; if (!class_exists($class, false) || !method_exists($class, 'save')) { - raise_error(array( + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, diff --git a/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php b/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php index 7849f915e..d5d0d47ec 100644 --- a/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php +++ b/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php @@ -73,8 +73,8 @@ class squirrelmail_usercopy extends rcube_plugin foreach ($this->abook as $rec) { // #1487096 handle multi-address and/or too long items $rec['email'] = array_shift(explode(';', $rec['email'])); - if (check_email(rcube_idn_to_ascii($rec['email']))) { - $rec['email'] = rcube_idn_to_utf8($rec['email']); + if (rcube_utils::check_email(rcube_utils::idn_to_ascii($rec['email']))) { + $rec['email'] = rcube_utils::idn_to_utf8($rec['email']); $contacts->insert($rec, true); } } @@ -167,7 +167,7 @@ class squirrelmail_usercopy extends rcube_plugin $sql_result = $db->query('SELECT * FROM '.$userprefs_table.' WHERE user=?', $uname); // ? is replaced with emailaddress while ($sql_array = $db->fetch_assoc($sql_result) ) { // fetch one row from result - $this->prefs[$sql_array['prefkey']] = rcube_charset_convert(rtrim($sql_array['prefval']), $db_charset); + $this->prefs[$sql_array['prefkey']] = rcube_charset::convert(rtrim($sql_array['prefval']), $db_charset); } /* retrieve address table data */ @@ -175,11 +175,11 @@ class squirrelmail_usercopy extends rcube_plugin // parse addres book while ($sql_array = $db->fetch_assoc($sql_result) ) { // fetch one row from result - $rec['name'] = rcube_charset_convert(rtrim($sql_array['nickname']), $db_charset); - $rec['firstname'] = rcube_charset_convert(rtrim($sql_array['firstname']), $db_charset); - $rec['surname'] = rcube_charset_convert(rtrim($sql_array['lastname']), $db_charset); - $rec['email'] = rcube_charset_convert(rtrim($sql_array['email']), $db_charset); - $rec['notes'] = rcube_charset_convert(rtrim($sql_array['label']), $db_charset); + $rec['name'] = rcube_charset::convert(rtrim($sql_array['nickname']), $db_charset); + $rec['firstname'] = rcube_charset::convert(rtrim($sql_array['firstname']), $db_charset); + $rec['surname'] = rcube_charset::convert(rtrim($sql_array['lastname']), $db_charset); + $rec['email'] = rcube_charset::convert(rtrim($sql_array['email']), $db_charset); + $rec['notes'] = rcube_charset::convert(rtrim($sql_array['label']), $db_charset); if ($rec['name'] && $rec['email']) $this->abook[] = $rec; diff --git a/plugins/subscriptions_option/subscriptions_option.php b/plugins/subscriptions_option/subscriptions_option.php index b81a5ac8a..7678d8e94 100644 --- a/plugins/subscriptions_option/subscriptions_option.php +++ b/plugins/subscriptions_option/subscriptions_option.php @@ -46,7 +46,7 @@ class subscriptions_option extends rcube_plugin $checkbox = new html_checkbox(array('name' => '_use_subscriptions', 'id' => $field_id, 'value' => 1)); $args['blocks']['main']['options']['use_subscriptions'] = array( - 'title' => html::label($field_id, Q($this->gettext('useimapsubscriptions'))), + 'title' => html::label($field_id, rcube::Q($this->gettext('useimapsubscriptions'))), 'content' => $checkbox->show($use_subscriptions?1:0), ); } diff --git a/plugins/userinfo/userinfo.php b/plugins/userinfo/userinfo.php index efb65f51d..a175563ef 100644 --- a/plugins/userinfo/userinfo.php +++ b/plugins/userinfo/userinfo.php @@ -31,25 +31,25 @@ class userinfo extends rcube_plugin $table = new html_table(array('cols' => 2, 'cellpadding' => 3)); $table->add('title', 'ID'); - $table->add('', Q($user->ID)); + $table->add('', rcube::Q($user->ID)); - $table->add('title', Q($this->gettext('username'))); - $table->add('', Q($user->data['username'])); + $table->add('title', rcube::Q($this->gettext('username'))); + $table->add('', rcube::Q($user->data['username'])); - $table->add('title', Q($this->gettext('server'))); - $table->add('', Q($user->data['mail_host'])); + $table->add('title', rcube::Q($this->gettext('server'))); + $table->add('', rcube::Q($user->data['mail_host'])); - $table->add('title', Q($this->gettext('created'))); - $table->add('', Q($user->data['created'])); + $table->add('title', rcube::Q($this->gettext('created'))); + $table->add('', rcube::Q($user->data['created'])); - $table->add('title', Q($this->gettext('lastlogin'))); - $table->add('', Q($user->data['last_login'])); + $table->add('title', rcube::Q($this->gettext('lastlogin'))); + $table->add('', rcube::Q($user->data['last_login'])); $identity = $user->get_identity(); - $table->add('title', Q($this->gettext('defaultidentity'))); - $table->add('', Q($identity['name'] . ' <' . $identity['email'] . '>')); + $table->add('title', rcube::Q($this->gettext('defaultidentity'))); + $table->add('', rcube::Q($identity['name'] . ' <' . $identity['email'] . '>')); - return html::tag('h4', null, Q('Infos for ' . $user->get_username())) . $table->show(); + return html::tag('h4', null, rcube::Q('Infos for ' . $user->get_username())) . $table->show(); } } diff --git a/plugins/vcard_attachments/vcard_attachments.php b/plugins/vcard_attachments/vcard_attachments.php index e7f7d5f1f..4905b373e 100644 --- a/plugins/vcard_attachments/vcard_attachments.php +++ b/plugins/vcard_attachments/vcard_attachments.php @@ -90,10 +90,10 @@ class vcard_attachments extends rcube_plugin $p['content'] .= html::p(array('class' => 'vcardattachment'), html::a(array( 'href' => "#", - 'onclick' => "return plugin_vcard_save_contact('" . JQ($part.':'.$idx) . "')", + 'onclick' => "return plugin_vcard_save_contact('" . rcube::JQ($part.':'.$idx) . "')", 'title' => $this->gettext('addvcardmsg'), ), - html::span(null, Q($display))) + html::span(null, rcube::Q($display))) ); } @@ -115,9 +115,9 @@ class vcard_attachments extends rcube_plugin { $this->add_texts('localization', true); - $uid = get_input_value('_uid', RCUBE_INPUT_POST); - $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); - $mime_id = get_input_value('_part', RCUBE_INPUT_POST); + $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); $rcmail = rcmail::get_instance(); $storage = $rcmail->get_storage(); @@ -144,7 +144,7 @@ class vcard_attachments extends rcube_plugin } else { // We're using UTF8 internally - $email = rcube_idn_to_utf8($email); + $email = rcube_utils::idn_to_utf8($email); // compare e-mail address $existing = $CONTACTS->search('email', $email, 1, false); diff --git a/plugins/virtuser_file/virtuser_file.php b/plugins/virtuser_file/virtuser_file.php index 01032616c..2c705b2d0 100644 --- a/plugins/virtuser_file/virtuser_file.php +++ b/plugins/virtuser_file/virtuser_file.php @@ -41,7 +41,7 @@ class virtuser_file extends rcube_plugin $arr = preg_split('/\s+/', $r[$i]); if (count($arr) > 0 && strpos($arr[0], '@')) { - $result[] = rcube_idn_to_ascii(trim(str_replace('\\@', '@', $arr[0]))); + $result[] = rcube_utils::idn_to_ascii(trim(str_replace('\\@', '@', $arr[0]))); if ($p['first']) { $p['email'] = $result[0]; diff --git a/plugins/virtuser_query/virtuser_query.php b/plugins/virtuser_query/virtuser_query.php index 073b4e230..c479a4f7f 100644 --- a/plugins/virtuser_query/virtuser_query.php +++ b/plugins/virtuser_query/virtuser_query.php @@ -28,8 +28,8 @@ class virtuser_query extends rcube_plugin function init() { - $this->app = rcmail::get_instance(); - $this->config = $this->app->config->get('virtuser_query'); + $this->app = rcmail::get_instance(); + $this->config = $this->app->config->get('virtuser_query'); if (!empty($this->config)) { if (is_string($this->config)) { @@ -53,35 +53,35 @@ class virtuser_query extends rcube_plugin */ function user2email($p) { - $dbh = $this->app->get_dbh(); - - $sql_result = $dbh->query(preg_replace('/%u/', $dbh->escapeSimple($p['user']), $this->config['email'])); - - while ($sql_arr = $dbh->fetch_array($sql_result)) { - if (strpos($sql_arr[0], '@')) { - if ($p['extended'] && count($sql_arr) > 1) { - $result[] = array( - 'email' => rcube_idn_to_ascii($sql_arr[0]), - 'name' => $sql_arr[1], - 'organization' => $sql_arr[2], - 'reply-to' => rcube_idn_to_ascii($sql_arr[3]), - 'bcc' => rcube_idn_to_ascii($sql_arr[4]), - 'signature' => $sql_arr[5], - 'html_signature' => (int)$sql_arr[6], - ); - } - else { - $result[] = $sql_arr[0]; - } - - if ($p['first']) - break; - } - } - - $p['email'] = $result; - - return $p; + $dbh = $this->app->get_dbh(); + + $sql_result = $dbh->query(preg_replace('/%u/', $dbh->escapeSimple($p['user']), $this->config['email'])); + + while ($sql_arr = $dbh->fetch_array($sql_result)) { + if (strpos($sql_arr[0], '@')) { + if ($p['extended'] && count($sql_arr) > 1) { + $result[] = array( + 'email' => rcube_utils::idn_to_ascii($sql_arr[0]), + 'name' => $sql_arr[1], + 'organization' => $sql_arr[2], + 'reply-to' => rcube_utils::idn_to_ascii($sql_arr[3]), + 'bcc' => rcube_utils::idn_to_ascii($sql_arr[4]), + 'signature' => $sql_arr[5], + 'html_signature' => (int)$sql_arr[6], + ); + } + else { + $result[] = $sql_arr[0]; + } + + if ($p['first']) + break; + } + } + + $p['email'] = $result; + + return $p; } /** diff --git a/plugins/zipdownload/zipdownload.php b/plugins/zipdownload/zipdownload.php index 8bad9b341..96c76eec9 100644 --- a/plugins/zipdownload/zipdownload.php +++ b/plugins/zipdownload/zipdownload.php @@ -30,7 +30,7 @@ class zipdownload extends rcube_plugin } $rcmail = rcmail::get_instance(); - $this->charset = $rcmail->config->get('zipdownload_charset', RCMAIL_CHARSET); + $this->charset = $rcmail->config->get('zipdownload_charset', RCUBE_CHARSET); $this->load_config(); $this->add_texts('localization'); @@ -62,11 +62,14 @@ class zipdownload extends rcube_plugin // only show the link if there is more than the configured number of attachments if (substr_count($p['content'], ' $rcmail->config->get('zipdownload_attachments', 1)) { - $link = html::a(array( - 'href' => rcmail_url('plugin.zipdownload.zip_attachments', array('_mbox' => $rcmail->output->env['mailbox'], '_uid' => $rcmail->output->env['uid'])), - 'class' => 'button zipdownload', - ), - Q($this->gettext('downloadall')) + $href = $rcmail->url(array( + '_action' => 'plugin.zipdownload.zip_attachments', + '_mbox' => $rcmail->output->env['mailbox'], + '_uid' => $rcmail->output->env['uid'], + )); + + $link = html::a(array('href' => $href, 'class' => 'button zipdownload'), + rcube::Q($this->gettext('downloadall')) ); // append link to attachments list, slightly different in some skins @@ -96,7 +99,7 @@ class zipdownload extends rcube_plugin $temp_dir = $rcmail->config->get('temp_dir'); $tmpfname = tempnam($temp_dir, 'zipdownload'); $tempfiles = array($tmpfname); - $message = new rcube_message(get_input_value('_uid', RCUBE_INPUT_GET)); + $message = new rcube_message(rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET)); // open zip file $zip = new ZipArchive(); @@ -140,7 +143,7 @@ class zipdownload extends rcube_plugin public function download_selection() { if (isset($_REQUEST['_uid'])) { - $uids = explode(",", get_input_value('_uid', RCUBE_INPUT_GPC)); + $uids = explode(",", rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GPC)); if (sizeof($uids) > 0) $this->_download_messages($uids); @@ -157,7 +160,7 @@ class zipdownload extends rcube_plugin // initialize searching result if search_filter is used if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { - $imap->search($mbox_name, $_SESSION['search_filter'], RCMAIL_CHARSET); + $imap->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET); } // fetch message headers for all pages @@ -234,7 +237,9 @@ class zipdownload extends rcube_plugin private function _deliver_zipfile($tmpfname, $filename) { $browser = new rcube_browser; - send_nocacheing_headers(); + $rcmail = rcmail::get_instance(); + + $rcmail->output->nocacheing_headers(); if ($browser->ie && $browser->ver < 7) $filename = rawurlencode(abbreviate_string($filename, 55)); @@ -258,9 +263,9 @@ class zipdownload extends rcube_plugin /** * Helper function to convert filenames to the configured charset */ - private function _convert_filename($str, $from = RCMAIL_CHARSET) + private function _convert_filename($str, $from = RCUBE_CHARSET) { - return strtr(rcube_charset_convert($str, $from, $this->charset), array(':'=>'', '/'=>'-')); + return strtr(rcube_charset::convert($str, $from, $this->charset), array(':'=>'', '/'=>'-')); } } diff --git a/program/include/rcmail.php b/program/include/rcmail.php index c734216ac..5f2a2177b 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1692,7 +1692,7 @@ class rcmail extends rcube $count = count($path); if ($count > 1) { - for ($i = 1; $i < $count; $i++) { + for ($i = 0; $i < $count; $i++) { $folder = implode($delimiter, array_slice($path, 0, -$i)); if ($folder_class = $this->folder_classname($folder)) { $name = implode($delimiter, array_slice($path, $count - $i)); -- cgit v1.2.3 From e24eba0fc5c45d0a42296ae5ddccc02556afda42 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 18 Jan 2013 18:22:32 +0100 Subject: DOn't use deprecated jQuery.browser, CS fixes (tabs to spaces) --- program/js/googiespell.js | 276 +++++++++++++++++++++++----------------------- 1 file changed, 138 insertions(+), 138 deletions(-) (limited to 'program') diff --git a/program/js/googiespell.js b/program/js/googiespell.js index 478858bac..9832116dd 100644 --- a/program/js/googiespell.js +++ b/program/js/googiespell.js @@ -30,16 +30,16 @@ function GoogieSpell(img_dir, server_url, has_dict) GOOGIE_CUR_LANG = cookie_value != null ? cookie_value : GOOGIE_DEFAULT_LANG; this.array_keys = function(arr) { - var res = []; - for (var key in arr) { res.push([key]); } - return res; + var res = []; + for (var key in arr) { res.push([key]); } + return res; } this.img_dir = img_dir; this.server_url = server_url; this.org_lang_to_word = { - "da": "Dansk", "de": "Deutsch", "en": "English", + "da": "Dansk", "de": "Deutsch", "en": "English", "es": "Español", "fr": "Français", "it": "Italiano", "nl": "Nederlands", "pl": "Polski", "pt": "Português", "ru": "Русский", "fi": "Suomi", "sv": "Svenska" @@ -96,8 +96,8 @@ function GoogieSpell(img_dir, server_url, has_dict) $(document).bind('click', function(e) { var target = $(e.target); if(target.attr('googie_action_btn') != '1' && ref.isLangWindowShown()) - ref.hideLangWindow(); - if(target.attr('googie_action_btn') != '1' && ref.isErrorWindowShown()) + ref.hideLangWindow(); + if(target.attr('googie_action_btn') != '1' && ref.isErrorWindowShown()) ref.hideErrorWindow(); }); @@ -225,8 +225,8 @@ this.escapeSpecial = function(val) this.createXMLReq = function (text) { return '' - + '' - + '' + text + ''; + + '' + + '' + text + ''; }; this.spellCheck = function(ignore) @@ -237,27 +237,27 @@ this.spellCheck = function(ignore) ref = this; $.ajax({ type: 'POST', url: this.getUrl(), data: this.createXMLReq(req_text), dataType: 'text', - error: function(o) { + error: function(o) { if (ref.custom_ajax_error) - ref.custom_ajax_error(ref); + ref.custom_ajax_error(ref); else - alert('An error was encountered on the server. Please try again later.'); + alert('An error was encountered on the server. Please try again later.'); if (ref.main_controller) { - $(ref.spell_span).remove(); - ref.removeIndicator(); + $(ref.spell_span).remove(); + ref.removeIndicator(); } ref.checkSpellingState(); - }, + }, success: function(data) { - ref.processData(data); - if (!ref.results.length) { - if (!ref.custom_no_spelling_error) - ref.flashNoSpellingErrorState(); - else - ref.custom_no_spelling_error(ref); - } - ref.removeIndicator(); - } + ref.processData(data); + if (!ref.results.length) { + if (!ref.custom_no_spelling_error) + ref.flashNoSpellingErrorState(); + else + ref.custom_no_spelling_error(ref); + } + ref.removeIndicator(); + } }); }; @@ -269,14 +269,14 @@ this.learnWord = function(word, id) req_text = '' + word + ''; $.ajax({ type: 'POST', url: this.getUrl(), data: req_text, dataType: 'text', - error: function(o) { + error: function(o) { if (ref.custom_ajax_error) - ref.custom_ajax_error(ref); + ref.custom_ajax_error(ref); else - alert('An error was encountered on the server. Please try again later.'); - }, + alert('An error was encountered on the server. Please try again later.'); + }, success: function(data) { - } + } }); }; @@ -350,9 +350,9 @@ this.parseResult = function(r_text) var only_text = matched_c[i].replace(/<[^>]*>/g, ''), split_t = only_text.split(re_split_text); for (var k=0; k < split_t.length; k++) { - if(split_t[k] != '') - item['suggestions'].push(split_t[k]); - } + if(split_t[k] != '') + item['suggestions'].push(split_t[k]); + } results.push(item); } @@ -363,8 +363,8 @@ this.processData = function(data) { this.results = this.parseResult(data); if (this.results.length) { - this.showErrorsInIframe(); - this.resumeEditingState(); + this.showErrorsInIframe(); + this.resumeEditingState(); } }; @@ -414,7 +414,7 @@ this.createListSeparator = function() tr = document.createElement('tr'); $(td).html(' ').attr('googie_action_btn', '1') - .css({'cursor': 'default', 'font-size': '3px', 'border-top': '1px solid #ccc', 'padding-top': '3px'}); + .css({'cursor': 'default', 'font-size': '3px', 'border-top': '1px solid #ccc', 'padding-top': '3px'}); tr.appendChild(td); return tr; @@ -493,10 +493,10 @@ this.showErrorWindow = function(elm, id) $(item).attr('googie_action_btn', '1').css('cursor', 'default') .mouseover(ref.item_onmouseover) .mouseout(ref.item_onmouseout) - .click(function(e) { - ref.learnWord(elm, id); - ref.ignoreError(elm, id); - }); + .click(function(e) { + ref.learnWord(elm, id); + ref.ignoreError(elm, id); + }); item.appendChild(dummy); row.appendChild(item); @@ -538,14 +538,14 @@ this.showErrorWindow = function(elm, id) revert = document.createElement('td'), rev_span = document.createElement('span'); - $(rev_span).addClass('googie_list_revert').html(this.lang_revert + ' ' + old_value); + $(rev_span).addClass('googie_list_revert').html(this.lang_revert + ' ' + old_value); $(revert).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout) - .click(function(e) { - ref.updateOrginalText(offset, elm.innerHTML, old_value, id); - $(elm).removeAttr('is_corrected').css('color', '#b91414').html(old_value); - ref.hideErrorWindow(); - }); + .click(function(e) { + ref.updateOrginalText(offset, elm.innerHTML, old_value, id); + $(elm).removeAttr('is_corrected').css('color', '#b91414').html(old_value); + ref.hideErrorWindow(); + }); revert.appendChild(rev_span); revert_row.appendChild(revert); @@ -557,7 +557,7 @@ this.showErrorWindow = function(elm, id) edit = document.createElement('td'), edit_input = document.createElement('input'), ok_pic = document.createElement('img'), - edit_form = document.createElement('form'); + edit_form = document.createElement('form'); var onsub = function () { if (edit_input.value != '') { @@ -565,34 +565,34 @@ this.showErrorWindow = function(elm, id) ref.saveOldValue(elm, elm.innerHTML); ref.updateOrginalText(offset, elm.innerHTML, edit_input.value, id); - $(elm).attr('is_corrected', true).css('color', 'green').html(edit_input.value); + $(elm).attr('is_corrected', true).css('color', 'green').html(edit_input.value); ref.hideErrorWindow(); } return false; }; - $(edit_input).width(120).css({'margin': 0, 'padding': 0}); - $(edit_input).val(elm.innerHTML).attr('googie_action_btn', '1'); - $(edit).css('cursor', 'default').attr('googie_action_btn', '1'); + $(edit_input).width(120).css({'margin': 0, 'padding': 0}); + $(edit_input).val(elm.innerHTML).attr('googie_action_btn', '1'); + $(edit).css('cursor', 'default').attr('googie_action_btn', '1'); - $(ok_pic).attr('src', this.img_dir + 'ok.gif') - .width(32).height(16) - .css({'cursor': 'pointer', 'margin-left': '2px', 'margin-right': '2px'}) - .click(onsub); + $(ok_pic).attr('src', this.img_dir + 'ok.gif') + .width(32).height(16) + .css({'cursor': 'pointer', 'margin-left': '2px', 'margin-right': '2px'}) + .click(onsub); $(edit_form).attr('googie_action_btn', '1') - .css({'margin': 0, 'padding': 0, 'cursor': 'default', 'white-space': 'nowrap'}) - .submit(onsub); + .css({'margin': 0, 'padding': 0, 'cursor': 'default', 'white-space': 'nowrap'}) + .submit(onsub); - edit_form.appendChild(edit_input); - edit_form.appendChild(ok_pic); + edit_form.appendChild(edit_input); + edit_form.appendChild(ok_pic); edit.appendChild(edit_form); edit_row.appendChild(edit); list.appendChild(edit_row); // Append extra menu items if (this.extra_menu_items.length > 0) - list.appendChild(this.createListSeparator()); + list.appendChild(this.createListSeparator()); var loop = function(i) { if (i < ref.extra_menu_items.length) { @@ -602,12 +602,12 @@ this.showErrorWindow = function(elm, id) var e_row = document.createElement('tr'), e_col = document.createElement('td'); - $(e_col).html(e_elm[0]) + $(e_col).html(e_elm[0]) .mouseover(ref.item_onmouseover) - .mouseout(ref.item_onmouseout) - .click(function() { return e_elm[1](elm, ref) }); + .mouseout(ref.item_onmouseout) + .click(function() { return e_elm[1](elm, ref) }); - e_row.appendChild(e_col); + e_row.appendChild(e_col); list.appendChild(e_row); } loop(i+1); @@ -619,7 +619,7 @@ this.showErrorWindow = function(elm, id) //Close button if (this.use_close_btn) { - list.appendChild(this.createCloseButton(this.hideErrorWindow)); + list.appendChild(this.createCloseButton(this.hideErrorWindow)); } } @@ -637,17 +637,17 @@ this.showErrorWindow = function(elm, id) $(this.error_window).css({'top': top+'px', 'left': left+'px'}).show(); // Dummy for IE - dropdown bug fix - if ($.browser.msie) { - if (!this.error_window_iframe) { + if (document.all && !window.opera) { + if (!this.error_window_iframe) { var iframe = $('