alecpl
2010-03-01 929a508d801d9434c8d98dccd0311e3a707303ba
program/include/main.inc
@@ -69,7 +69,7 @@
 */
function get_sequence_name($sequence)
  {
  // return table name if configured
  // return sequence name if configured
  $config_key = 'db_sequence_'.$sequence;
  $opt = rcmail::get_instance()->config->get($config_key);
@@ -128,7 +128,9 @@
 */
function rcmail_temp_gc()
  {
  $tmp = unslashify($CONFIG['temp_dir']);
  $rcmail = rcmail::get_instance();
  $tmp = unslashify($rcmail->config->get('temp_dir'));
  $expire = mktime() - 172800;  // expire in 48 hours
  if ($dir = opendir($tmp))
@@ -168,6 +170,18 @@
/**
 * Catch an error and throw an exception.
 *
 * @param  int    Level of the error
 * @param  string Error message
 */
function rcube_error_handler($errno, $errstr)
  {
  throw new ErrorException($errstr, 0, $errno);
  }
/**
 * Convert a string from one charset to another.
 * Uses mbstring and iconv functions if possible
 *
@@ -178,56 +192,56 @@
 */
function rcube_charset_convert($str, $from, $to=NULL)
  {
  static $iconv_options = null;
  static $mbstring_loaded = null;
  static $mbstring_list = null;
  static $convert_warning = false;
  static $conv = null;
  $error = false;
  $from = strtoupper($from);
  $to = $to==NULL ? strtoupper(RCMAIL_CHARSET) : strtoupper($to);
  $error = false; $conv = null;
  # RFC1642
  if ($from == 'UNICODE-1-1-UTF-7')
    $from = 'UTF-7';
  if ($to == 'UNICODE-1-1-UTF-7')
    $to = 'UTF-7';
  $to = empty($to) ? strtoupper(RCMAIL_CHARSET) : rcube_parse_charset($to);
  $from = rcube_parse_charset($from);
  if ($from == $to || empty($str) || empty($from))
    return $str;
  $aliases = array(
    'US-ASCII'         => 'ISO-8859-1',
    'ANSI_X3.110-1983' => 'ISO-8859-1',
    'ANSI_X3.4-1968'   => 'ISO-8859-1',
    'UNKNOWN-8BIT'     => 'ISO-8859-15',
    'X-UNKNOWN'        => 'ISO-8859-15',
    'X-USER-DEFINED'   => 'ISO-8859-15',
    'ISO-8859-8-I'     => 'ISO-8859-8',
    'KS_C_5601-1987'   => 'EUC-KR',
  );
  // convert charset using iconv module  
  if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7') {
    $aliases['GB2312'] = 'GB18030';
    $_iconv = iconv(($aliases[$from] ? $aliases[$from] : $from), ($aliases[$to] ? $aliases[$to] : $to) . "//IGNORE", $str);
    if ($iconv_options === null) {
      // transliterate characters not available in output charset
      $iconv_options = '//TRANSLIT';
      if (iconv('', $iconv_options, '') === false) {
        // iconv implementation does not support options
        $iconv_options = '';
      }
    }
    // throw an exception if iconv reports an illegal character in input
    // it means that input string has been truncated
    set_error_handler('rcube_error_handler', E_NOTICE);
    try {
      $_iconv = iconv($from, $to . $iconv_options, $str);
    } catch (ErrorException $e) {
      $_iconv = false;
    }
    restore_error_handler();
    if ($_iconv !== false) {
        return $_iconv;
      return $_iconv;
    }
  }
  if (is_null($mbstring_loaded))
  if ($mbstring_loaded === null)
    $mbstring_loaded = extension_loaded('mbstring');
    
  // convert charset using mbstring module
  if ($mbstring_loaded) {
    $aliases['UTF-7'] = 'UTF7-IMAP';
    $aliases['WINDOWS-1257'] = 'ISO-8859-13';
    
    if (is_null($mbstring_list)) {
    if ($mbstring_list === null) {
      $mbstring_list = mb_list_encodings();
      $mbstring_list = array_map('strtoupper', $mbstring_list);
    }
    $mb_from = $aliases[$from] ? $aliases[$from] : $from;
    $mb_to = $aliases[$to] ? $aliases[$to] : $to;
    
@@ -238,57 +252,227 @@
    }
  }
  # try to convert with custom classes
  if (class_exists('utf8'))
    $conv = new utf8();
  // convert charset using bundled classes/functions
  if ($to == 'UTF-8') {
    if ($from == 'UTF7-IMAP') {
      if ($_str = utf7_to_utf8($str))
        return $_str;
    }
    else if ($from == 'UTF-7') {
      if ($_str = rcube_utf7_to_utf8($str))
        return $_str;
    }
    else if (($from == 'ISO-8859-1') && function_exists('utf8_encode')) {
      return utf8_encode($str);
    }
    else if (class_exists('utf8')) {
      if (!$conv)
        $conv = new utf8($from);
      else
        $conv->loadCharset($from);
  // convert string to UTF-8
  if ($from == 'UTF-7') {
    if ($_str = utf7_to_utf8($str))
      $str = $_str;
    else
      $error = true;
  }
  else if (($from == 'ISO-8859-1') && function_exists('utf8_encode')) {
    $str = utf8_encode($str);
  }
  else if ($from != 'UTF-8' && $conv) {
    $conv->loadCharset($from);
    $str = $conv->strToUtf8($str);
  }
  else if ($from != 'UTF-8')
      if($_str = $conv->strToUtf8($str))
        return $_str;
    }
    $error = true;
  }
  // encode string for output
  if ($to == 'UTF-7') {
    return utf8_to_utf7($str);
  }
  else if ($to == 'ISO-8859-1' && function_exists('utf8_decode')) {
    return utf8_decode($str);
  }
  else if ($to != 'UTF-8' && $conv) {
    $conv->loadCharset($to);
    return $conv->utf8ToStr($str);
  }
  else if ($to != 'UTF-8') {
  if ($from == 'UTF-8') {
    // @TODO: we need a function for UTF-7 (RFC2152) conversion
    if ($to == 'UTF7-IMAP' || $to == 'UTF-7') {
      if ($_str = utf8_to_utf7($str))
        return $_str;
    }
    else if ($to == 'ISO-8859-1' && function_exists('utf8_decode')) {
      return utf8_decode($str);
    }
    else if (class_exists('utf8')) {
      if (!$conv)
        $conv = new utf8($to);
      else
        $conv->loadCharset($from);
      if ($_str = $conv->strToUtf8($str))
        return $_str;
    }
    $error = true;
  }
  
  // report error
  if ($error && !$convert_warning){
  if ($error && !$convert_warning) {
    raise_error(array(
      'code' => 500,
      'type' => 'php',
      'file' => __FILE__,
      'message' => "Could not convert string from $from to $to. Make sure iconv is installed or lib/utf8.class is available"
      'line' => __LINE__,
      'message' => "Could not convert string from $from to $to. Make sure iconv/mbstring is installed or lib/utf8.class is available."
      ), true, false);
    
    $convert_warning = true;
  }
  
  // return UTF-8 string
  // return UTF-8 or original string
  return $str;
  }
/**
 * Parse and validate charset name string (see #1485758).
 * Sometimes charset string is malformed, there are also charset aliases
 * but we need strict names for charset conversion (specially utf8 class)
 *
 * @param  string  Input charset name
 * @return The validated charset name
 */
function rcube_parse_charset($charset)
  {
  $charset = strtoupper($charset);
  $charset = preg_replace(array(
    '/^[^0-9A-Z]+/',   // e.g. _ISO-8859-JP$SIO
    '/\$.*$/',      // e.g. _ISO-8859-JP$SIO
    '/UNICODE-1-1-*/',   // RFC1641/1642
    ), '', $charset);
  # Aliases: some of them from HTML5 spec.
  $aliases = array(
    'USASCII'       => 'WINDOWS-1252',
    'ANSIX31101983' => 'WINDOWS-1252',
    'ANSIX341968'   => 'WINDOWS-1252',
    'UNKNOWN8BIT'   => 'ISO-8859-15',
    'UNKNOWN'       => 'ISO-8859-15',
    'USERDEFINED'   => 'ISO-8859-15',
    'KSC56011987'   => 'EUC-KR',
    'GB2312'        => 'GBK',
    'GB231280'       => 'GBK',
    'UNICODE'       => 'UTF-8',
    'UTF7IMAP'       => 'UTF7-IMAP',
    'TIS620'       => 'WINDOWS-874',
    'ISO88599'       => 'WINDOWS-1254',
    'ISO885911'       => 'WINDOWS-874',
    'MACROMAN'       => 'MACINTOSH',
    '238'           => 'WINDOWS-1250',
    '178'           => 'WINDOWS-1256',
    '177'           => 'WINDOWS-1255',
    '204'           => 'WINDOWS-1251',
    '161'           => 'WINDOWS-1253',
    '222'           => 'WINDOWS-874',
    '134'           => 'GBK',
    '238'           => 'WINDOWS-1250',
    '128'           => 'SHIFT-JIS'
  );
  // allow a-z and 0-9 only and remove X- prefix (e.g. X-ROMAN8 => ROMAN8)
  $str = preg_replace(array('/[^A-Z0-9]/', '/^X+/'), '', $charset);
  if (isset($aliases[$str]))
    return $aliases[$str];
  if (preg_match('/U[A-Z][A-Z](7|8|16|32)(BE|LE)*/', $str, $m))
    return 'UTF-' . $m[1] . $m[2];
  if (preg_match('/ISO8859([0-9]{0,2})/', $str, $m)) {
    $iso = 'ISO-8859-' . ($m[1] ? $m[1] : 1);
    # some clients sends windows-1252 text as latin1,
    # it is safe to use windows-1252 for all latin1
    return $iso == 'ISO-8859-1' ? 'WINDOWS-1252' : $iso;
    }
  // handle broken charset names e.g. WINDOWS-1250HTTP-EQUIVCONTENT-TYPE
  if (preg_match('/WINDOWS([0-9]+)/', $str, $m)) {
    return 'WINDOWS-' . $m[1];
    }
  return $charset;
  }
/**
 * Converts string from standard UTF-7 (RFC 2152) to UTF-8.
 *
 * @param  string  Input string
 * @return The converted string
 */
function rcube_utf7_to_utf8($str)
{
  $Index_64 = array(
    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
    0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,
    1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
    0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
    1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
    0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
    1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
  );
  $u7len = strlen($str);
  $str = strval($str);
  $res = '';
  for ($i=0; $u7len > 0; $i++, $u7len--)
  {
    $u7 = $str[$i];
    if ($u7 == '+')
    {
      $i++;
      $u7len--;
      $ch = '';
      for (; $u7len > 0; $i++, $u7len--)
      {
        $u7 = $str[$i];
        if (!$Index_64[ord($u7)])
          break;
   $ch .= $u7;
      }
      if ($ch == '') {
        if ($u7 == '-')
          $res .= '+';
        continue;
      }
      $res .= rcube_utf16_to_utf8(base64_decode($ch));
    }
    else
    {
      $res .= $u7;
    }
  }
  return $res;
}
/**
 * Converts string from UTF-16 to UTF-8 (helper for utf-7 to utf-8 conversion)
 *
 * @param  string  Input string
 * @return The converted string
 */
function rcube_utf16_to_utf8($str)
{
  $len = strlen($str);
  $dec = '';
  for ($i = 0; $i < $len; $i += 2) {
    $c = ord($str[$i]) << 8 | ord($str[$i + 1]);
    if ($c >= 0x0001 && $c <= 0x007F) {
      $dec .= chr($c);
    } else if ($c > 0x07FF) {
      $dec .= chr(0xE0 | (($c >> 12) & 0x0F));
      $dec .= chr(0x80 | (($c >>  6) & 0x3F));
      $dec .= chr(0x80 | (($c >>  0) & 0x3F));
    } else {
      $dec .= chr(0xC0 | (($c >>  6) & 0x1F));
      $dec .= chr(0x80 | (($c >>  0) & 0x3F));
    }
  }
  return $dec;
}
/**
@@ -306,17 +490,8 @@
  static $js_rep_table = false;
  static $xml_rep_table = false;
  $charset = rcmail::get_instance()->config->get('charset', RCMAIL_CHARSET);
  $is_iso_8859_1 = false;
  if ($charset == 'ISO-8859-1') {
    $is_iso_8859_1 = true;
  }
  if (!$enctype)
    $enctype = $OUTPUT->type;
  // encode for plaintext
  if ($enctype=='text')
    return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
  // encode for HTML output
  if ($enctype=='html')
@@ -347,9 +522,6 @@
    return $newlines ? nl2br($out) : $out;
    }
  if ($enctype=='url')
    return rawurlencode($str);
  // if the replace tables for XML and JS are not yet defined
  if ($js_rep_table===false)
    {
@@ -357,31 +529,31 @@
    $xml_rep_table['&'] = '&amp;';
    for ($c=160; $c<256; $c++)  // can be increased to support more charsets
      {
      $xml_rep_table[Chr($c)] = "&#$c;";
      if ($is_iso_8859_1)
        $js_rep_table[Chr($c)] = sprintf("\\u%04x", $c);
      }
      $xml_rep_table[chr($c)] = "&#$c;";
    $xml_rep_table['"'] = '&quot;';
    $js_rep_table['"'] = '\\"';
    $js_rep_table["'"] = "\\'";
    $js_rep_table["\\"] = "\\\\";
    // Unicode line and paragraph separators (#1486310)
    $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A8))] = '&#8232;';
    $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A9))] = '&#8233;';
    }
  // encode for javascript use
  if ($enctype=='js')
    return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table));
  // encode for plaintext
  if ($enctype=='text')
    return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
  if ($enctype=='url')
    return rawurlencode($str);
  // encode for XML
  if ($enctype=='xml')
    return strtr($str, $xml_rep_table);
  // encode for javascript use
  if ($enctype=='js')
    {
    if ($charset!='UTF-8')
      $str = rcube_charset_convert($str, RCMAIL_CHARSET,$charset);
    return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table));
    }
  // no encoding given -> return original string
  return $str;
@@ -423,8 +595,7 @@
 * @return string   Field value or NULL if not available
 */
function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
  {
  global $OUTPUT;
{
  $value = NULL;
  
  if ($source==RCUBE_INPUT_GET && isset($_GET[$fname]))
@@ -440,7 +611,32 @@
    else if (isset($_COOKIE[$fname]))
      $value = $_COOKIE[$fname];
    }
  return parse_input_value($value, $allow_html, $charset);
}
/**
 * Parse/validate input value. See get_input_value()
 * Performs stripslashes() and charset conversion if necessary
 *
 * @param  string   Input value
 * @param  boolean  Allow HTML tags in field value
 * @param  string   Charset to convert into
 * @return string   Parsed value
 */
function parse_input_value($value, $allow_html=FALSE, $charset=NULL)
{
  global $OUTPUT;
  if (empty($value))
    return $value;
  if (is_array($value)) {
    foreach ($value as $idx => $val)
      $value[$idx] = parse_input_value($val, $allow_html, $charset);
    return $value;
  }
  // strip single quotes if magic_quotes_sybase is enabled
  if (ini_get('magic_quotes_sybase'))
    $value = str_replace("''", "'", $value);
@@ -453,20 +649,39 @@
    $value = strip_tags($value);
  
  // convert to internal charset
  if (is_object($OUTPUT))
  if (is_object($OUTPUT) && $charset)
    return rcube_charset_convert($value, $OUTPUT->get_charset(), $charset);
  else
    return $value;
}
/**
 * Convert array of request parameters (prefixed with _)
 * to a regular array with non-prefixed keys.
 *
 * @param  int   Source to get value from (GPC)
 * @return array Hash array with all request parameters
 */
function request2param($mode = RCUBE_INPUT_GPC)
{
  $out = array();
  $src = $mode == RCUBE_INPUT_GET ? $_GET : ($mode == RCUBE_INPUT_POST ? $_POST : $_REQUEST);
  foreach ($src as $key => $value) {
    $fname = $key[0] == '_' ? substr($key, 1) : $key;
    $out[$fname] = get_input_value($key, $mode);
  }
  return $out;
}
/**
 * Remove all non-ascii and non-word chars
 * except . and -
 * except ., -, _
 */
function asciiwords($str, $css_id = false)
function asciiwords($str, $css_id = false, $replace_with = '')
{
  $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : '');
  return preg_replace("/[^$allowed]/i", '', $str);
  return preg_replace("/[^$allowed]/i", $replace_with, $str);
}
/**
@@ -519,7 +734,7 @@
    while ($table_data && ($sql_arr = $db->fetch_assoc($table_data)))
    {
      $zebra_class = $c % 2 ? 'even' : 'odd';
      $table->add_row(array('id' => 'rcmrow' . $sql_arr[$id_col], 'class' => "contact $zebra_class"));
      $table->add_row(array('id' => 'rcmrow' . $sql_arr[$id_col], 'class' => $zebra_class));
      // format each col
      foreach ($a_show_cols as $col)
@@ -533,7 +748,7 @@
    foreach ($table_data as $row_data)
    {
      $zebra_class = $c % 2 ? 'even' : 'odd';
      $table->add_row(array('id' => 'rcmrow' . $row_data[$id_col], 'class' => "contact $zebra_class"));
      $table->add_row(array('id' => 'rcmrow' . $row_data[$id_col], 'class' => $zebra_class));
      // format each col
      foreach ($a_show_cols as $col)
@@ -599,7 +814,7 @@
  $replacements = new rcube_string_replacer;
  
  // ignore the whole block if evil styles are detected
  $stripped = preg_replace('/[^a-z\(:]/', '', rcmail_xss_entitiy_decode($source));
  $stripped = preg_replace('/[^a-z\(:]/', '', rcmail_xss_entity_decode($source));
  if (preg_match('/expression|behavior|url\(|import/', $stripped))
    return '/* evil! */';
@@ -640,22 +855,22 @@
 * @param string CSS content to decode
 * @return string Decoded string
 */
function rcmail_xss_entitiy_decode($content)
function rcmail_xss_entity_decode($content)
{
  $out = html_entity_decode(html_entity_decode($content));
  $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entitiy_decode_callback', $out);
  $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out);
  $out = preg_replace('#/\*.*\*/#Um', '', $out);
  return $out;
}
/**
 * preg_replace_callback callback for rcmail_xss_entitiy_decode_callback
 * preg_replace_callback callback for rcmail_xss_entity_decode_callback
 *
 * @param array matches result from preg_replace_callback
 * @return string decoded entity
 */ 
function rcmail_xss_entitiy_decode_callback($matches)
function rcmail_xss_entity_decode_callback($matches)
  return chr(hexdec($matches[1]));
}
@@ -756,14 +971,19 @@
  $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']);
  $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']);
  // define date format depending on current time
  if ($CONFIG['prettydate'] && !$format && $timestamp > $today_limit && $timestamp < $now)
    return sprintf('%s %s', rcube_label('today'), date($CONFIG['date_today'] ? $CONFIG['date_today'] : 'H:i', $timestamp));
  else if ($CONFIG['prettydate'] && !$format && $timestamp > $week_limit && $timestamp < $now)
    $format = $CONFIG['date_short'] ? $CONFIG['date_short'] : 'D H:i';
  else if (!$format)
    $format = $CONFIG['date_long'] ? $CONFIG['date_long'] : 'd.m.Y H:i';
  // define date format depending on current time
  if (!$format) {
    if ($CONFIG['prettydate'] && $timestamp > $today_limit && $timestamp < $now)
      return sprintf('%s %s', rcube_label('today'), date($CONFIG['date_today'] ? $CONFIG['date_today'] : 'H:i', $timestamp));
    else if ($CONFIG['prettydate'] && $timestamp > $week_limit && $timestamp < $now)
      $format = $CONFIG['date_short'] ? $CONFIG['date_short'] : 'D H:i';
    else
      $format = $CONFIG['date_long'] ? $CONFIG['date_long'] : 'd.m.Y H:i';
    }
  // strftime() format
  if (preg_match('/%[a-z]+/i', $format))
    return strftime($format, $timestamp);
  // parse format string manually in order to provide localized weekday and month names
  // an alternative would be to convert the date() format string to fit with strftime()
