Changeset 6073 in subversion for trunk/roundcubemail
- Timestamp:
- Apr 13, 2012 4:52:02 AM (14 months ago)
- Location:
- trunk/roundcubemail
- Files:
-
- 4 deleted
- 38 edited
- 8 copied
-
. (modified) (1 prop)
-
CHANGELOG (modified) (1 diff)
-
bin/msgexport.sh (modified) (1 diff)
-
index.php (modified) (11 diffs)
-
installer/index.php (modified) (1 diff)
-
installer/utils.php (modified) (2 diffs)
-
plugins (modified) (1 prop)
-
program/include/clisetup.php (modified) (1 diff)
-
program/include/html.php (modified) (7 diffs)
-
program/include/iniset.php (modified) (3 diffs)
-
program/include/main.inc (modified) (7 diffs)
-
program/include/rcmail.php (modified) (31 diffs)
-
program/include/rcube.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube.php) (3 diffs)
-
program/include/rcube_addressbook.php (modified) (1 diff)
-
program/include/rcube_base_replacer.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube_base_replacer.php) (1 diff)
-
program/include/rcube_cache.php (modified) (7 diffs)
-
program/include/rcube_config.php (modified) (6 diffs)
-
program/include/rcube_contacts.php (modified) (20 diffs)
-
program/include/rcube_html_page.php (deleted)
-
program/include/rcube_imap.php (modified) (23 diffs)
-
program/include/rcube_imap_cache.php (modified) (22 diffs)
-
program/include/rcube_imap_generic.php (modified) (7 diffs)
-
program/include/rcube_json_output.php (deleted)
-
program/include/rcube_ldap.php (modified) (10 diffs)
-
program/include/rcube_mdb2.php (modified) (42 diffs)
-
program/include/rcube_message.php (modified) (6 diffs)
-
program/include/rcube_message_header.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube_message_header.php) (1 diff)
-
program/include/rcube_message_part.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube_message_part.php) (1 diff)
-
program/include/rcube_output.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube_output.php) (2 diffs)
-
program/include/rcube_output_html.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube_output_html.php) (8 diffs)
-
program/include/rcube_output_json.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube_output_json.php) (2 diffs)
-
program/include/rcube_plugin.php (modified) (4 diffs)
-
program/include/rcube_plugin_api.php (modified) (18 diffs)
-
program/include/rcube_session.php (modified) (9 diffs)
-
program/include/rcube_shared.inc (modified) (8 diffs)
-
program/include/rcube_smtp.php (modified) (3 diffs)
-
program/include/rcube_spellchecker.php (modified) (7 diffs)
-
program/include/rcube_sqlite.inc (deleted)
-
program/include/rcube_storage.php (modified) (6 diffs)
-
program/include/rcube_string_replacer.php (modified) (2 diffs)
-
program/include/rcube_template.php (deleted)
-
program/include/rcube_ui.php (copied) (copied from branches/devel-framework/roundcubemail/program/include/rcube_ui.php) (13 diffs)
-
program/include/rcube_user.php (modified) (17 diffs)
-
program/include/rcube_vcard.php (modified) (3 diffs)
-
program/steps/addressbook/func.inc (modified) (1 diff)
-
program/steps/mail/compose.inc (modified) (1 diff)
-
program/steps/mail/func.inc (modified) (3 diffs)
-
program/steps/mail/get.inc (modified) (3 diffs)
-
program/steps/mail/show.inc (modified) (1 diff)
-
program/steps/utils/error.inc (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/roundcubemail
- Property svn:mergeinfo changed
/branches/devel-framework/roundcubemail merged: 5807,5821-5822,5825-5830,5834-5836,5854-5855,5866,5880-5885
- Property svn:mergeinfo changed
-
trunk/roundcubemail/CHANGELOG
r6062 r6073 2 2 =========================== 3 3 4 - Roundcube Framework: 5 Add possibility to replace IMAP driver with custom class 6 Add IMAP auto-connection feature, improving performance with caching enabled 7 Replace imap_init hook with storage_init (with additional 'driver' argument) 8 Improved performance by caching IMAP server's capabilities in session 9 Unified global functions naming (rcube_ prefix) 10 Move global functions from main.inc and rcube_shared.inc into classes 11 Better classes separation 12 13 RELEASE 0.8-rc 14 ---------------- 4 15 - Set flexible width to login form fields (#1488418) 5 16 - Fix re-draw bug on list columns change in IE8 (#1487822) -
trunk/roundcubemail/bin/msgexport.sh
r5781 r6073 35 35 36 36 $index = $IMAP->index($mbox, null, 'ASC'); 37 $count = $index->count Messages();37 $count = $index->count(); 38 38 $index = $index->get(); 39 39 -
trunk/roundcubemail/index.php
r5787 r6073 3 3 +-------------------------------------------------------------------------+ 4 4 | Roundcube Webmail IMAP Client | 5 | Version 0. 8-svn |5 | Version 0.9-svn | 6 6 | | 7 7 | Copyright (C) 2005-2012, The Roundcube Dev Team | … … 46 46 47 47 // Make the whole PHP output non-cacheable (#1487797) 48 send_nocacheing_headers();48 $RCMAIL->output->nocacheing_headers(); 49 49 50 50 // turn on output buffering … … 68 68 69 69 // error steps 70 if ($RCMAIL->action =='error' && !empty($_GET['_code'])) {70 if ($RCMAIL->action == 'error' && !empty($_GET['_code'])) { 71 71 raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE); 72 72 } … … 75 75 if (empty($_SESSION['user_id']) && ($force_https = $RCMAIL->config->get('force_https', false))) { 76 76 $https_port = is_bool($force_https) ? 443 : $force_https; 77 if (!rcube_ https_check($https_port)) {77 if (!rcube_ui::https_check($https_port)) { 78 78 $host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']); 79 79 $host .= ($https_port != 443 ? ':' . $https_port : ''); … … 90 90 // try to log in 91 91 if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') { 92 $request_valid = $_SESSION['temp'] && $RCMAIL->check_request( RCUBE_INPUT_POST, 'login');92 $request_valid = $_SESSION['temp'] && $RCMAIL->check_request(rcube_ui::INPUT_POST, 'login'); 93 93 94 94 // purge the session in case of new login when a session already exists … … 97 97 $auth = $RCMAIL->plugins->exec_hook('authenticate', array( 98 98 'host' => $RCMAIL->autoselect_host(), 99 'user' => trim( get_input_value('_user', RCUBE_INPUT_POST)),100 'pass' => get_input_value('_pass', RCUBE_INPUT_POST, true,99 'user' => trim(rcube_ui::get_input_value('_user', rcube_ui::INPUT_POST)), 100 'pass' => rcube_ui::get_input_value('_pass', rcube_ui::INPUT_POST, true, 101 101 $RCMAIL->config->get('password_charset', 'ISO-8859-1')), 102 102 'cookiecheck' => true, … … 120 120 121 121 // log successful login 122 rcmail_log_login();122 $RCMAIL->log_login(); 123 123 124 124 // restore original request parameters 125 125 $query = array(); 126 if ($url = get_input_value('_url', RCUBE_INPUT_POST)) {126 if ($url = rcube_ui::get_input_value('_url', rcube_ui::INPUT_POST)) { 127 127 parse_str($url, $query); 128 128 … … 150 150 151 151 // end session (after optional referer check) 152 else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id']) && (!$RCMAIL->config->get('referer_check') || rc ube_check_referer())) {152 else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id']) && (!$RCMAIL->config->get('referer_check') || rcmail::check_referer())) { 153 153 $userdata = array( 154 154 'user' => $_SESSION['username'], … … 173 173 if (empty($RCMAIL->user->ID)) { 174 174 // log session failures 175 if (($task = get_input_value('_task', RCUBE_INPUT_GPC)) && !in_array($task, array('login','logout')) && !$session_error && ($sess_id = $_COOKIE[ini_get('session.name')])) { 175 $task = rcube_ui::get_input_value('_task', rcube_ui::INPUT_GPC); 176 if ($task && !in_array($task, array('login','logout')) && !$session_error && ($sess_id = $_COOKIE[ini_get('session.name')])) { 176 177 $RCMAIL->session->log("Aborted session " . $sess_id . "; no valid session data found"); 177 178 $session_error = true; … … 209 210 // check client X-header to verify request origin 210 211 if ($OUTPUT->ajax_call) { 211 if (rc _request_header('X-Roundcube-Request') != $RCMAIL->get_request_token() && !$RCMAIL->config->get('devel_mode')) {212 if (rcube_request_header('X-Roundcube-Request') != $RCMAIL->get_request_token() && !$RCMAIL->config->get('devel_mode')) { 212 213 header('HTTP/1.1 403 Forbidden'); 213 214 die("Invalid Request"); … … 221 222 222 223 // check referer if configured 223 if (!$request_check_whitelist[$RCMAIL->action] && $RCMAIL->config->get('referer_check') && !rc ube_check_referer()) {224 if (!$request_check_whitelist[$RCMAIL->action] && $RCMAIL->config->get('referer_check') && !rcmail::check_referer()) { 224 225 raise_error(array( 225 226 'code' => 403, -
trunk/roundcubemail/installer/index.php
r6036 r6073 54 54 55 55 require_once 'utils.php'; 56 require_once 'rcube_shared.inc'; 57 // deprecated aliases (to be removed) 56 58 require_once 'main.inc'; 57 59 -
trunk/roundcubemail/installer/utils.php
r5787 r6073 46 46 } 47 47 48 49 /**50 * Fake internal error handler to catch errors51 */52 function raise_error($p)53 {54 $rci = rcube_install::get_instance();55 $rci->raise_error($p);56 }57 58 48 /** 59 49 * Local callback function for PEAR errors 60 50 */ 61 function rcube_pear_error($err)51 function __pear_error($err) 62 52 { 63 r aise_error(array(53 rcmail::raise_error(array( 64 54 'code' => $err->getCode(), 65 55 'message' => $err->getMessage(), … … 68 58 69 59 // set PEAR error handling (will also load the PEAR main class) 70 PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, ' rcube_pear_error');60 PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, '__pear_error'); -
trunk/roundcubemail/plugins
- Property svn:mergeinfo changed
/branches/devel-framework/roundcubemail/plugins (added) merged: 5780-5994
- Property svn:mergeinfo changed
-
trunk/roundcubemail/program/include/clisetup.php
r5787 r6073 56 56 57 57 $args[$key] = preg_replace(array('/^["\']/', '/["\']$/'), '', $value); 58 58 59 59 if ($alias = $aliases[$key]) 60 60 $args[$alias] = $args[$key]; -
trunk/roundcubemail/program/include/html.php
r5992 r6073 278 278 foreach ($attrib as $key => $value) { 279 279 // skip size if not numeric 280 if ( ($key=='size' && !is_numeric($value))) {280 if ($key == 'size' && !is_numeric($value)) { 281 281 continue; 282 282 } … … 298 298 } 299 299 } 300 else if ($key=='value') {301 $attrib_arr[] = $key . '="' . Q($value, 'strict', false) . '"';302 }303 300 else { 304 $attrib_arr[] = $key . '="' . Q($value) . '"'; 305 } 306 } 301 $attrib_arr[] = $key . '="' . self::quote($value) . '"'; 302 } 303 } 304 307 305 return count($attrib_arr) ? ' '.implode(' ', $attrib_arr) : ''; 308 306 } 307 308 /** 309 * Convert a HTML attribute string attributes to an associative array (name => value) 310 * 311 * @param string Input string 312 * @return array Key-value pairs of parsed attributes 313 */ 314 public static function parse_attrib_string($str) 315 { 316 $attrib = array(); 317 $regexp = '/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/Ui'; 318 319 preg_match_all($regexp, stripslashes($str), $regs, PREG_SET_ORDER); 320 321 // convert attributes to an associative array (name => value) 322 if ($regs) { 323 foreach ($regs as $attr) { 324 $attrib[strtolower($attr[1])] = html_entity_decode($attr[3] . $attr[4]); 325 } 326 } 327 328 return $attrib; 329 } 330 331 /** 332 * Replacing specials characters in html attribute value 333 * 334 * @param string $str Input string 335 * 336 * @return string The quoted string 337 */ 338 public static function quote($str) 339 { 340 $str = htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET); 341 342 // avoid douple quotation of & 343 // @TODO: get rid of it? 344 $str = preg_replace('/&([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $str); 345 346 return $str; 347 } 309 348 } 349 310 350 311 351 /** … … 318 358 protected $tagname = 'input'; 319 359 protected $type = 'text'; 320 protected $allowed = array('type','name','value','size','tabindex', 360 protected $allowed = array( 361 'type','name','value','size','tabindex', 321 362 'autocomplete','checked','onchange','onclick','disabled','readonly', 322 'spellcheck','results','maxlength','src','multiple','placeholder'); 363 'spellcheck','results','maxlength','src','multiple','placeholder', 364 ); 323 365 324 366 /** … … 518 560 519 561 if (!empty($value) && !preg_match('/mce_editor/', $this->attrib['class'])) { 520 $value = Q($value, 'strict', false);562 $value = self::quote($value); 521 563 } 522 564 523 565 return self::tag($this->tagname, $this->attrib, $value, 524 array_merge(self::$common_attrib, $this->allowed));566 array_merge(self::$common_attrib, $this->allowed)); 525 567 } 526 568 } … … 551 593 protected $allowed = array('name','size','tabindex','autocomplete', 552 594 'multiple','onchange','disabled','rel'); 553 595 554 596 /** 555 597 * Add a new option to this drop-down … … 592 634 in_array($option['text'], $select, true)) ? 1 : null); 593 635 594 $this->content .= self::tag('option', $attr, Q($option['text'])); 595 } 636 $this->content .= self::tag('option', $attr, self::quote($option['text'])); 637 } 638 596 639 return parent::show(); 597 640 } … … 804 847 805 848 } 806 -
trunk/roundcubemail/program/include/iniset.php
r5958 r6073 41 41 42 42 // application constants 43 define('RCMAIL_VERSION', '0. 8-svn');43 define('RCMAIL_VERSION', '0.9-svn'); 44 44 define('RCMAIL_CHARSET', 'UTF-8'); 45 45 define('JS_OBJECT_NAME', 'rcmail'); … … 52 52 if (!defined('RCMAIL_CONFIG_DIR')) { 53 53 define('RCMAIL_CONFIG_DIR', INSTALL_PATH . 'config'); 54 }55 56 // make sure path_separator is defined57 if (!defined('PATH_SEPARATOR')) {58 define('PATH_SEPARATOR', (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') ? ';' : ':');59 54 } 60 55 … … 81 76 } 82 77 83 /** 84 * Use PHP5 autoload for dynamic class loading 85 * 86 * @todo Make Zend, PEAR etc play with this 87 * @todo Make our classes conform to a more straight forward CS. 88 */ 89 function rcube_autoload($classname) 90 { 91 $filename = preg_replace( 92 array( 93 '/MDB2_(.+)/', 94 '/Mail_(.+)/', 95 '/Net_(.+)/', 96 '/Auth_(.+)/', 97 '/^html_.+/', 98 '/^utf8$/', 99 ), 100 array( 101 'MDB2/\\1', 102 'Mail/\\1', 103 'Net/\\1', 104 'Auth/\\1', 105 'html', 106 'utf8.class', 107 ), 108 $classname 109 ); 78 // include global functions 79 require_once INSTALL_PATH . 'program/include/rcube_shared.inc'; 110 80 111 if ($fp = @fopen("$filename.php", 'r', true)) { 112 fclose($fp); 113 include_once("$filename.php"); 114 return true; 115 } 116 117 return false; 118 } 119 81 // Register autoloader 120 82 spl_autoload_register('rcube_autoload'); 121 122 /**123 * Local callback function for PEAR errors124 */125 function rcube_pear_error($err)126 {127 error_log(sprintf("%s (%s): %s",128 $err->getMessage(),129 $err->getCode(),130 $err->getUserinfo()), 0);131 }132 83 133 84 // set PEAR error handling (will also load the PEAR main class) 134 85 PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error'); 135 86 136 // include global functions87 // backward compatybility (to be removed) 137 88 require_once INSTALL_PATH . 'program/include/main.inc'; 138 require_once INSTALL_PATH . 'program/include/rcube_shared.inc'; -
trunk/roundcubemail/program/include/main.inc
r6050 r6073 6 6 | | 7 7 | This file is part of the Roundcube Webmail client | 8 | Copyright (C) 2005-201 1, The Roundcube Dev Team |8 | Copyright (C) 2005-2012, The Roundcube Dev Team | 9 9 | | 10 10 | Licensed under the GNU General Public License version 3 or | … … 13 13 | | 14 14 | PURPOSE: | 15 | Provide basic functions for the webmail package|15 | Provide deprecated functions aliases for backward compatibility | 16 16 | | 17 17 +-----------------------------------------------------------------------+ … … 24 24 25 25 /** 26 * Roundcube Webmail commonfunctions26 * Roundcube Webmail deprecated functions 27 27 * 28 28 * @package Core … … 30 30 */ 31 31 32 require_once INSTALL_PATH . 'program/include/rcube_shared.inc'; 33 34 // define constannts for input reading 35 define('RCUBE_INPUT_GET', 0x0101); 36 define('RCUBE_INPUT_POST', 0x0102); 37 define('RCUBE_INPUT_GPC', 0x0103); 38 39 40 41 /** 42 * Return correct name for a specific database table 43 * 44 * @param string Table name 45 * @return string Translated table name 46 */ 32 // constants for input reading 33 define('RCUBE_INPUT_GET', rcube_ui::INPUT_GET); 34 define('RCUBE_INPUT_POST', rcube_ui::INPUT_POST); 35 define('RCUBE_INPUT_GPC', rcube_ui::INPUT_GPC); 36 37 47 38 function get_table_name($table) 48 { 49 global $CONFIG; 50 51 // return table name if configured 52 $config_key = 'db_table_'.$table; 53 54 if (strlen($CONFIG[$config_key])) 55 return $CONFIG[$config_key]; 56 57 return $table; 58 } 59 60 61 /** 62 * Return correct name for a specific database sequence 63 * (used for Postgres only) 64 * 65 * @param string Secuence name 66 * @return string Translated sequence name 67 */ 39 { 40 return rcmail::get_instance()->db->table_name($table); 41 } 42 68 43 function get_sequence_name($sequence) 69 { 70 // return sequence name if configured 71 $config_key = 'db_sequence_'.$sequence; 72 $opt = rcmail::get_instance()->config->get($config_key); 73 74 if (!empty($opt)) 75 return $opt; 76 77 return $sequence; 78 } 79 80 81 /** 82 * Get localized text in the desired language 83 * It's a global wrapper for rcmail::gettext() 84 * 85 * @param mixed Named parameters array or label name 86 * @param string Domain to search in (e.g. plugin name) 87 * @return string Localized text 88 * @see rcmail::gettext() 89 */ 44 { 45 return rcmail::get_instance()->db->sequence_name($sequence); 46 } 47 90 48 function rcube_label($p, $domain=null) 91 49 { 92 return rcmail::get_instance()->gettext($p, $domain); 93 } 94 95 96 /** 97 * Global wrapper of rcmail::text_exists() 98 * to check whether a text label is defined 99 * 100 * @see rcmail::text_exists() 101 */ 50 return rcmail::get_instance()->gettext($p, $domain); 51 } 52 102 53 function rcube_label_exists($name, $domain=null, &$ref_domain = null) 103 54 { 104 return rcmail::get_instance()->text_exists($name, $domain, $ref_domain); 105 } 106 107 108 /** 109 * Overwrite action variable 110 * 111 * @param string New action value 112 */ 55 return rcmail::get_instance()->text_exists($name, $domain, $ref_domain); 56 } 57 113 58 function rcmail_overwrite_action($action) 114 { 115 $app = rcmail::get_instance(); 116 $app->action = $action; 117 $app->output->set_env('action', $action); 118 } 119 120 121 /** 122 * Compose an URL for a specific action 123 * 124 * @param string Request action 125 * @param array More URL parameters 126 * @param string Request task (omit if the same) 127 * @return The application URL 128 */ 59 { 60 rcmail::get_instance()->overwrite_action($action); 61 } 62 129 63 function rcmail_url($action, $p=array(), $task=null) 130 64 { 131 $app = rcmail::get_instance(); 132 return $app->url((array)$p + array('_action' => $action, 'task' => $task)); 133 } 134 135 136 /** 137 * Garbage collector function for temp files. 138 * Remove temp files older than two days 139 */ 65 return rcube_ui::url($action, $p, $task); 66 } 67 140 68 function rcmail_temp_gc() 141 69 { 142 $rcmail = rcmail::get_instance(); 143 144 $tmp = unslashify($rcmail->config->get('temp_dir')); 145 $expire = mktime() - 172800; // expire in 48 hours 146 147 if ($dir = opendir($tmp)) { 148 while (($fname = readdir($dir)) !== false) { 149 if ($fname{0} == '.') 150 continue; 151 152 if (filemtime($tmp.'/'.$fname) < $expire) 153 @unlink($tmp.'/'.$fname); 154 } 155 156 closedir($dir); 157 } 158 } 159 160 161 // Deprecated 70 $rcmail = rcmail::get_instance()->temp_gc(); 71 } 72 162 73 function rcube_charset_convert($str, $from, $to=NULL) 163 74 { … … 165 76 } 166 77 167 168 // Deprecated169 78 function rc_detect_encoding($string, $failover='') 170 79 { … … 172 81 } 173 82 174 175 // Deprecated176 83 function rc_utf8_clean($input) 177 84 { … … 179 86 } 180 87 181 182 /**183 * Convert a variable into a javascript object notation184 *185 * @param mixed Input value186 * @return string Serialized JSON string187 */188 88 function json_serialize($input) 189 89 { 190 $input = rcube_charset::clean($input); 191 192 // sometimes even using rcube_charset::clean() the input contains invalid UTF-8 sequences 193 // that's why we have @ here 194 return @json_encode($input); 195 } 196 197 198 /** 199 * Replacing specials characters to a specific encoding type 200 * 201 * @param string Input string 202 * @param string Encoding type: text|html|xml|js|url 203 * @param string Replace mode for tags: show|replace|remove 204 * @param boolean Convert newlines 205 * @return string The quoted string 206 */ 90 return rcube_output::json_serialize($input); 91 } 92 207 93 function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE) 208 { 209 static $html_encode_arr = false; 210 static $js_rep_table = false; 211 static $xml_rep_table = false; 212 213 if (!$enctype) 214 $enctype = $OUTPUT->type; 215 216 // encode for HTML output 217 if ($enctype=='html') 218 { 219 if (!$html_encode_arr) 220 { 221 $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS); 222 unset($html_encode_arr['?']); 223 } 224 225 $ltpos = strpos($str, '<'); 226 $encode_arr = $html_encode_arr; 227 228 // don't replace quotes and html tags 229 if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false) 230 { 231 unset($encode_arr['"']); 232 unset($encode_arr['<']); 233 unset($encode_arr['>']); 234 unset($encode_arr['&']); 235 } 236 else if ($mode=='remove') 237 $str = strip_tags($str); 238 239 $out = strtr($str, $encode_arr); 240 241 // avoid douple quotation of & 242 $out = preg_replace('/&([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $out); 243 244 return $newlines ? nl2br($out) : $out; 245 } 246 247 // if the replace tables for XML and JS are not yet defined 248 if ($js_rep_table===false) 249 { 250 $js_rep_table = $xml_rep_table = array(); 251 $xml_rep_table['&'] = '&'; 252 253 for ($c=160; $c<256; $c++) // can be increased to support more charsets 254 $xml_rep_table[chr($c)] = "&#$c;"; 255 256 $xml_rep_table['"'] = '"'; 257 $js_rep_table['"'] = '\\"'; 258 $js_rep_table["'"] = "\\'"; 259 $js_rep_table["\\"] = "\\\\"; 260 // Unicode line and paragraph separators (#1486310) 261 $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A8))] = '
'; 262 $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A9))] = '
'; 263 } 264 265 // encode for javascript use 266 if ($enctype=='js') 267 return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table)); 268 269 // encode for plaintext 270 if ($enctype=='text') 271 return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str); 272 273 if ($enctype=='url') 274 return rawurlencode($str); 275 276 // encode for XML 277 if ($enctype=='xml') 278 return strtr($str, $xml_rep_table); 279 280 // no encoding given -> return original string 281 return $str; 282 } 283 284 /** 285 * Quote a given string. 286 * Shortcut function for rep_specialchars_output 287 * 288 * @return string HTML-quoted string 289 * @see rep_specialchars_output() 290 */ 94 { 95 return rcube_ui::rep_specialchars_output($str, $enctype, $mode, $newlines); 96 } 97 291 98 function Q($str, $mode='strict', $newlines=TRUE) 292 { 293 return rep_specialchars_output($str, 'html', $mode, $newlines); 294 } 295 296 /** 297 * Quote a given string for javascript output. 298 * Shortcut function for rep_specialchars_output 299 * 300 * @return string JS-quoted string 301 * @see rep_specialchars_output() 302 */ 99 { 100 return rcube_ui::Q($str, $mode, $newlines); 101 } 102 303 103 function JQ($str) 304 { 305 return rep_specialchars_output($str, 'js'); 306 } 307 308 309 /** 310 * Read input value and convert it for internal use 311 * Performs stripslashes() and charset conversion if necessary 312 * 313 * @param string Field name to read 314 * @param int Source to get value from (GPC) 315 * @param boolean Allow HTML tags in field value 316 * @param string Charset to convert into 317 * @return string Field value or NULL if not available 318 */ 104 { 105 return rcube_ui::JQ($str); 106 } 107 319 108 function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL) 320 109 { 321 $value = NULL; 322 323 if ($source == RCUBE_INPUT_GET) { 324 if (isset($_GET[$fname])) 325 $value = $_GET[$fname]; 326 } 327 else if ($source == RCUBE_INPUT_POST) { 328 if (isset($_POST[$fname])) 329 $value = $_POST[$fname]; 330 } 331 else if ($source == RCUBE_INPUT_GPC) { 332 if (isset($_POST[$fname])) 333 $value = $_POST[$fname]; 334 else if (isset($_GET[$fname])) 335 $value = $_GET[$fname]; 336 else if (isset($_COOKIE[$fname])) 337 $value = $_COOKIE[$fname]; 338 } 339 340 return parse_input_value($value, $allow_html, $charset); 341 } 342 343 /** 344 * Parse/validate input value. See get_input_value() 345 * Performs stripslashes() and charset conversion if necessary 346 * 347 * @param string Input value 348 * @param boolean Allow HTML tags in field value 349 * @param string Charset to convert into 350 * @return string Parsed value 351 */ 110 return rcube_ui::get_input_value($fname, $source, $allow_html, $charset); 111 } 112 352 113 function parse_input_value($value, $allow_html=FALSE, $charset=NULL) 353 114 { 354 global $OUTPUT; 355 356 if (empty($value)) 357 return $value; 358 359 if (is_array($value)) { 360 foreach ($value as $idx => $val) 361 $value[$idx] = parse_input_value($val, $allow_html, $charset); 362 return $value; 363 } 364 365 // strip single quotes if magic_quotes_sybase is enabled 366 if (ini_get('magic_quotes_sybase')) 367 $value = str_replace("''", "'", $value); 368 // strip slashes if magic_quotes enabled 369 else if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) 370 $value = stripslashes($value); 371 372 // remove HTML tags if not allowed 373 if (!$allow_html) 374 $value = strip_tags($value); 375 376 $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null; 377 378 // remove invalid characters (#1488124) 379 if ($output_charset == 'UTF-8') 380 $value = rc_utf8_clean($value); 381 382 // convert to internal charset 383 if ($charset && $output_charset) 384 $value = rcube_charset_convert($value, $output_charset, $charset); 385 386 return $value; 387 } 388 389 /** 390 * Convert array of request parameters (prefixed with _) 391 * to a regular array with non-prefixed keys. 392 * 393 * @param int Source to get value from (GPC) 394 * @return array Hash array with all request parameters 395 */ 115 return rcube_ui::parse_input_value($value, $allow_html, $charset); 116 } 117 396 118 function request2param($mode = RCUBE_INPUT_GPC, $ignore = 'task|action') 397 119 { 398 $out = array(); 399 $src = $mode == RCUBE_INPUT_GET ? $_GET : ($mode == RCUBE_INPUT_POST ? $_POST : $_REQUEST); 400 foreach ($src as $key => $value) { 401 $fname = $key[0] == '_' ? substr($key, 1) : $key; 402 if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) 403 $out[$fname] = get_input_value($key, $mode); 404 } 405 406 return $out; 407 } 408 409 /** 410 * Remove all non-ascii and non-word chars 411 * except ., -, _ 412 */ 413 function asciiwords($str, $css_id = false, $replace_with = '') 414 { 415 $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : ''); 416 return preg_replace("/[^$allowed]/i", $replace_with, $str); 417 } 418 419 /** 420 * Convert the given string into a valid HTML identifier 421 * Same functionality as done in app.js with rcube_webmail.html_identifier() 422 */ 120 return rcube_ui::request2param($mode, $ignore); 121 } 122 423 123 function html_identifier($str, $encode=false) 424 124 { 425 if ($encode) 426 return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); 427 else 428 return asciiwords($str, true, '_'); 429 } 430 431 /** 432 * Remove single and double quotes from given string 433 * 434 * @param string Input value 435 * @return string Dequoted string 436 */ 437 function strip_quotes($str) 438 { 439 return str_replace(array("'", '"'), '', $str); 440 } 441 442 443 /** 444 * Remove new lines characters from given string 445 * 446 * @param string Input value 447 * @return string Stripped string 448 */ 449 function strip_newlines($str) 450 { 451 return preg_replace('/[\r\n]/', '', $str); 452 } 453 454 455 /** 456 * Create a HTML table based on the given data 457 * 458 * @param array Named table attributes 459 * @param mixed Table row data. Either a two-dimensional array or a valid SQL result set 460 * @param array List of cols to show 461 * @param string Name of the identifier col 462 * @return string HTML table code 463 */ 125 return rcube_ui::html_identifier($str, $encode); 126 } 127 464 128 function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col) 465 129 { 466 global $RCMAIL; 467 468 $table = new html_table(/*array('cols' => count($a_show_cols))*/); 469 470 // add table header 471 if (!$attrib['noheader']) 472 foreach ($a_show_cols as $col) 473 $table->add_header($col, Q(rcube_label($col))); 474 475 $c = 0; 476 if (!is_array($table_data)) 477 { 478 $db = $RCMAIL->get_dbh(); 479 while ($table_data && ($sql_arr = $db->fetch_assoc($table_data))) 480 { 481 $table->add_row(array('id' => 'rcmrow' . html_identifier($sql_arr[$id_col]))); 482 483 // format each col 484 foreach ($a_show_cols as $col) 485 $table->add($col, Q($sql_arr[$col])); 486 487 $c++; 488 } 489 } 490 else { 491 foreach ($table_data as $row_data) 492 { 493 $class = !empty($row_data['class']) ? $row_data['class'] : ''; 494 495 $table->add_row(array('id' => 'rcmrow' . html_identifier($row_data[$id_col]), 'class' => $class)); 496 497 // format each col 498 foreach ($a_show_cols as $col) 499 $table->add($col, Q(is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col])); 500 501 $c++; 502 } 503 } 504 505 return $table->show($attrib); 506 } 507 508 509 /** 510 * Create an edit field for inclusion on a form 511 * 512 * @param string col field name 513 * @param string value field value 514 * @param array attrib HTML element attributes for field 515 * @param string type HTML element type (default 'text') 516 * @return string HTML field definition 517 */ 130 return rcube_ui::table_output($attrib, $table_data, $a_show_cols, $id_col); 131 } 132 518 133 function rcmail_get_edit_field($col, $value, $attrib, $type='text') 519 134 { 520 static $colcounts = array(); 521 522 $fname = '_'.$col; 523 $attrib['name'] = $fname . ($attrib['array'] ? '[]' : ''); 524 $attrib['class'] = trim($attrib['class'] . ' ff_' . $col); 525 526 if ($type == 'checkbox') { 527 $attrib['value'] = '1'; 528 $input = new html_checkbox($attrib); 529 } 530 else if ($type == 'textarea') { 531 $attrib['cols'] = $attrib['size']; 532 $input = new html_textarea($attrib); 533 } 534 else if ($type == 'select') { 535 $input = new html_select($attrib); 536 $input->add('---', ''); 537 $input->add(array_values($attrib['options']), array_keys($attrib['options'])); 538 } 539 else if ($attrib['type'] == 'password') { 540 $input = new html_passwordfield($attrib); 541 } 542 else { 543 if ($attrib['type'] != 'text' && $attrib['type'] != 'hidden') 544 $attrib['type'] = 'text'; 545 $input = new html_inputfield($attrib); 546 } 547 548 // use value from post 549 if (isset($_POST[$fname])) { 550 $postvalue = get_input_value($fname, RCUBE_INPUT_POST, true); 551 $value = $attrib['array'] ? $postvalue[intval($colcounts[$col]++)] : $postvalue; 552 } 553 554 $out = $input->show($value); 555 556 return $out; 557 } 558 559 560 /** 561 * Replace all css definitions with #container [def] 562 * and remove css-inlined scripting 563 * 564 * @param string CSS source code 565 * @param string Container ID to use as prefix 566 * @return string Modified CSS source 567 */ 135 return rcube_ui::get_edit_field($col, $value, $attrib, $type); 136 } 137 568 138 function rcmail_mod_css_styles($source, $container_id, $allow_remote=false) 569 { 570 $last_pos = 0; 571 $replacements = new rcube_string_replacer; 572 573 // ignore the whole block if evil styles are detected 574 $source = rcmail_xss_entity_decode($source); 575 $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); 576 $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); 577 if (preg_match("/$evilexpr/i", $stripped)) 578 return '/* evil! */'; 579 580 // cut out all contents between { and } 581 while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { 582 $styles = substr($source, $pos+1, $pos2-($pos+1)); 583 584 // check every line of a style block... 585 if ($allow_remote) { 586 $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); 587 foreach ($a_styles as $line) { 588 $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); 589 // ... and only allow strict url() values 590 if (stripos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims', $line)) { 591 $a_styles = array('/* evil! */'); 592 break; 593 } 594 } 595 $styles = join(";\n", $a_styles); 596 } 597 598 $key = $replacements->add($styles); 599 $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2); 600 $last_pos = $pos+2; 601 } 602 603 // remove html comments and add #container to each tag selector. 604 // also replace body definition because we also stripped off the <body> tag 605 $styles = preg_replace( 606 array( 607 '/(^\s*<!--)|(-->\s*$)/', 608 '/(^\s*|,\s*|\}\s*)([a-z0-9\._#\*][a-z0-9\.\-_]*)/im', 609 '/'.preg_quote($container_id, '/').'\s+body/i', 610 ), 611 array( 612 '', 613 "\\1#$container_id \\2", 614 $container_id, 615 ), 616 $source); 617 618 // put block contents back in 619 $styles = $replacements->resolve($styles); 620 621 return $styles; 622 } 623 624 625 /** 626 * Decode escaped entities used by known XSS exploits. 627 * See http://downloads.securityfocus.com/vulnerabilities/exploits/26800.eml for examples 628 * 629 * @param string CSS content to decode 630 * @return string Decoded string 631 */ 139 { 140 return rcube_ui::mod_css_styles($source, $container_id, $allow_remote); 141 } 142 632 143 function rcmail_xss_entity_decode($content) 633 144 { 634 $out = html_entity_decode(html_entity_decode($content)); 635 $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out); 636 $out = preg_replace('#/\*.*\*/#Ums', '', $out); 637 return $out; 638 } 639 640 641 /** 642 * preg_replace_callback callback for rcmail_xss_entity_decode_callback 643 * 644 * @param array matches result from preg_replace_callback 645 * @return string decoded entity 646 */ 647 function rcmail_xss_entity_decode_callback($matches) 648 { 649 return chr(hexdec($matches[1])); 650 } 651 652 /** 653 * Compose a valid attribute string for HTML tags 654 * 655 * @param array Named tag attributes 656 * @param array List of allowed attributes 657 * @return string HTML formatted attribute string 658 */ 145 return rcube_ui::xss_entity_decode($content); 146 } 147 659 148 function create_attrib_string($attrib, $allowed_attribs=array('id', 'class', 'style')) 660 { 661 // allow the following attributes to be added to the <iframe> tag 662 $attrib_str = ''; 663 foreach ($allowed_attribs as $a) 664 if (isset($attrib[$a])) 665 $attrib_str .= sprintf(' %s="%s"', $a, str_replace('"', '"', $attrib[$a])); 666 667 return $attrib_str; 668 } 669 670 671 /** 672 * Convert a HTML attribute string attributes to an associative array (name => value) 673 * 674 * @param string Input string 675 * @return array Key-value pairs of parsed attributes 676 */ 149 { 150 return html::attrib_string($attrib, $allowed_attribs); 151 } 152 677 153 function parse_attrib_string($str) 678 { 679 $attrib = array(); 680 preg_match_all('/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/Ui', stripslashes($str), $regs, PREG_SET_ORDER); 681 682 // convert attributes to an associative array (name => value) 683 if ($regs) { 684 foreach ($regs as $attr) { 685 $attrib[strtolower($attr[1])] = html_entity_decode($attr[3] . $attr[4]); 686 } 687 } 688 689 return $attrib; 690 } 691 692 693 /** 694 * Improved equivalent to strtotime() 695 * 696 * @param string Date string 697 * @return int 698 */ 699 function rcube_strtotime($date) 700 { 701 // check for MS Outlook vCard date format YYYYMMDD 702 if (preg_match('/^([12][90]\d\d)([01]\d)(\d\d)$/', trim($date), $matches)) { 703 return mktime(0,0,0, intval($matches[2]), intval($matches[3]), intval($matches[1])); 704 } 705 else if (is_numeric($date)) 706 return $date; 707 708 // support non-standard "GMTXXXX" literal 709 $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); 710 711 // if date parsing fails, we have a date in non-rfc format. 712 // remove token from the end and try again 713 while ((($ts = @strtotime($date)) === false) || ($ts < 0)) { 714 $d = explode(' ', $date); 715 array_pop($d); 716 if (!$d) break; 717 $date = implode(' ', $d); 718 } 719 720 return $ts; 721 } 722 723 724 /** 725 * Convert the given date to a human readable form 726 * This uses the date formatting properties from config 727 * 728 * @param mixed Date representation (string, timestamp or DateTime object) 729 * @param string Date format to use 730 * @param bool Enables date convertion according to user timezone 731 * 732 * @return string Formatted date string 733 */ 154 { 155 return html::parse_attrib_string($str); 156 } 157 734 158 function format_date($date, $format=NULL, $convert=true) 735 159 { 736 global $RCMAIL, $CONFIG; 737 738 if (is_object($date) && is_a($date, 'DateTime')) { 739 $timestamp = $date->format('U'); 740 } 741 else { 742 if (!empty($date)) 743 $timestamp = rcube_strtotime($date); 744 745 if (empty($timestamp)) 746 return ''; 747 748 try { 749 $date = new DateTime("@".$timestamp); 750 } 751 catch (Exception $e) { 752 return ''; 753 } 754 } 755 756 if ($convert) { 757 try { 758 // convert to the right timezone 759 $stz = date_default_timezone_get(); 760 $tz = new DateTimeZone($RCMAIL->config->get('timezone')); 761 $date->setTimezone($tz); 762 date_default_timezone_set($tz->getName()); 763 764 $timestamp = $date->format('U'); 765 } 766 catch (Exception $e) { 767 } 768 } 769 770 // define date format depending on current time 771 if (!$format) { 772 $now = time(); 773 $now_date = getdate($now); 774 $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']); 775 $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']); 776 777 if ($CONFIG['prettydate'] && $timestamp > $today_limit && $timestamp < $now) { 778 $format = $RCMAIL->config->get('date_today', $RCMAIL->config->get('time_format', 'H:i')); 779 $today = true; 780 } 781 else if ($CONFIG['prettydate'] && $timestamp > $week_limit && $timestamp < $now) 782 $format = $RCMAIL->config->get('date_short', 'D H:i'); 783 else 784 $format = $RCMAIL->config->get('date_long', 'Y-m-d H:i'); 785 } 786 787 // strftime() format 788 if (preg_match('/%[a-z]+/i', $format)) { 789 $format = strftime($format, $timestamp); 790 791 if ($convert && $stz) { 792 date_default_timezone_set($stz); 793 } 794 795 return $today ? (rcube_label('today') . ' ' . $format) : $format; 796 } 797 798 // parse format string manually in order to provide localized weekday and month names 799 // an alternative would be to convert the date() format string to fit with strftime() 800 $out = ''; 801 for ($i=0; $i<strlen($format); $i++) { 802 if ($format[$i]=='\\') // skip escape chars 803 continue; 804 805 // write char "as-is" 806 if ($format[$i]==' ' || $format{$i-1}=='\\') 807 $out .= $format[$i]; 808 // weekday (short) 809 else if ($format[$i]=='D') 810 $out .= rcube_label(strtolower(date('D', $timestamp))); 811 // weekday long 812 else if ($format[$i]=='l') 813 $out .= rcube_label(strtolower(date('l', $timestamp))); 814 // month name (short) 815 else if ($format[$i]=='M') 816 $out .= rcube_label(strtolower(date('M', $timestamp))); 817 // month name (long) 818 else if ($format[$i]=='F') 819 $out .= rcube_label('long'.strtolower(date('M', $timestamp))); 820 else if ($format[$i]=='x') 821 $out .= strftime('%x %X', $timestamp); 822 else 823 $out .= date($format[$i], $timestamp); 824 } 825 826 if ($today) { 827 $label = rcube_label('today'); 828 // replcae $ character with "Today" label (#1486120) 829 if (strpos($out, '$') !== false) { 830 $out = preg_replace('/\$/', $label, $out, 1); 831 } 832 else { 833 $out = $label . ' ' . $out; 834 } 835 } 836 837 if ($convert && $stz) { 838 date_default_timezone_set($stz); 839 } 840 841 return $out; 842 } 843 844 845 /** 846 * Compose a valid representation of name and e-mail address 847 * 848 * @param string E-mail address 849 * @param string Person name 850 * @return string Formatted string 851 */ 852 function format_email_recipient($email, $name='') 853 { 854 if ($name && $name != $email) { 855 // Special chars as defined by RFC 822 need to in quoted string (or escaped). 856 return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, trim($email)); 857 } 858 859 return trim($email); 860 } 861 862 863 /** 864 * Return the mailboxlist in HTML 865 * 866 * @param array Named parameters 867 * @return string HTML code for the gui object 868 */ 160 return rcube_ui::format_date($date, $format, $convert); 161 } 162 869 163 function rcmail_mailbox_list($attrib) 870 164 { 871 global $RCMAIL; 872 static $a_mailboxes; 873 874 $attrib += array('maxlength' => 100, 'realnames' => false, 'unreadwrap' => ' (%s)'); 875 876 // add some labels to client 877 $RCMAIL->output->add_label('purgefolderconfirm', 'deletemessagesconfirm'); 878 879 $type = $attrib['type'] ? $attrib['type'] : 'ul'; 880 unset($attrib['type']); 881 882 if ($type=='ul' && !$attrib['id']) 883 $attrib['id'] = 'rcmboxlist'; 884 885 if (empty($attrib['folder_name'])) 886 $attrib['folder_name'] = '*'; 887 888 // get mailbox list 889 $mbox_name = $RCMAIL->storage->get_folder(); 890 891 // build the folders tree 892 if (empty($a_mailboxes)) { 893 // get mailbox list 894 $a_folders = $RCMAIL->storage->list_folders_subscribed('', $attrib['folder_name'], $attrib['folder_filter']); 895 $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); 896 $a_mailboxes = array(); 897 898 foreach ($a_folders as $folder) 899 rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter); 900 } 901 902 // allow plugins to alter the folder tree or to localize folder names 903 $hook = $RCMAIL->plugins->exec_hook('render_mailboxlist', array( 904 'list' => $a_mailboxes, 905 'delimiter' => $delimiter, 906 'type' => $type, 907 'attribs' => $attrib, 908 )); 909 910 $a_mailboxes = $hook['list']; 911 $attrib = $hook['attribs']; 912 913 if ($type == 'select') { 914 $select = new html_select($attrib); 915 916 // add no-selection option 917 if ($attrib['noselection']) 918 $select->add(rcube_label($attrib['noselection']), ''); 919 920 rcmail_render_folder_tree_select($a_mailboxes, $mbox_name, $attrib['maxlength'], $select, $attrib['realnames']); 921 $out = $select->show($attrib['default']); 922 } 923 else { 924 $js_mailboxlist = array(); 925 $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($a_mailboxes, $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib); 926 927 $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']); 928 $RCMAIL->output->set_env('mailboxes', $js_mailboxlist); 929 $RCMAIL->output->set_env('unreadwrap', $attrib['unreadwrap']); 930 $RCMAIL->output->set_env('collapsed_folders', (string)$RCMAIL->config->get('collapsed_folders')); 931 } 932 933 return $out; 934 } 935 936 937 /** 938 * Return the mailboxlist as html_select object 939 * 940 * @param array Named parameters 941 * @return html_select HTML drop-down object 942 */ 943 function rcmail_mailbox_select($p = array()) 944 { 945 global $RCMAIL; 946 947 $p += array('maxlength' => 100, 'realnames' => false); 948 $a_mailboxes = array(); 949 $storage = $RCMAIL->get_storage(); 950 951 if (empty($p['folder_name'])) { 952 $p['folder_name'] = '*'; 953 } 954 955 if ($p['unsubscribed']) 956 $list = $storage->list_folders('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); 957 else 958 $list = $storage->list_folders_subscribed('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); 959 960 $delimiter = $storage->get_hierarchy_delimiter(); 961 962 foreach ($list as $folder) { 963 if (empty($p['exceptions']) || !in_array($folder, $p['exceptions'])) 964 rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter); 965 } 966 967 $select = new html_select($p); 968 969 if ($p['noselection']) 970 $select->add($p['noselection'], ''); 971 972 rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p); 973 974 return $select; 975 } 976 977 978 /** 979 * Create a hierarchical array of the mailbox list 980 * @access private 981 * @return void 982 */ 983 function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='') 984 { 985 global $RCMAIL; 986 987 // Handle namespace prefix 988 $prefix = ''; 989 if (!$path) { 990 $n_folder = $folder; 991 $folder = $RCMAIL->storage->mod_folder($folder); 992 993 if ($n_folder != $folder) { 994 $prefix = substr($n_folder, 0, -strlen($folder)); 995 } 996 } 997 998 $pos = strpos($folder, $delm); 999 1000 if ($pos !== false) { 1001 $subFolders = substr($folder, $pos+1); 1002 $currentFolder = substr($folder, 0, $pos); 1003 1004 // sometimes folder has a delimiter as the last character 1005 if (!strlen($subFolders)) 1006 $virtual = false; 1007 else if (!isset($arrFolders[$currentFolder])) 1008 $virtual = true; 1009 else 1010 $virtual = $arrFolders[$currentFolder]['virtual']; 1011 } 1012 else { 1013 $subFolders = false; 1014 $currentFolder = $folder; 1015 $virtual = false; 1016 } 1017 1018 $path .= $prefix.$currentFolder; 1019 1020 if (!isset($arrFolders[$currentFolder])) { 1021 $arrFolders[$currentFolder] = array( 1022 'id' => $path, 1023 'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'), 1024 'virtual' => $virtual, 1025 'folders' => array()); 1026 } 1027 else 1028 $arrFolders[$currentFolder]['virtual'] = $virtual; 1029 1030 if (strlen($subFolders)) 1031 rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm); 1032 } 1033 1034 1035 /** 1036 * Return html for a structured list <ul> for the mailbox tree 1037 * @access private 1038 * @return string 1039 */ 1040 function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $attrib, $nestLevel=0) 1041 { 1042 global $RCMAIL, $CONFIG; 1043 1044 $maxlength = intval($attrib['maxlength']); 1045 $realnames = (bool)$attrib['realnames']; 1046 $msgcounts = $RCMAIL->storage->get_cache('messagecount'); 1047 1048 $out = ''; 1049 foreach ($arrFolders as $key => $folder) { 1050 $title = null; 1051 $folder_class = rcmail_folder_classname($folder['id']); 1052 $collapsed = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false; 1053 $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0; 1054 1055 if ($folder_class && !$realnames) { 1056 $foldername = rcube_label($folder_class); 1057 } 1058 else { 1059 $foldername = $folder['name']; 1060 1061 // shorten the folder name to a given length 1062 if ($maxlength && $maxlength > 1) { 1063 $fname = abbreviate_string($foldername, $maxlength); 1064 if ($fname != $foldername) 1065 $title = $foldername; 1066 $foldername = $fname; 1067 } 1068 } 1069 1070 // make folder name safe for ids and class names 1071 $folder_id = html_identifier($folder['id'], true); 1072 $classes = array('mailbox'); 1073 1074 // set special class for Sent, Drafts, Trash and Junk 1075 if ($folder_class) 1076 $classes[] = $folder_class; 1077 1078 if ($folder['id'] == $mbox_name) 1079 $classes[] = 'selected'; 1080 1081 if ($folder['virtual']) 1082 $classes[] = 'virtual'; 1083 else if ($unread) 1084 $classes[] = 'unread'; 1085 1086 $js_name = JQ($folder['id']); 1087 $html_name = Q($foldername) . ($unread ? html::span('unreadcount', sprintf($attrib['unreadwrap'], $unread)) : ''); 1088 $link_attrib = $folder['virtual'] ? array() : array( 1089 'href' => rcmail_url('', array('_mbox' => $folder['id'])), 1090 'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name), 1091 'rel' => $folder['id'], 1092 'title' => $title, 1093 ); 1094 1095 $out .= html::tag('li', array( 1096 'id' => "rcmli".$folder_id, 1097 'class' => join(' ', $classes), 1098 'noclose' => true), 1099 html::a($link_attrib, $html_name) . 1100 (!empty($folder['folders']) ? html::div(array( 1101 'class' => ($collapsed ? 'collapsed' : 'expanded'), 1102 'style' => "position:absolute", 1103 'onclick' => sprintf("%s.command('collapse-folder', '%s')", JS_OBJECT_NAME, $js_name) 1104 ), ' ') : '')); 1105 1106 $jslist[$folder_id] = array('id' => $folder['id'], 'name' => $foldername, 'virtual' => $folder['virtual']); 1107 1108 if (!empty($folder['folders'])) { 1109 $out .= html::tag('ul', array('style' => ($collapsed ? "display:none;" : null)), 1110 rcmail_render_folder_tree_html($folder['folders'], $mbox_name, $jslist, $attrib, $nestLevel+1)); 1111 } 1112 1113 $out .= "</li>\n"; 1114 } 1115 1116 return $out; 1117 } 1118 1119 1120 /** 1121 * Return html for a flat list <select> for the mailbox tree 1122 * @access private 1123 * @return string 1124 */ 1125 function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $opts=array()) 1126 { 1127 global $RCMAIL; 1128 1129 $out = ''; 1130 1131 foreach ($arrFolders as $key => $folder) { 1132 // skip exceptions (and its subfolders) 1133 if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { 1134 continue; 1135 } 1136 1137 // skip folders in which it isn't possible to create subfolders 1138 if (!empty($opts['skip_noinferiors']) && ($attrs = $RCMAIL->storage->folder_attributes($folder['id'])) 1139 && in_array('\\Noinferiors', $attrs) 1140 ) { 1141 continue; 1142 } 1143 1144 if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) 1145 $foldername = rcube_label($folder_class); 1146 else { 1147 $foldername = $folder['name']; 1148 1149 // shorten the folder name to a given length 1150 if ($maxlength && $maxlength>1) 1151 $foldername = abbreviate_string($foldername, $maxlength); 1152 } 1153 1154 $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); 1155 1156 if (!empty($folder['folders'])) 1157 $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, 1158 $select, $realnames, $nestLevel+1, $opts); 1159 } 1160 1161 return $out; 1162 } 1163 1164 1165 /** 1166 * Return internal name for the given folder if it matches the configured special folders 1167 * @access private 1168 * @return string 1169 */ 1170 function rcmail_folder_classname($folder_id) 1171 { 1172 global $CONFIG; 1173 1174 if ($folder_id == 'INBOX') 1175 return 'inbox'; 1176 1177 // for these mailboxes we have localized labels and css classes 1178 foreach (array('sent', 'drafts', 'trash', 'junk') as $smbx) 1179 { 1180 if ($folder_id == $CONFIG[$smbx.'_mbox']) 1181 return $smbx; 1182 } 1183 } 1184 1185 1186 /** 1187 * Try to localize the given IMAP folder name. 1188 * UTF-7 decode it in case no localized text was found 1189 * 1190 * @param string Folder name 1191 * @return string Localized folder name in UTF-8 encoding 1192 */ 165 return rcube_ui::folder_list($attrib); 166 } 167 168 function rcmail_mailbox_select($attrib = array()) 169 { 170 return rcube_ui::folder_selector($attrib); 171 } 172 1193 173 function rcmail_localize_foldername($name) 1194 174 { 1195 if ($folder_class = rcmail_folder_classname($name)) 1196 return rcube_label($folder_class); 1197 else 1198 return rcube_charset_convert($name, 'UTF7-IMAP'); 1199 } 1200 175 return rcube_ui::localize_foldername($name); 176 } 1201 177 1202 178 function rcmail_localize_folderpath($path) 1203 179 { 1204 global $RCMAIL; 1205 1206 $protect_folders = $RCMAIL->config->get('protect_default_folders'); 1207 $default_folders = (array) $RCMAIL->config->get('default_folders'); 1208 $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); 1209 $path = explode($delimiter, $path); 1210 $result = array(); 1211 1212 foreach ($path as $idx => $dir) { 1213 $directory = implode($delimiter, array_slice($path, 0, $idx+1)); 1214 if ($protect_folders && in_array($directory, $default_folders)) { 1215 unset($result); 1216 $result[] = rcmail_localize_foldername($directory); 1217 } 1218 else { 1219 $result[] = rcube_charset_convert($dir, 'UTF7-IMAP'); 1220 } 1221 } 1222 1223 return implode($delimiter, $result); 1224 } 1225 180 return rcube_ui::localize_folderpath($path); 181 } 1226 182 1227 183 function rcmail_quota_display($attrib) 1228 184 { 1229 global $OUTPUT; 1230 1231 if (!$attrib['id']) 1232 $attrib['id'] = 'rcmquotadisplay'; 1233 1234 $_SESSION['quota_display'] = !empty($attrib['display']) ? $attrib['display'] : 'text'; 1235 1236 $OUTPUT->add_gui_object('quotadisplay', $attrib['id']); 1237 1238 $quota = rcmail_quota_content($attrib); 1239 1240 $OUTPUT->add_script('rcmail.set_quota('.json_serialize($quota).');', 'docready'); 1241 1242 return html::span($attrib, ''); 1243 } 1244 1245 1246 function rcmail_quota_content($attrib=NULL) 1247 { 1248 global $RCMAIL; 1249 1250 $quota = $RCMAIL->storage->get_quota(); 1251 $quota = $RCMAIL->plugins->exec_hook('quota', $quota); 1252 1253 $quota_result = (array) $quota; 1254 $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : ''; 1255 1256 if (!$quota['total'] && $RCMAIL->config->get('quota_zero_as_unlimited')) { 1257 $quota_result['title'] = rcube_label('unlimited'); 1258 $quota_result['percent'] = 0; 1259 } 1260 else if ($quota['total']) { 1261 if (!isset($quota['percent'])) 1262 $quota_result['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100)); 1263 1264 $title = sprintf('%s / %s (%.0f%%)', 1265 show_bytes($quota['used'] * 1024), show_bytes($quota['total'] * 1024), 1266 $quota_result['percent']); 1267 1268 $quota_result['title'] = $title; 1269 1270 if ($attrib['width']) 1271 $quota_result['width'] = $attrib['width']; 1272 if ($attrib['height']) 1273 $quota_result['height'] = $attrib['height']; 1274 } 1275 else { 1276 $quota_result['title'] = rcube_label('unknown'); 1277 $quota_result['percent'] = 0; 1278 } 1279 1280 return $quota_result; 1281 } 1282 1283 1284 /** 1285 * Outputs error message according to server error/response codes 1286 * 1287 * @param string Fallback message label 1288 * @param string Fallback message label arguments 1289 * 1290 * @return void 1291 */ 185 return rcube_ui::quota_display($attrib); 186 } 187 188 function rcmail_quota_content($attrib = null) 189 { 190 return rcube_ui::quota_content($attrib); 191 } 192 1292 193 function rcmail_display_server_error($fallback=null, $fallback_args=null) 1293 194 { 1294 global $RCMAIL; 1295 1296 $err_code = $RCMAIL->storage->get_error_code(); 1297 $res_code = $RCMAIL->storage->get_response_code(); 1298 1299 if ($err_code < 0) { 1300 $RCMAIL->output->show_message('storageerror', 'error'); 1301 } 1302 else if ($res_code == rcube_storage::NOPERM) { 1303 $RCMAIL->output->show_message('errornoperm', 'error'); 1304 } 1305 else if ($res_code == rcube_storage::READONLY) { 1306 $RCMAIL->output->show_message('errorreadonly', 'error'); 1307 } 1308 else if ($err_code && ($err_str = $RCMAIL->storage->get_error_str())) { 1309 // try to detect access rights problem and display appropriate message 1310 if (stripos($err_str, 'Permission denied') !== false) 1311 $RCMAIL->output->show_message('errornoperm', 'error'); 1312 else 1313 $RCMAIL->output->show_message('servererrormsg', 'error', array('msg' => $err_str)); 1314 } 1315 else if ($fallback) { 1316 $RCMAIL->output->show_message($fallback, 'error', $fallback_args); 1317 } 1318 1319 return true; 1320 } 1321 1322 1323 /** 1324 * Generate CSS classes from mimetype and filename extension 1325 * 1326 * @param string Mimetype 1327 * @param string The filename 1328 * @return string CSS classes separated by space 1329 */ 195 rcube_ui::display_server_error($fallback, $fallback_args); 196 } 197 1330 198 function rcmail_filetype2classname($mimetype, $filename) 1331 199 { 1332 list($primary, $secondary) = explode('/', $mimetype); 1333 1334 $classes = array($primary ? $primary : 'unknown'); 1335 if ($secondary) { 1336 $classes[] = $secondary; 1337 } 1338 if (preg_match('/\.([a-z0-9]+)$/i', $filename, $m)) { 1339 $classes[] = $m[1]; 1340 } 1341 1342 return strtolower(join(" ", $classes)); 1343 } 1344 1345 /** 1346 * Output HTML editor scripts 1347 * 1348 * @param string Editor mode 1349 * @return void 1350 */ 200 return rcube_ui::file2class($mimetype, $filename); 201 } 202 1351 203 function rcube_html_editor($mode='') 1352 204 { 1353 global $RCMAIL; 1354 1355 $hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode)); 1356 1357 if ($hook['abort']) 1358 return; 1359 1360 $lang = strtolower($_SESSION['language']); 1361 1362 // TinyMCE uses two-letter lang codes, with exception of Chinese 1363 if (strpos($lang, 'zh_') === 0) 1364 $lang = str_replace('_', '-', $lang); 1365 else 1366 $lang = substr($lang, 0, 2); 1367 1368 if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js')) 1369 $lang = 'en'; 1370 1371 $RCMAIL->output->include_script('tiny_mce/tiny_mce.js'); 1372 $RCMAIL->output->include_script('editor.js'); 1373 $RCMAIL->output->add_script(sprintf("rcmail_editor_init(%s)", 1374 json_encode(array( 1375 'mode' => $mode, 1376 'lang' => $lang, 1377 'skin_path' => $RCMAIL->output->get_skin_path(), 1378 'spellcheck' => intval($RCMAIL->config->get('enable_spellcheck')), 1379 'spelldict' => intval($RCMAIL->config->get('spellcheck_dictionary')), 1380 ))), 'docready'); 1381 } 1382 1383 1384 /** 1385 * Replaces TinyMCE's emoticon images with plain-text representation 1386 * 1387 * @param string HTML content 1388 * @return string HTML content 1389 */ 205 rcube_ui::html_editor($mode); 206 } 207 1390 208 function rcmail_replace_emoticons($html) 1391 209 { 1392 $emoticons = array( 1393 '8-)' => 'smiley-cool', 1394 ':-#' => 'smiley-foot-in-mouth', 1395 ':-*' => 'smiley-kiss', 1396 ':-X' => 'smiley-sealed', 1397 ':-P' => 'smiley-tongue-out', 1398 ':-@' => 'smiley-yell', 1399 ":'(" => 'smiley-cry', 1400 ':-(' => 'smiley-frown', 1401 ':-D' => 'smiley-laughing', 1402 ':-)' => 'smiley-smile', 1403 ':-S' => 'smiley-undecided', 1404 ':-$' => 'smiley-embarassed', 1405 'O:-)' => 'smiley-innocent', 1406 ':-|' => 'smiley-money-mouth', 1407 ':-O' => 'smiley-surprised', 1408 ';-)' => 'smiley-wink', 1409 ); 1410 1411 foreach ($emoticons as $idx => $file) { 1412 // <img title="Cry" src="http://.../program/js/tiny_mce/plugins/emotions/img/smiley-cry.gif" border="0" alt="Cry" /> 1413 $search[] = '/<img title="[a-z ]+" src="https?:\/\/[a-z0-9_.\/-]+\/tiny_mce\/plugins\/emotions\/img\/'.$file.'.gif"[^>]+\/>/i'; 1414 $replace[] = $idx; 1415 } 1416 1417 return preg_replace($search, $replace, $html); 1418 } 1419 1420 1421 /** 1422 * Send the given message using the configured method 1423 * 1424 * @param object $message Reference to Mail_MIME object 1425 * @param string $from Sender address string 1426 * @param array $mailto Array of recipient address strings 1427 * @param array $smtp_error SMTP error array (reference) 1428 * @param string $body_file Location of file with saved message body (reference), 1429 * used when delay_file_io is enabled 1430 * @param array $smtp_opts SMTP options (e.g. DSN request) 1431 * 1432 * @return boolean Send status. 1433 */ 210 return rcube_ui::replace_emoticons($html); 211 } 212 1434 213 function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file=null, $smtp_opts=null) 1435 214 { 1436 global $CONFIG, $RCMAIL; 1437 1438 $headers = $message->headers(); 1439 1440 // send thru SMTP server using custom SMTP library 1441 if ($CONFIG['smtp_server']) { 1442 // generate list of recipients 1443 $a_recipients = array($mailto); 1444 1445 if (strlen($headers['Cc'])) 1446 $a_recipients[] = $headers['Cc']; 1447 if (strlen($headers['Bcc'])) 1448 $a_recipients[] = $headers['Bcc']; 1449 1450 // clean Bcc from header for recipients 1451 $send_headers = $headers; 1452 unset($send_headers['Bcc']); 1453 // here too, it because txtHeaders() below use $message->_headers not only $send_headers 1454 unset($message->_headers['Bcc']); 1455 1456 $smtp_headers = $message->txtHeaders($send_headers, true); 1457 1458 if ($message->getParam('delay_file_io')) { 1459 // use common temp dir 1460 $temp_dir = $RCMAIL->config->get('temp_dir'); 1461 $body_file = tempnam($temp_dir, 'rcmMsg'); 1462 if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) { 1463 raise_error(array('code' => 650, 'type' => 'php', 1464 'file' => __FILE__, 'line' => __LINE__, 1465 'message' => "Could not create message: ".$mime_result->getMessage()), 1466 TRUE, FALSE); 1467 return false; 1468 } 1469 $msg_body = fopen($body_file, 'r'); 1470 } else { 1471 $msg_body = $message->get(); 1472 } 1473 1474 // send message 1475 if (!is_object($RCMAIL->smtp)) 1476 $RCMAIL->smtp_init(true); 1477 1478 $sent = $RCMAIL->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts); 1479 $smtp_response = $RCMAIL->smtp->get_response(); 1480 $smtp_error = $RCMAIL->smtp->get_error(); 1481 1482 // log error 1483 if (!$sent) 1484 raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__, 1485 'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE); 1486 } 1487 // send mail using PHP's mail() function 1488 else { 1489 // unset some headers because they will be added by the mail() function 1490 $headers_enc = $message->headers($headers); 1491 $headers_php = $message->_headers; 1492 unset($headers_php['To'], $headers_php['Subject']); 1493 1494 // reset stored headers and overwrite 1495 $message->_headers = array(); 1496 $header_str = $message->txtHeaders($headers_php); 1497 1498 // #1485779 1499 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 1500 if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) { 1501 $headers_enc['To'] = implode(', ', $m[1]); 1502 } 1503 } 1504 1505 $msg_body = $message->get(); 1506 1507 if (PEAR::isError($msg_body)) 1508 raise_error(array('code' => 650, 'type' => 'php', 1509 'file' => __FILE__, 'line' => __LINE__, 1510 'message' => "Could not create message: ".$msg_body->getMessage()), 1511 TRUE, FALSE); 1512 else { 1513 $delim = $RCMAIL->config->header_delimiter(); 1514 $to = $headers_enc['To']; 1515 $subject = $headers_enc['Subject']; 1516 $header_str = rtrim($header_str); 1517 1518 if ($delim != "\r\n") { 1519 $header_str = str_replace("\r\n", $delim, $header_str); 1520 $msg_body = str_replace("\r\n", $delim, $msg_body); 1521 $to = str_replace("\r\n", $delim, $to); 1522 $subject = str_replace("\r\n", $delim, $subject); 1523 } 1524 1525 if (ini_get('safe_mode')) 1526 $sent = mail($to, $subject, $msg_body, $header_str); 1527 else 1528 $sent = mail($to, $subject, $msg_body, $header_str, "-f$from"); 1529 } 1530 } 1531 1532 if ($sent) { 1533 $RCMAIL->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); 1534 1535 // remove MDN headers after sending 1536 unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); 1537 1538 // get all recipients 1539 if ($headers['Cc']) 1540 $mailto .= $headers['Cc']; 1541 if ($headers['Bcc']) 1542 $mailto .= $headers['Bcc']; 1543 if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m)) 1544 $mailto = implode(', ', array_unique($m[1])); 1545 1546 if ($CONFIG['smtp_log']) { 1547 write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", 1548 $RCMAIL->user->get_username(), 1549 $_SERVER['REMOTE_ADDR'], 1550 $mailto, 1551 !empty($smtp_response) ? join('; ', $smtp_response) : '')); 1552 } 1553 } 1554 1555 if (is_resource($msg_body)) { 1556 fclose($msg_body); 1557 } 1558 1559 $message->_headers = array(); 1560 $message->headers($headers); 1561 1562 return $sent; 1563 } 1564 1565 1566 // Returns unique Message-ID 215 return rcmail::get_instance()->deliver_message($message, $from, $mailto, $smtp_error, $body_file, $smtp_opts); 216 } 217 1567 218 function rcmail_gen_message_id() 1568 219 { 1569 global $RCMAIL; 1570 1571 $local_part = md5(uniqid('rcmail'.mt_rand(),true)); 1572 $domain_part = $RCMAIL->user->get_username('domain'); 1573 1574 // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924) 1575 if (!preg_match('/\.[a-z]+$/i', $domain_part)) { 1576 if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST'])) 1577 && preg_match('/\.[a-z]+$/i', $host)) { 1578 $domain_part = $host; 1579 } 1580 else if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['SERVER_NAME'])) 1581 && preg_match('/\.[a-z]+$/i', $host)) { 1582 $domain_part = $host; 1583 } 1584 } 1585 1586 return sprintf('<%s@%s>', $local_part, $domain_part); 1587 } 1588 1589 1590 // Returns RFC2822 formatted current date in user's timezone 220 return rcmail::get_instance()->gen_message_id(); 221 } 222 1591 223 function rcmail_user_date() 1592 224 { 1593 global $RCMAIL; 1594 1595 // get user's timezone 1596 try { 1597 $tz = new DateTimeZone($RCMAIL->config->get('timezone')); 1598 $date = new DateTime('now', $tz); 1599 } 1600 catch (Exception $e) { 1601 $date = new DateTime(); 1602 } 1603 1604 return $date->format('r'); 1605 } 1606 1607 1608 /** 1609 * Check if we can process not exceeding memory_limit 1610 * 1611 * @param integer Required amount of memory 1612 * @return boolean 1613 */ 225 return rcmail::get_instance()->user_date(); 226 } 227 1614 228 function rcmail_mem_check($need) 1615 229 { 1616 $mem_limit = parse_bytes(ini_get('memory_limit')); 1617 $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB 1618 1619 return $mem_limit > 0 && $memory + $need > $mem_limit ? false : true; 1620 } 1621 1622 1623 /** 1624 * Check if working in SSL mode 1625 * 1626 * @param integer HTTPS port number 1627 * @param boolean Enables 'use_https' option checking 1628 * @return boolean 1629 */ 230 return rcube_ui::mem_check($need); 231 } 232 1630 233 function rcube_https_check($port=null, $use_https=true) 1631 234 { 1632 global $RCMAIL; 1633 1634 if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') 1635 return true; 1636 if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') 1637 return true; 1638 if ($port && $_SERVER['SERVER_PORT'] == $port) 1639 return true; 1640 if ($use_https && isset($RCMAIL) && $RCMAIL->config->get('use_https')) 1641 return true; 1642 1643 return false; 1644 } 1645 1646 1647 /** 1648 * For backward compatibility. 1649 * 1650 * @global rcmail $RCMAIL 1651 * @param string $var_name Variable name. 1652 * @return void 1653 */ 235 return rcube_ui::https_check($port, $use_https); 236 } 237 1654 238 function rcube_sess_unset($var_name=null) 1655 239 { 1656 global $RCMAIL; 1657 1658 $RCMAIL->session->remove($var_name); 1659 } 1660 1661 1662 /** 1663 * Replaces hostname variables 1664 * 1665 * @param string $name Hostname 1666 * @param string $host Optional IMAP hostname 1667 * @return string 1668 */ 240 rcmail::get_instance()->session->remove($var_name); 241 } 242 1669 243 function rcube_parse_host($name, $host='') 1670 244 { 1671 // %n - host 1672 $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); 1673 // %d - domain name without first part, e.g. %n=mail.domain.tld, %d=domain.tld 1674 $d = preg_replace('/^[^\.]+\./', '', $n); 1675 // %h - IMAP host 1676 $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host; 1677 // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld 1678 $z = preg_replace('/^[^\.]+\./', '', $h); 1679 // %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided 1680 if ( strpos($name, '%s') !== false ){ 1681 $user_email = rcube_idn_convert(get_input_value('_user', RCUBE_INPUT_POST), true); 1682 if ( preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s) < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false ) 1683 return false; 1684 } 1685 1686 $name = str_replace(array('%n', '%d', '%h', '%z', '%s'), array($n, $d, $h, $z, $s[2]), $name); 1687 return $name; 1688 } 1689 1690 1691 /** 1692 * E-mail address validation 1693 * 1694 * @param string $email Email address 1695 * @param boolean $dns_check True to check dns 1696 * @return boolean 1697 */ 245 return rcmail::parse_host($name, $host); 246 } 247 1698 248 function check_email($email, $dns_check=true) 1699 249 { 1700 // Check for invalid characters 1701 if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) 1702 return false; 1703 1704 // Check for length limit specified by RFC 5321 (#1486453) 1705 if (strlen($email) > 254) 1706 return false; 1707 1708 $email_array = explode('@', $email); 1709 1710 // Check that there's one @ symbol 1711 if (count($email_array) < 2) 1712 return false; 1713 1714 $domain_part = array_pop($email_array); 1715 $local_part = implode('@', $email_array); 1716 1717 // from PEAR::Validate 1718 $regexp = '&^(?: 1719 ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name 1720 ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322) 1721 $&xi'; 1722 1723 if (!preg_match($regexp, $local_part)) 1724 return false; 1725 1726 // Check domain part 1727 if (preg_match('/^\[*(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]*$/', $domain_part)) 1728 return true; // IP address 1729 else { 1730 // If not an IP address 1731 $domain_array = explode('.', $domain_part); 1732 if (sizeof($domain_array) < 2) 1733 return false; // Not enough parts to be a valid domain 1734 1735 foreach ($domain_array as $part) 1736 if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) 1737 return false; 1738 1739 if (!$dns_check || !rcmail::get_instance()->config->get('email_dns_check')) 1740 return true; 1741 1742 if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { 1743 $lookup = array(); 1744 @exec("nslookup -type=MX " . escapeshellarg($domain_part) . " 2>&1", $lookup); 1745 foreach ($lookup as $line) { 1746 if (strpos($line, 'MX preference')) 1747 return true; 1748 } 1749 return false; 1750 } 1751 1752 // find MX record(s) 1753 if (getmxrr($domain_part, $mx_records)) 1754 return true; 1755 1756 // find any DNS record 1757 if (checkdnsrr($domain_part, 'ANY')) 1758 return true; 1759 } 1760 1761 return false; 1762 } 1763 1764 /* 1765 * Idn_to_ascii wrapper. 1766 * Intl/Idn modules version of this function doesn't work with e-mail address 1767 */ 1768 function rcube_idn_to_ascii($str) 1769 { 1770 return rcube_idn_convert($str, true); 1771 } 1772 1773 /* 1774 * Idn_to_ascii wrapper. 1775 * Intl/Idn modules version of this function doesn't work with e-mail address 1776 */ 1777 function rcube_idn_to_utf8($str) 1778 { 1779 return rcube_idn_convert($str, false); 1780 } 1781 1782 function rcube_idn_convert($input, $is_utf=false) 1783 { 1784 if ($at = strpos($input, '@')) { 1785 $user = substr($input, 0, $at); 1786 $domain = substr($input, $at+1); 1787 } 1788 else { 1789 $domain = $input; 1790 } 1791 1792 $domain = $is_utf ? idn_to_ascii($domain) : idn_to_utf8($domain); 1793 1794 if ($domain === false) { 1795 return ''; 1796 } 1797 1798 return $at ? $user . '@' . $domain : $domain; 1799 } 1800 1801 1802 /** 1803 * Helper class to turn relative urls into absolute ones 1804 * using a predefined base 1805 */ 1806 class rcube_base_replacer 1807 { 1808 private $base_url; 1809 1810 public function __construct($base) 1811 { 1812 $this->base_url = $base; 1813 } 1814 1815 public function callback($matches) 1816 { 1817 return $matches[1] . '="' . self::absolute_url($matches[3], $this->base_url) . '"'; 1818 } 1819 1820 public function replace($body) 1821 { 1822 return preg_replace_callback(array( 1823 '/(src|background|href)=(["\']?)([^"\'\s]+)(\2|\s|>)/Ui', 1824 '/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/Ui', 1825 ), 1826 array($this, 'callback'), $body); 1827 } 1828 1829 /** 1830 * Convert paths like ../xxx to an absolute path using a base url 1831 * 1832 * @param string $path Relative path 1833 * @param string $base_url Base URL 1834 * 1835 * @return string Absolute URL 1836 */ 1837 public static function absolute_url($path, $base_url) 1838 { 1839 $host_url = $base_url; 1840 $abs_path = $path; 1841 1842 // check if path is an absolute URL 1843 if (preg_match('/^[fhtps]+:\/\//', $path)) { 1844 return $path; 1845 } 1846 1847 // check if path is a content-id scheme 1848 if (strpos($path, 'cid:') === 0) { 1849 return $path; 1850 } 1851 1852 // cut base_url to the last directory 1853 if (strrpos($base_url, '/') > 7) { 1854 $host_url = substr($base_url, 0, strpos($base_url, '/', 7)); 1855 $base_url = substr($base_url, 0, strrpos($base_url, '/')); 1856 } 1857 1858 // $path is absolute 1859 if ($path[0] == '/') { 1860 $abs_path = $host_url.$path; 1861 } 1862 else { 1863 // strip './' because its the same as '' 1864 $path = preg_replace('/^\.\//', '', $path); 1865 1866 if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) { 1867 foreach ($matches as $a_match) { 1868 if (strrpos($base_url, '/')) { 1869 $base_url = substr($base_url, 0, strrpos($base_url, '/')); 1870 } 1871 $path = substr($path, 3); 1872 } 1873 } 1874 1875 $abs_path = $base_url.'/'.$path; 1876 } 1877 1878 return $abs_path; 1879 } 1880 } 1881 1882 1883 /****** debugging and logging functions ********/ 1884 1885 /** 1886 * Print or write debug messages 1887 * 1888 * @param mixed Debug message or data 1889 * @return void 1890 */ 250 return rcmail::get_instance()->check_email($email, $dns_check); 251 } 252 1891 253 function console() 1892 254 { 1893 $args = func_get_args(); 1894 1895 if (class_exists('rcmail', false)) { 1896 $rcmail = rcmail::get_instance(); 1897 if (is_object($rcmail->plugins)) { 1898 $plugin = $rcmail->plugins->exec_hook('console', array('args' => $args)); 1899 if ($plugin['abort']) 1900 return; 1901 $args = $plugin['args']; 1902 } 1903 } 1904 1905 $msg = array(); 1906 foreach ($args as $arg) 1907 $msg[] = !is_string($arg) ? var_export($arg, true) : $arg; 1908 1909 write_log('console', join(";\n", $msg)); 1910 } 1911 1912 1913 /** 1914 * Append a line to a logfile in the logs directory. 1915 * Date will be added automatically to the line. 1916 * 1917 * @param $name name of log file 1918 * @param line Line to append 1919 * @return void 1920 */ 255 call_user_func_array(array('rcmail', 'console'), func_get_args()); 256 } 257 1921 258 function write_log($name, $line) 1922 259 { 1923 global $CONFIG, $RCMAIL; 1924 1925 if (!is_string($line)) 1926 $line = var_export($line, true); 1927 1928 if (empty($CONFIG['log_date_format'])) 1929 $CONFIG['log_date_format'] = 'd-M-Y H:i:s O'; 1930 1931 $date = date($CONFIG['log_date_format']); 1932 1933 // trigger logging hook 1934 if (is_object($RCMAIL) && is_object($RCMAIL->plugins)) { 1935 $log = $RCMAIL->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line)); 1936 $name = $log['name']; 1937 $line = $log['line']; 1938 $date = $log['date']; 1939 if ($log['abort']) 1940 return true; 1941 } 1942 1943 if ($CONFIG['log_driver'] == 'syslog') { 1944 $prio = $name == 'errors' ? LOG_ERR : LOG_INFO; 1945 syslog($prio, $line); 1946 return true; 1947 } 1948 else { 1949 $line = sprintf("[%s]: %s\n", $date, $line); 1950 1951 // log_driver == 'file' is assumed here 1952 if (empty($CONFIG['log_dir'])) 1953 $CONFIG['log_dir'] = INSTALL_PATH.'logs'; 1954 1955 // try to open specific log file for writing 1956 $logfile = $CONFIG['log_dir'].'/'.$name; 1957 if ($fp = @fopen($logfile, 'a')) { 1958 fwrite($fp, $line); 1959 fflush($fp); 1960 fclose($fp); 1961 return true; 1962 } 1963 else 1964 trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING); 1965 } 1966 1967 return false; 1968 } 1969 1970 1971 /** 1972 * Write login data (name, ID, IP address) to the 'userlogins' log file. 1973 * 1974 * @return void 1975 */ 260 return rcmail::write_log($name, $line); 261 } 262 1976 263 function rcmail_log_login() 1977 264 { 1978 global $RCMAIL; 1979 1980 if (!$RCMAIL->config->get('log_logins') || !$RCMAIL->user) 1981 return; 1982 1983 write_log('userlogins', sprintf('Successful login for %s (ID: %d) from %s in session %s', 1984 $RCMAIL->user->get_username(), $RCMAIL->user->ID, rcmail_remote_ip(), session_id())); 1985 } 1986 1987 1988 /** 1989 * Returns remote IP address and forwarded addresses if found 1990 * 1991 * @return string Remote IP address(es) 1992 */ 265 return rcmail::get_instance()->log_login(); 266 } 267 1993 268 function rcmail_remote_ip() 1994 269 { 1995 $address = $_SERVER['REMOTE_ADDR']; 1996 1997 // append the NGINX X-Real-IP header, if set 1998 if (!empty($_SERVER['HTTP_X_REAL_IP'])) { 1999 $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP']; 2000 } 2001 // append the X-Forwarded-For header, if set 2002 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 2003 $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR']; 2004 } 2005 2006 if (!empty($remote_ip)) 2007 $address .= '(' . implode(',', $remote_ip) . ')'; 2008 2009 return $address; 2010 } 2011 2012 2013 /** 2014 * Check whether the HTTP referer matches the current request 2015 * 2016 * @return boolean True if referer is the same host+path, false if not 2017 */ 270 return rcmail::remote_ip(); 271 } 272 2018 273 function rcube_check_referer() 2019 274 { 2020 $uri = parse_url($_SERVER['REQUEST_URI']); 2021 $referer = parse_url(rc_request_header('Referer')); 2022 return $referer['host'] == rc_request_header('Host') && $referer['path'] == $uri['path']; 2023 } 2024 2025 2026 /** 2027 * @access private 2028 * @return mixed 2029 */ 275 return rcmail::check_referer(); 276 } 277 2030 278 function rcube_timer() 2031 279 { 2032 return microtime(true); 2033 } 2034 2035 2036 /** 2037 * @access private 2038 * @return void 2039 */ 280 return rcmail::timer(); 281 } 282 2040 283 function rcube_print_time($timer, $label='Timer', $dest='console') 2041 284 { 2042 static $print_count = 0; 2043 2044 $print_count++; 2045 $now = rcube_timer(); 2046 $diff = $now-$timer; 2047 2048 if (empty($label)) 2049 $label = 'Timer '.$print_count; 2050 2051 write_log($dest, sprintf("%s: %0.4f sec", $label, $diff)); 2052 } 2053 2054 2055 /** 2056 * Throw system error and show error page 2057 * 2058 * @param array Named parameters 2059 * - code: Error code (required) 2060 * - type: Error type [php|db|imap|javascript] (required) 2061 * - message: Error message 2062 * - file: File where error occured 2063 * - line: Line where error occured 2064 * @param boolean True to log the error 2065 * @param boolean Terminate script execution 2066 */ 2067 // may be defined in Installer 2068 if (!function_exists('raise_error')) { 285 rcmail::print_timer($timer, $label, $dest); 286 } 287 2069 288 function raise_error($arg=array(), $log=false, $terminate=false) 2070 289 { 2071 global $__page_content, $CONFIG, $OUTPUT, $ERROR_CODE, $ERROR_MESSAGE; 2072 2073 // report bug (if not incompatible browser) 2074 if ($log && $arg['type'] && $arg['message']) 2075 rcube_log_bug($arg); 2076 2077 // display error page and terminate script 2078 if ($terminate) { 2079 $ERROR_CODE = $arg['code']; 2080 $ERROR_MESSAGE = $arg['message']; 2081 include INSTALL_PATH . 'program/steps/utils/error.inc'; 2082 exit; 2083 } 2084 } 2085 } 2086 2087 2088 /** 2089 * Report error according to configured debug_level 2090 * 2091 * @param array Named parameters 2092 * @return void 2093 * @see raise_error() 2094 */ 290 rcmail::raise_error($arg, $log, $terminate); 291 } 292 2095 293 function rcube_log_bug($arg_arr) 2096 294 { 2097 global $CONFIG; 2098 2099 $program = strtoupper($arg_arr['type']); 2100 $level = $CONFIG['debug_level']; 2101 2102 // disable errors for ajax requests, write to log instead (#1487831) 2103 if (($level & 4) && !empty($_REQUEST['_remote'])) { 2104 $level = ($level ^ 4) | 1; 2105 } 2106 2107 // write error to local log file 2108 if ($level & 1) { 2109 $post_query = ($_SERVER['REQUEST_METHOD'] == 'POST' ? '?_task='.urlencode($_POST['_task']).'&_action='.urlencode($_POST['_action']) : ''); 2110 $log_entry = sprintf("%s Error: %s%s (%s %s)", 2111 $program, 2112 $arg_arr['message'], 2113 $arg_arr['file'] ? sprintf(' in %s on line %d', $arg_arr['file'], $arg_arr['line']) : '', 2114 $_SERVER['REQUEST_METHOD'], 2115 $_SERVER['REQUEST_URI'] . $post_query); 2116 2117 if (!write_log('errors', $log_entry)) { 2118 // send error to PHPs error handler if write_log didn't succeed 2119 trigger_error($arg_arr['message']); 2120 } 2121 } 2122 2123 // report the bug to the global bug reporting system 2124 if ($level & 2) { 2125 // TODO: Send error via HTTP 2126 } 2127 2128 // show error if debug_mode is on 2129 if ($level & 4) { 2130 print "<b>$program Error"; 2131 2132 if (!empty($arg_arr['file']) && !empty($arg_arr['line'])) 2133 print " in $arg_arr[file] ($arg_arr[line])"; 2134 2135 print ':</b> '; 2136 print nl2br($arg_arr['message']); 2137 print '<br />'; 2138 flush(); 2139 } 295 rcmail::log_bug($arg_arr); 2140 296 } 2141 297 2142 298 function rcube_upload_progress() 2143 299 { 2144 global $RCMAIL; 2145 2146 $prefix = ini_get('apc.rfc1867_prefix'); 2147 $params = array( 2148 'action' => $RCMAIL->action, 2149 'name' => get_input_value('_progress', RCUBE_INPUT_GET), 2150 ); 2151 2152 if (function_exists('apc_fetch')) { 2153 $status = apc_fetch($prefix . $params['name']); 2154 2155 if (!empty($status)) { 2156 $status['percent'] = round($status['current']/$status['total']*100); 2157 $params = array_merge($status, $params); 2158 } 2159 } 2160 2161 if (isset($params['percent'])) 2162 $params['text'] = rcube_label(array('name' => 'uploadprogress', 'vars' => array( 2163 'percent' => $params['percent'] . '%', 2164 'current' => show_bytes($params['current']), 2165 'total' => show_bytes($params['total']) 2166 ))); 2167 2168 $RCMAIL->output->command('upload_progress_update', $params); 2169 $RCMAIL->output->send(); 300 rcube_ui::upload_progress(); 2170 301 } 2171 302 2172 303 function rcube_upload_init() 2173 304 { 2174 global $RCMAIL; 2175 2176 // Enable upload progress bar 2177 if (($seconds = $RCMAIL->config->get('upload_progress')) && ini_get('apc.rfc1867')) { 2178 if ($field_name = ini_get('apc.rfc1867_name')) { 2179 $RCMAIL->output->set_env('upload_progress_name', $field_name); 2180 $RCMAIL->output->set_env('upload_progress_time', (int) $seconds); 2181 } 2182 } 2183 2184 // find max filesize value 2185 $max_filesize = parse_bytes(ini_get('upload_max_filesize')); 2186 $max_postsize = parse_bytes(ini_get('post_max_size')); 2187 if ($max_postsize && $max_postsize < $max_filesize) 2188 $max_filesize = $max_postsize; 2189 2190 $RCMAIL->output->set_env('max_filesize', $max_filesize); 2191 $max_filesize = show_bytes($max_filesize); 2192 $RCMAIL->output->set_env('filesizeerror', rcube_label(array( 2193 'name' => 'filesizeerror', 'vars' => array('size' => $max_filesize)))); 2194 2195 return $max_filesize; 2196 } 2197 2198 /** 2199 * Initializes client-side autocompletion 2200 */ 305 return rcube_ui::upload_init(); 306 } 307 2201 308 function rcube_autocomplete_init() 2202 309 { 2203 global $RCMAIL; 2204 static $init; 2205 2206 if ($init) 2207 return; 2208 2209 $init = 1; 2210 2211 if (($threads = (int)$RCMAIL->config->get('autocomplete_threads')) > 0) { 2212 $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql'); 2213 if (count($book_types) > 1) { 2214 $RCMAIL->output->set_env('autocomplete_threads', $threads); 2215 $RCMAIL->output->set_env('autocomplete_sources', $book_types); 2216 } 2217 } 2218 2219 $RCMAIL->output->set_env('autocomplete_max', (int)$RCMAIL->config->get('autocomplete_max', 15)); 2220 $RCMAIL->output->set_env('autocomplete_min_length', $RCMAIL->config->get('autocomplete_min_length')); 2221 $RCMAIL->output->add_label('autocompletechars', 'autocompletemore'); 310 rcube_ui::autocomplete_init(); 2222 311 } 2223 312 2224 313 function rcube_fontdefs($font = null) 2225 314 { 2226 $fonts = array( 2227 'Andale Mono' => '"Andale Mono",Times,monospace', 2228 'Arial' => 'Arial,Helvetica,sans-serif', 2229 'Arial Black' => '"Arial Black","Avant Garde",sans-serif', 2230 'Book Antiqua' => '"Book Antiqua",Palatino,serif', 2231 'Courier New' => '"Courier New",Courier,monospace', 2232 'Georgia' => 'Georgia,Palatino,serif', 2233 'Helvetica' => 'Helvetica,Arial,sans-serif', 2234 'Impact' => 'Impact,Chicago,sans-serif', 2235 'Tahoma' => 'Tahoma,Arial,Helvetica,sans-serif', 2236 'Terminal' => 'Terminal,Monaco,monospace', 2237 'Times New Roman' => '"Times New Roman",Times,serif', 2238 'Trebuchet MS' => '"Trebuchet MS",Geneva,sans-serif', 2239 'Verdana' => 'Verdana,Geneva,sans-serif', 2240 ); 2241 2242 if ($font) 2243 return $fonts[$font]; 2244 2245 return $fonts; 2246 } 315 return rcube_ui::font_defs($font); 316 } 317 318 function send_nocacheing_headers() 319 { 320 return rcmail::get_instance()->output->nocacheing_headers(); 321 } 322 323 function show_bytes($bytes) 324 { 325 return rcube_ui::show_bytes($bytes); 326 } 327 328 function rc_wordwrap($string, $width=75, $break="\n", $cut=false) 329 { 330 return rcube_mime::wordwrap($string, $width, $break, $cut); 331 } 332 333 function rc_request_header($name) 334 { 335 return rcube_request_header($name); 336 } 337 338 function rc_mime_content_type($path, $name, $failover = 'application/octet-stream', $is_stream=false) 339 { 340 return rcube_mime::file_content_type($path, $name, $failover, $is_stream); 341 } 342 343 function rc_image_content_type($data) 344 { 345 return rcube_mime::image_content_type($data); 346 } -
trunk/roundcubemail/program/include/rcmail.php
r6030 r6073 6 6 | | 7 7 | This file is part of the Roundcube Webmail client | 8 | Copyright (C) 2008-201 1, The Roundcube Dev Team |9 | Copyright (C) 2011 , Kolab Systems AG|8 | Copyright (C) 2008-2012, The Roundcube Dev Team | 9 | Copyright (C) 2011-2012, Kolab Systems AG | 10 10 | | 11 11 | Licensed under the GNU General Public License version 3 or | … … 31 31 * @package Core 32 32 */ 33 class rcmail 33 class rcmail extends rcube 34 34 { 35 35 /** … … 39 39 */ 40 40 static public $main_tasks = array('mail','settings','addressbook','login','logout','utils','dummy'); 41 42 /**43 * Singleton instace of rcmail44 *45 * @var rcmail46 */47 static private $instance;48 49 /**50 * Stores instance of rcube_config.51 *52 * @var rcube_config53 */54 public $config;55 56 /**57 * Stores rcube_user instance.58 *59 * @var rcube_user60 */61 public $user;62 63 /**64 * Instace of database class.65 *66 * @var rcube_mdb267 */68 public $db;69 70 /**71 * Instace of Memcache class.72 *73 * @var rcube_mdb274 */75 public $memcache;76 77 /**78 * Instace of rcube_session class.79 *80 * @var rcube_session81 */82 public $session;83 84 /**85 * Instance of rcube_smtp class.86 *87 * @var rcube_smtp88 */89 public $smtp;90 91 /**92 * Instance of rcube_storage class.93 *94 * @var rcube_storage95 */96 public $storage;97 98 /**99 * Instance of rcube_template class.100 *101 * @var rcube_template102 */103 public $output;104 105 /**106 * Instance of rcube_plugin_api.107 *108 * @var rcube_plugin_api109 */110 public $plugins;111 41 112 42 /** … … 125 55 public $comm_path = './'; 126 56 127 private $texts;128 57 private $address_books = array(); 129 private $caches = array();130 58 private $action_map = array(); 131 private $shutdown_functions = array();132 private $expunge_cache = false;133 59 134 60 … … 140 66 static function get_instance() 141 67 { 142 if (!self::$instance ) {68 if (!self::$instance || !is_a(self::$instance, 'rcmail')) { 143 69 self::$instance = new rcmail(); 144 70 self::$instance->startup(); // init AFTER object was linked with self::$instance … … 150 76 151 77 /** 152 * Private constructor153 */154 private function __construct()155 {156 // load configuration157 $this->config = new rcube_config();158 159 register_shutdown_function(array($this, 'shutdown'));160 }161 162 163 /**164 78 * Initial startup function 165 79 * to register session, create database and imap connections 166 80 */ 167 private function startup() 168 { 169 // initialize syslog 170 if ($this->config->get('log_driver') == 'syslog') { 171 $syslog_id = $this->config->get('syslog_id', 'roundcube'); 172 $syslog_facility = $this->config->get('syslog_facility', LOG_USER); 173 openlog($syslog_id, LOG_ODELAY, $syslog_facility); 174 } 175 176 // connect to database 177 $this->get_dbh(); 81 protected function startup() 82 { 83 $this->init(self::INIT_WITH_DB | self::INIT_WITH_PLUGINS); 178 84 179 85 // start session … … 187 93 188 94 // set task and action properties 189 $this->set_task( get_input_value('_task', RCUBE_INPUT_GPC));190 $this->action = asciiwords( get_input_value('_action', RCUBE_INPUT_GPC));95 $this->set_task(rcube_ui::get_input_value('_task', rcube_ui::INPUT_GPC)); 96 $this->action = asciiwords(rcube_ui::get_input_value('_action', rcube_ui::INPUT_GPC)); 191 97 192 98 // reset some session parameters when changing task … … 204 110 $GLOBALS['OUTPUT'] = $this->load_gui(!empty($_REQUEST['_framed'])); 205 111 206 // create plugin API and load plugins 207 $this->plugins = rcube_plugin_api::get_instance(); 208 209 // init plugins 210 $this->plugins->init(); 112 // load plugins 113 $this->plugins->init($this, $this->task); 114 $this->plugins->load_plugins((array)$this->config->get('plugins', array()), array('filesystem_attachments', 'jqueryui')); 211 115 } 212 116 … … 256 160 if (in_array($_SESSION['language'], array('tr_TR', 'ku', 'az_AZ'))) 257 161 setlocale(LC_CTYPE, 'en_US' . '.utf8'); 258 }259 260 261 /**262 * Check the given string and return a valid language code263 *264 * @param string Language code265 * @return string Valid language code266 */267 private function language_prop($lang)268 {269 static $rcube_languages, $rcube_language_aliases;270 271 // user HTTP_ACCEPT_LANGUAGE if no language is specified272 if (empty($lang) || $lang == 'auto') {273 $accept_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);274 $lang = str_replace('-', '_', $accept_langs[0]);275 }276 277 if (empty($rcube_languages)) {278 @include(INSTALL_PATH . 'program/localization/index.inc');279 }280 281 // check if we have an alias for that language282 if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang])) {283 $lang = $rcube_language_aliases[$lang];284 }285 // try the first two chars286 else if (!isset($rcube_languages[$lang])) {287 $short = substr($lang, 0, 2);288 289 // check if we have an alias for the short language code290 if (!isset($rcube_languages[$short]) && isset($rcube_language_aliases[$short])) {291 $lang = $rcube_language_aliases[$short];292 }293 // expand 'nn' to 'nn_NN'294 else if (!isset($rcube_languages[$short])) {295 $lang = $short.'_'.strtoupper($short);296 }297 }298 299 if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {300 $lang = 'en_US';301 }302 303 return $lang;304 }305 306 307 /**308 * Get the current database connection309 *310 * @return rcube_mdb2 Database connection object311 */312 public function get_dbh()313 {314 if (!$this->db) {315 $config_all = $this->config->all();316 317 $this->db = new rcube_mdb2($config_all['db_dsnw'], $config_all['db_dsnr'], $config_all['db_persistent']);318 $this->db->sqlite_initials = INSTALL_PATH . 'SQL/sqlite.initial.sql';319 $this->db->set_debug((bool)$config_all['sql_debug']);320 }321 322 return $this->db;323 }324 325 326 /**327 * Get global handle for memcache access328 *329 * @return object Memcache330 */331 public function get_memcache()332 {333 if (!isset($this->memcache)) {334 // no memcache support in PHP335 if (!class_exists('Memcache')) {336 $this->memcache = false;337 return false;338 }339 340 $this->memcache = new Memcache;341 $this->mc_available = 0;342 343 // add alll configured hosts to pool344 $pconnect = $this->config->get('memcache_pconnect', true);345 foreach ($this->config->get('memcache_hosts', array()) as $host) {346 list($host, $port) = explode(':', $host);347 if (!$port) $port = 11211;348 $this->mc_available += intval($this->memcache->addServer($host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure')));349 }350 351 // test connection and failover (will result in $this->mc_available == 0 on complete failure)352 $this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist353 354 if (!$this->mc_available)355 $this->memcache = false;356 }357 358 return $this->memcache;359 }360 361 /**362 * Callback for memcache failure363 */364 public function memcache_failure($host, $port)365 {366 static $seen = array();367 368 // only report once369 if (!$seen["$host:$port"]++) {370 $this->mc_available--;371 raise_error(array('code' => 604, 'type' => 'db',372 'line' => __LINE__, 'file' => __FILE__,373 'message' => "Memcache failure on host $host:$port"),374 true, false);375 }376 }377 378 379 /**380 * Initialize and get cache object381 *382 * @param string $name Cache identifier383 * @param string $type Cache type ('db', 'apc' or 'memcache')384 * @param int $ttl Expiration time for cache items in seconds385 * @param bool $packed Enables/disables data serialization386 *387 * @return rcube_cache Cache object388 */389 public function get_cache($name, $type='db', $ttl=0, $packed=true)390 {391 if (!isset($this->caches[$name])) {392 $this->caches[$name] = new rcube_cache($type, $_SESSION['user_id'], $name, $ttl, $packed);393 }394 395 return $this->caches[$name];396 162 } 397 163 … … 426 192 } 427 193 else if ($id === '0') { 428 $contacts = new rcube_contacts($this->db, $this-> user->ID);194 $contacts = new rcube_contacts($this->db, $this->get_user_id()); 429 195 } 430 196 else { … … 447 213 448 214 if (!$contacts) { 449 raise_error(array(215 self::raise_error(array( 450 216 'code' => 700, 'type' => 'php', 451 217 'file' => __FILE__, 'line' => __LINE__, … … 482 248 if ($abook_type != 'ldap') { 483 249 if (!isset($this->address_books['0'])) 484 $this->address_books['0'] = new rcube_contacts($this->db, $this-> user->ID);250 $this->address_books['0'] = new rcube_contacts($this->db, $this->get_user_id()); 485 251 $list['0'] = array( 486 252 'id' => '0', 487 'name' => rcube_label('personaladrbook'),253 'name' => $this->gettext('personaladrbook'), 488 254 'groups' => $this->address_books['0']->groups, 489 255 'readonly' => $this->address_books['0']->readonly, … … 533 299 * 534 300 * @param boolean True if this request is loaded in a (i)frame 535 * @return rcube_ templateReference to HTML output object301 * @return rcube_output_html Reference to HTML output object 536 302 */ 537 303 public function load_gui($framed = false) 538 304 { 539 305 // init output page 540 if (!($this->output instanceof rcube_ template))541 $this->output = new rcube_ template($this->task, $framed);306 if (!($this->output instanceof rcube_output_html)) 307 $this->output = new rcube_output_html($this->task, $framed); 542 308 543 309 // set keep-alive/check-recent interval … … 566 332 * Create an output object for JSON responses 567 333 * 568 * @return rcube_ json_outputReference to JSON output object334 * @return rcube_output_json Reference to JSON output object 569 335 */ 570 336 public function json_init() 571 337 { 572 if (!($this->output instanceof rcube_ json_output))573 $this->output = new rcube_ json_output($this->task);338 if (!($this->output instanceof rcube_output_json)) 339 $this->output = new rcube_output_json($this->task); 574 340 575 341 return $this->output; 576 }577 578 579 /**580 * Create SMTP object and connect to server581 *582 * @param boolean True if connection should be established583 */584 public function smtp_init($connect = false)585 {586 $this->smtp = new rcube_smtp();587 588 if ($connect)589 $this->smtp->connect();590 }591 592 593 /**594 * Initialize and get storage object595 *596 * @return rcube_storage Storage object597 */598 public function get_storage()599 {600 // already initialized601 if (!is_object($this->storage)) {602 $this->storage_init();603 }604 605 return $this->storage;606 }607 608 609 /**610 * Connect to the IMAP server with stored session data.611 *612 * @return bool True on success, False on error613 * @deprecated614 */615 public function imap_connect()616 {617 return $this->storage_connect();618 }619 620 621 /**622 * Initialize IMAP object.623 *624 * @deprecated625 */626 public function imap_init()627 {628 $this->storage_init();629 }630 631 632 /**633 * Initialize storage object634 */635 public function storage_init()636 {637 // already initialized638 if (is_object($this->storage)) {639 return;640 }641 642 $driver = $this->config->get('storage_driver', 'imap');643 $driver_class = "rcube_{$driver}";644 645 if (!class_exists($driver_class)) {646 raise_error(array(647 'code' => 700, 'type' => 'php',648 'file' => __FILE__, 'line' => __LINE__,649 'message' => "Storage driver class ($driver) not found!"),650 true, true);651 }652 653 // Initialize storage object654 $this->storage = new $driver_class;655 656 // for backward compat. (deprecated, will be removed)657 $this->imap = $this->storage;658 659 // enable caching of mail data660 $storage_cache = $this->config->get("{$driver}_cache");661 $messages_cache = $this->config->get('messages_cache');662 // for backward compatybility663 if ($storage_cache === null && $messages_cache === null && $this->config->get('enable_caching')) {664 $storage_cache = 'db';665 $messages_cache = true;666 }667 668 if ($storage_cache)669 $this->storage->set_caching($storage_cache);670 if ($messages_cache)671 $this->storage->set_messages_caching(true);672 673 // set pagesize from config674 $pagesize = $this->config->get('mail_pagesize');675 if (!$pagesize) {676 $pagesize = $this->config->get('pagesize', 50);677 }678 $this->storage->set_pagesize($pagesize);679 680 // set class options681 $options = array(682 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'),683 'auth_cid' => $this->config->get("{$driver}_auth_cid"),684 'auth_pw' => $this->config->get("{$driver}_auth_pw"),685 'debug' => (bool) $this->config->get("{$driver}_debug"),686 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"),687 'timeout' => (int) $this->config->get("{$driver}_timeout"),688 'skip_deleted' => (bool) $this->config->get('skip_deleted'),689 'driver' => $driver,690 );691 692 if (!empty($_SESSION['storage_host'])) {693 $options['host'] = $_SESSION['storage_host'];694 $options['user'] = $_SESSION['username'];695 $options['port'] = $_SESSION['storage_port'];696 $options['ssl'] = $_SESSION['storage_ssl'];697 $options['password'] = $this->decrypt($_SESSION['password']);698 // set 'imap_host' for backwards compatibility699 $_SESSION[$driver.'_host'] = &$_SESSION['storage_host'];700 }701 702 $options = $this->plugins->exec_hook("storage_init", $options);703 704 $this->storage->set_options($options);705 $this->set_storage_prop();706 }707 708 709 /**710 * Connect to the mail storage server with stored session data711 *712 * @return bool True on success, False on error713 */714 public function storage_connect()715 {716 $storage = $this->get_storage();717 718 if ($_SESSION['storage_host'] && !$storage->is_connected()) {719 $host = $_SESSION['storage_host'];720 $user = $_SESSION['username'];721 $port = $_SESSION['storage_port'];722 $ssl = $_SESSION['storage_ssl'];723 $pass = $this->decrypt($_SESSION['password']);724 725 if (!$storage->connect($host, $user, $pass, $port, $ssl)) {726 if ($this->output)727 $this->output->show_message($storage->get_error_code() == -1 ? 'storageerror' : 'sessionerror', 'error');728 }729 else {730 $this->set_storage_prop();731 }732 }733 734 return $storage->is_connected();735 342 } 736 343 … … 758 365 } 759 366 760 ini_set('session.cookie_secure', rcube_ https_check());367 ini_set('session.cookie_secure', rcube_ui::https_check()); 761 368 ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid'); 762 369 ini_set('session.use_cookies', 1); … … 767 374 $this->session = new rcube_session($this->get_dbh(), $this->config); 768 375 769 $this->session->register_gc_handler( 'rcmail_temp_gc');376 $this->session->register_gc_handler(array($this, 'temp_gc')); 770 377 $this->session->register_gc_handler(array($this, 'cache_gc')); 771 378 … … 843 450 return false; 844 451 } 845 else if (!empty($config['default_host']) && $host != rcube_parse_host($config['default_host']))452 else if (!empty($config['default_host']) && $host != self::parse_host($config['default_host'])) 846 453 return false; 847 454 … … 867 474 if (!empty($config['username_domain']) && strpos($username, '@') === false) { 868 475 if (is_array($config['username_domain']) && isset($config['username_domain'][$host])) 869 $username .= '@'. rcube_parse_host($config['username_domain'][$host], $host);476 $username .= '@'.self::parse_host($config['username_domain'][$host], $host); 870 477 else if (is_string($config['username_domain'])) 871 $username .= '@'. rcube_parse_host($config['username_domain'], $host);478 $username .= '@'.self::parse_host($config['username_domain'], $host); 872 479 } 873 480 … … 930 537 } 931 538 else { 932 raise_error(array(539 self::raise_error(array( 933 540 'code' => 620, 'type' => 'php', 934 541 'file' => __FILE__, 'line' => __LINE__, … … 938 545 } 939 546 else { 940 raise_error(array(547 self::raise_error(array( 941 548 'code' => 621, 'type' => 'php', 942 549 'file' => __FILE__, 'line' => __LINE__, … … 985 592 986 593 /** 987 * Set storage parameters.988 * This must be done AFTER connecting to the server!989 */990 private function set_storage_prop()991 {992 $storage = $this->get_storage();993 994 $storage->set_charset($this->config->get('default_charset', RCMAIL_CHARSET));995 996 if ($default_folders = $this->config->get('default_folders')) {997 $storage->set_default_folders($default_folders);998 }999 if (isset($_SESSION['mbox'])) {1000 $storage->set_folder($_SESSION['mbox']);1001 }1002 if (isset($_SESSION['page'])) {1003 $storage->set_page($_SESSION['page']);1004 }1005 }1006 1007 1008 /**1009 594 * Auto-select IMAP host based on the posted login information 1010 595 * … … 1017 602 1018 603 if (is_array($default_host)) { 1019 $post_host = get_input_value('_host', RCUBE_INPUT_POST);604 $post_host = rcube_ui::get_input_value('_host', rcube_ui::INPUT_POST); 1020 605 1021 606 // direct match in default_host array … … 1025 610 1026 611 // try to select host by mail domain 1027 list($user, $domain) = explode('@', get_input_value('_user', RCUBE_INPUT_POST));612 list($user, $domain) = explode('@', rcube_ui::get_input_value('_user', rcube_ui::INPUT_POST)); 1028 613 if (!empty($domain)) { 1029 614 foreach ($default_host as $storage_host => $mail_domains) { … … 1046 631 } 1047 632 else if (empty($default_host)) { 1048 $host = get_input_value('_host', RCUBE_INPUT_POST);633 $host = rcube_ui::get_input_value('_host', rcube_ui::INPUT_POST); 1049 634 } 1050 635 else 1051 $host = rcube_parse_host($default_host);636 $host = self::parse_host($default_host); 1052 637 1053 638 return $host; 1054 }1055 1056 1057 /**1058 * Get localized text in the desired language1059 *1060 * @param mixed $attrib Named parameters array or label name1061 * @param string $domain Label domain (plugin) name1062 *1063 * @return string Localized text1064 */1065 public function gettext($attrib, $domain=null)1066 {1067 // load localization files if not done yet1068 if (empty($this->texts))1069 $this->load_language();1070 1071 // extract attributes1072 if (is_string($attrib))1073 $attrib = array('name' => $attrib);1074 1075 $name = $attrib['name'] ? $attrib['name'] : '';1076 1077 // attrib contain text values: use them from now1078 if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us']))1079 $this->texts[$name] = $setval;1080 1081 // check for text with domain1082 if ($domain && ($text = $this->texts[$domain.'.'.$name]))1083 ;1084 // text does not exist1085 else if (!($text = $this->texts[$name])) {1086 return "[$name]";1087 }1088 1089 // replace vars in text1090 if (is_array($attrib['vars'])) {1091 foreach ($attrib['vars'] as $var_key => $var_value)1092 $text = str_replace($var_key[0]!='$' ? '$'.$var_key : $var_key, $var_value, $text);1093 }1094 1095 // format output1096 if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])1097 return ucfirst($text);1098 else if ($attrib['uppercase'])1099 return mb_strtoupper($text);1100 else if ($attrib['lowercase'])1101 return mb_strtolower($text);1102 1103 return strtr($text, array('\n' => "\n"));1104 }1105 1106 1107 /**1108 * Check if the given text label exists1109 *1110 * @param string $name Label name1111 * @param string $domain Label domain (plugin) name or '*' for all domains1112 * @param string $ref_domain Sets domain name if label is found1113 *1114 * @return boolean True if text exists (either in the current language or in en_US)1115 */1116 public function text_exists($name, $domain = null, &$ref_domain = null)1117 {1118 // load localization files if not done yet1119 if (empty($this->texts))1120 $this->load_language();1121 1122 if (isset($this->texts[$name])) {1123 $ref_domain = '';1124 return true;1125 }1126 1127 // any of loaded domains (plugins)1128 if ($domain == '*') {1129 foreach ($this->plugins->loaded_plugins() as $domain)1130 if (isset($this->texts[$domain.'.'.$name])) {1131 $ref_domain = $domain;1132 return true;1133 }1134 }1135 // specified domain1136 else if ($domain) {1137 $ref_domain = $domain;1138 return isset($this->texts[$domain.'.'.$name]);1139 }1140 1141 return false;1142 }1143 1144 /**1145 * Load a localization package1146 *1147 * @param string Language ID1148 */1149 public function load_language($lang = null, $add = array())1150 {1151 $lang = $this->language_prop(($lang ? $lang : $_SESSION['language']));1152 1153 // load localized texts1154 if (empty($this->texts) || $lang != $_SESSION['language']) {1155 $this->texts = array();1156 1157 // handle empty lines after closing PHP tag in localization files1158 ob_start();1159 1160 // get english labels (these should be complete)1161 @include(INSTALL_PATH . 'program/localization/en_US/labels.inc');1162 @include(INSTALL_PATH . 'program/localization/en_US/messages.inc');1163 1164 if (is_array($labels))1165 $this->texts = $labels;1166 if (is_array($messages))1167 $this->texts = array_merge($this->texts, $messages);1168 1169 // include user language files1170 if ($lang != 'en' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {1171 include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc');1172 include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc');1173 1174 if (is_array($labels))1175 $this->texts = array_merge($this->texts, $labels);1176 if (is_array($messages))1177 $this->texts = array_merge($this->texts, $messages);1178 }1179 1180 ob_end_clean();1181 1182 $_SESSION['language'] = $lang;1183 }1184 1185 // append additional texts (from plugin)1186 if (is_array($add) && !empty($add))1187 $this->texts += $add;1188 }1189 1190 1191 /**1192 * Read directory program/localization and return a list of available languages1193 *1194 * @return array List of available localizations1195 */1196 public function list_languages()1197 {1198 static $sa_languages = array();1199 1200 if (!sizeof($sa_languages)) {1201 @include(INSTALL_PATH . 'program/localization/index.inc');1202 1203 if ($dh = @opendir(INSTALL_PATH . 'program/localization')) {1204 while (($name = readdir($dh)) !== false) {1205 if ($name[0] == '.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name))1206 continue;1207 1208 if ($label = $rcube_languages[$name])1209 $sa_languages[$name] = $label;1210 }1211 closedir($dh);1212 }1213 }1214 1215 return $sa_languages;1216 639 } 1217 640 … … 1261 684 1262 685 /** 1263 * Function to be executed in script shutdown1264 * Registered with register_shutdown_function()1265 */1266 public function shutdown()1267 {1268 foreach ($this->shutdown_functions as $function)1269 call_user_func($function);1270 1271 if (is_object($this->smtp))1272 $this->smtp->disconnect();1273 1274 foreach ($this->address_books as $book) {1275 if (is_object($book) && is_a($book, 'rcube_addressbook'))1276 $book->close();1277 }1278 1279 foreach ($this->caches as $cache) {1280 if (is_object($cache))1281 $cache->close();1282 }1283 1284 if (is_object($this->storage)) {1285 if ($this->expunge_cache)1286 $this->storage->expunge_cache();1287 $this->storage->close();1288 }1289 1290 // before closing the database connection, write session data1291 if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) {1292 session_write_close();1293 }1294 1295 // write performance stats to logs/console1296 if ($this->config->get('devel_mode')) {1297 if (function_exists('memory_get_usage'))1298 $mem = show_bytes(memory_get_usage());1299 if (function_exists('memory_get_peak_usage'))1300 $mem .= '/'.show_bytes(memory_get_peak_usage());1301 1302 $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : '');1303 if (defined('RCMAIL_START'))1304 rcube_print_time(RCMAIL_START, $log);1305 else1306 console($log);1307 }1308 }1309 1310 1311 /**1312 * Registers shutdown function to be executed on shutdown.1313 * The functions will be executed before destroying any1314 * objects like smtp, imap, session, etc.1315 *1316 * @param callback Function callback1317 */1318 public function add_shutdown_function($function)1319 {1320 $this->shutdown_functions[] = $function;1321 }1322 1323 1324 /**1325 686 * Garbage collector for cache entries. 1326 687 * Set flag to expunge caches on shutdown … … 1343 704 $sess_id = $_COOKIE[ini_get('session.name')]; 1344 705 if (!$sess_id) $sess_id = session_id(); 1345 $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this-> user->ID. $this->config->get('des_key') . $sess_id)));706 $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->get_user_id() . $this->config->get('des_key') . $sess_id))); 1346 707 return $plugin['value']; 1347 708 } … … 1354 715 * @return boolean True if request token is valid false if not 1355 716 */ 1356 public function check_request($mode = RCUBE_INPUT_POST)1357 { 1358 $token = get_input_value('_token', $mode);717 public function check_request($mode = rcube_ui::INPUT_POST) 718 { 719 $token = rcube_ui::get_input_value('_token', $mode); 1359 720 $sess_id = $_COOKIE[ini_get('session.name')]; 1360 721 return !empty($sess_id) && $token == $this->get_request_token(); … … 1383 744 } 1384 745 1385 1386 /**1387 * Encrypt using 3DES1388 *1389 * @param string $clear clear text input1390 * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key'1391 * @param boolean $base64 whether or not to base64_encode() the result before returning1392 *1393 * @return string encrypted text1394 */1395 public function encrypt($clear, $key = 'des_key', $base64 = true)1396 {1397 if (!$clear)1398 return '';1399 /*-1400 * Add a single canary byte to the end of the clear text, which1401 * will help find out how much of padding will need to be removed1402 * upon decryption; see http://php.net/mcrypt_generic#680821403 */1404 $clear = pack("a*H2", $clear, "80");1405 1406 if (function_exists('mcrypt_module_open') &&1407 ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, "")))1408 {1409 $iv = $this->create_iv(mcrypt_enc_get_iv_size($td));1410 mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);1411 $cipher = $iv . mcrypt_generic($td, $clear);1412 mcrypt_generic_deinit($td);1413 mcrypt_module_close($td);1414 }1415 else {1416 @include_once 'des.inc';1417 1418 if (function_exists('des')) {1419 $des_iv_size = 8;1420 $iv = $this->create_iv($des_iv_size);1421 $cipher = $iv . des($this->config->get_crypto_key($key), $clear, 1, 1, $iv);1422 }1423 else {1424 raise_error(array(1425 'code' => 500, 'type' => 'php',1426 'file' => __FILE__, 'line' => __LINE__,1427 'message' => "Could not perform encryption; make sure Mcrypt is installed or lib/des.inc is available"1428 ), true, true);1429 }1430 }1431 1432 return $base64 ? base64_encode($cipher) : $cipher;1433 }1434 1435 /**1436 * Decrypt 3DES-encrypted string1437 *1438 * @param string $cipher encrypted text1439 * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key'1440 * @param boolean $base64 whether or not input is base64-encoded1441 *1442 * @return string decrypted text1443 */1444 public function decrypt($cipher, $key = 'des_key', $base64 = true)1445 {1446 if (!$cipher)1447 return '';1448 1449 $cipher = $base64 ? base64_decode($cipher) : $cipher;1450 1451 if (function_exists('mcrypt_module_open') &&1452 ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, "")))1453 {1454 $iv_size = mcrypt_enc_get_iv_size($td);1455 $iv = substr($cipher, 0, $iv_size);1456 1457 // session corruption? (#1485970)1458 if (strlen($iv) < $iv_size)1459 return '';1460 1461 $cipher = substr($cipher, $iv_size);1462 mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);1463 $clear = mdecrypt_generic($td, $cipher);1464 mcrypt_generic_deinit($td);1465 mcrypt_module_close($td);1466 }1467 else {1468 @include_once 'des.inc';1469 1470 if (function_exists('des')) {1471 $des_iv_size = 8;1472 $iv = substr($cipher, 0, $des_iv_size);1473 $cipher = substr($cipher, $des_iv_size);1474 $clear = des($this->config->get_crypto_key($key), $cipher, 0, 1, $iv);1475 }1476 else {1477 raise_error(array(1478 'code' => 500, 'type' => 'php',1479 'file' => __FILE__, 'line' => __LINE__,1480 'message' => "Could not perform decryption; make sure Mcrypt is installed or lib/des.inc is available"1481 ), true, true);1482 }1483 }1484 1485 /*-1486 * Trim PHP's padding and the canary byte; see note in1487 * rcmail::encrypt() and http://php.net/mcrypt_generic#680821488 */1489 $clear = substr(rtrim($clear, "\0"), 0, -1);1490 1491 return $clear;1492 }1493 1494 /**1495 * Generates encryption initialization vector (IV)1496 *1497 * @param int Vector size1498 * @return string Vector string1499 */1500 private function create_iv($size)1501 {1502 // mcrypt_create_iv() can be slow when system lacks entrophy1503 // we'll generate IV vector manually1504 $iv = '';1505 for ($i = 0; $i < $size; $i++)1506 $iv .= chr(mt_rand(0, 255));1507 return $iv;1508 }1509 746 1510 747 /** … … 1537 774 1538 775 /** 1539 * Construct shell command, execute it and return output as string. 1540 * Keywords {keyword} are replaced with arguments 1541 * 1542 * @param $cmd Format string with {keywords} to be replaced 1543 * @param $values (zero, one or more arrays can be passed) 1544 * @return output of command. shell errors not detectable 1545 */ 1546 public static function exec(/* $cmd, $values1 = array(), ... */) 1547 { 1548 $args = func_get_args(); 1549 $cmd = array_shift($args); 1550 $values = $replacements = array(); 1551 1552 // merge values into one array 1553 foreach ($args as $arg) 1554 $values += (array)$arg; 1555 1556 preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER); 1557 foreach ($matches as $tags) { 1558 list(, $tag, $option, $key) = $tags; 1559 $parts = array(); 1560 1561 if ($option) { 1562 foreach ((array)$values["-$key"] as $key => $value) { 1563 if ($value === true || $value === false || $value === null) 1564 $parts[] = $value ? $key : ""; 1565 else foreach ((array)$value as $val) 1566 $parts[] = "$key " . escapeshellarg($val); 1567 } 1568 } 1569 else { 1570 foreach ((array)$values[$key] as $value) 1571 $parts[] = escapeshellarg($value); 1572 } 1573 1574 $replacements[$tag] = join(" ", $parts); 1575 } 1576 1577 // use strtr behaviour of going through source string once 1578 $cmd = strtr($cmd, $replacements); 1579 1580 return (string)shell_exec($cmd); 1581 } 1582 776 * Function to be executed in script shutdown 777 */ 778 public function shutdown() 779 { 780 parent::shutdown(); 781 782 foreach ($this->address_books as $book) { 783 if (is_object($book) && is_a($book, 'rcube_addressbook')) 784 $book->close(); 785 } 786 787 // before closing the database connection, write session data 788 if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) { 789 session_write_close(); 790 } 791 792 // write performance stats to logs/console 793 if ($this->config->get('devel_mode')) { 794 if (function_exists('memory_get_usage')) 795 $mem = rcube_ui::show_bytes(memory_get_usage()); 796 if (function_exists('memory_get_peak_usage')) 797 $mem .= '/'.rcube_ui::show_bytes(memory_get_peak_usage()); 798 799 $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : ''); 800 if (defined('RCMAIL_START')) 801 self::print_timer(RCMAIL_START, $log); 802 else 803 self::console($log); 804 } 805 } 1583 806 1584 807 /** … … 1597 820 1598 821 setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'], 1599 rcube_ https_check(), true);822 rcube_ui::https_check(), true); 1600 823 } 1601 824 … … 1728 951 } 1729 952 953 954 /** 955 * Overwrite action variable 956 * 957 * @param string New action value 958 */ 959 public function overwrite_action($action) 960 { 961 $this->action = $action; 962 $this->output->set_env('action', $action); 963 } 964 965 966 /** 967 * Send the given message using the configured method. 968 * 969 * @param object $message Reference to Mail_MIME object 970 * @param string $from Sender address string 971 * @param array $mailto Array of recipient address strings 972 * @param array $smtp_error SMTP error array (reference) 973 * @param string $body_file Location of file with saved message body (reference), 974 * used when delay_file_io is enabled 975 * @param array $smtp_opts SMTP options (e.g. DSN request) 976 * 977 * @return boolean Send status. 978 */ 979 public function deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file = null, $smtp_opts = null) 980 { 981 $headers = $message->headers(); 982 983 // send thru SMTP server using custom SMTP library 984 if ($this->config->get('smtp_server')) { 985 // generate list of recipients 986 $a_recipients = array($mailto); 987 988 if (strlen($headers['Cc'])) 989 $a_recipients[] = $headers['Cc']; 990 if (strlen($headers['Bcc'])) 991 $a_recipients[] = $headers['Bcc']; 992 993 // clean Bcc from header for recipients 994 $send_headers = $headers; 995 unset($send_headers['Bcc']); 996 // here too, it because txtHeaders() below use $message->_headers not only $send_headers 997 unset($message->_headers['Bcc']); 998 999 $smtp_headers = $message->txtHeaders($send_headers, true); 1000 1001 if ($message->getParam('delay_file_io')) { 1002 // use common temp dir 1003 $temp_dir = $this->config->get('temp_dir'); 1004 $body_file = tempnam($temp_dir, 'rcmMsg'); 1005 if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) { 1006 self::raise_error(array('code' => 650, 'type' => 'php', 1007 'file' => __FILE__, 'line' => __LINE__, 1008 'message' => "Could not create message: ".$mime_result->getMessage()), 1009 TRUE, FALSE); 1010 return false; 1011 } 1012 $msg_body = fopen($body_file, 'r'); 1013 } 1014 else { 1015 $msg_body = $message->get(); 1016 } 1017 1018 // send message 1019 if (!is_object($this->smtp)) { 1020 $this->smtp_init(true); 1021 } 1022 1023 $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts); 1024 $smtp_response = $this->smtp->get_response(); 1025 $smtp_error = $this->smtp->get_error(); 1026 1027 // log error 1028 if (!$sent) { 1029 self::raise_error(array('code' => 800, 'type' => 'smtp', 1030 'line' => __LINE__, 'file' => __FILE__, 1031 'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE); 1032 } 1033 } 1034 // send mail using PHP's mail() function 1035 else { 1036 // unset some headers because they will be added by the mail() function 1037 $headers_enc = $message->headers($headers); 1038 $headers_php = $message->_headers; 1039 unset($headers_php['To'], $headers_php['Subject']); 1040 1041 // reset stored headers and overwrite 1042 $message->_headers = array(); 1043 $header_str = $message->txtHeaders($headers_php); 1044 1045 // #1485779 1046 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 1047 if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) { 1048 $headers_enc['To'] = implode(', ', $m[1]); 1049 } 1050 } 1051 1052 $msg_body = $message->get(); 1053 1054 if (PEAR::isError($msg_body)) { 1055 self::raise_error(array('code' => 650, 'type' => 'php', 1056 'file' => __FILE__, 'line' => __LINE__, 1057 'message' => "Could not create message: ".$msg_body->getMessage()), 1058 TRUE, FALSE); 1059 } 1060 else { 1061 $delim = $this->config->header_delimiter(); 1062 $to = $headers_enc['To']; 1063 $subject = $headers_enc['Subject']; 1064 $header_str = rtrim($header_str); 1065 1066 if ($delim != "\r\n") { 1067 $header_str = str_replace("\r\n", $delim, $header_str); 1068 $msg_body = str_replace("\r\n", $delim, $msg_body); 1069 $to = str_replace("\r\n", $delim, $to); 1070 $subject = str_replace("\r\n", $delim, $subject); 1071 } 1072 1073 if (ini_get('safe_mode')) 1074 $sent = mail($to, $subject, $msg_body, $header_str); 1075 else 1076 $sent = mail($to, $subject, $msg_body, $header_str, "-f$from"); 1077 } 1078 } 1079 1080 if ($sent) { 1081 $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); 1082 1083 // remove MDN headers after sending 1084 unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); 1085 1086 // get all recipients 1087 if ($headers['Cc']) 1088 $mailto .= $headers['Cc']; 1089 if ($headers['Bcc']) 1090 $mailto .= $headers['Bcc']; 1091 if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m)) 1092 $mailto = implode(', ', array_unique($m[1])); 1093 1094 if ($this->config->get('smtp_log')) { 1095 self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", 1096 $this->user->get_username(), 1097 $_SERVER['REMOTE_ADDR'], 1098 $mailto, 1099 !empty($smtp_response) ? join('; ', $smtp_response) : '')); 1100 } 1101 } 1102 1103 if (is_resource($msg_body)) { 1104 fclose($msg_body); 1105 } 1106 1107 $message->_headers = array(); 1108 $message->headers($headers); 1109 1110 return $sent; 1111 } 1112 1113 1114 /** 1115 * Unique Message-ID generator. 1116 * 1117 * @return string Message-ID 1118 */ 1119 public function gen_message_id() 1120 { 1121 $local_part = md5(uniqid('rcmail'.mt_rand(),true)); 1122 $domain_part = $this->user->get_username('domain'); 1123 1124 // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924) 1125 if (!preg_match('/\.[a-z]+$/i', $domain_part)) { 1126 foreach (array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']) as $host) { 1127 $host = preg_replace('/:[0-9]+$/', '', $host); 1128 if ($host && preg_match('/\.[a-z]+$/i', $host)) { 1129 $domain_part = $host; 1130 } 1131 } 1132 } 1133 1134 return sprintf('<%s@%s>', $local_part, $domain_part); 1135 } 1136 1137 1138 /** 1139 * Returns RFC2822 formatted current date in user's timezone 1140 * 1141 * @return string Date 1142 */ 1143 public function user_date() 1144 { 1145 // get user's timezone 1146 try { 1147 $tz = new DateTimeZone($this->config->get('timezone')); 1148 $date = new DateTime('now', $tz); 1149 } 1150 catch (Exception $e) { 1151 $date = new DateTime(); 1152 } 1153 1154 return $date->format('r'); 1155 } 1156 1157 1158 /** 1159 * E-mail address validation. 1160 * 1161 * @param string $email Email address 1162 * @param boolean $dns_check True to check dns 1163 * 1164 * @return boolean True on success, False if address is invalid 1165 */ 1166 public function check_email($email, $dns_check=true) 1167 { 1168 // Check for invalid characters 1169 if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) { 1170 return false; 1171 } 1172 1173 // Check for length limit specified by RFC 5321 (#1486453) 1174 if (strlen($email) > 254) { 1175 return false; 1176 } 1177 1178 $email_array = explode('@', $email); 1179 1180 // Check that there's one @ symbol 1181 if (count($email_array) < 2) { 1182 return false; 1183 } 1184 1185 $domain_part = array_pop($email_array); 1186 $local_part = implode('@', $email_array); 1187 1188 // from PEAR::Validate 1189 $regexp = '&^(?: 1190 ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name 1191 ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322) 1192 $&xi'; 1193 1194 if (!preg_match($regexp, $local_part)) { 1195 return false; 1196 } 1197 1198 // Check domain part 1199 if (preg_match('/^\[*(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]*$/', $domain_part)) { 1200 return true; // IP address 1201 } 1202 else { 1203 // If not an IP address 1204 $domain_array = explode('.', $domain_part); 1205 // Not enough parts to be a valid domain 1206 if (sizeof($domain_array) < 2) { 1207 return false; 1208 } 1209 1210 foreach ($domain_array as $part) { 1211 if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) { 1212 return false; 1213 } 1214 } 1215 1216 if (!$dns_check || !$this->config->get('email_dns_check')) { 1217 return true; 1218 } 1219 1220 if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { 1221 $lookup = array(); 1222 @exec("nslookup -type=MX " . escapeshellarg($domain_part) . " 2>&1", $lookup); 1223 foreach ($lookup as $line) { 1224 if (strpos($line, 'MX preference')) { 1225 return true; 1226 } 1227 } 1228 return false; 1229 } 1230 1231 // find MX record(s) 1232 if (getmxrr($domain_part, $mx_records)) { 1233 return true; 1234 } 1235 1236 // find any DNS record 1237 if (checkdnsrr($domain_part, 'ANY')) { 1238 return true; 1239 } 1240 } 1241 1242 return false; 1243 } 1244 1245 1246 /** 1247 * Write login data (name, ID, IP address) to the 'userlogins' log file. 1248 */ 1249 public function log_login() 1250 { 1251 if (!$this->config->get('log_logins')) { 1252 return; 1253 } 1254 1255 $user_name = $this->get_user_name(); 1256 $user_id = $this->get_user_id(); 1257 1258 if (!$user_id) { 1259 return; 1260 } 1261 1262 self::write_log('userlogins', 1263 sprintf('Successful login for %s (ID: %d) from %s in session %s', 1264 $user_name, $user_id, self::remote_ip(), session_id())); 1265 } 1266 1267 1268 /** 1269 * Check whether the HTTP referer matches the current request 1270 * 1271 * @return boolean True if referer is the same host+path, false if not 1272 */ 1273 public static function check_referer() 1274 { 1275 $uri = parse_url($_SERVER['REQUEST_URI']); 1276 $referer = parse_url(rcube_request_header('Referer')); 1277 return $referer['host'] == rcube_request_header('Host') && $referer['path'] == $uri['path']; 1278 } 1279 1280 1281 /** 1282 * Garbage collector function for temp files. 1283 * Remove temp files older than two days 1284 */ 1285 public function temp_gc() 1286 { 1287 $tmp = unslashify($this->config->get('temp_dir')); 1288 $expire = mktime() - 172800; // expire in 48 hours 1289 1290 if ($dir = opendir($tmp)) { 1291 while (($fname = readdir($dir)) !== false) { 1292 if ($fname{0} == '.') { 1293 continue; 1294 } 1295 1296 if (filemtime($tmp.'/'.$fname) < $expire) { 1297 @unlink($tmp.'/'.$fname); 1298 } 1299 } 1300 1301 closedir($dir); 1302 } 1303 } 1304 1730 1305 } -
trunk/roundcubemail/program/include/rcube.php
r5994 r6073 6 6 | | 7 7 | This file is part of the Roundcube Webmail client | 8 | Copyright (C) 2008-2011, The Roundcube Dev Team | 9 | Copyright (C) 2011, Kolab Systems AG | 10 | Licensed under the GNU GPL | 8 | Copyright (C) 2008-2012, The Roundcube Dev Team | 9 | Copyright (C) 2011-2012, Kolab Systems AG | 10 | | 11 | Licensed under the GNU General Public License version 3 or | 12 | any later version with exceptions for skins & plugins. | 13 | See the README file for a full license statement. | 11 14 | | 12 15 | PURPOSE: | … … 101 104 protected $caches = array(); 102 105 protected $shutdown_functions = array(); 106 protected $expunge_cache = false; 103 107 104 108 … … 769 773 } 770 774 771 if (is_object($this->storage)) 775 if (is_object($this->storage)) { 776 if ($this->expunge_cache) 777 $this->storage->expunge_cache(); 772 778 $this->storage->close(); 779 } 773 780 } 774 781 -
trunk/roundcubemail/program/include/rcube_addressbook.php
r5871 r6073 212 212 public function validate(&$save_data, $autofix = false) 213 213 { 214 $rcmail = rcmail::get_instance(); 215 214 216 // check validity of email addresses 215 217 foreach ($this->get_col_values('email', $save_data, true) as $email) { 216 218 if (strlen($email)) { 217 if (!check_email(rcube_idn_to_ascii($email))) { 218 $this->set_error(self::ERROR_VALIDATE, rcube_label(array('name' => 'emailformaterror', 'vars' => array('email' => $email)))); 219 if (!$rcmail->check_email(rcube_idn_to_ascii($email))) { 220 $error = $rcmail->gettext(array('name' => 'emailformaterror', 'vars' => array('email' => $email))); 221 $this->set_error(self::ERROR_VALIDATE, $error); 219 222 return false; 220 223 } -
trunk/roundcubemail/program/include/rcube_base_replacer.php
r5994 r6073 7 7 | This file is part of the Roundcube Webmail client | 8 8 | Copyright (C) 2005-2012, The Roundcube Dev Team | 9 | Licensed under the GNU GPL | 9 | | 10 | Licensed under the GNU General Public License version 3 or | 11 | any later version with exceptions for skins & plugins. | 12 | See the README file for a full license statement. | 10 13 | | 11 14 | PURPOSE: | -
trunk/roundcubemail/program/include/rcube_cache.php
r5787 r6073 67 67 function __construct($type, $userid, $prefix='', $ttl=0, $packed=true) 68 68 { 69 $rcmail = rc mail::get_instance();69 $rcmail = rcube::get_instance(); 70 70 $type = strtolower($type); 71 71 … … 198 198 if ($this->type == 'db' && $this->db) { 199 199 $this->db->query( 200 "DELETE FROM ". get_table_name('cache').200 "DELETE FROM ".$this->db->table_name('cache'). 201 201 " WHERE user_id = ?". 202 202 " AND cache_key LIKE ?". … … 275 275 $sql_result = $this->db->limitquery( 276 276 "SELECT cache_id, data, cache_key". 277 " FROM ". get_table_name('cache').277 " FROM ".$this->db->table_name('cache'). 278 278 " WHERE user_id = ?". 279 279 " AND cache_key = ?". … … 331 331 if ($data == 'N;') { 332 332 $this->db->query( 333 "DELETE FROM ". get_table_name('cache').333 "DELETE FROM ".$this->db->table_name('cache'). 334 334 " WHERE user_id = ?". 335 335 " AND cache_key = ?", … … 342 342 if ($key_exists) { 343 343 $result = $this->db->query( 344 "UPDATE ". get_table_name('cache').344 "UPDATE ".$this->db->table_name('cache'). 345 345 " SET created = ". $this->db->now().", data = ?". 346 346 " WHERE user_id = ?". … … 353 353 // so, no need to check if record exist (see rcube_cache::read_record()) 354 354 $result = $this->db->query( 355 "INSERT INTO ". get_table_name('cache').355 "INSERT INTO ".$this->db->table_name('cache'). 356 356 " (created, user_id, cache_key, data)". 357 357 " VALUES (".$this->db->now().", ?, ?, ?)", … … 417 417 418 418 $this->db->query( 419 "DELETE FROM ". get_table_name('cache').419 "DELETE FROM ".$this->db->table_name('cache'). 420 420 " WHERE user_id = ?" . $where, 421 421 $this->userid); -
trunk/roundcubemail/program/include/rcube_config.php
r5815 r6073 86 86 // fix default imap folders encoding 87 87 foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder) 88 $this->prop[$folder] = rcube_charset _convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF7-IMAP');88 $this->prop[$folder] = rcube_charset::convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF7-IMAP'); 89 89 90 90 if (!empty($this->prop['default_folders'])) 91 91 foreach ($this->prop['default_folders'] as $n => $folder) 92 $this->prop['default_folders'][$n] = rcube_charset _convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');92 $this->prop['default_folders'][$n] = rcube_charset::convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP'); 93 93 94 94 // set PHP error logging according to config … … 187 187 } 188 188 189 $rcmail = rc mail::get_instance();189 $rcmail = rcube::get_instance(); 190 190 191 191 if ($name == 'timezone' && isset($this->prop['_timezone_value'])) … … 301 301 // Bomb out if the requested key does not exist 302 302 if (!array_key_exists($key, $this->prop)) { 303 r aise_error(array(303 rcube::raise_error(array( 304 304 'code' => 500, 'type' => 'php', 305 305 'file' => __FILE__, 'line' => __LINE__, … … 312 312 // Bomb out if the configured key is not exactly 24 bytes long 313 313 if (strlen($key) != 24) { 314 r aise_error(array(314 rcube::raise_error(array( 315 315 'code' => 500, 'type' => 'php', 316 316 'file' => __FILE__, 'line' => __LINE__, … … 336 336 return $delim; 337 337 else 338 r aise_error(array(338 rcube::raise_error(array( 339 339 'code' => 500, 'type' => 'php', 340 340 'file' => __FILE__, 'line' => __LINE__, … … 371 371 } 372 372 else if (!empty($this->prop['mail_domain'])) 373 $domain = rc ube_parse_host($this->prop['mail_domain']);373 $domain = rcmail::parse_host($this->prop['mail_domain']); 374 374 375 375 if ($encode) -
trunk/roundcubemail/program/include/rcube_contacts.php
r5958 r6073 154 154 155 155 $sql_result = $this->db->query( 156 "SELECT * FROM ". get_table_name($this->db_groups).156 "SELECT * FROM ".$this->db->table_name($this->db_groups). 157 157 " WHERE del<>1". 158 158 " AND user_id=?". … … 179 179 { 180 180 $sql_result = $this->db->query( 181 "SELECT * FROM ". get_table_name($this->db_groups).181 "SELECT * FROM ".$this->db->table_name($this->db_groups). 182 182 " WHERE del<>1". 183 183 " AND contactgroup_id=?". … … 215 215 216 216 if ($this->group_id) 217 $join = " LEFT JOIN ". get_table_name($this->db_groupmembers)." AS m".217 $join = " LEFT JOIN ".$this->db->table_name($this->db_groupmembers)." AS m". 218 218 " ON (m.contact_id = c.".$this->primary_key.")"; 219 219 … … 229 229 230 230 $sql_result = $this->db->limitquery( 231 "SELECT * FROM ". get_table_name($this->db_name)." AS c" .231 "SELECT * FROM ".$this->db->table_name($this->db_name)." AS c" . 232 232 $join . 233 233 " WHERE c.del<>1" . … … 489 489 { 490 490 if ($this->group_id) 491 $join = " LEFT JOIN ". get_table_name($this->db_groupmembers)." AS m".491 $join = " LEFT JOIN ".$this->db->table_name($this->db_groupmembers)." AS m". 492 492 " ON (m.contact_id=c.".$this->primary_key.")"; 493 493 … … 495 495 $sql_result = $this->db->query( 496 496 "SELECT COUNT(c.contact_id) AS rows". 497 " FROM ". get_table_name($this->db_name)." AS c".497 " FROM ".$this->db->table_name($this->db_name)." AS c". 498 498 $join. 499 499 " WHERE c.del<>1". … … 537 537 538 538 $this->db->query( 539 "SELECT * FROM ". get_table_name($this->db_name).539 "SELECT * FROM ".$this->db->table_name($this->db_name). 540 540 " WHERE contact_id=?". 541 541 " AND user_id=?". … … 569 569 570 570 $sql_result = $this->db->query( 571 "SELECT cgm.contactgroup_id, cg.name FROM " . get_table_name($this->db_groupmembers) . " AS cgm" .572 " LEFT JOIN " . get_table_name($this->db_groups) . " AS cg ON (cgm.contactgroup_id = cg.contactgroup_id AND cg.del<>1)" .571 "SELECT cgm.contactgroup_id, cg.name FROM " . $this->db->table_name($this->db_groupmembers) . " AS cgm" . 572 " LEFT JOIN " . $this->db->table_name($this->db_groups) . " AS cg ON (cgm.contactgroup_id = cg.contactgroup_id AND cg.del<>1)" . 573 573 " WHERE cgm.contact_id=?", 574 574 $id … … 639 639 if (!$existing->count && !empty($a_insert_cols)) { 640 640 $this->db->query( 641 "INSERT INTO ". get_table_name($this->db_name).641 "INSERT INTO ".$this->db->table_name($this->db_name). 642 642 " (user_id, changed, del, ".join(', ', $a_insert_cols).")". 643 643 " VALUES (".intval($this->user_id).", ".$this->db->now().", 0, ".join(', ', $a_insert_values).")" … … 677 677 if (!empty($write_sql)) { 678 678 $this->db->query( 679 "UPDATE ". get_table_name($this->db_name).679 "UPDATE ".$this->db->table_name($this->db_name). 680 680 " SET changed=".$this->db->now().", ".join(', ', $write_sql). 681 681 " WHERE contact_id=?". … … 773 773 // flag record as deleted (always) 774 774 $this->db->query( 775 "UPDATE ". get_table_name($this->db_name).775 "UPDATE ".$this->db->table_name($this->db_name). 776 776 " SET del=1, changed=".$this->db->now(). 777 777 " WHERE user_id=?". … … 800 800 // clear deleted flag 801 801 $this->db->query( 802 "UPDATE ". get_table_name($this->db_name).802 "UPDATE ".$this->db->table_name($this->db_name). 803 803 " SET del=0, changed=".$this->db->now(). 804 804 " WHERE user_id=?". … … 820 820 $this->cache = null; 821 821 822 $this->db->query("UPDATE ". get_table_name($this->db_name).822 $this->db->query("UPDATE ".$this->db->table_name($this->db_name). 823 823 " SET del=1, changed=".$this->db->now(). 824 824 " WHERE user_id = ?", $this->user_id); … … 842 842 843 843 $this->db->query( 844 "INSERT INTO ". get_table_name($this->db_groups).844 "INSERT INTO ".$this->db->table_name($this->db_groups). 845 845 " (user_id, changed, name)". 846 846 " VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")" … … 864 864 // flag group record as deleted 865 865 $sql_result = $this->db->query( 866 "UPDATE ". get_table_name($this->db_groups).866 "UPDATE ".$this->db->table_name($this->db_groups). 867 867 " SET del=1, changed=".$this->db->now(). 868 868 " WHERE contactgroup_id=?". … … 890 890 891 891 $sql_result = $this->db->query( 892 "UPDATE ". get_table_name($this->db_groups).892 "UPDATE ".$this->db->table_name($this->db_groups). 893 893 " SET name=?, changed=".$this->db->now(). 894 894 " WHERE contactgroup_id=?". … … 918 918 // get existing assignments ... 919 919 $sql_result = $this->db->query( 920 "SELECT contact_id FROM ". get_table_name($this->db_groupmembers).920 "SELECT contact_id FROM ".$this->db->table_name($this->db_groupmembers). 921 921 " WHERE contactgroup_id=?". 922 922 " AND contact_id IN (".$this->db->array2list($ids, 'integer').")", … … 931 931 foreach ($ids as $contact_id) { 932 932 $this->db->query( 933 "INSERT INTO ". get_table_name($this->db_groupmembers).933 "INSERT INTO ".$this->db->table_name($this->db_groupmembers). 934 934 " (contactgroup_id, contact_id, created)". 935 935 " VALUES (?, ?, ".$this->db->now().")", … … 961 961 962 962 $sql_result = $this->db->query( 963 "DELETE FROM ". get_table_name($this->db_groupmembers).963 "DELETE FROM ".$this->db->table_name($this->db_groupmembers). 964 964 " WHERE contactgroup_id=?". 965 965 " AND contact_id IN ($ids)", … … 984 984 do { 985 985 $sql_result = $this->db->query( 986 "SELECT 1 FROM ". get_table_name($this->db_groups).986 "SELECT 1 FROM ".$this->db->table_name($this->db_groups). 987 987 " WHERE del<>1". 988 988 " AND user_id=?". -
trunk/roundcubemail/program/include/rcube_imap.php
r6023 r6073 133 133 } 134 134 else if ($use_ssl) { 135 r aise_error(array('code' => 403, 'type' => 'imap',135 rcube::raise_error(array('code' => 403, 'type' => 'imap', 136 136 'file' => __FILE__, 'line' => __LINE__, 137 137 'message' => "OpenSSL not available"), true, false); … … 155 155 $attempt = 0; 156 156 do { 157 $data = rc mail::get_instance()->plugins->exec_hook('imap_connect',157 $data = rcube::get_instance()->plugins->exec_hook('imap_connect', 158 158 array_merge($this->options, array('host' => $host, 'user' => $user, 159 159 'attempt' => ++$attempt))); … … 186 186 if ($pass && $user) { 187 187 $message = sprintf("Login failed for %s from %s. %s", 188 $user, rcmail _remote_ip(), $this->conn->error);189 190 r aise_error(array('code' => 403, 'type' => 'imap',188 $user, rcmail::remote_ip(), $this->conn->error); 189 190 rcube::raise_error(array('code' => 403, 'type' => 'imap', 191 191 'file' => __FILE__, 'line' => __LINE__, 192 192 'message' => $message), true, false); … … 458 458 } 459 459 460 $config = rc mail::get_instance()->config;460 $config = rcube::get_instance()->config; 461 461 $imap_personal = $config->get('imap_ns_personal'); 462 462 $imap_other = $config->get('imap_ns_other'); … … 547 547 } 548 548 549 return $this-> messagecount($folder, $mode, $force, $status);549 return $this->countmessages($folder, $mode, $force, $status); 550 550 } 551 551 … … 563 563 * @see rcube_imap::count() 564 564 */ 565 protected function messagecount($folder, $mode='ALL', $force=false, $status=true)565 protected function countmessages($folder, $mode='ALL', $force=false, $status=true) 566 566 { 567 567 $mode = strtoupper($mode); … … 835 835 * depth, has_children and unread_children 836 836 * 837 * @param array $headersReference to headers array indexed by message UID838 * @param rcube_ imap_result $threadsThreads data object837 * @param array $headers Reference to headers array indexed by message UID 838 * @param rcube_result_thread $threads Threads data object 839 839 * 840 840 * @return array Message headers array indexed by message UID … … 1049 1049 if ($sort) { 1050 1050 // use this class for message sorting 1051 $sorter = new rcube_ header_sorter();1051 $sorter = new rcube_message_header_sorter(); 1052 1052 $sorter->set_index($msgs); 1053 1053 $sorter->sort_headers($a_msg_headers); … … 1076 1076 1077 1077 // refresh message count -> will update 1078 $this-> messagecount($folder, 'ALL', true);1078 $this->countmessages($folder, 'ALL', true); 1079 1079 1080 1080 $result = 0; … … 1457 1457 $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n 1458 1458 $string = substr($str, $string_offset - 1, $m[0]); 1459 $string = rcube_charset _convert($string, $charset, $dest_charset);1459 $string = rcube_charset::convert($string, $charset, $dest_charset); 1460 1460 if ($string === false) { 1461 1461 continue; … … 1499 1499 * @param bool $force True to skip cache 1500 1500 * 1501 * @return rcube_m ail_header Message headers1501 * @return rcube_message_header Message headers 1502 1502 */ 1503 1503 public function get_message_headers($uid, $folder = null, $force = false) … … 1530 1530 * @param string $folder Folder to read from 1531 1531 * 1532 * @return object rcube_m ail_header Message data1532 * @return object rcube_message_header Message data 1533 1533 */ 1534 1534 public function get_message($uid, $folder = null) … … 1949 1949 } 1950 1950 else { 1951 $charset = rc _detect_encoding($filename_mime, $this->default_charset);1951 $charset = rcube_charset::detect($filename_mime, $this->default_charset); 1952 1952 } 1953 1953 … … 1961 1961 } 1962 1962 1963 $part->filename = rcube_charset _convert(urldecode($filename_encoded), $filename_charset);1963 $part->filename = rcube_charset::convert(urldecode($filename_encoded), $filename_charset); 1964 1964 } 1965 1965 } … … 2040 2040 } 2041 2041 } 2042 $body = rcube_charset _convert($body, $o_part->charset);2042 $body = rcube_charset::convert($body, $o_part->charset); 2043 2043 } 2044 2044 } … … 2228 2228 } 2229 2229 2230 $config = rc mail::get_instance()->config;2230 $config = rcube::get_instance()->config; 2231 2231 $to_trash = $to_mbox == $config->get('trash_mbox'); 2232 2232 … … 2511 2511 2512 2512 // Give plugins a chance to provide a list of folders 2513 $data = rc mail::get_instance()->plugins->exec_hook('storage_folders',2513 $data = rcube::get_instance()->plugins->exec_hook('storage_folders', 2514 2514 array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LSUB')); 2515 2515 … … 2522 2522 else { 2523 2523 // Server supports LIST-EXTENDED, we can use selection options 2524 $config = rc mail::get_instance()->config;2524 $config = rcube::get_instance()->config; 2525 2525 // #1486225: Some dovecot versions returns wrong result using LIST-EXTENDED 2526 2526 if (!$config->get('imap_force_lsub') && $this->get_capability('LIST-EXTENDED')) { … … 3531 3531 { 3532 3532 if ($this->caching && !$this->cache) { 3533 $rcmail = rc mail::get_instance();3533 $rcmail = rcube::get_instance(); 3534 3534 $ttl = $rcmail->config->get('message_cache_lifetime', '10d') - mktime(); 3535 3535 $this->cache = $rcmail->get_cache('IMAP', $this->caching, $ttl); … … 3590 3590 } 3591 3591 3592 if ($this->cache) 3592 if ($this->cache) { 3593 3593 $this->cache->expunge(); 3594 } 3594 3595 } 3595 3596 … … 3625 3626 { 3626 3627 if ($this->messages_caching && !$this->mcache) { 3627 $rcmail = rc mail::get_instance();3628 $rcmail = rcube::get_instance(); 3628 3629 if ($dbh = $rcmail->get_dbh()) { 3629 3630 $this->mcache = new rcube_imap_cache( 3630 $dbh, $this, $rcmail-> user->ID, $this->options['skip_deleted']);3631 $dbh, $this, $rcmail->get_user_id(), $this->options['skip_deleted']); 3631 3632 } 3632 3633 } … … 3692 3693 } 3693 3694 else { 3694 $folders[$folder] = rcube_charset _convert($folder, 'UTF7-IMAP');3695 $folders[$folder] = rcube_charset::convert($folder, 'UTF7-IMAP'); 3695 3696 } 3696 3697 } … … 3852 3853 public function debug_handler(&$imap, $message) 3853 3854 { 3854 write_log('imap', $message);3855 rcmail::write_log('imap', $message); 3855 3856 } 3856 3857 -
trunk/roundcubemail/program/include/rcube_imap_cache.php
r6020 r6073 96 96 $this->db = $db; 97 97 $this->imap = $imap; 98 $this->userid = (int)$userid;98 $this->userid = $userid; 99 99 $this->skip_deleted = $skip_deleted; 100 100 } … … 291 291 * @param array $msgs Message UIDs 292 292 * 293 * @return array The list of messages (rcube_m ail_header) indexed by UID293 * @return array The list of messages (rcube_message_header) indexed by UID 294 294 */ 295 295 function get_messages($mailbox, $msgs = array()) … … 302 302 $sql_result = $this->db->query( 303 303 "SELECT uid, data, flags" 304 ." FROM ". get_table_name('cache_messages')304 ." FROM ".$this->db->table_name('cache_messages') 305 305 ." WHERE user_id = ?" 306 306 ." AND mailbox = ?" … … 349 349 * @param bool $no_cache Enables internal cache usage 350 350 * 351 * @return rcube_m ail_header Message data351 * @return rcube_message_header Message data 352 352 */ 353 353 function get_message($mailbox, $uid, $update = true, $cache = true) … … 363 363 $sql_result = $this->db->query( 364 364 "SELECT flags, data" 365 ." FROM ". get_table_name('cache_messages')365 ." FROM ".$this->db->table_name('cache_messages') 366 366 ." WHERE user_id = ?" 367 367 ." AND mailbox = ?" … … 405 405 * Saves the message in cache. 406 406 * 407 * @param string $mailbox Folder name408 * @param rcube_m ail_header $message Message data409 * @param bool $force Skips message in-cache existance check407 * @param string $mailbox Folder name 408 * @param rcube_message_header $message Message data 409 * @param bool $force Skips message in-cache existance check 410 410 */ 411 411 function add_message($mailbox, $message, $force = false) … … 431 431 if (!$force) { 432 432 $res = $this->db->query( 433 "UPDATE ". get_table_name('cache_messages')433 "UPDATE ".$this->db->table_name('cache_messages') 434 434 ." SET flags = ?, data = ?, changed = ".$this->db->now() 435 435 ." WHERE user_id = ?" … … 445 445 // insert new record 446 446 $this->db->query( 447 "INSERT INTO ". get_table_name('cache_messages')447 "INSERT INTO ".$this->db->table_name('cache_messages') 448 448 ." (user_id, mailbox, uid, flags, changed, data)" 449 449 ." VALUES (?, ?, ?, ?, ".$this->db->now().", ?)", … … 480 480 481 481 $this->db->query( 482 "UPDATE ". get_table_name('cache_messages')482 "UPDATE ".$this->db->table_name('cache_messages') 483 483 ." SET changed = ".$this->db->now() 484 484 .", flags = flags ".($enabled ? "+ $idx" : "- $idx") … … 501 501 if (!strlen($mailbox)) { 502 502 $this->db->query( 503 "DELETE FROM ". get_table_name('cache_messages')503 "DELETE FROM ".$this->db->table_name('cache_messages') 504 504 ." WHERE user_id = ?", 505 505 $this->userid); … … 514 514 515 515 $this->db->query( 516 "DELETE FROM ". get_table_name('cache_messages')516 "DELETE FROM ".$this->db->table_name('cache_messages') 517 517 ." WHERE user_id = ?" 518 ." AND mailbox = ".$this->db->quote($mailbox)518 ." AND mailbox = ?" 519 519 .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""), 520 $this->userid );520 $this->userid, $mailbox); 521 521 } 522 522 … … 537 537 if ($remove) { 538 538 $this->db->query( 539 "DELETE FROM ".get_table_name('cache_index') 540 ." WHERE user_id = ".intval($this->userid) 541 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") 539 "DELETE FROM ".$this->db->table_name('cache_index') 540 ." WHERE user_id = ?" 541 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""), 542 $this->userid 542 543 ); 543 544 } 544 545 else { 545 546 $this->db->query( 546 "UPDATE ". get_table_name('cache_index')547 "UPDATE ".$this->db->table_name('cache_index') 547 548 ." SET valid = 0" 548 ." WHERE user_id = ".intval($this->userid) 549 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") 549 ." WHERE user_id = ?" 550 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""), 551 $this->userid 550 552 ); 551 553 } … … 570 572 { 571 573 $this->db->query( 572 "DELETE FROM ".get_table_name('cache_thread') 573 ." WHERE user_id = ".intval($this->userid) 574 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") 574 "DELETE FROM ".$this->db->table_name('cache_thread') 575 ." WHERE user_id = ?" 576 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""), 577 $this->userid 575 578 ); 576 579 … … 629 632 $sql_result = $this->db->query( 630 633 "SELECT data, valid" 631 ." FROM ". get_table_name('cache_index')634 ." FROM ".$this->db->table_name('cache_index') 632 635 ." WHERE user_id = ?" 633 636 ." AND mailbox = ?", … … 666 669 $sql_result = $this->db->query( 667 670 "SELECT data" 668 ." FROM ". get_table_name('cache_thread')671 ." FROM ".$this->db->table_name('cache_thread') 669 672 ." WHERE user_id = ?" 670 673 ." AND mailbox = ?", … … 710 713 if ($exists) { 711 714 $sql_result = $this->db->query( 712 "UPDATE ". get_table_name('cache_index')715 "UPDATE ".$this->db->table_name('cache_index') 713 716 ." SET data = ?, valid = 1, changed = ".$this->db->now() 714 717 ." WHERE user_id = ?" … … 718 721 else { 719 722 $sql_result = $this->db->query( 720 "INSERT INTO ". get_table_name('cache_index')723 "INSERT INTO ".$this->db->table_name('cache_index') 721 724 ." (user_id, mailbox, data, valid, changed)" 722 725 ." VALUES (?, ?, ?, 1, ".$this->db->now().")", … … 741 744 if ($exists) { 742 745 $sql_result = $this->db->query( 743 "UPDATE ". get_table_name('cache_thread')746 "UPDATE ".$this->db->table_name('cache_thread') 744 747 ." SET data = ?, changed = ".$this->db->now() 745 748 ." WHERE user_id = ?" … … 749 752 else { 750 753 $sql_result = $this->db->query( 751 "INSERT INTO ". get_table_name('cache_thread')754 "INSERT INTO ".$this->db->table_name('cache_thread') 752 755 ." (user_id, mailbox, data, changed)" 753 756 ." VALUES (?, ?, ?, ".$this->db->now().")", … … 957 960 $sql_result = $this->db->query( 958 961 "SELECT uid" 959 ." FROM ". get_table_name('cache_messages')962 ." FROM ".$this->db->table_name('cache_messages') 960 963 ." WHERE user_id = ?" 961 964 ." AND mailbox = ?", … … 1004 1007 1005 1008 $this->db->query( 1006 "UPDATE ". get_table_name('cache_messages')1009 "UPDATE ".$this->db->table_name('cache_messages') 1007 1010 ." SET flags = ?, changed = ".$this->db->now() 1008 1011 ." WHERE user_id = ?" … … 1059 1062 * @param array $sql_arr Message row data 1060 1063 * 1061 * @return rcube_m ail_header Message object1064 * @return rcube_message_header Message object 1062 1065 */ 1063 1066 private function build_message($sql_arr) -
trunk/roundcubemail/program/include/rcube_imap_generic.php
r6027 r6073 30 30 */ 31 31 32 /** 33 * Struct representing an e-mail message header 34 * 35 * @package Mail 36 * @author Aleksander Machniak <alec@alec.pl> 37 */ 38 class rcube_mail_header 39 { 40 public $id; 41 public $uid; 42 public $subject; 43 public $from; 44 public $to; 45 public $cc; 46 public $replyto; 47 public $in_reply_to; 48 public $date; 49 public $messageID; 50 public $size; 51 public $encoding; 52 public $charset; 53 public $ctype; 54 public $timestamp; 55 public $bodystructure; 56 public $internaldate; 57 public $references; 58 public $priority; 59 public $mdn_to; 60 public $others = array(); 61 public $flags = array(); 62 } 63 64 // For backward compatibility with cached messages (#1486602) 65 class iilBasicHeader extends rcube_mail_header 66 { 67 } 32 // for backward copat. 33 class rcube_mail_header extends rcube_message_header { } 34 68 35 69 36 /** … … 1546 1513 function sort($mailbox, $field, $add='', $return_uid=false, $encoding = 'US-ASCII') 1547 1514 { 1548 require_once dirname(__FILE__) . '/rcube_result_index.php';1549 1550 1515 $field = strtoupper($field); 1551 1516 if ($field == 'INTERNALDATE') { … … 1596 1561 function thread($mailbox, $algorithm='REFERENCES', $criteria='', $return_uid=false, $encoding='US-ASCII') 1597 1562 { 1598 require_once dirname(__FILE__) . '/rcube_result_thread.php';1599 1600 1563 $old_sel = $this->selected; 1601 1564 … … 1636 1599 function search($mailbox, $criteria, $return_uid=false, $items=array()) 1637 1600 { 1638 require_once dirname(__FILE__) . '/rcube_result_index.php';1639 1640 1601 $old_sel = $this->selected; 1641 1602 … … 1697 1658 $uidfetch=false, $return_uid=false) 1698 1659 { 1699 require_once dirname(__FILE__) . '/rcube_result_index.php';1700 1701 1660 $msg_index = $this->fetchHeaderIndex($mailbox, $message_set, 1702 1661 $index_field, $skip_deleted, $uidfetch, $return_uid); … … 2035 1994 * @param bool $vanished Enables VANISHED parameter (RFC5162) for CHANGEDSINCE query 2036 1995 * 2037 * @return array List of rcube_m ail_header elements, False on error1996 * @return array List of rcube_message_header elements, False on error 2038 1997 * @since 0.6 2039 1998 */ … … 2075 2034 $id = intval($m[1]); 2076 2035 2077 $result[$id] = new rcube_m ail_header;2036 $result[$id] = new rcube_message_header; 2078 2037 $result[$id]->id = $id; 2079 2038 $result[$id]->subject = ''; -
trunk/roundcubemail/program/include/rcube_ldap.php
r6067 r6073 64 64 * Object constructor 65 65 * 66 * @param array LDAP connection properties 67 * @param boolean Enables debug mode 68 * @param string Current user mail domain name 69 * @param integer User-ID 66 * @param array $p LDAP connection properties 67 * @param boolean $debug Enables debug mode 68 * @param string $mail_domain Current user mail domain name 70 69 */ 71 function __construct($p, $debug =false, $mail_domain=NULL)70 function __construct($p, $debug = false, $mail_domain = null) 72 71 { 73 72 $this->prop = $p; … … 177 176 private function _connect() 178 177 { 179 global $RCMAIL;178 $RCMAIL = rcmail::get_instance(); 180 179 181 180 if (!function_exists('ldap_connect')) 182 r aise_error(array('code' => 100, 'type' => 'ldap',181 rcube::raise_error(array('code' => 100, 'type' => 'ldap', 183 182 'file' => __FILE__, 'line' => __LINE__, 184 183 'message' => "No ldap support in this installation of PHP"), … … 196 195 foreach ($this->prop['hosts'] as $host) 197 196 { 198 $host = idn_to_ascii(rc ube_parse_host($host));197 $host = idn_to_ascii(rcmail::parse_host($host)); 199 198 $hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : ''); 200 199 … … 226 225 227 226 if (!is_resource($this->conn)) { 228 r aise_error(array('code' => 100, 'type' => 'ldap',227 rcube::raise_error(array('code' => 100, 'type' => 'ldap', 229 228 'file' => __FILE__, 'line' => __LINE__, 230 229 'message' => "Could not connect to any LDAP server, last tried $hostname"), true); … … 249 248 250 249 // Get the pieces needed for variable replacement. 251 if ($fu = $RCMAIL-> user->get_username())250 if ($fu = $RCMAIL->get_user_name()) 252 251 list($u, $d) = explode('@', $fu); 253 252 else … … 288 287 $replaces['%dn'] = $this->prop['search_dn_default']; 289 288 else { 290 r aise_error(array(289 rcube::raise_error(array( 291 290 'code' => 100, 'type' => 'ldap', 292 291 'file' => __FILE__, 'line' => __LINE__, … … 342 341 343 342 if (!function_exists('ldap_sasl_bind')) { 344 r aise_error(array('code' => 100, 'type' => 'ldap',343 rcube::raise_error(array('code' => 100, 'type' => 'ldap', 345 344 'file' => __FILE__, 'line' => __LINE__, 346 345 'message' => "Unable to bind: ldap_sasl_bind() not exists"), … … 368 367 $this->_debug("S: ".ldap_error($this->conn)); 369 368 370 r aise_error(array(369 rcube::raise_error(array( 371 370 'code' => ldap_errno($this->conn), 'type' => 'ldap', 372 371 'file' => __FILE__, 'line' => __LINE__, … … 401 400 $this->_debug("S: ".ldap_error($this->conn)); 402 401 403 r aise_error(array(402 rcube::raise_error(array( 404 403 'code' => ldap_errno($this->conn), 'type' => 'ldap', 405 404 'file' => __FILE__, 'line' => __LINE__, … … 1563 1562 private function _debug($str) 1564 1563 { 1565 if ($this->debug) 1566 write_log('ldap', $str); 1564 if ($this->debug) { 1565 rcmail::write_log('ldap', $str); 1566 } 1567 1567 } 1568 1568 -
trunk/roundcubemail/program/include/rcube_mdb2.php
r5850 r6073 60 60 * @param string $db_dsnr Optional DSN for read only operations 61 61 */ 62 function __construct($db_dsnw, $db_dsnr='', $pconn=false)63 { 64 if (empty($db_dsnr)) 62 public function __construct($db_dsnw, $db_dsnr='', $pconn=false) 63 { 64 if (empty($db_dsnr)) { 65 65 $db_dsnr = $db_dsnw; 66 } 66 67 67 68 $this->db_dsnw = $db_dsnw; … … 89 90 'debug' => $this->debug_mode, 90 91 'debug_handler' => array($this, 'debug_handler'), 91 'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL); 92 'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL, 93 ); 92 94 93 95 if ($this->db_provider == 'pgsql') { … … 104 106 $this->db_error_msg = $dbh->getMessage(); 105 107 106 r aise_error(array('code' => 500, 'type' => 'db',108 rcube::raise_error(array('code' => 500, 'type' => 'db', 107 109 'line' => __LINE__, 'file' => __FILE__, 108 110 'message' => $dbh->getUserInfo()), true, false); … … 110 112 else if ($this->db_provider == 'sqlite') { 111 113 $dsn_array = MDB2::parseDSN($dsn); 112 if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) 113 $this->_sqlite_create_database($dbh, $this->sqlite_initials); 114 } 115 else if ($this->db_provider!='mssql' && $this->db_provider!='sqlsrv') 114 if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) { 115 $this->sqlite_create_database($dbh, $this->sqlite_initials); 116 } 117 } 118 else if ($this->db_provider != 'mssql' && $this->db_provider != 'sqlsrv') { 116 119 $dbh->setCharset('utf8'); 120 } 117 121 118 122 return $dbh; … … 124 128 * 125 129 * @param string $mode Connection mode (r|w) 126 * @access public 127 */ 128 function db_connect($mode) 130 */ 131 public function db_connect($mode) 129 132 { 130 133 // previous connection failed, don't attempt to connect again … … 158 161 } 159 162 160 if ($this->db_connected) 163 if ($this->db_connected) { 161 164 $this->db_mode = $mode; 162 else 165 } 166 else { 163 167 $this->conn_failure = true; 168 } 164 169 } 165 170 … … 169 174 * 170 175 * @param boolean $dbg True if SQL queries should be logged 171 * @access public 172 */ 173 function set_debug($dbg = true) 176 */ 177 public function set_debug($dbg = true) 174 178 { 175 179 $this->debug_mode = $dbg; … … 185 189 * 186 190 * @param boolean True on error 187 * @access public 188 */ 189 function is_error() 191 */ 192 public function is_error() 190 193 { 191 194 return $this->db_error ? $this->db_error_msg : false; … … 197 200 * 198 201 * @param boolean True if in connected state 199 * @access public 200 */ 201 function is_connected() 202 */ 203 public function is_connected() 202 204 { 203 205 return PEAR::isError($this->db_handle) ? false : $this->db_connected; … … 209 211 * This returns true if dsnw != dsnr 210 212 */ 211 function is_replicated()213 public function is_replicated() 212 214 { 213 215 return !empty($this->db_dsnr) && $this->db_dsnw != $this->db_dsnr; … … 220 222 * @param string SQL query to execute 221 223 * @param mixed Values to be inserted in query 224 * 222 225 * @return number Query handle identifier 223 * @access public 224 */ 225 function query() 226 */ 227 public function query() 226 228 { 227 229 $params = func_get_args(); … … 229 231 230 232 // Support one argument of type array, instead of n arguments 231 if (count($params) == 1 && is_array($params[0])) 233 if (count($params) == 1 && is_array($params[0])) { 232 234 $params = $params[0]; 235 } 233 236 234 237 return $this->_query($query, 0, 0, $params); … … 243 246 * @param number Number of rows for LIMIT statement 244 247 * @param mixed Values to be inserted in query 248 * 245 249 * @return number Query handle identifier 246 * @access public 247 */ 248 function limitquery() 250 */ 251 public function limitquery() 249 252 { 250 253 $params = func_get_args(); … … 275 278 276 279 // check connection before proceeding 277 if (!$this->is_connected()) 280 if (!$this->is_connected()) { 278 281 return null; 279 280 if ($this->db_provider == 'sqlite') 281 $this->_sqlite_prepare(); 282 283 if ($numrows || $offset) 282 } 283 284 if ($this->db_provider == 'sqlite') { 285 $this->sqlite_prepare(); 286 } 287 288 if ($numrows || $offset) { 284 289 $result = $this->db_handle->setLimit($numrows,$offset); 285 286 if (empty($params)) 290 } 291 292 if (empty($params)) { 287 293 $result = $mode == 'r' ? $this->db_handle->query($query) : $this->db_handle->exec($query); 294 } 288 295 else { 289 296 $params = (array)$params; … … 293 300 $this->db_error_msg = $q->userinfo; 294 301 295 r aise_error(array('code' => 500, 'type' => 'db',302 rcube::raise_error(array('code' => 500, 'type' => 'db', 296 303 'line' => __LINE__, 'file' => __FILE__, 297 304 'message' => $this->db_error_msg), true, false); … … 316 323 * @param number $res_id Optional query handle identifier 317 324 * @return mixed Number of rows or false on failure 318 * @access public 319 */ 320 function num_rows($res_id=null) 321 { 322 if (!$this->db_connected) 325 */ 326 public function num_rows($res_id=null) 327 { 328 if (!$this->db_connected) { 323 329 return false; 324 325 if ($result = $this->_get_result($res_id)) 330 } 331 332 if ($result = $this->_get_result($res_id)) { 326 333 return $result->numRows(); 327 else 328 return false; 334 } 335 336 return false; 329 337 } 330 338 … … 335 343 * @param number $res_id Optional query handle identifier 336 344 * @return mixed Number of rows or false on failure 337 * @access public 338 */ 339 function affected_rows($res_id = null) 340 { 341 if (!$this->db_connected) 345 */ 346 public function affected_rows($res_id = null) 347 { 348 if (!$this->db_connected) { 342 349 return false; 350 } 343 351 344 352 return $this->_get_result($res_id); … … 351 359 * 352 360 * @param string $table Table name (to find the incremented sequence) 361 * 353 362 * @return mixed ID or false on failure 354 * @access public 355 */ 356 function insert_id($table = '') 357 { 358 if (!$this->db_connected || $this->db_mode == 'r') 363 */ 364 public function insert_id($table = '') 365 { 366 if (!$this->db_connected || $this->db_mode == 'r') { 359 367 return false; 368 } 360 369 361 370 if ($table) { 362 if ($this->db_provider == 'pgsql') 371 if ($this->db_provider == 'pgsql') { 363 372 // find sequence name 364 $table = get_sequence_name($table); 365 else 373 $table = $this->sequence_name($table); 374 } 375 else { 366 376 // resolve table name 367 $table = get_table_name($table); 377 $table = $this->table_name($table); 378 } 368 379 } 369 380 … … 379 390 * 380 391 * @param number $res_id Optional query handle identifier 392 * 381 393 * @return mixed Array with col values or false on failure 382 * @access public 383 */ 384 function fetch_assoc($res_id=null) 394 */ 395 public function fetch_assoc($res_id = null) 385 396 { 386 397 $result = $this->_get_result($res_id); … … 394 405 * 395 406 * @param number $res_id Optional query handle identifier 407 * 396 408 * @return mixed Array with col values or false on failure 397 * @access public 398 */ 399 function fetch_array($res_id=null) 409 */ 410 public function fetch_array($res_id = null) 400 411 { 401 412 $result = $this->_get_result($res_id); … … 409 420 * @param MDB2_Result_Common Query $result result handle 410 421 * @param number $mode Fetch mode identifier 411 * @return mixed Array with col values or false on failure412 * @ access private422 * 423 * @return mixed Array with col values or false on failure 413 424 */ 414 425 private function _fetch_row($result, $mode) 415 426 { 416 if ($result === false || PEAR::isError($result) || !$this->is_connected()) 427 if ($result === false || PEAR::isError($result) || !$this->is_connected()) { 417 428 return false; 429 } 418 430 419 431 return $result->fetchRow($mode); … … 425 437 * 426 438 * @return array List of all tables of the current database 427 * @access public428 439 * @since 0.4-beta 429 440 */ 430 function list_tables()441 public function list_tables() 431 442 { 432 443 // get tables if not cached 433 444 if (!$this->tables) { 434 445 $this->db_handle->loadModule('Manager'); 435 if (!PEAR::isError($result = $this->db_handle->listTables())) 446 if (!PEAR::isError($result = $this->db_handle->listTables())) { 436 447 $this->tables = $result; 437 else 448 } 449 else { 438 450 $this->tables = array(); 451 } 439 452 } 440 453 … … 447 460 * 448 461 * @param string Table name 462 * 449 463 * @return array List of table cols 450 464 */ 451 function list_cols($table)465 public function list_cols($table) 452 466 { 453 467 $this->db_handle->loadModule('Manager'); … … 465 479 * @param mixed $input Value to quote 466 480 * @param string $type Type of data 481 * 467 482 * @return string Quoted/converted string for use in query 468 * @access public 469 */ 470 function quote($input, $type = null) 483 */ 484 public function quote($input, $type = null) 471 485 { 472 486 // handle int directly for better performance 473 if ($type == 'integer') 487 if ($type == 'integer') { 474 488 return intval($input); 489 } 475 490 476 491 // create DB handle if not available 477 if (!$this->db_handle) 492 if (!$this->db_handle) { 478 493 $this->db_connect('r'); 494 } 479 495 480 496 return $this->db_connected ? $this->db_handle->quote($input, $type) : addslashes($input); … … 486 502 * 487 503 * @param string $str Value to quote 504 * 488 505 * @return string Quoted string for use in query 489 506 * @deprecated Replaced by rcube_MDB2::quote_identifier 490 507 * @see rcube_mdb2::quote_identifier 491 * @access public 492 */ 493 function quoteIdentifier($str) 508 */ 509 public function quoteIdentifier($str) 494 510 { 495 511 return $this->quote_identifier($str); … … 501 517 * 502 518 * @param string $str Value to quote 519 * 503 520 * @return string Quoted string for use in query 504 * @access public 505 */ 506 function quote_identifier($str) 507 { 508 if (!$this->db_handle) 521 */ 522 public function quote_identifier($str) 523 { 524 if (!$this->db_handle) { 509 525 $this->db_connect('r'); 526 } 510 527 511 528 return $this->db_connected ? $this->db_handle->quoteIdentifier($str) : $str; … … 517 534 * 518 535 * @param string $str The string to be escaped 536 * 519 537 * @return string The escaped string 520 * @access public521 538 * @since 0.1.1 522 539 */ 523 function escapeSimple($str)524 { 525 if (!$this->db_handle) 540 public function escapeSimple($str) 541 { 542 if (!$this->db_handle) { 526 543 $this->db_connect('r'); 544 } 527 545 528 546 return $this->db_handle->escape($str); … … 534 552 * 535 553 * @return string SQL function to use in query 536 * @access public 537 */ 538 function now() 554 */ 555 public function now() 539 556 { 540 557 switch ($this->db_provider) { … … 554 571 * @param array $arr Input array 555 572 * @param string $type Type of data 573 * 556 574 * @return string Comma-separated list of quoted values for use in query 557 * @access public 558 */ 559 function array2list($arr, $type = null) 560 { 561 if (!is_array($arr)) 575 */ 576 public function array2list($arr, $type = null) 577 { 578 if (!is_array($arr)) { 562 579 return $this->quote($arr, $type); 563 564 foreach ($arr as $idx => $item) 580 } 581 582 foreach ($arr as $idx => $item) { 565 583 $arr[$idx] = $this->quote($item, $type); 584 } 566 585 567 586 return implode(',', $arr); … … 576 595 * 577 596 * @param string $field Field name 597 * 578 598 * @return string SQL statement to use in query 579 599 * @deprecated 580 600 */ 581 function unixtimestamp($field)601 public function unixtimestamp($field) 582 602 { 583 603 switch($this->db_provider) { … … 599 619 * 600 620 * @param string $timestamp Field name 621 * 601 622 * @return string SQL statement to use in query 602 * @access public 603 */ 604 function fromunixtime($timestamp) 623 */ 624 public function fromunixtime($timestamp) 605 625 { 606 626 return date("'Y-m-d H:i:s'", $timestamp); … … 613 633 * @param string $column Field name 614 634 * @param string $value Search value 635 * 615 636 * @return string SQL statement to use in query 616 * @access public 617 */ 618 function ilike($column, $value) 637 */ 638 public function ilike($column, $value) 619 639 { 620 640 // TODO: use MDB2's matchPattern() function 621 switch ($this->db_provider) {641 switch ($this->db_provider) { 622 642 case 'pgsql': 623 643 return $this->quote_identifier($column).' ILIKE '.$this->quote($value); … … 627 647 } 628 648 649 629 650 /** 630 651 * Abstract SQL statement for value concatenation 631 652 * 632 653 * @return string SQL statement to be used in query 633 * @access public 634 */ 635 function concat(/* col1, col2, ... */) 654 */ 655 public function concat(/* col1, col2, ... */) 636 656 { 637 657 $func = ''; … … 640 660 $args = $args[0]; 641 661 642 switch ($this->db_provider) {662 switch ($this->db_provider) { 643 663 case 'mysql': 644 664 case 'mysqli': … … 662 682 * 663 683 * @param mixed $input Data to fix 684 * 664 685 * @return mixed Properly UTF-8 encoded data 665 * @access public 666 */ 667 function encode($input) 686 */ 687 public static function encode($input) 668 688 { 669 689 if (is_object($input)) { 670 foreach (get_object_vars($input) as $idx => $value) 671 $input->$idx = $this->encode($value); 690 foreach (get_object_vars($input) as $idx => $value) { 691 $input->$idx = self::encode($value); 692 } 672 693 return $input; 673 694 } 674 695 else if (is_array($input)) { 675 foreach ($input as $idx => $value) 676 $input[$idx] = $this->encode($value); 677 return $input; 696 foreach ($input as $idx => $value) { 697 $input[$idx] = self::encode($value); 698 } 699 return $input; 678 700 } 679 701 … … 686 708 * 687 709 * @param mixed $input Input data 710 * 688 711 * @return mixed Decoded data 689 * @access public 690 */ 691 function decode($input) 712 */ 713 public static function decode($input) 692 714 { 693 715 if (is_object($input)) { 694 foreach (get_object_vars($input) as $idx => $value) 695 $input->$idx = $this->decode($value); 716 foreach (get_object_vars($input) as $idx => $value) { 717 $input->$idx = self::decode($value); 718 } 696 719 return $input; 697 720 } 698 721 else if (is_array($input)) { 699 foreach ($input as $idx => $value) 700 $input[$idx] = $this->decode($value); 701 return $input; 722 foreach ($input as $idx => $value) { 723 $input[$idx] = self::decode($value); 724 } 725 return $input; 702 726 } 703 727 … … 710 734 * 711 735 * @param object $res Query handle 736 * 712 737 * @return mixed Handle ID
