diff --git a/CHANGELOG b/CHANGELOG index 047901f00..6a0f3351f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix handling of debug_level=4 in ajax requests (#1487831) - Support 'abort' and 'result' response in 'preferences_save' hook, add error handling - Fix bug where some content would cause hang on html2text conversion (#1487863) - Improve space-stuffing handling in format=flowed messages (#1487861) diff --git a/program/include/main.inc b/program/include/main.inc index 64fea702d..54ce67d00 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -1141,192 +1141,13 @@ function format_date($date, $format=NULL) * @return string Formatted string */ function format_email_recipient($email, $name='') - { - if ($name && $name != $email) - { +{ + if ($name && $name != $email) { // Special chars as defined by RFC 822 need to in quoted string (or escaped). return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, trim($email)); - } - else - return trim($email); - } - - - -/****** debugging functions ********/ - - -/** - * Print or write debug messages - * - * @param mixed Debug message or data - * @return void - */ -function console() - { - $args = func_get_args(); - - if (class_exists('rcmail', false)) { - $rcmail = rcmail::get_instance(); - if (is_object($rcmail->plugins)) - $rcmail->plugins->exec_hook('console', $args); - } - - $msg = array(); - foreach ($args as $arg) - $msg[] = !is_string($arg) ? var_export($arg, true) : $arg; - - if (!($GLOBALS['CONFIG']['debug_level'] & 4)) - write_log('console', join(";\n", $msg)); - else if ($GLOBALS['OUTPUT']->ajax_call) - print "/*\n " . join(";\n", $msg) . " \n*/\n"; - else - { - print '
';
-    print join(";
\n", $msg); - print "
\n"; - } } - -/** - * Append a line to a logfile in the logs directory. - * Date will be added automatically to the line. - * - * @param $name name of log file - * @param line Line to append - * @return void - */ -function write_log($name, $line) - { - global $CONFIG, $RCMAIL; - - if (!is_string($line)) - $line = var_export($line, true); - - if (empty($CONFIG['log_date_format'])) - $CONFIG['log_date_format'] = 'd-M-Y H:i:s O'; - - $date = date($CONFIG['log_date_format']); - - // trigger logging hook - if (is_object($RCMAIL) && is_object($RCMAIL->plugins)) { - $log = $RCMAIL->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line)); - $name = $log['name']; - $line = $log['line']; - $date = $log['date']; - if ($log['abort']) - return true; - } - - if ($CONFIG['log_driver'] == 'syslog') { - $prio = $name == 'errors' ? LOG_ERR : LOG_INFO; - syslog($prio, $line); - return true; - } - else { - $line = sprintf("[%s]: %s\n", $date, $line); - - // log_driver == 'file' is assumed here - if (empty($CONFIG['log_dir'])) - $CONFIG['log_dir'] = INSTALL_PATH.'logs'; - - // try to open specific log file for writing - $logfile = $CONFIG['log_dir'].'/'.$name; - if ($fp = @fopen($logfile, 'a')) { - fwrite($fp, $line); - fflush($fp); - fclose($fp); - return true; - } - else - trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING); - } - return false; -} - - -/** - * Write login data (name, ID, IP address) to the 'userlogins' log file. - * - * @return void - */ -function rcmail_log_login() -{ - global $RCMAIL; - - if (!$RCMAIL->config->get('log_logins') || !$RCMAIL->user) - return; - - write_log('userlogins', sprintf('Successful login for %s (ID: %d) from %s', - $RCMAIL->user->get_username(), $RCMAIL->user->ID, rcmail_remote_ip())); -} - - -/** - * Returns remote IP address and forwarded addresses if found - * - * @return string Remote IP address(es) - */ -function rcmail_remote_ip() -{ - $address = $_SERVER['REMOTE_ADDR']; - - // append the NGINX X-Real-IP header, if set - if (!empty($_SERVER['HTTP_X_REAL_IP'])) { - $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP']; - } - // append the X-Forwarded-For header, if set - if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR']; - } - - if (!empty($remote_ip)) - $address .= '(' . implode(',', $remote_ip) . ')'; - - return $address; -} - - -/** - * Check whether the HTTP referer matches the current request - * - * @return boolean True if referer is the same host+path, false if not - */ -function rcube_check_referer() -{ - $uri = parse_url($_SERVER['REQUEST_URI']); - $referer = parse_url(rc_request_header('Referer')); - return $referer['host'] == rc_request_header('Host') && $referer['path'] == $uri['path']; -} - - -/** - * @access private - * @return mixed - */ -function rcube_timer() -{ - return microtime(true); -} - - -/** - * @access private - * @return void - */ -function rcube_print_time($timer, $label='Timer', $dest='console') -{ - static $print_count = 0; - - $print_count++; - $now = rcube_timer(); - $diff = $now-$timer; - - if (empty($label)) - $label = 'Timer '.$print_count; - - write_log($dest, sprintf("%s: %0.4f sec", $label, $diff)); + return trim($email); } @@ -1844,7 +1665,6 @@ function rcube_sess_unset($var_name=null) } - /** * Replaces hostname variables * @@ -1995,6 +1815,178 @@ class rcube_base_replacer } +/****** debugging and logging functions ********/ + +/** + * Print or write debug messages + * + * @param mixed Debug message or data + * @return void + */ +function console() +{ + $args = func_get_args(); + + if (class_exists('rcmail', false)) { + $rcmail = rcmail::get_instance(); + if (is_object($rcmail->plugins)) { + $plugin = $rcmail->plugins->exec_hook('console', array('args' => $args)); + if ($plugin['abort']) + return; + $args = $plugin['args']; + } + } + + $msg = array(); + foreach ($args as $arg) + $msg[] = !is_string($arg) ? var_export($arg, true) : $arg; + + write_log('console', join(";\n", $msg)); +} + + +/** + * Append a line to a logfile in the logs directory. + * Date will be added automatically to the line. + * + * @param $name name of log file + * @param line Line to append + * @return void + */ +function write_log($name, $line) +{ + global $CONFIG, $RCMAIL; + + if (!is_string($line)) + $line = var_export($line, true); + + if (empty($CONFIG['log_date_format'])) + $CONFIG['log_date_format'] = 'd-M-Y H:i:s O'; + + $date = date($CONFIG['log_date_format']); + + // trigger logging hook + if (is_object($RCMAIL) && is_object($RCMAIL->plugins)) { + $log = $RCMAIL->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line)); + $name = $log['name']; + $line = $log['line']; + $date = $log['date']; + if ($log['abort']) + return true; + } + + if ($CONFIG['log_driver'] == 'syslog') { + $prio = $name == 'errors' ? LOG_ERR : LOG_INFO; + syslog($prio, $line); + return true; + } + else { + $line = sprintf("[%s]: %s\n", $date, $line); + + // log_driver == 'file' is assumed here + if (empty($CONFIG['log_dir'])) + $CONFIG['log_dir'] = INSTALL_PATH.'logs'; + + // try to open specific log file for writing + $logfile = $CONFIG['log_dir'].'/'.$name; + if ($fp = @fopen($logfile, 'a')) { + fwrite($fp, $line); + fflush($fp); + fclose($fp); + return true; + } + else + trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING); + } + + return false; +} + + +/** + * Write login data (name, ID, IP address) to the 'userlogins' log file. + * + * @return void + */ +function rcmail_log_login() +{ + global $RCMAIL; + + if (!$RCMAIL->config->get('log_logins') || !$RCMAIL->user) + return; + + write_log('userlogins', sprintf('Successful login for %s (ID: %d) from %s', + $RCMAIL->user->get_username(), $RCMAIL->user->ID, rcmail_remote_ip())); +} + + +/** + * Returns remote IP address and forwarded addresses if found + * + * @return string Remote IP address(es) + */ +function rcmail_remote_ip() +{ + $address = $_SERVER['REMOTE_ADDR']; + + // append the NGINX X-Real-IP header, if set + if (!empty($_SERVER['HTTP_X_REAL_IP'])) { + $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP']; + } + // append the X-Forwarded-For header, if set + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR']; + } + + if (!empty($remote_ip)) + $address .= '(' . implode(',', $remote_ip) . ')'; + + return $address; +} + + +/** + * Check whether the HTTP referer matches the current request + * + * @return boolean True if referer is the same host+path, false if not + */ +function rcube_check_referer() +{ + $uri = parse_url($_SERVER['REQUEST_URI']); + $referer = parse_url(rc_request_header('Referer')); + return $referer['host'] == rc_request_header('Host') && $referer['path'] == $uri['path']; +} + + +/** + * @access private + * @return mixed + */ +function rcube_timer() +{ + return microtime(true); +} + + +/** + * @access private + * @return void + */ +function rcube_print_time($timer, $label='Timer', $dest='console') +{ + static $print_count = 0; + + $print_count++; + $now = rcube_timer(); + $diff = $now-$timer; + + if (empty($label)) + $label = 'Timer '.$print_count; + + write_log($dest, sprintf("%s: %0.4f sec", $label, $diff)); +} + + /** * Throw system error and show error page * @@ -2015,7 +2007,7 @@ function raise_error($arg=array(), $log=false, $terminate=false) // report bug (if not incompatible browser) if ($log && $arg['type'] && $arg['message']) - log_bug($arg); + rcube_log_bug($arg); // display error page and terminate script if ($terminate) { @@ -2035,13 +2027,20 @@ function raise_error($arg=array(), $log=false, $terminate=false) * @return void * @see raise_error() */ -function log_bug($arg_arr) +function rcube_log_bug($arg_arr) { global $CONFIG; + $program = strtoupper($arg_arr['type']); + $level = $CONFIG['debug_level']; + + // disable errors for ajax requests, write to log instead (#1487831) + if (($level & 4) && !empty($_REQUEST['_remote'])) { + $level = ($level ^ 4) | 1; + } // write error to local log file - if ($CONFIG['debug_level'] & 1) { + if ($level & 1) { $post_query = ($_SERVER['REQUEST_METHOD'] == 'POST' ? '?_task='.urlencode($_POST['_task']).'&_action='.urlencode($_POST['_action']) : ''); $log_entry = sprintf("%s Error: %s%s (%s %s)", $program, @@ -2056,13 +2055,13 @@ function log_bug($arg_arr) } } - // resport the bug to the global bug reporting system - if ($CONFIG['debug_level'] & 2) { + // report the bug to the global bug reporting system + if ($level & 2) { // TODO: Send error via HTTP } // show error if debug_mode is on - if ($CONFIG['debug_level'] & 4) { + if ($level & 4) { print "$program Error"; if (!empty($arg_arr['file']) && !empty($arg_arr['line'])) diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php index 5d176053e..31608a3cc 100644 --- a/program/include/rcube_config.php +++ b/program/include/rcube_config.php @@ -87,12 +87,9 @@ class rcube_config ini_set('error_log', $this->prop['log_dir'].'/errors'); } } - if ($this->prop['debug_level'] & 4) { - ini_set('display_errors', 1); - } - else { - ini_set('display_errors', 0); - } + + // enable display_errors in 'show' level, but not for ajax requests + ini_set('display_errors', intval(empty($_REQUEST['_remote']) && ($this->prop['debug_level'] & 4))); // export config data $GLOBALS['CONFIG'] = &$this->prop;