@@ -799,7 +1019,7 @@
/**
 * Compose a valid representaion of name and e-mail address
 * Compose a valid representation of name and e-mail address
 *
 * @param string E-mail address
 * @param string Person name
@@ -810,10 +1030,10 @@
  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, $email);
    return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, trim($email));
    }
  else
    return $email;
    return trim($email);
  }
@@ -829,12 +1049,16 @@
function console()
  {
  $args = func_get_args();
  if (class_exists('rcmail', false))
      rcmail::get_instance()->plugins->exec_hook('console', $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;
    $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
  if (!($GLOBALS['CONFIG']['debug_level'] & 4))
    write_log('console', join(";\n", $msg));
@@ -858,34 +1082,50 @@
 */
function write_log($name, $line)
  {
  global $CONFIG;
  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;
  }
 
  $log_entry = sprintf("[%s]: %s\n", date($CONFIG['log_date_format']), $line);
  $log_entry = sprintf("[%s]: %s\n", $date, $line);
  if ($CONFIG['log_driver'] == 'syslog') {
    if ($name == 'errors')
      $prio = LOG_ERR;
    else
      $prio = LOG_INFO;
    $prio = $name == 'errors' ? LOG_ERR : LOG_INFO;
    syslog($prio, $log_entry);
  } else {
    return true;
  }
  else {
    // 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
    if ($fp = @fopen($CONFIG['log_dir'].'/'.$name, 'a')) {
    $logfile = $CONFIG['log_dir'].'/'.$name;
    if ($fp = @fopen($logfile, 'a')) {
      fwrite($fp, $log_entry);
      fflush($fp);
      fclose($fp);
      return true;
    }
    else
      trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING);
  }
  return false;
}
@@ -893,17 +1133,16 @@
 * @access private
 */
function rcube_timer()
  {
  list($usec, $sec) = explode(" ", microtime());
  return ((float)$usec + (float)$sec);
  }
{
  return microtime(true);
}
  
/**
 * @access private
 */
function rcube_print_time($timer, $label='Timer')
  {
function rcube_print_time($timer, $label='Timer', $dest='console')
{
  static $print_count = 0;
  
  $print_count++;
@@ -913,8 +1152,8 @@
  if (empty($label))
    $label = 'Timer '.$print_count;
  
  console(sprintf("%s: %0.4f sec", $label, $diff));
  }
  write_log($dest, sprintf("%s: %0.4f sec", $label, $diff));
}
/**
@@ -928,7 +1167,7 @@
  global $RCMAIL;
  static $a_mailboxes;
  
  $attrib += array('maxlength' => 100, 'relanames' => false);
  $attrib += array('maxlength' => 100, 'realnames' => false);
  // add some labels to client
  $RCMAIL->output->add_label('purgefolderconfirm', 'deletemessagesconfirm');
@@ -952,6 +1191,9 @@
    foreach ($a_folders as $folder)
      rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter);
  }
  // allow plugins to alter the folder tree or to localize folder names
  $hook = $RCMAIL->plugins->exec_hook('render_mailboxlist', array('list' => $a_mailboxes, 'delimiter' => $delimiter));
  if ($type=='select') {
    $select = new html_select($attrib);
@@ -960,12 +1202,12 @@
    if ($attrib['noselection'])
      $select->add(rcube_label($attrib['noselection']), '0');
    
    rcmail_render_folder_tree_select($a_mailboxes, $mbox_name, $attrib['maxlength'], $select, $attrib['realnames']);
    rcmail_render_folder_tree_select($hook['list'], $mbox_name, $attrib['maxlength'], $select, $attrib['realnames']);
    $out = $select->show();
  }
  else {
    $js_mailboxlist = array();
    $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($a_mailboxes, $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib);
    $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($hook['list'], $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib);
    
    $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']);
    $RCMAIL->output->set_env('mailboxes', $js_mailboxlist);
@@ -986,11 +1228,12 @@
{
  global $RCMAIL;
  
  $p += array('maxlength' => 100, 'relanames' => false);
  $p += array('maxlength' => 100, 'realnames' => false);
  $a_mailboxes = array();
  
  foreach ($RCMAIL->imap->list_mailboxes() as $folder)
    rcmail_build_folder_tree($a_mailboxes, $folder, $RCMAIL->imap->get_hierarchy_delimiter());
    if (empty($p['exceptions']) || !in_array($folder, $p['exceptions']))
      rcmail_build_folder_tree($a_mailboxes, $folder, $RCMAIL->imap->get_hierarchy_delimiter());
  $select = new html_select($p);
  
@@ -1026,7 +1269,7 @@
  if (!isset($arrFolders[$currentFolder])) {
    $arrFolders[$currentFolder] = array(
      'id' => $path,
      'name' => rcube_charset_convert($currentFolder, 'UTF-7'),
      'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'),
      'virtual' => $virtual,
      'folders' => array());
  }
@@ -1072,7 +1315,7 @@
    }
    // make folder name safe for ids and class names
    $folder_id = asciiwords($folder['id'], true);
    $folder_id = asciiwords($folder['id'], true, '_');
    $classes = array('mailbox');
    // set special class for Sent, Drafts, Trash and Junk
@@ -1201,7 +1444,7 @@
  if ($folder_class = rcmail_folder_classname($name))
    return rcube_label($folder_class);
  else
    return rcube_charset_convert($name, 'UTF-7');
    return rcube_charset_convert($name, 'UTF7-IMAP');
}
@@ -1212,18 +1455,104 @@
 */
function rcube_html_editor($mode='')
{
  global $OUTPUT, $CONFIG;
  global $RCMAIL, $CONFIG;
  $lang = $tinylang = strtolower(substr($_SESSION['language'], 0, 2));
  if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$tinylang.'.js'))
    $tinylang = 'en';
  $hook = $RCMAIL->plugins->exec_hook('hmtl_editor', array('mode' => $mode));
  $OUTPUT->include_script('tiny_mce/tiny_mce.js');
  $OUTPUT->include_script('editor.js');
  $OUTPUT->add_script('rcmail_editor_init("$__skin_path", "'.JQ($tinylang).'", '.intval($CONFIG['enable_spellcheck']).', "'.$mode.'");');
  if ($hook['abort'])
    return;
  $lang = strtolower(substr($_SESSION['language'], 0, 2));
  if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js'))
    $lang = 'en';
  $RCMAIL->output->include_script('tiny_mce/tiny_mce.js');
  $RCMAIL->output->include_script('editor.js');
  $RCMAIL->output->add_script('rcmail_editor_init("$__skin_path",
    "'.JQ($lang).'", '.intval($CONFIG['enable_spellcheck']).', "'.$mode.'");');
}
/**
 * Check if working in SSL mode
 *
 * @param integer HTTPS port number
 * @param boolean Enables 'use_https' option checking
 */
function rcube_https_check($port=null, $use_https=true)
{
  global $RCMAIL;
  if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off')
    return true;
  if ($port && $_SERVER['SERVER_PORT'] == $port)
    return true;
  if ($use_https && isset($RCMAIL) && $RCMAIL->config->get('use_https'))
    return true;
  return false;
}
// for backward compatibility
function rcube_sess_unset($var_name=null)
{
  global $RCMAIL;
  $RCMAIL->session->remove($var_name);
}
/**
 * E-mail address validation
 */
function check_email($email)
{
  // Check for invalid characters
  if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email))
    return false;
  // Check that there's one @ symbol, and that the lengths are right
  if (!preg_match('/^([^@]{1,64})@([^@]{1,255})$/', $email, $email_array))
    return false;
  // Check local part
  $local_array = explode('.', $email_array[1]);
  foreach ($local_array as $local_part)
    if (!preg_match('/^(([A-Za-z0-9!#$%&\'*+\/=?^_`{|}~-]+)|("[^"]+"))$/', $local_part))
      return false;
  // Check domain part
  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}$/', $email_array[2])
      || 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}\]$/', $email_array[2]))
    return true; // If an IP address
  else {
    // If not an IP address
    $domain_array = explode('.', $email_array[2]);
    if (sizeof($domain_array) < 2)
      return false; // Not enough parts to be a valid domain
    foreach ($domain_array as $domain_part)
      if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $domain_part))
        return false;
    if (!rcmail::get_instance()->config->get('email_dns_check'))
      return true;
    if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<'))
      return true;
    // find MX record(s)
    if (getmxrr($email_array[2], $mx_records))
      return true;
    // find any DNS record
    if (checkdnsrr($email_array[2], 'ANY'))
      return true;
  }
  return false;
}
/**
 * Helper class to turn relative urls into absolute ones