Changeset 5807 in subversion


Ignore:
Timestamp:
Jan 20, 2012 6:23:32 AM (17 months ago)
Author:
alec
Message:
  • Move global functions from main.inc and rcube_shared.inc into classes Leave main.inc with aliases for backward compat. (to be removed)
  • Unified naming of the rest global functions (rcube_ prefix)
Location:
branches/devel-framework/roundcubemail
Files:
2 added
10 edited

Legend:

Unmodified
Added
Removed
  • branches/devel-framework/roundcubemail/installer/index.php

    r5152 r5807  
    4343 
    4444require_once 'utils.php'; 
     45require_once 'rcube_shared.inc'; 
     46// deprecated aliases (to be removed) 
    4547require_once 'main.inc'; 
    4648 
  • branches/devel-framework/roundcubemail/installer/utils.php

    r5152 r5807  
    6969 * Local callback function for PEAR errors 
    7070 */ 
    71 function rcube_pear_error($err) 
     71function __pear_error($err) 
    7272{ 
    7373    raise_error(array( 
     
    7878 
    7979// set PEAR error handling (will also load the PEAR main class) 
    80 PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error'); 
     80PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, '__pear_error'); 
  • branches/devel-framework/roundcubemail/program/include/clisetup.php

    r5299 r5807  
    5353 
    5454                $args[$key] = preg_replace(array('/^["\']/', '/["\']$/'), '', $value); 
    55                  
     55 
    5656                if ($alias = $aliases[$key]) 
    5757                        $args[$alias] = $args[$key]; 
  • branches/devel-framework/roundcubemail/program/include/html.php

    r5672 r5807  
    304304        return count($attrib_arr) ? ' '.implode(' ', $attrib_arr) : ''; 
    305305    } 
     306 
     307    /** 
     308     * Convert a HTML attribute string attributes to an associative array (name => value) 
     309     * 
     310     * @param string Input string 
     311     * @return array Key-value pairs of parsed attributes 
     312     */ 
     313    public static function parse_attrib_string($str) 
     314    { 
     315        $attrib = array(); 
     316        $regexp = '/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/Ui'; 
     317 
     318        preg_match_all($regexp, stripslashes($str), $regs, PREG_SET_ORDER); 
     319 
     320        // convert attributes to an associative array (name => value) 
     321        if ($regs) { 
     322            foreach ($regs as $attr) { 
     323                $attrib[strtolower($attr[1])] = html_entity_decode($attr[3] . $attr[4]); 
     324            } 
     325        } 
     326 
     327        return $attrib; 
     328    } 
    306329} 
    307330 
     
    804827 
    805828} 
    806  
  • branches/devel-framework/roundcubemail/program/include/iniset.php

    r5768 r5807  
    7878} 
    7979 
    80 /** 
    81  * Use PHP5 autoload for dynamic class loading 
    82  *  
    83  * @todo Make Zend, PEAR etc play with this 
    84  * @todo Make our classes conform to a more straight forward CS. 
    85  */ 
    86 function rcube_autoload($classname) 
    87 { 
    88     $filename = preg_replace( 
    89         array( 
    90             '/MDB2_(.+)/', 
    91             '/Mail_(.+)/', 
    92             '/Net_(.+)/', 
    93             '/Auth_(.+)/', 
    94             '/^html_.+/', 
    95             '/^utf8$/', 
    96         ), 
    97         array( 
    98             'MDB2/\\1', 
    99             'Mail/\\1', 
    100             'Net/\\1', 
    101             'Auth/\\1', 
    102             'html', 
    103             'utf8.class', 
    104         ), 
    105         $classname 
    106     ); 
     80// include global functions 
     81require_once INSTALL_PATH . 'program/include/rcube_shared.inc'; 
    10782 
    108     if ($fp = @fopen("$filename.php", 'r', true)) { 
    109         fclose($fp); 
    110         include_once("$filename.php"); 
    111         return true; 
    112     } 
    113  
    114     return false; 
    115 } 
    116  
     83// Register autoloader 
    11784spl_autoload_register('rcube_autoload'); 
    118  
    119 /** 
    120  * Local callback function for PEAR errors 
    121  */ 
    122 function rcube_pear_error($err) 
    123 { 
    124     error_log(sprintf("%s (%s): %s", 
    125         $err->getMessage(), 
    126         $err->getCode(), 
    127         $err->getUserinfo()), 0); 
    128 } 
    12985 
    13086// set PEAR error handling (will also load the PEAR main class) 
    13187PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error'); 
    13288 
    133 // include global functions 
     89// backward compatybility (to be removed) 
    13490require_once INSTALL_PATH . 'program/include/main.inc'; 
    135 require_once INSTALL_PATH . 'program/include/rcube_shared.inc'; 
  • branches/devel-framework/roundcubemail/program/include/main.inc

    r5776 r5807  
    66 |                                                                       | 
    77 | This file is part of the Roundcube Webmail client                     | 
    8  | Copyright (C) 2005-2011, The Roundcube Dev Team                       | 
     8 | Copyright (C) 2005-2012, The Roundcube Dev Team                       | 
    99 | Licensed under the GNU GPL                                            | 
    1010 |                                                                       | 
    1111 | PURPOSE:                                                              | 
    12  |   Provide basic functions for the webmail package                     | 
     12 |   Provide deprecated functions aliases for backward compatibility     | 
    1313 |                                                                       | 
    1414 +-----------------------------------------------------------------------+ 
     
    2121 
    2222/** 
    23  * Roundcube Webmail common functions 
     23 * Roundcube Webmail deprecated functions 
    2424 * 
    2525 * @package Core 
     
    2727 */ 
    2828 
    29 require_once INSTALL_PATH . 'program/include/rcube_shared.inc'; 
    30  
    31 // define constannts for input reading 
    32 define('RCUBE_INPUT_GET', 0x0101); 
    33 define('RCUBE_INPUT_POST', 0x0102); 
    34 define('RCUBE_INPUT_GPC', 0x0103); 
    35  
    36  
    37  
    38 /** 
    39  * Return correct name for a specific database table 
    40  * 
    41  * @param string Table name 
    42  * @return string Translated table name 
    43  */ 
     29// constants for input reading 
     30define('RCUBE_INPUT_GET',  rcube_ui::INPUT_GET); 
     31define('RCUBE_INPUT_POST', rcube_ui::INPUT_POST); 
     32define('RCUBE_INPUT_GPC',  rcube_ui::INPUT_GPC); 
     33 
     34 
    4435function get_table_name($table) 
    45   { 
    46   global $CONFIG; 
    47  
    48   // return table name if configured 
    49   $config_key = 'db_table_'.$table; 
    50  
    51   if (strlen($CONFIG[$config_key])) 
    52     return $CONFIG[$config_key]; 
    53  
    54   return $table; 
    55   } 
    56  
    57  
    58 /** 
    59  * Return correct name for a specific database sequence 
    60  * (used for Postgres only) 
    61  * 
    62  * @param string Secuence name 
    63  * @return string Translated sequence name 
    64  */ 
     36{ 
     37    return rcmail::get_instance()->db->table_name($table); 
     38} 
     39 
    6540function get_sequence_name($sequence) 
    66   { 
    67   // return sequence name if configured 
    68   $config_key = 'db_sequence_'.$sequence; 
    69   $opt = rcmail::get_instance()->config->get($config_key); 
    70  
    71   if (!empty($opt)) 
    72     return $opt; 
    73      
    74   return $sequence; 
    75   } 
    76  
    77  
    78 /** 
    79  * Get localized text in the desired language 
    80  * It's a global wrapper for rcmail::gettext() 
    81  * 
    82  * @param mixed Named parameters array or label name 
    83  * @param string Domain to search in (e.g. plugin name) 
    84  * @return string Localized text 
    85  * @see rcmail::gettext() 
    86  */ 
     41{ 
     42    return rcmail::get_instance()->db->sequence_name($sequence); 
     43} 
     44 
    8745function rcube_label($p, $domain=null) 
    8846{ 
    89   return rcmail::get_instance()->gettext($p, $domain); 
    90 } 
    91  
    92  
    93 /** 
    94  * Global wrapper of rcmail::text_exists() 
    95  * to check whether a text label is defined 
    96  * 
    97  * @see rcmail::text_exists() 
    98  */ 
     47    return rcmail::get_instance()->gettext($p, $domain); 
     48} 
     49 
    9950function rcube_label_exists($name, $domain=null, &$ref_domain = null) 
    10051{ 
    101   return rcmail::get_instance()->text_exists($name, $domain, $ref_domain); 
    102 } 
    103  
    104  
    105 /** 
    106  * Overwrite action variable 
    107  * 
    108  * @param string New action value 
    109  */ 
     52    return rcmail::get_instance()->text_exists($name, $domain, $ref_domain); 
     53} 
     54 
    11055function rcmail_overwrite_action($action) 
    111   { 
    112   $app = rcmail::get_instance(); 
    113   $app->action = $action; 
    114   $app->output->set_env('action', $action); 
    115   } 
    116  
    117  
    118 /** 
    119  * Compose an URL for a specific action 
    120  * 
    121  * @param string  Request action 
    122  * @param array   More URL parameters 
    123  * @param string  Request task (omit if the same) 
    124  * @return The application URL 
    125  */ 
     56{ 
     57    rcmail::get_instance()->overwrite_action($action); 
     58} 
     59 
    12660function rcmail_url($action, $p=array(), $task=null) 
    12761{ 
    128   $app = rcmail::get_instance(); 
    129   return $app->url((array)$p + array('_action' => $action, 'task' => $task)); 
    130 } 
    131  
    132  
    133 /** 
    134  * Garbage collector function for temp files. 
    135  * Remove temp files older than two days 
    136  */ 
     62    return rcube_ui::url($action, $p, $task); 
     63} 
     64 
    13765function rcmail_temp_gc() 
    13866{ 
    139   $rcmail = rcmail::get_instance(); 
    140  
    141   $tmp = unslashify($rcmail->config->get('temp_dir')); 
    142   $expire = mktime() - 172800;  // expire in 48 hours 
    143  
    144   if ($dir = opendir($tmp)) { 
    145     while (($fname = readdir($dir)) !== false) { 
    146       if ($fname{0} == '.') 
    147         continue; 
    148  
    149       if (filemtime($tmp.'/'.$fname) < $expire) 
    150         @unlink($tmp.'/'.$fname); 
    151     } 
    152  
    153     closedir($dir); 
    154   } 
    155 } 
    156  
    157  
    158 /** 
    159  * Garbage collector for cache entries. 
    160  * Remove all expired message cache records 
    161  * @return void 
    162  */ 
     67  $rcmail = rcmail::get_instance()->temp_gc(); 
     68} 
     69 
    16370function rcmail_cache_gc() 
    16471{ 
    165   $rcmail = rcmail::get_instance(); 
    166   $db = $rcmail->get_dbh(); 
    167  
    168   // get target timestamp 
    169   $ts = get_offset_time($rcmail->config->get('message_cache_lifetime', '30d'), -1); 
    170  
    171   $db->query("DELETE FROM ".get_table_name('cache_messages') 
    172         ." WHERE changed < " . $db->fromunixtime($ts)); 
    173  
    174   $db->query("DELETE FROM ".get_table_name('cache_index') 
    175         ." WHERE changed < " . $db->fromunixtime($ts)); 
    176  
    177   $db->query("DELETE FROM ".get_table_name('cache_thread') 
    178         ." WHERE changed < " . $db->fromunixtime($ts)); 
    179  
    180   $db->query("DELETE FROM ".get_table_name('cache') 
    181         ." WHERE created < " . $db->fromunixtime($ts)); 
    182 } 
    183  
    184  
    185 // Deprecated 
     72  $rcmail = rcmail::get_instance()->cache_gc(); 
     73} 
     74 
    18675function rcube_charset_convert($str, $from, $to=NULL) 
    18776{ 
     
    18978} 
    19079 
    191  
    192 // Deprecated 
    19380function rc_detect_encoding($string, $failover='') 
    19481{ 
     
    19683} 
    19784 
    198  
    199 // Deprecated 
    20085function rc_utf8_clean($input) 
    20186{ 
     
    20388} 
    20489 
    205  
    206 /** 
    207  * Convert a variable into a javascript object notation 
    208  * 
    209  * @param mixed Input value 
    210  * @return string Serialized JSON string 
    211  */ 
    21290function json_serialize($input) 
    21391{ 
    214     $input = rcube_charset::clean($input); 
    215  
    216     // sometimes even using rcube_charset::clean() the input contains invalid UTF-8 sequences 
    217     // that's why we have @ here 
    218     return @json_encode($input); 
    219 } 
    220  
    221  
    222 /** 
    223  * Replacing specials characters to a specific encoding type 
    224  * 
    225  * @param  string  Input string 
    226  * @param  string  Encoding type: text|html|xml|js|url 
    227  * @param  string  Replace mode for tags: show|replace|remove 
    228  * @param  boolean Convert newlines 
    229  * @return string  The quoted string 
    230  */ 
     92    return rcube_ui::json_serialize($input); 
     93} 
     94 
    23195function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE) 
    232   { 
    233   static $html_encode_arr = false; 
    234   static $js_rep_table = false; 
    235   static $xml_rep_table = false; 
    236  
    237   if (!$enctype) 
    238     $enctype = $OUTPUT->type; 
    239  
    240   // encode for HTML output 
    241   if ($enctype=='html') 
    242     { 
    243     if (!$html_encode_arr) 
    244       { 
    245       $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS); 
    246       unset($html_encode_arr['?']); 
    247       } 
    248  
    249     $ltpos = strpos($str, '<'); 
    250     $encode_arr = $html_encode_arr; 
    251  
    252     // don't replace quotes and html tags 
    253     if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false) 
    254       { 
    255       unset($encode_arr['"']); 
    256       unset($encode_arr['<']); 
    257       unset($encode_arr['>']); 
    258       unset($encode_arr['&']); 
    259       } 
    260     else if ($mode=='remove') 
    261       $str = strip_tags($str); 
    262  
    263     $out = strtr($str, $encode_arr); 
    264  
    265     // avoid douple quotation of & 
    266     $out = preg_replace('/&amp;([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $out); 
    267  
    268     return $newlines ? nl2br($out) : $out; 
    269     } 
    270  
    271   // if the replace tables for XML and JS are not yet defined 
    272   if ($js_rep_table===false) 
    273     { 
    274     $js_rep_table = $xml_rep_table = array(); 
    275     $xml_rep_table['&'] = '&amp;'; 
    276  
    277     for ($c=160; $c<256; $c++)  // can be increased to support more charsets 
    278       $xml_rep_table[chr($c)] = "&#$c;"; 
    279  
    280     $xml_rep_table['"'] = '&quot;'; 
    281     $js_rep_table['"'] = '\\"'; 
    282     $js_rep_table["'"] = "\\'"; 
    283     $js_rep_table["\\"] = "\\\\"; 
    284     // Unicode line and paragraph separators (#1486310) 
    285     $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A8))] = '&#8232;'; 
    286     $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A9))] = '&#8233;'; 
    287     } 
    288  
    289   // encode for javascript use 
    290   if ($enctype=='js') 
    291     return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table)); 
    292  
    293   // encode for plaintext 
    294   if ($enctype=='text') 
    295     return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str); 
    296  
    297   if ($enctype=='url') 
    298     return rawurlencode($str); 
    299  
    300   // encode for XML 
    301   if ($enctype=='xml') 
    302     return strtr($str, $xml_rep_table); 
    303  
    304   // no encoding given -> return original string 
    305   return $str; 
    306   } 
    307    
    308 /** 
    309  * Quote a given string. 
    310  * Shortcut function for rep_specialchars_output 
    311  * 
    312  * @return string HTML-quoted string 
    313  * @see rep_specialchars_output() 
    314  */ 
     96{ 
     97    return rcube_ui::rep_specialchars_output($str, $enctype, $mode, $newlines); 
     98} 
     99 
    315100function Q($str, $mode='strict', $newlines=TRUE) 
    316   { 
    317   return rep_specialchars_output($str, 'html', $mode, $newlines); 
    318   } 
    319  
    320 /** 
    321  * Quote a given string for javascript output. 
    322  * Shortcut function for rep_specialchars_output 
    323  *  
    324  * @return string JS-quoted string 
    325  * @see rep_specialchars_output() 
    326  */ 
     101{ 
     102    return rcube_ui::Q($str, $mode, $newlines); 
     103} 
     104 
    327105function JQ($str) 
    328   { 
    329   return rep_specialchars_output($str, 'js'); 
    330   } 
    331  
    332  
    333 /** 
    334  * Read input value and convert it for internal use 
    335  * Performs stripslashes() and charset conversion if necessary 
    336  *  
    337  * @param  string   Field name to read 
    338  * @param  int      Source to get value from (GPC) 
    339  * @param  boolean  Allow HTML tags in field value 
    340  * @param  string   Charset to convert into 
    341  * @return string   Field value or NULL if not available 
    342  */ 
     106{ 
     107    return rcube_ui::JQ($str); 
     108} 
     109 
    343110function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL) 
    344111{ 
    345   $value = NULL; 
    346  
    347   if ($source == RCUBE_INPUT_GET) { 
    348     if (isset($_GET[$fname])) 
    349       $value = $_GET[$fname]; 
    350   } 
    351   else if ($source == RCUBE_INPUT_POST) { 
    352     if (isset($_POST[$fname])) 
    353       $value = $_POST[$fname]; 
    354   } 
    355   else if ($source == RCUBE_INPUT_GPC) { 
    356     if (isset($_POST[$fname])) 
    357       $value = $_POST[$fname]; 
    358     else if (isset($_GET[$fname])) 
    359       $value = $_GET[$fname]; 
    360     else if (isset($_COOKIE[$fname])) 
    361       $value = $_COOKIE[$fname]; 
    362   } 
    363  
    364   return parse_input_value($value, $allow_html, $charset); 
    365 } 
    366  
    367 /** 
    368  * Parse/validate input value. See get_input_value() 
    369  * Performs stripslashes() and charset conversion if necessary 
    370  * 
    371  * @param  string   Input value 
    372  * @param  boolean  Allow HTML tags in field value 
    373  * @param  string   Charset to convert into 
    374  * @return string   Parsed value 
    375  */ 
     112    return rcube_ui::get_input_value($fname, $source, $allow_html, $charset); 
     113} 
     114 
    376115function parse_input_value($value, $allow_html=FALSE, $charset=NULL) 
    377116{ 
    378   global $OUTPUT; 
    379  
    380   if (empty($value)) 
    381     return $value; 
    382  
    383   if (is_array($value)) { 
    384     foreach ($value as $idx => $val) 
    385       $value[$idx] = parse_input_value($val, $allow_html, $charset); 
    386     return $value; 
    387   } 
    388  
    389   // strip single quotes if magic_quotes_sybase is enabled 
    390   if (ini_get('magic_quotes_sybase')) 
    391     $value = str_replace("''", "'", $value); 
    392   // strip slashes if magic_quotes enabled 
    393   else if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) 
    394     $value = stripslashes($value); 
    395  
    396   // remove HTML tags if not allowed 
    397   if (!$allow_html) 
    398     $value = strip_tags($value); 
    399  
    400   $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null; 
    401  
    402   // remove invalid characters (#1488124) 
    403   if ($output_charset == 'UTF-8') 
    404     $value = rc_utf8_clean($value); 
    405  
    406   // convert to internal charset 
    407   if ($charset && $output_charset) 
    408     $value = rcube_charset_convert($value, $output_charset, $charset); 
    409  
    410   return $value; 
    411 } 
    412  
    413 /** 
    414  * Convert array of request parameters (prefixed with _) 
    415  * to a regular array with non-prefixed keys. 
    416  * 
    417  * @param  int   Source to get value from (GPC) 
    418  * @return array Hash array with all request parameters 
    419  */ 
     117    return rcube_ui::parse_input_value($value, $allow_html, $charset); 
     118} 
     119 
    420120function request2param($mode = RCUBE_INPUT_GPC, $ignore = 'task|action') 
    421121{ 
    422   $out = array(); 
    423   $src = $mode == RCUBE_INPUT_GET ? $_GET : ($mode == RCUBE_INPUT_POST ? $_POST : $_REQUEST); 
    424   foreach ($src as $key => $value) { 
    425     $fname = $key[0] == '_' ? substr($key, 1) : $key; 
    426     if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) 
    427       $out[$fname] = get_input_value($key, $mode); 
    428   } 
    429  
    430   return $out; 
    431 } 
    432  
    433 /** 
    434  * Remove all non-ascii and non-word chars 
    435  * except ., -, _ 
    436  */ 
    437 function asciiwords($str, $css_id = false, $replace_with = '') 
    438 { 
    439   $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : ''); 
    440   return preg_replace("/[^$allowed]/i", $replace_with, $str); 
    441 } 
    442  
    443 /** 
    444  * Convert the given string into a valid HTML identifier 
    445  * Same functionality as done in app.js with rcube_webmail.html_identifier() 
    446  */ 
     122    return rcube_ui::request2param($mode, $ignore); 
     123} 
     124 
    447125function html_identifier($str, $encode=false) 
    448126{ 
    449   if ($encode) 
    450     return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); 
    451   else 
    452     return asciiwords($str, true, '_'); 
    453 } 
    454  
    455 /** 
    456  * Remove single and double quotes from given string 
    457  * 
    458  * @param string Input value 
    459  * @return string Dequoted string 
    460  */ 
    461 function strip_quotes($str) 
    462 { 
    463   return str_replace(array("'", '"'), '', $str); 
    464 } 
    465  
    466  
    467 /** 
    468  * Remove new lines characters from given string 
    469  * 
    470  * @param string Input value 
    471  * @return string Stripped string 
    472  */ 
    473 function strip_newlines($str) 
    474 { 
    475   return preg_replace('/[\r\n]/', '', $str); 
    476 } 
    477  
    478  
    479 /** 
    480  * Create a HTML table based on the given data 
    481  * 
    482  * @param  array  Named table attributes 
    483  * @param  mixed  Table row data. Either a two-dimensional array or a valid SQL result set 
    484  * @param  array  List of cols to show 
    485  * @param  string Name of the identifier col 
    486  * @return string HTML table code 
    487  */ 
     127    return rcube_ui::html_identifier($str, $encode); 
     128} 
     129 
    488130function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col) 
    489131{ 
    490   global $RCMAIL; 
    491  
    492   $table = new html_table(/*array('cols' => count($a_show_cols))*/); 
    493  
    494   // add table header 
    495   if (!$attrib['noheader']) 
    496     foreach ($a_show_cols as $col) 
    497       $table->add_header($col, Q(rcube_label($col))); 
    498  
    499   $c = 0; 
    500   if (!is_array($table_data)) 
    501   { 
    502     $db = $RCMAIL->get_dbh(); 
    503     while ($table_data && ($sql_arr = $db->fetch_assoc($table_data))) 
    504     { 
    505       $table->add_row(array('id' => 'rcmrow' . html_identifier($sql_arr[$id_col]))); 
    506  
    507       // format each col 
    508       foreach ($a_show_cols as $col) 
    509         $table->add($col, Q($sql_arr[$col])); 
    510  
    511       $c++; 
    512     } 
    513   } 
    514   else { 
    515     foreach ($table_data as $row_data) 
    516     { 
    517       $class = !empty($row_data['class']) ? $row_data['class'] : ''; 
    518  
    519       $table->add_row(array('id' => 'rcmrow' . html_identifier($row_data[$id_col]), 'class' => $class)); 
    520  
    521       // format each col 
    522       foreach ($a_show_cols as $col) 
    523         $table->add($col, Q(is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col])); 
    524  
    525       $c++; 
    526     } 
    527   } 
    528  
    529   return $table->show($attrib); 
    530 } 
    531  
    532  
    533 /** 
    534  * Create an edit field for inclusion on a form 
    535  *  
    536  * @param string col field name 
    537  * @param string value field value 
    538  * @param array attrib HTML element attributes for field 
    539  * @param string type HTML element type (default 'text') 
    540  * @return string HTML field definition 
    541  */ 
     132    return rcube_ui::table_output($attrib, $table_data, $a_show_cols, $id_col); 
     133} 
     134 
    542135function rcmail_get_edit_field($col, $value, $attrib, $type='text') 
    543136{ 
    544   static $colcounts = array(); 
    545  
    546   $fname = '_'.$col; 
    547   $attrib['name'] = $fname . ($attrib['array'] ? '[]' : ''); 
    548   $attrib['class'] = trim($attrib['class'] . ' ff_' . $col); 
    549  
    550   if ($type == 'checkbox') { 
    551     $attrib['value'] = '1'; 
    552     $input = new html_checkbox($attrib); 
    553   } 
    554   else if ($type == 'textarea') { 
    555     $attrib['cols'] = $attrib['size']; 
    556     $input = new html_textarea($attrib); 
    557   } 
    558   else if ($type == 'select') { 
    559     $input = new html_select($attrib); 
    560     $input->add('---', ''); 
    561     $input->add(array_values($attrib['options']), array_keys($attrib['options'])); 
    562   } 
    563   else if ($attrib['type'] == 'password') { 
    564     $input = new html_passwordfield($attrib); 
    565   } 
    566   else { 
    567     if ($attrib['type'] != 'text' && $attrib['type'] != 'hidden') 
    568         $attrib['type'] = 'text'; 
    569     $input = new html_inputfield($attrib); 
    570   } 
    571  
    572   // use value from post 
    573   if (isset($_POST[$fname])) { 
    574     $postvalue = get_input_value($fname, RCUBE_INPUT_POST, true); 
    575     $value = $attrib['array'] ? $postvalue[intval($colcounts[$col]++)] : $postvalue; 
    576   } 
    577  
    578   $out = $input->show($value); 
    579  
    580   return $out; 
    581 } 
    582  
    583  
    584 /** 
    585  * Replace all css definitions with #container [def] 
    586  * and remove css-inlined scripting 
    587  * 
    588  * @param string CSS source code 
    589  * @param string Container ID to use as prefix 
    590  * @return string Modified CSS source 
    591  */ 
     137  return rcube_ui::get_edit_field($col, $value, $attrib, $type); 
     138} 
     139 
    592140function rcmail_mod_css_styles($source, $container_id, $allow_remote=false) 
    593   { 
    594   $last_pos = 0; 
    595   $replacements = new rcube_string_replacer; 
    596  
    597   // ignore the whole block if evil styles are detected 
    598   $source = rcmail_xss_entity_decode($source); 
    599   $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); 
    600   $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); 
    601   if (preg_match("/$evilexpr/i", $stripped)) 
    602     return '/* evil! */'; 
    603  
    604   // cut out all contents between { and } 
    605   while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { 
    606     $styles = substr($source, $pos+1, $pos2-($pos+1)); 
    607  
    608     // check every line of a style block... 
    609     if ($allow_remote) { 
    610       $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); 
    611       foreach ($a_styles as $line) { 
    612         $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); 
    613         // ... and only allow strict url() values 
    614         if (stripos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims', $line)) { 
    615           $a_styles = array('/* evil! */'); 
    616           break; 
    617         } 
    618       } 
    619       $styles = join(";\n", $a_styles); 
    620     } 
    621  
    622     $key = $replacements->add($styles); 
    623     $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2); 
    624     $last_pos = $pos+2; 
    625   } 
    626  
    627   // remove html comments and add #container to each tag selector. 
    628   // also replace body definition because we also stripped off the <body> tag 
    629   $styles = preg_replace( 
    630     array( 
    631       '/(^\s*<!--)|(-->\s*$)/', 
    632       '/(^\s*|,\s*|\}\s*)([a-z0-9\._#\*][a-z0-9\.\-_]*)/im', 
    633       '/'.preg_quote($container_id, '/').'\s+body/i', 
    634     ), 
    635     array( 
    636       '', 
    637       "\\1#$container_id \\2", 
    638       $container_id, 
    639     ), 
    640     $source); 
    641  
    642   // put block contents back in 
    643   $styles = $replacements->resolve($styles); 
    644  
    645   return $styles; 
    646   } 
    647  
    648  
    649 /** 
    650  * Decode escaped entities used by known XSS exploits. 
    651  * See http://downloads.securityfocus.com/vulnerabilities/exploits/26800.eml for examples 
    652  * 
    653  * @param string CSS content to decode 
    654  * @return string Decoded string 
    655  */ 
     141{ 
     142    return rcube_ui::mod_css_styles($source, $container_id, $allow_remote); 
     143} 
     144 
    656145function rcmail_xss_entity_decode($content) 
    657146{ 
    658   $out = html_entity_decode(html_entity_decode($content)); 
    659   $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out); 
    660   $out = preg_replace('#/\*.*\*/#Ums', '', $out); 
    661   return $out; 
    662 } 
    663  
    664  
    665 /** 
    666  * preg_replace_callback callback for rcmail_xss_entity_decode_callback 
    667  * 
    668  * @param array matches result from preg_replace_callback 
    669  * @return string decoded entity 
    670  */  
    671 function rcmail_xss_entity_decode_callback($matches) 
    672 {  
    673   return chr(hexdec($matches[1])); 
    674 } 
    675  
    676 /** 
    677  * Compose a valid attribute string for HTML tags 
    678  * 
    679  * @param array Named tag attributes 
    680  * @param array List of allowed attributes 
    681  * @return string HTML formatted attribute string 
    682  */ 
     147    return rcube_ui::xss_entity_decode($content); 
     148} 
     149 
    683150function create_attrib_string($attrib, $allowed_attribs=array('id', 'class', 'style')) 
    684   { 
    685   // allow the following attributes to be added to the <iframe> tag 
    686   $attrib_str = ''; 
    687   foreach ($allowed_attribs as $a) 
    688     if (isset($attrib[$a])) 
    689       $attrib_str .= sprintf(' %s="%s"', $a, str_replace('"', '&quot;', $attrib[$a])); 
    690  
    691   return $attrib_str; 
    692   } 
    693  
    694  
    695 /** 
    696  * Convert a HTML attribute string attributes to an associative array (name => value) 
    697  * 
    698  * @param string Input string 
    699  * @return array Key-value pairs of parsed attributes 
    700  */ 
     151{ 
     152    return html::attrib_string($attrib, $allowed_attribs); 
     153} 
     154 
    701155function parse_attrib_string($str) 
    702   { 
    703   $attrib = array(); 
    704   preg_match_all('/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/Ui', stripslashes($str), $regs, PREG_SET_ORDER); 
    705  
    706   // convert attributes to an associative array (name => value) 
    707   if ($regs) { 
    708     foreach ($regs as $attr) { 
    709       $attrib[strtolower($attr[1])] = html_entity_decode($attr[3] . $attr[4]); 
    710     } 
    711   } 
    712  
    713   return $attrib; 
    714   } 
    715  
    716  
    717 /** 
    718  * Improved equivalent to strtotime() 
    719  * 
    720  * @param string Date string 
    721  * @return int  
    722  */ 
    723 function rcube_strtotime($date) 
    724 { 
    725   // check for MS Outlook vCard date format YYYYMMDD 
    726   if (preg_match('/^([12][90]\d\d)([01]\d)(\d\d)$/', trim($date), $matches)) { 
    727     return mktime(0,0,0, intval($matches[2]), intval($matches[3]), intval($matches[1])); 
    728   } 
    729   else if (is_numeric($date)) 
    730     return $date; 
    731  
    732   // support non-standard "GMTXXXX" literal 
    733   $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); 
    734  
    735   // if date parsing fails, we have a date in non-rfc format. 
    736   // remove token from the end and try again 
    737   while ((($ts = @strtotime($date)) === false) || ($ts < 0)) { 
    738     $d = explode(' ', $date); 
    739     array_pop($d); 
    740     if (!$d) break; 
    741     $date = implode(' ', $d); 
    742   } 
    743  
    744   return $ts; 
    745 } 
    746  
    747  
    748 /** 
    749  * Convert the given date to a human readable form 
    750  * This uses the date formatting properties from config 
    751  * 
    752  * @param mixed  Date representation (string or timestamp) 
    753  * @param string Date format to use 
    754  * @param bool   Enables date convertion according to user timezone 
    755  * 
    756  * @return string Formatted date string 
    757  */ 
     156{ 
     157    return html::parse_attrib_string($str); 
     158} 
     159 
    758160function format_date($date, $format=NULL, $convert=true) 
    759161{ 
    760   global $RCMAIL, $CONFIG; 
    761  
    762   if (!empty($date)) 
    763     $ts = rcube_strtotime($date); 
    764  
    765   if (empty($ts)) 
    766     return ''; 
    767  
    768   try { 
    769     $date = new DateTime("@".$ts); 
    770   } 
    771   catch (Exception $e) { 
    772     return ''; 
    773   } 
    774  
    775   try { 
    776     // convert to the right timezone 
    777     $stz = date_default_timezone_get(); 
    778     $tz = new DateTimeZone($convert ? $RCMAIL->config->get('timezone') : 'GMT'); 
    779     $date->setTimezone($tz); 
    780     date_default_timezone_set($tz->getName()); 
    781  
    782     $timestamp = $date->format('U'); 
    783   } 
    784   catch (Exception $e) { 
    785     $timestamp = $ts; 
    786   } 
    787  
    788   // define date format depending on current time 
    789   if (!$format) { 
    790     $now_date    = getdate($now); 
    791     $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']); 
    792     $week_limit  = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']); 
    793  
    794     if ($CONFIG['prettydate'] && $timestamp > $today_limit && $timestamp < $now) { 
    795       $format = $RCMAIL->config->get('date_today', $RCMAIL->config->get('time_format', 'H:i')); 
    796       $today  = true; 
    797     } 
    798     else if ($CONFIG['prettydate'] && $timestamp > $week_limit && $timestamp < $now) 
    799       $format = $RCMAIL->config->get('date_short', 'D H:i'); 
    800     else 
    801       $format = $RCMAIL->config->get('date_long', 'Y-m-d H:i'); 
    802   } 
    803  
    804   // strftime() format 
    805   if (preg_match('/%[a-z]+/i', $format)) { 
    806     $format = strftime($format, $timestamp); 
    807     date_default_timezone_set($stz); 
    808     return $today ? (rcube_label('today') . ' ' . $format) : $format; 
    809   } 
    810  
    811   // parse format string manually in order to provide localized weekday and month names 
    812   // an alternative would be to convert the date() format string to fit with strftime() 
    813   $out = ''; 
    814   for($i=0; $i<strlen($format); $i++) { 
    815     if ($format[$i]=='\\')  // skip escape chars 
    816       continue; 
    817  
    818     // write char "as-is" 
    819     if ($format[$i]==' ' || $format{$i-1}=='\\') 
    820       $out .= $format[$i]; 
    821     // weekday (short) 
    822     else if ($format[$i]=='D') 
    823       $out .= rcube_label(strtolower($date->format('D'))); 
    824     // weekday long 
    825     else if ($format[$i]=='l') 
    826       $out .= rcube_label(strtolower($date->format('l'))); 
    827     // month name (short) 
    828     else if ($format[$i]=='M') 
    829       $out .= rcube_label(strtolower($date->format('M'))); 
    830     // month name (long) 
    831     else if ($format[$i]=='F') 
    832       $out .= rcube_label('long'.strtolower($date->format('M'))); 
    833     else if ($format[$i]=='x') 
    834       $out .= strftime('%x %X', $timestamp); 
    835     else 
    836       $out .= $date->format($format[$i]); 
    837   } 
    838  
    839   if ($today) { 
    840     $label = rcube_label('today'); 
    841     // replcae $ character with "Today" label (#1486120) 
    842     if (strpos($out, '$') !== false) { 
    843       $out = preg_replace('/\$/', $label, $out, 1); 
    844     } 
    845     else { 
    846       $out = $label . ' ' . $out; 
    847     } 
    848   } 
    849  
    850   date_default_timezone_set($stz); 
    851   return $out; 
    852 } 
    853  
    854  
    855 /** 
    856  * Compose a valid representation of name and e-mail address 
    857  * 
    858  * @param string E-mail address 
    859  * @param string Person name 
    860  * @return string Formatted string 
    861  */ 
    862 function format_email_recipient($email, $name='') 
    863 { 
    864   if ($name && $name != $email) { 
    865     // Special chars as defined by RFC 822 need to in quoted string (or escaped). 
    866     return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, trim($email)); 
    867   } 
    868  
    869   return trim($email); 
    870 } 
    871  
    872  
    873 /** 
    874  * Return the mailboxlist in HTML 
    875  * 
    876  * @param array Named parameters 
    877  * @return string HTML code for the gui object 
    878  */ 
     162    return rcube_ui::format_date($date, $format, $convert); 
     163} 
     164 
    879165function rcmail_mailbox_list($attrib) 
    880166{ 
    881   global $RCMAIL; 
    882   static $a_mailboxes; 
    883  
    884   $attrib += array('maxlength' => 100, 'realnames' => false, 'unreadwrap' => ' (%s)'); 
    885  
    886   // add some labels to client 
    887   $RCMAIL->output->add_label('purgefolderconfirm', 'deletemessagesconfirm'); 
    888  
    889   $type = $attrib['type'] ? $attrib['type'] : 'ul'; 
    890   unset($attrib['type']); 
    891  
    892   if ($type=='ul' && !$attrib['id']) 
    893     $attrib['id'] = 'rcmboxlist'; 
    894  
    895   if (empty($attrib['folder_name'])) 
    896     $attrib['folder_name'] = '*'; 
    897  
    898   // get mailbox list 
    899   $mbox_name = $RCMAIL->storage->get_folder(); 
    900  
    901   // build the folders tree 
    902   if (empty($a_mailboxes)) { 
    903     // get mailbox list 
    904     $a_folders = $RCMAIL->storage->list_folders_subscribed('', $attrib['folder_name'], $attrib['folder_filter']); 
    905     $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); 
    906     $a_mailboxes = array(); 
    907  
    908     foreach ($a_folders as $folder) 
    909       rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter); 
    910   } 
    911  
    912   // allow plugins to alter the folder tree or to localize folder names 
    913   $hook = $RCMAIL->plugins->exec_hook('render_mailboxlist', array('list' => $a_mailboxes, 'delimiter' => $delimiter)); 
    914  
    915   if ($type == 'select') { 
    916     $select = new html_select($attrib); 
    917  
    918     // add no-selection option 
    919     if ($attrib['noselection']) 
    920       $select->add(rcube_label($attrib['noselection']), ''); 
    921  
    922     rcmail_render_folder_tree_select($hook['list'], $mbox_name, $attrib['maxlength'], $select, $attrib['realnames']); 
    923     $out = $select->show(); 
    924   } 
    925   else { 
    926     $js_mailboxlist = array(); 
    927     $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($hook['list'], $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib); 
    928  
    929     $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']); 
    930     $RCMAIL->output->set_env('mailboxes', $js_mailboxlist); 
    931     $RCMAIL->output->set_env('unreadwrap', $attrib['unreadwrap']); 
    932     $RCMAIL->output->set_env('collapsed_folders', (string)$RCMAIL->config->get('collapsed_folders')); 
    933   } 
    934  
    935   return $out; 
    936 } 
    937  
    938  
    939 /** 
    940  * Return the mailboxlist as html_select object 
    941  * 
    942  * @param array Named parameters 
    943  * @return html_select HTML drop-down object 
    944  */ 
    945 function rcmail_mailbox_select($p = array()) 
    946 { 
    947   global $RCMAIL; 
    948  
    949   $p += array('maxlength' => 100, 'realnames' => false); 
    950   $a_mailboxes = array(); 
    951   $storage = $RCMAIL->get_storage(); 
    952  
    953   if (empty($p['folder_name'])) { 
    954     $p['folder_name'] = '*'; 
    955   } 
    956  
    957   if ($p['unsubscribed']) 
    958     $list = $storage->list_folders('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); 
    959   else 
    960     $list = $storage->list_folders_subscribed('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); 
    961  
    962   $delimiter = $storage->get_hierarchy_delimiter(); 
    963  
    964   foreach ($list as $folder) { 
    965     if (empty($p['exceptions']) || !in_array($folder, $p['exceptions'])) 
    966       rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter); 
    967   } 
    968  
    969   $select = new html_select($p); 
    970  
    971   if ($p['noselection']) 
    972     $select->add($p['noselection'], ''); 
    973  
    974   rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p); 
    975  
    976   return $select; 
    977 } 
    978  
    979  
    980 /** 
    981  * Create a hierarchical array of the mailbox list 
    982  * @access private 
    983  * @return void 
    984  */ 
    985 function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='') 
    986 { 
    987   global $RCMAIL; 
    988  
    989   // Handle namespace prefix 
    990   $prefix = ''; 
    991   if (!$path) { 
    992     $n_folder = $folder; 
    993     $folder = $RCMAIL->storage->mod_folder($folder); 
    994  
    995     if ($n_folder != $folder) { 
    996       $prefix = substr($n_folder, 0, -strlen($folder)); 
    997     } 
    998   } 
    999  
    1000   $pos = strpos($folder, $delm); 
    1001  
    1002   if ($pos !== false) { 
    1003     $subFolders = substr($folder, $pos+1); 
    1004     $currentFolder = substr($folder, 0, $pos); 
    1005  
    1006     // sometimes folder has a delimiter as the last character 
    1007     if (!strlen($subFolders)) 
    1008       $virtual = false; 
    1009     else if (!isset($arrFolders[$currentFolder])) 
    1010       $virtual = true; 
    1011     else 
    1012       $virtual = $arrFolders[$currentFolder]['virtual']; 
    1013   } 
    1014   else { 
    1015     $subFolders = false; 
    1016     $currentFolder = $folder; 
    1017     $virtual = false; 
    1018   } 
    1019  
    1020   $path .= $prefix.$currentFolder; 
    1021  
    1022   if (!isset($arrFolders[$currentFolder])) { 
    1023     $arrFolders[$currentFolder] = array( 
    1024       'id' => $path, 
    1025       'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'), 
    1026       'virtual' => $virtual, 
    1027       'folders' => array()); 
    1028   } 
    1029   else 
    1030     $arrFolders[$currentFolder]['virtual'] = $virtual; 
    1031  
    1032   if (strlen($subFolders)) 
    1033     rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm); 
    1034 } 
    1035  
    1036  
    1037 /** 
    1038  * Return html for a structured list &lt;ul&gt; for the mailbox tree 
    1039  * @access private 
    1040  * @return string 
    1041  */ 
    1042 function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $attrib, $nestLevel=0) 
    1043 { 
    1044   global $RCMAIL, $CONFIG; 
    1045  
    1046   $maxlength = intval($attrib['maxlength']); 
    1047   $realnames = (bool)$attrib['realnames']; 
    1048   $msgcounts = $RCMAIL->storage->get_cache('messagecount'); 
    1049  
    1050   $out = ''; 
    1051   foreach ($arrFolders as $key => $folder) { 
    1052     $title        = null; 
    1053     $folder_class = rcmail_folder_classname($folder['id']); 
    1054     $collapsed    = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false; 
    1055     $unread       = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0; 
    1056  
    1057     if ($folder_class && !$realnames) { 
    1058       $foldername = rcube_label($folder_class); 
    1059     } 
    1060     else { 
    1061       $foldername = $folder['name']; 
    1062  
    1063       // shorten the folder name to a given length 
    1064       if ($maxlength && $maxlength > 1) { 
    1065         $fname = abbreviate_string($foldername, $maxlength); 
    1066         if ($fname != $foldername) 
    1067           $title = $foldername; 
    1068         $foldername = $fname; 
    1069       } 
    1070     } 
    1071  
    1072     // make folder name safe for ids and class names 
    1073     $folder_id = html_identifier($folder['id'], true); 
    1074     $classes = array('mailbox'); 
    1075  
    1076     // set special class for Sent, Drafts, Trash and Junk 
    1077     if ($folder_class) 
    1078       $classes[] = $folder_class; 
    1079  
    1080     if ($folder['id'] == $mbox_name) 
    1081       $classes[] = 'selected'; 
    1082  
    1083     if ($folder['virtual']) 
    1084       $classes[] = 'virtual'; 
    1085     else if ($unread) 
    1086       $classes[] = 'unread'; 
    1087  
    1088     $js_name = JQ($folder['id']); 
    1089     $html_name = Q($foldername) . ($unread ? html::span('unreadcount', sprintf($attrib['unreadwrap'], $unread)) : ''); 
    1090     $link_attrib = $folder['virtual'] ? array() : array( 
    1091       'href' => rcmail_url('', array('_mbox' => $folder['id'])), 
    1092       'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name), 
    1093       'rel' => $folder['id'], 
    1094       'title' => $title, 
    1095     ); 
    1096  
    1097     $out .= html::tag('li', array( 
    1098         'id' => "rcmli".$folder_id, 
    1099         'class' => join(' ', $classes), 
    1100         'noclose' => true), 
    1101       html::a($link_attrib, $html_name) . 
    1102       (!empty($folder['folders']) ? html::div(array( 
    1103         'class' => ($collapsed ? 'collapsed' : 'expanded'), 
    1104         'style' => "position:absolute", 
    1105         'onclick' => sprintf("%s.command('collapse-folder', '%s')", JS_OBJECT_NAME, $js_name) 
    1106       ), '&nbsp;') : '')); 
    1107  
    1108     $jslist[$folder_id] = array('id' => $folder['id'], 'name' => $foldername, 'virtual' => $folder['virtual']); 
    1109  
    1110     if (!empty($folder['folders'])) { 
    1111       $out .= html::tag('ul', array('style' => ($collapsed ? "display:none;" : null)), 
    1112         rcmail_render_folder_tree_html($folder['folders'], $mbox_name, $jslist, $attrib, $nestLevel+1)); 
    1113     } 
    1114  
    1115     $out .= "</li>\n"; 
    1116   } 
    1117  
    1118   return $out; 
    1119 } 
    1120  
    1121  
    1122 /** 
    1123  * Return html for a flat list <select> for the mailbox tree 
    1124  * @access private 
    1125  * @return string 
    1126  */ 
    1127 function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $opts=array()) 
    1128 { 
    1129   global $RCMAIL; 
    1130  
    1131   $out = ''; 
    1132  
    1133   foreach ($arrFolders as $key => $folder) { 
    1134     // skip exceptions (and its subfolders) 
    1135     if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { 
    1136       continue; 
    1137     } 
    1138  
    1139     // skip folders in which it isn't possible to create subfolders 
    1140     if (!empty($opts['skip_noinferiors']) && ($attrs = $RCMAIL->storage->folder_attributes($folder['id'])) 
    1141         && in_array('\\Noinferiors', $attrs) 
    1142     ) { 
    1143       continue; 
    1144     } 
    1145  
    1146     if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) 
    1147       $foldername = rcube_label($folder_class); 
    1148     else { 
    1149       $foldername = $folder['name']; 
    1150  
    1151       // shorten the folder name to a given length 
    1152       if ($maxlength && $maxlength>1) 
    1153         $foldername = abbreviate_string($foldername, $maxlength); 
    1154     } 
    1155  
    1156     $select->add(str_repeat('&nbsp;', $nestLevel*4) . $foldername, $folder['id']); 
    1157  
    1158     if (!empty($folder['folders'])) 
    1159       $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, 
    1160         $select, $realnames, $nestLevel+1, $opts); 
    1161   } 
    1162  
    1163   return $out; 
    1164 } 
    1165  
    1166  
    1167 /** 
    1168  * Return internal name for the given folder if it matches the configured special folders 
    1169  * @access private 
    1170  * @return string 
    1171  */ 
    1172 function rcmail_folder_classname($folder_id) 
    1173 { 
    1174   global $CONFIG; 
    1175  
    1176   if ($folder_id == 'INBOX') 
    1177     return 'inbox'; 
    1178  
    1179   // for these mailboxes we have localized labels and css classes 
    1180   foreach (array('sent', 'drafts', 'trash', 'junk') as $smbx) 
    1181   { 
    1182     if ($folder_id == $CONFIG[$smbx.'_mbox']) 
    1183       return $smbx; 
    1184   } 
    1185 } 
    1186  
    1187  
    1188 /** 
    1189  * Try to localize the given IMAP folder name. 
    1190  * UTF-7 decode it in case no localized text was found 
    1191  * 
    1192  * @param string Folder name 
    1193  * @return string Localized folder name in UTF-8 encoding 
    1194  */ 
     167    return rcube_ui::folder_list($attrib); 
     168} 
     169 
     170function rcmail_mailbox_select($attrib = array()) 
     171{ 
     172    return rcube_ui::folder_selector($attrib); 
     173} 
     174 
    1195175function rcmail_localize_foldername($name) 
    1196176{ 
    1197   if ($folder_class = rcmail_folder_classname($name)) 
    1198     return rcube_label($folder_class); 
    1199   else 
    1200     return rcube_charset_convert($name, 'UTF7-IMAP'); 
    1201 } 
    1202  
     177    return rcube_ui::localize_foldername($name); 
     178} 
    1203179 
    1204180function rcmail_localize_folderpath($path) 
    1205181{ 
    1206     global $RCMAIL; 
    1207  
    1208     $protect_folders = $RCMAIL->config->get('protect_default_folders'); 
    1209     $default_folders = (array) $RCMAIL->config->get('default_folders'); 
    1210     $delimiter       = $RCMAIL->storage->get_hierarchy_delimiter(); 
    1211     $path            = explode($delimiter, $path); 
    1212     $result          = array(); 
    1213  
    1214     foreach ($path as $idx => $dir) { 
    1215         $directory = implode($delimiter, array_slice($path, 0, $idx+1)); 
    1216         if ($protect_folders && in_array($directory, $default_folders)) { 
    1217             unset($result); 
    1218             $result[] = rcmail_localize_foldername($directory); 
    1219         } 
    1220         else { 
    1221             $result[] = rcube_charset_convert($dir, 'UTF7-IMAP'); 
    1222         } 
    1223     } 
    1224  
    1225     return implode($delimiter, $result); 
    1226 } 
    1227  
     182    return rcube_ui::localize_folderpath($path); 
     183} 
    1228184 
    1229185function rcmail_quota_display($attrib) 
    1230186{ 
    1231   global $OUTPUT; 
    1232  
    1233   if (!$attrib['id']) 
    1234     $attrib['id'] = 'rcmquotadisplay'; 
    1235  
    1236   if(isset($attrib['display'])) 
    1237     $_SESSION['quota_display'] = $attrib['display']; 
    1238  
    1239   $OUTPUT->add_gui_object('quotadisplay', $attrib['id']); 
    1240  
    1241   $quota = rcmail_quota_content($attrib); 
    1242  
    1243   $OUTPUT->add_script('rcmail.set_quota('.json_serialize($quota).');', 'docready'); 
    1244  
    1245   return html::span($attrib, ''); 
    1246 } 
    1247  
    1248  
    1249 function rcmail_quota_content($attrib=NULL) 
    1250 { 
    1251   global $RCMAIL; 
    1252  
    1253   $quota = $RCMAIL->storage->get_quota(); 
    1254   $quota = $RCMAIL->plugins->exec_hook('quota', $quota); 
    1255  
    1256   $quota_result = (array) $quota; 
    1257   $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : ''; 
    1258  
    1259   if (!$quota['total'] && $RCMAIL->config->get('quota_zero_as_unlimited')) { 
    1260     $quota_result['title'] = rcube_label('unlimited'); 
    1261     $quota_result['percent'] = 0; 
    1262   } 
    1263   else if ($quota['total']) { 
    1264     if (!isset($quota['percent'])) 
    1265       $quota_result['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100)); 
    1266  
    1267     $title = sprintf('%s / %s (%.0f%%)', 
    1268         show_bytes($quota['used'] * 1024), show_bytes($quota['total'] * 1024), 
    1269         $quota_result['percent']); 
    1270  
    1271     $quota_result['title'] = $title; 
    1272  
    1273     if ($attrib['width']) 
    1274       $quota_result['width'] = $attrib['width']; 
    1275     if ($attrib['height']) 
    1276       $quota_result['height']   = $attrib['height']; 
    1277   } 
    1278   else { 
    1279     $quota_result['title'] = rcube_label('unknown'); 
    1280     $quota_result['percent'] = 0; 
    1281   } 
    1282  
    1283   return $quota_result; 
    1284 } 
    1285  
    1286  
    1287 /** 
    1288  * Outputs error message according to server error/response codes 
    1289  * 
    1290  * @param string Fallback message label 
    1291  * @param string Fallback message label arguments 
    1292  * 
    1293  * @return void 
    1294  */ 
     187    return rcube_ui::quota_display($attrib); 
     188} 
     189 
     190function rcmail_quota_content($attrib = null) 
     191{ 
     192    return rcube_ui::quota_content($attrib); 
     193} 
     194 
    1295195function rcmail_display_server_error($fallback=null, $fallback_args=null) 
    1296196{ 
    1297     global $RCMAIL; 
    1298  
    1299     $err_code = $RCMAIL->storage->get_error_code(); 
    1300     $res_code = $RCMAIL->storage->get_response_code(); 
    1301  
    1302     if ($err_code < 0) { 
    1303         $RCMAIL->output->show_message('storageerror', 'error'); 
    1304     } 
    1305     else if ($res_code == rcube_storage::NOPERM) { 
    1306         $RCMAIL->output->show_message('errornoperm', 'error'); 
    1307     } 
    1308     else if ($res_code == rcube_storage::READONLY) { 
    1309         $RCMAIL->output->show_message('errorreadonly', 'error'); 
    1310     } 
    1311     else if ($err_code && ($err_str = $RCMAIL->storage->get_error_str())) { 
    1312         // try to detect access rights problem and display appropriate message 
    1313         if (stripos($err_str, 'Permission denied') !== false) 
    1314             $RCMAIL->output->show_message('errornoperm', 'error'); 
    1315         else 
    1316             $RCMAIL->output->show_message('servererrormsg', 'error', array('msg' => $err_str)); 
    1317     } 
    1318     else if ($fallback) { 
    1319         $RCMAIL->output->show_message($fallback, 'error', $fallback_args); 
    1320     } 
    1321  
    1322     return true; 
    1323 } 
    1324  
    1325  
    1326 /** 
    1327  * Generate CSS classes from mimetype and filename extension 
    1328  * 
    1329  * @param string Mimetype 
    1330  * @param string The filename 
    1331  * @return string CSS classes separated by space 
    1332  */ 
     197    rcube_ui::display_server_error($fallback, $fallback_args); 
     198} 
     199 
    1333200function rcmail_filetype2classname($mimetype, $filename) 
    1334201{ 
    1335   list($primary, $secondary) = explode('/', $mimetype); 
    1336  
    1337   $classes = array($primary ? $primary : 'unknown'); 
    1338   if ($secondary) 
    1339     $classes[] = $secondary; 
    1340   if (preg_match('/\.([a-z0-9]+)$/', $filename, $m)) 
    1341     $classes[] = $m[1]; 
    1342  
    1343   return join(" ", $classes); 
    1344 } 
    1345  
    1346 /** 
    1347  * Output HTML editor scripts 
    1348  * 
    1349  * @param string Editor mode 
    1350  * @return void 
    1351  */ 
     202    return rcube_ui::file2class($mimetype, $filename); 
     203} 
     204 
    1352205function rcube_html_editor($mode='') 
    1353206{ 
    1354   global $RCMAIL; 
    1355  
    1356   $hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode)); 
    1357  
    1358   if ($hook['abort']) 
    1359     return; 
    1360  
    1361   $lang = strtolower($_SESSION['language']); 
    1362  
    1363   // TinyMCE uses two-letter lang codes, with exception of Chinese 
    1364   if (strpos($lang, 'zh_') === 0) 
    1365     $lang = str_replace('_', '-', $lang); 
    1366   else 
    1367     $lang = substr($lang, 0, 2); 
    1368  
    1369   if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js')) 
    1370     $lang = 'en'; 
    1371  
    1372   $RCMAIL->output->include_script('tiny_mce/tiny_mce.js'); 
    1373   $RCMAIL->output->include_script('editor.js'); 
    1374   $RCMAIL->output->add_script(sprintf("rcmail_editor_init(%s)", 
    1375     json_encode(array( 
    1376         'mode'       => $mode, 
    1377         'skin_path'  => '$__skin_path', 
    1378         'lang'       => $lang, 
    1379         'spellcheck' => intval($RCMAIL->config->get('enable_spellcheck')), 
    1380         'spelldict'  => intval($RCMAIL->config->get('spellcheck_dictionary')), 
    1381     ))), 'foot'); 
    1382 } 
    1383  
    1384  
    1385 /** 
    1386  * Replaces TinyMCE's emoticon images with plain-text representation 
    1387  * 
    1388  * @param string HTML content 
    1389  * @return string HTML content 
    1390  */ 
     207    rcube_ui::html_editor($mode); 
     208} 
     209 
    1391210function rcmail_replace_emoticons($html) 
    1392211{ 
    1393   $emoticons = array( 
    1394     '8-)' => 'smiley-cool', 
    1395     ':-#' => 'smiley-foot-in-mouth', 
    1396     ':-*' => 'smiley-kiss', 
    1397     ':-X' => 'smiley-sealed', 
    1398     ':-P' => 'smiley-tongue-out', 
    1399     ':-@' => 'smiley-yell', 
    1400     ":'(" => 'smiley-cry', 
    1401     ':-(' => 'smiley-frown', 
    1402     ':-D' => 'smiley-laughing', 
    1403     ':-)' => 'smiley-smile', 
    1404     ':-S' => 'smiley-undecided', 
    1405     ':-$' => 'smiley-embarassed', 
    1406     'O:-)' => 'smiley-innocent', 
    1407     ':-|' => 'smiley-money-mouth', 
    1408     ':-O' => 'smiley-surprised', 
    1409     ';-)' => 'smiley-wink', 
    1410   ); 
    1411  
    1412   foreach ($emoticons as $idx => $file) { 
    1413     // <img title="Cry" src="http://.../program/js/tiny_mce/plugins/emotions/img/smiley-cry.gif" border="0" alt="Cry" /> 
    1414     $search[]  = '/<img title="[a-z ]+" src="https?:\/\/[a-z0-9_.\/-]+\/tiny_mce\/plugins\/emotions\/img\/'.$file.'.gif"[^>]+\/>/i'; 
    1415     $replace[] = $idx; 
    1416   } 
    1417  
    1418   return preg_replace($search, $replace, $html); 
    1419 } 
    1420  
    1421  
    1422 /** 
    1423  * Send the given message using the configured method 
    1424  * 
    1425  * @param object $message    Reference to Mail_MIME object 
    1426  * @param string $from       Sender address string 
    1427  * @param array  $mailto     Array of recipient address strings 
    1428  * @param array  $smtp_error SMTP error array (reference) 
    1429  * @param string $body_file  Location of file with saved message body (reference), 
    1430  *                           used when delay_file_io is enabled 
    1431  * @param array  $smtp_opts  SMTP options (e.g. DSN request) 
    1432  * 
    1433  * @return boolean Send status. 
    1434  */ 
     212    return rcube_ui::replace_emoticons($html); 
     213} 
     214 
    1435215function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file=null, $smtp_opts=null) 
    1436216{ 
    1437   global $CONFIG, $RCMAIL; 
    1438  
    1439   $headers = $message->headers(); 
    1440  
    1441   // send thru SMTP server using custom SMTP library 
    1442   if ($CONFIG['smtp_server']) { 
    1443     // generate list of recipients 
    1444     $a_recipients = array($mailto); 
    1445  
    1446     if (strlen($headers['Cc'])) 
    1447       $a_recipients[] = $headers['Cc']; 
    1448     if (strlen($headers['Bcc'])) 
    1449       $a_recipients[] = $headers['Bcc']; 
    1450  
    1451     // clean Bcc from header for recipients 
    1452     $send_headers = $headers; 
    1453     unset($send_headers['Bcc']); 
    1454     // here too, it because txtHeaders() below use $message->_headers not only $send_headers 
    1455     unset($message->_headers['Bcc']); 
    1456  
    1457     $smtp_headers = $message->txtHeaders($send_headers, true); 
    1458  
    1459     if ($message->getParam('delay_file_io')) { 
    1460       // use common temp dir 
    1461       $temp_dir = $RCMAIL->config->get('temp_dir'); 
    1462       $body_file = tempnam($temp_dir, 'rcmMsg'); 
    1463       if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) { 
    1464         raise_error(array('code' => 650, 'type' => 'php', 
    1465             'file' => __FILE__, 'line' => __LINE__, 
    1466             'message' => "Could not create message: ".$mime_result->getMessage()), 
    1467             TRUE, FALSE); 
    1468         return false; 
    1469       } 
    1470       $msg_body = fopen($body_file, 'r'); 
    1471     } else { 
    1472       $msg_body = $message->get(); 
    1473     } 
    1474  
    1475     // send message 
    1476     if (!is_object($RCMAIL->smtp)) 
    1477       $RCMAIL->smtp_init(true); 
    1478  
    1479     $sent = $RCMAIL->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts); 
    1480     $smtp_response = $RCMAIL->smtp->get_response(); 
    1481     $smtp_error = $RCMAIL->smtp->get_error(); 
    1482  
    1483     // log error 
    1484     if (!$sent) 
    1485       raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__, 
    1486                         'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE); 
    1487   } 
    1488   // send mail using PHP's mail() function 
    1489   else { 
    1490     // unset some headers because they will be added by the mail() function 
    1491     $headers_enc = $message->headers($headers); 
    1492     $headers_php = $message->_headers; 
    1493     unset($headers_php['To'], $headers_php['Subject']); 
    1494  
    1495     // reset stored headers and overwrite 
    1496     $message->_headers = array(); 
    1497     $header_str = $message->txtHeaders($headers_php); 
    1498  
    1499     // #1485779 
    1500     if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 
    1501       if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) { 
    1502         $headers_enc['To'] = implode(', ', $m[1]); 
    1503       } 
    1504     } 
    1505  
    1506     $msg_body = $message->get(); 
    1507  
    1508     if (PEAR::isError($msg_body)) 
    1509       raise_error(array('code' => 650, 'type' => 'php', 
    1510             'file' => __FILE__, 'line' => __LINE__, 
    1511             'message' => "Could not create message: ".$msg_body->getMessage()), 
    1512             TRUE, FALSE); 
    1513     else { 
    1514       $delim   = $RCMAIL->config->header_delimiter(); 
    1515       $to      = $headers_enc['To']; 
    1516       $subject = $headers_enc['Subject']; 
    1517       $header_str = rtrim($header_str); 
    1518  
    1519       if ($delim != "\r\n") { 
    1520         $header_str = str_replace("\r\n", $delim, $header_str); 
    1521         $msg_body   = str_replace("\r\n", $delim, $msg_body); 
    1522         $to         = str_replace("\r\n", $delim, $to); 
    1523         $subject    = str_replace("\r\n", $delim, $subject); 
    1524       } 
    1525  
    1526       if (ini_get('safe_mode')) 
    1527         $sent = mail($to, $subject, $msg_body, $header_str); 
    1528       else 
    1529         $sent = mail($to, $subject, $msg_body, $header_str, "-f$from"); 
    1530     } 
    1531   } 
    1532  
    1533   if ($sent) { 
    1534     $RCMAIL->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); 
    1535  
    1536     // remove MDN headers after sending 
    1537     unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); 
    1538  
    1539     // get all recipients 
    1540     if ($headers['Cc']) 
    1541       $mailto .= $headers['Cc']; 
    1542     if ($headers['Bcc']) 
    1543       $mailto .= $headers['Bcc']; 
    1544     if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m)) 
    1545       $mailto = implode(', ', array_unique($m[1])); 
    1546  
    1547     if ($CONFIG['smtp_log']) { 
    1548       write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", 
    1549         $RCMAIL->user->get_username(), 
    1550         $_SERVER['REMOTE_ADDR'], 
    1551         $mailto, 
    1552         !empty($smtp_response) ? join('; ', $smtp_response) : '')); 
    1553     } 
    1554   } 
    1555  
    1556   if (is_resource($msg_body)) { 
    1557     fclose($msg_body); 
    1558   } 
    1559  
    1560   $message->_headers = array(); 
    1561   $message->headers($headers); 
    1562  
    1563   return $sent; 
    1564 } 
    1565  
    1566  
    1567 // Returns unique Message-ID 
     217    return rcmail::get_instance()->deliver_message($message, $from, $mailto, $smtp_error, $body_file, $smtp_opts); 
     218} 
     219 
    1568220function rcmail_gen_message_id() 
    1569221{ 
    1570   global $RCMAIL; 
    1571  
    1572   $local_part  = md5(uniqid('rcmail'.mt_rand(),true)); 
    1573   $domain_part = $RCMAIL->user->get_username('domain'); 
    1574  
    1575   // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924) 
    1576   if (!preg_match('/\.[a-z]+$/i', $domain_part)) { 
    1577     if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST'])) 
    1578       && preg_match('/\.[a-z]+$/i', $host)) { 
    1579         $domain_part = $host; 
    1580     } 
    1581     else if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['SERVER_NAME'])) 
    1582       && preg_match('/\.[a-z]+$/i', $host)) { 
    1583         $domain_part = $host; 
    1584     } 
    1585   } 
    1586  
    1587   return sprintf('<%s@%s>', $local_part, $domain_part); 
    1588 } 
    1589  
    1590  
    1591 // Returns RFC2822 formatted current date in user's timezone 
     222    return rcmail::get_instance()->gen_message_id(); 
     223} 
     224 
    1592225function rcmail_user_date() 
    1593226{ 
    1594   global $RCMAIL; 
    1595  
    1596   // get user's timezone 
    1597   try { 
    1598     $tz   = new DateTimeZone($RCMAIL->config->get('timezone')); 
    1599     $date = new DateTime('now', $tz); 
    1600   } 
    1601   catch (Exception $e) { 
    1602     $date = new DateTime(); 
    1603   } 
    1604  
    1605   return $date->format('r'); 
    1606 } 
    1607  
    1608  
    1609 /** 
    1610  * Check if we can process not exceeding memory_limit 
    1611  * 
    1612  * @param integer Required amount of memory 
    1613  * @return boolean 
    1614  */ 
     227    return rcmail::get_instance()->user_date(); 
     228} 
     229 
    1615230function rcmail_mem_check($need) 
    1616231{ 
    1617   $mem_limit = parse_bytes(ini_get('memory_limit')); 
    1618   $memory    = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB 
    1619  
    1620   return $mem_limit && $memory + $need > $mem_limit ? false : true; 
    1621 } 
    1622  
    1623  
    1624 /** 
    1625  * Check if working in SSL mode 
    1626  * 
    1627  * @param integer HTTPS port number 
    1628  * @param boolean Enables 'use_https' option checking 
    1629  * @return boolean 
    1630  */ 
     232    return rcube_ui::mem_check($need); 
     233} 
     234 
    1631235function rcube_https_check($port=null, $use_https=true) 
    1632236{ 
    1633   global $RCMAIL; 
    1634  
    1635   if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') 
    1636     return true; 
    1637   if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') 
    1638     return true; 
    1639   if ($port && $_SERVER['SERVER_PORT'] == $port) 
    1640     return true; 
    1641   if ($use_https && isset($RCMAIL) && $RCMAIL->config->get('use_https')) 
    1642     return true; 
    1643  
    1644   return false; 
    1645 } 
    1646  
    1647  
    1648 /** 
    1649  * For backward compatibility. 
    1650  * 
    1651  * @global rcmail $RCMAIL 
    1652  * @param string $var_name Variable name. 
    1653  * @return void 
    1654  */ 
     237    return rcube_ui::https_check($port, $use_https); 
     238} 
     239 
    1655240function rcube_sess_unset($var_name=null) 
    1656241{ 
    1657   global $RCMAIL; 
    1658  
    1659   $RCMAIL->session->remove($var_name); 
    1660 } 
    1661  
    1662  
    1663 /** 
    1664  * Replaces hostname variables 
    1665  * 
    1666  * @param string $name Hostname 
    1667  * @param string $host Optional IMAP hostname 
    1668  * @return string 
    1669  */ 
     242    rcmail::get_instance()->session->remove($var_name); 
     243} 
     244 
    1670245function rcube_parse_host($name, $host='') 
    1671246{ 
    1672   // %n - host 
    1673   $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); 
    1674   // %d - domain name without first part, e.g. %n=mail.domain.tld, %d=domain.tld 
    1675   $d = preg_replace('/^[^\.]+\./', '', $n); 
    1676   // %h - IMAP host 
    1677   $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host; 
    1678   // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld 
    1679   $z = preg_replace('/^[^\.]+\./', '', $h); 
    1680   // %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided 
    1681   if ( strpos($name, '%s') !== false ){ 
    1682     $user_email = rcube_idn_convert(get_input_value('_user', RCUBE_INPUT_POST), true); 
    1683     if ( preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s) < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false ) 
    1684       return false; 
    1685   } 
    1686  
    1687   $name = str_replace(array('%n', '%d', '%h', '%z', '%s'), array($n, $d, $h, $z, $s[2]), $name); 
    1688   return $name; 
    1689 } 
    1690  
    1691  
    1692 /** 
    1693  * E-mail address validation 
    1694  * 
    1695  * @param string $email Email address 
    1696  * @param boolean $dns_check True to check dns 
    1697  * @return boolean 
    1698  */ 
     247    return rcmail::parse_host($name, $host); 
     248} 
     249 
    1699250function check_email($email, $dns_check=true) 
    1700251{ 
    1701   // Check for invalid characters 
    1702   if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) 
    1703     return false; 
    1704  
    1705   // Check for length limit specified by RFC 5321 (#1486453) 
    1706   if (strlen($email) > 254)  
    1707     return false; 
    1708  
    1709   $email_array = explode('@', $email); 
    1710  
    1711   // Check that there's one @ symbol 
    1712   if (count($email_array) < 2) 
    1713     return false; 
    1714  
    1715   $domain_part = array_pop($email_array); 
    1716   $local_part = implode('@', $email_array); 
    1717  
    1718   // from PEAR::Validate 
    1719   $regexp = '&^(?: 
    1720         ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")|                             #1 quoted name 
    1721         ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*))  #2 OR dot-atom (RFC5322) 
    1722         $&xi'; 
    1723  
    1724   if (!preg_match($regexp, $local_part)) 
    1725     return false; 
    1726  
    1727   // Check domain part 
    1728   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)) 
    1729     return true; // IP address 
    1730   else { 
    1731     // If not an IP address 
    1732     $domain_array = explode('.', $domain_part); 
    1733     if (sizeof($domain_array) < 2) 
    1734       return false; // Not enough parts to be a valid domain 
    1735  
    1736     foreach ($domain_array as $part) 
    1737       if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) 
    1738         return false; 
    1739  
    1740     if (!$dns_check || !rcmail::get_instance()->config->get('email_dns_check')) 
    1741       return true; 
    1742  
    1743     if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { 
    1744       $lookup = array(); 
    1745       @exec("nslookup -type=MX " . escapeshellarg($domain_part) . " 2>&1", $lookup); 
    1746       foreach ($lookup as $line) { 
    1747         if (strpos($line, 'MX preference')) 
    1748           return true; 
    1749       } 
    1750       return false; 
    1751     } 
    1752  
    1753     // find MX record(s) 
    1754     if (getmxrr($domain_part, $mx_records)) 
    1755       return true; 
    1756  
    1757     // find any DNS record 
    1758     if (checkdnsrr($domain_part, 'ANY')) 
    1759       return true; 
    1760   } 
    1761  
    1762   return false; 
    1763 } 
    1764  
    1765 /* 
    1766  * Idn_to_ascii wrapper. 
    1767  * Intl/Idn modules version of this function doesn't work with e-mail address 
    1768  */ 
    1769 function rcube_idn_to_ascii($str) 
    1770 { 
    1771   return rcube_idn_convert($str, true); 
    1772 } 
    1773  
    1774 /* 
    1775  * Idn_to_ascii wrapper. 
    1776  * Intl/Idn modules version of this function doesn't work with e-mail address 
    1777  */ 
    1778 function rcube_idn_to_utf8($str) 
    1779 { 
    1780   return rcube_idn_convert($str, false); 
    1781 } 
    1782  
    1783 function rcube_idn_convert($input, $is_utf=false) 
    1784 { 
    1785   if ($at = strpos($input, '@')) { 
    1786     $user   = substr($input, 0, $at); 
    1787     $domain = substr($input, $at+1); 
    1788   } 
    1789   else { 
    1790     $domain = $input; 
    1791   } 
    1792  
    1793   $domain = $is_utf ? idn_to_ascii($domain) : idn_to_utf8($domain); 
    1794  
    1795   if ($domain === false) { 
    1796     return ''; 
    1797   } 
    1798  
    1799   return $at ? $user . '@' . $domain : $domain; 
    1800 } 
    1801  
    1802  
    1803 /** 
    1804  * Helper class to turn relative urls into absolute ones 
    1805  * using a predefined base 
    1806  */ 
    1807 class rcube_base_replacer 
    1808 { 
    1809   private $base_url; 
    1810  
    1811   public function __construct($base) 
    1812   { 
    1813     $this->base_url = $base; 
    1814   } 
    1815  
    1816   public function callback($matches) 
    1817   { 
    1818     return $matches[1] . '="' . self::absolute_url($matches[3], $this->base_url) . '"'; 
    1819   } 
    1820  
    1821   public function replace($body) 
    1822   { 
    1823     return preg_replace_callback(array( 
    1824       '/(src|background|href)=(["\']?)([^"\'\s]+)(\2|\s|>)/Ui', 
    1825       '/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/Ui', 
    1826       ), 
    1827       array($this, 'callback'), $body); 
    1828   } 
    1829  
    1830   /** 
    1831    * Convert paths like ../xxx to an absolute path using a base url 
    1832    * 
    1833    * @param string $path     Relative path 
    1834    * @param string $base_url Base URL 
    1835    * 
    1836    * @return string Absolute URL 
    1837    */ 
    1838   public static function absolute_url($path, $base_url) 
    1839   { 
    1840     $host_url = $base_url; 
    1841     $abs_path = $path; 
    1842  
    1843     // check if path is an absolute URL 
    1844     if (preg_match('/^[fhtps]+:\/\//', $path)) { 
    1845       return $path; 
    1846     } 
    1847  
    1848     // check if path is a content-id scheme 
    1849     if (strpos($path, 'cid:') === 0) { 
    1850       return $path; 
    1851     } 
    1852  
    1853     // cut base_url to the last directory 
    1854     if (strrpos($base_url, '/') > 7) { 
    1855       $host_url = substr($base_url, 0, strpos($base_url, '/', 7)); 
    1856       $base_url = substr($base_url, 0, strrpos($base_url, '/')); 
    1857     } 
    1858  
    1859     // $path is absolute 
    1860     if ($path[0] == '/') { 
    1861       $abs_path = $host_url.$path; 
    1862     } 
    1863     else { 
    1864       // strip './' because its the same as '' 
    1865       $path = preg_replace('/^\.\//', '', $path); 
    1866  
    1867       if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) { 
    1868         foreach ($matches as $a_match) { 
    1869           if (strrpos($base_url, '/')) { 
    1870             $base_url = substr($base_url, 0, strrpos($base_url, '/')); 
    1871           } 
    1872           $path = substr($path, 3); 
    1873         } 
    1874       } 
    1875  
    1876       $abs_path = $base_url.'/'.$path; 
    1877     } 
    1878  
    1879     return $abs_path; 
    1880   } 
    1881 } 
    1882  
    1883  
    1884 /****** debugging and logging functions ********/ 
    1885  
    1886 /** 
    1887  * Print or write debug messages 
    1888  * 
    1889  * @param mixed Debug message or data 
    1890  * @return void 
    1891  */ 
     252    return rcmail::get_instance()->check_email($email, $dns_check); 
     253} 
     254 
    1892255function console() 
    1893256{ 
    1894     $args = func_get_args(); 
    1895  
    1896     if (class_exists('rcmail', false)) { 
    1897         $rcmail = rcmail::get_instance(); 
    1898         if (is_object($rcmail->plugins)) { 
    1899             $plugin = $rcmail->plugins->exec_hook('console', array('args' => $args)); 
    1900             if ($plugin['abort']) 
    1901                 return; 
    1902             $args = $plugin['args']; 
    1903         } 
    1904     } 
    1905  
    1906     $msg = array(); 
    1907     foreach ($args as $arg) 
    1908         $msg[] = !is_string($arg) ? var_export($arg, true) : $arg; 
    1909  
    1910     write_log('console', join(";\n", $msg)); 
    1911 } 
    1912  
    1913  
    1914 /** 
    1915  * Append a line to a logfile in the logs directory. 
    1916  * Date will be added automatically to the line. 
    1917  * 
    1918  * @param $name name of log file 
    1919  * @param line Line to append 
    1920  * @return void 
    1921  */ 
     257    call_user_func_array(array('rcmail', 'console'), func_get_args()); 
     258} 
     259 
    1922260function write_log($name, $line) 
    1923261{ 
    1924   global $CONFIG, $RCMAIL; 
    1925  
    1926   if (!is_string($line)) 
    1927     $line = var_export($line, true); 
    1928   
    1929   if (empty($CONFIG['log_date_format'])) 
    1930     $CONFIG['log_date_format'] = 'd-M-Y H:i:s O'; 
    1931    
    1932   $date = date($CONFIG['log_date_format']); 
    1933    
    1934   // trigger logging hook 
    1935   if (is_object($RCMAIL) && is_object($RCMAIL->plugins)) { 
    1936     $log = $RCMAIL->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line)); 
    1937     $name = $log['name']; 
    1938     $line = $log['line']; 
    1939     $date = $log['date']; 
    1940     if ($log['abort']) 
    1941       return true; 
    1942   } 
    1943   
    1944   if ($CONFIG['log_driver'] == 'syslog') { 
    1945     $prio = $name == 'errors' ? LOG_ERR : LOG_INFO; 
    1946     syslog($prio, $line); 
    1947     return true; 
    1948   } 
    1949   else { 
    1950     $line = sprintf("[%s]: %s\n", $date, $line); 
    1951  
    1952     // log_driver == 'file' is assumed here 
    1953     if (empty($CONFIG['log_dir'])) 
    1954       $CONFIG['log_dir'] = INSTALL_PATH.'logs'; 
    1955  
    1956     // try to open specific log file for writing 
    1957     $logfile = $CONFIG['log_dir'].'/'.$name; 
    1958     if ($fp = @fopen($logfile, 'a')) { 
    1959       fwrite($fp, $line); 
    1960       fflush($fp); 
    1961       fclose($fp); 
    1962       return true; 
    1963     } 
    1964     else 
    1965       trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING); 
    1966   } 
    1967  
    1968   return false; 
    1969 } 
    1970  
    1971  
    1972 /** 
    1973  * Write login data (name, ID, IP address) to the 'userlogins' log file. 
    1974  * 
    1975  * @return void 
    1976  */ 
     262    return rcmail::write_log($name, $line); 
     263} 
     264 
    1977265function rcmail_log_login() 
    1978266{ 
    1979   global $RCMAIL; 
    1980  
    1981   if (!$RCMAIL->config->get('log_logins') || !$RCMAIL->user) 
    1982     return; 
    1983  
    1984   write_log('userlogins', sprintf('Successful login for %s (ID: %d) from %s in session %s', 
    1985     $RCMAIL->user->get_username(), $RCMAIL->user->ID, rcmail_remote_ip(), session_id())); 
    1986 } 
    1987  
    1988  
    1989 /** 
    1990  * Returns remote IP address and forwarded addresses if found 
    1991  * 
    1992  * @return string Remote IP address(es) 
    1993  */ 
     267    return rcmail::get_instance()->log_login(); 
     268} 
     269 
    1994270function rcmail_remote_ip() 
    1995271{ 
    1996     $address = $_SERVER['REMOTE_ADDR']; 
    1997  
    1998     // append the NGINX X-Real-IP header, if set 
    1999     if (!empty($_SERVER['HTTP_X_REAL_IP'])) { 
    2000         $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP']; 
    2001     } 
    2002     // append the X-Forwarded-For header, if set 
    2003     if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 
    2004         $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR']; 
    2005     } 
    2006  
    2007     if (!empty($remote_ip)) 
    2008         $address .= '(' . implode(',', $remote_ip) . ')'; 
    2009  
    2010     return $address; 
    2011 } 
    2012  
    2013  
    2014 /** 
    2015  * Check whether the HTTP referer matches the current request 
    2016  * 
    2017  * @return boolean True if referer is the same host+path, false if not 
    2018  */ 
     272    return rcmail::remote_ip(); 
     273} 
     274 
    2019275function rcube_check_referer() 
    2020276{ 
    2021   $uri = parse_url($_SERVER['REQUEST_URI']); 
    2022   $referer = parse_url(rc_request_header('Referer')); 
    2023   return $referer['host'] == rc_request_header('Host') && $referer['path'] == $uri['path']; 
    2024 } 
    2025  
    2026  
    2027 /** 
    2028  * @access private 
    2029  * @return mixed 
    2030  */ 
     277    return rcmail::check_referer(); 
     278} 
     279 
    2031280function rcube_timer() 
    2032281{ 
    2033   return microtime(true); 
    2034 } 
    2035  
    2036  
    2037 /** 
    2038  * @access private 
    2039  * @return void 
    2040  */ 
     282    return rcmail::timer(); 
     283} 
     284 
    2041285function rcube_print_time($timer, $label='Timer', $dest='console') 
    2042286{ 
    2043   static $print_count = 0; 
    2044  
    2045   $print_count++; 
    2046   $now = rcube_timer(); 
    2047   $diff = $now-$timer; 
    2048  
    2049   if (empty($label)) 
    2050     $label = 'Timer '.$print_count; 
    2051  
    2052   write_log($dest, sprintf("%s: %0.4f sec", $label, $diff)); 
    2053 } 
    2054  
    2055  
    2056 /** 
    2057  * Throw system error and show error page 
    2058  * 
    2059  * @param array Named parameters 
    2060  *  - code: Error code (required) 
    2061  *  - type: Error type [php|db|imap|javascript] (required) 
    2062  *  - message: Error message 
    2063  *  - file: File where error occured 
    2064  *  - line: Line where error occured 
    2065  * @param boolean True to log the error 
    2066  * @param boolean Terminate script execution 
    2067  */ 
     287    rcmail::print_timer($timer, $label, $dest); 
     288} 
     289 
     290 
    2068291// may be defined in Installer 
    2069292if (!function_exists('raise_error')) { 
    2070293function raise_error($arg=array(), $log=false, $terminate=false) 
    2071294{ 
    2072     global $__page_content, $CONFIG, $OUTPUT, $ERROR_CODE, $ERROR_MESSAGE; 
    2073  
    2074     // report bug (if not incompatible browser) 
    2075     if ($log && $arg['type'] && $arg['message']) 
    2076         rcube_log_bug($arg); 
    2077  
    2078     // display error page and terminate script 
    2079     if ($terminate) { 
    2080         $ERROR_CODE = $arg['code']; 
    2081         $ERROR_MESSAGE = $arg['message']; 
    2082         include INSTALL_PATH . 'program/steps/utils/error.inc'; 
    2083         exit; 
    2084     } 
    2085 } 
    2086 } 
    2087  
    2088  
    2089 /** 
    2090  * Report error according to configured debug_level 
    2091  * 
    2092  * @param array Named parameters 
    2093  * @return void 
    2094  * @see raise_error() 
    2095  */ 
     295    rcube_ui::raise_error($arg, $log, $terminate); 
     296} 
     297} 
     298 
    2096299function rcube_log_bug($arg_arr) 
    2097300{ 
    2098     global $CONFIG; 
    2099  
    2100     $program = strtoupper($arg_arr['type']); 
    2101     $level   = $CONFIG['debug_level']; 
    2102  
    2103     // disable errors for ajax requests, write to log instead (#1487831) 
    2104     if (($level & 4) && !empty($_REQUEST['_remote'])) { 
    2105         $level = ($level ^ 4) | 1; 
    2106     } 
    2107  
    2108     // write error to local log file 
    2109     if ($level & 1) { 
    2110         $post_query = ($_SERVER['REQUEST_METHOD'] == 'POST' ? '?_task='.urlencode($_POST['_task']).'&_action='.urlencode($_POST['_action']) : ''); 
    2111         $log_entry = sprintf("%s Error: %s%s (%s %s)", 
    2112             $program, 
    2113             $arg_arr['message'], 
    2114             $arg_arr['file'] ? sprintf(' in %s on line %d', $arg_arr['file'], $arg_arr['line']) : '', 
    2115             $_SERVER['REQUEST_METHOD'], 
    2116             $_SERVER['REQUEST_URI'] . $post_query); 
    2117  
    2118         if (!write_log('errors', $log_entry)) { 
    2119             // send error to PHPs error handler if write_log didn't succeed 
    2120             trigger_error($arg_arr['message']); 
    2121         } 
    2122     } 
    2123  
    2124     // report the bug to the global bug reporting system 
    2125     if ($level & 2) { 
    2126         // TODO: Send error via HTTP 
    2127     } 
    2128  
    2129     // show error if debug_mode is on 
    2130     if ($level & 4) { 
    2131         print "<b>$program Error"; 
    2132  
    2133         if (!empty($arg_arr['file']) && !empty($arg_arr['line'])) 
    2134             print " in $arg_arr[file] ($arg_arr[line])"; 
    2135  
    2136         print ':</b>&nbsp;'; 
    2137         print nl2br($arg_arr['message']); 
    2138         print '<br />'; 
    2139         flush(); 
    2140     } 
     301    rcube_ui::log_bug($arg_arr); 
    2141302} 
    2142303 
    2143304function rcube_upload_progress() 
    2144305{ 
    2145     global $RCMAIL; 
    2146  
    2147     $prefix = ini_get('apc.rfc1867_prefix'); 
    2148     $params = array( 
    2149         'action' => $RCMAIL->action, 
    2150         'name' => get_input_value('_progress', RCUBE_INPUT_GET), 
    2151     ); 
    2152  
    2153     if (function_exists('apc_fetch')) { 
    2154         $status = apc_fetch($prefix . $params['name']); 
    2155  
    2156         if (!empty($status)) { 
    2157             $status['percent'] = round($status['current']/$status['total']*100); 
    2158             $params = array_merge($status, $params); 
    2159         } 
    2160     } 
    2161  
    2162     if (isset($params['percent'])) 
    2163         $params['text'] = rcube_label(array('name' => 'uploadprogress', 'vars' => array( 
    2164             'percent' => $params['percent'] . '%', 
    2165             'current' => show_bytes($params['current']), 
    2166             'total'   => show_bytes($params['total']) 
    2167         ))); 
    2168  
    2169     $RCMAIL->output->command('upload_progress_update', $params); 
    2170     $RCMAIL->output->send(); 
     306    rcube_ui::upload_progress(); 
    2171307} 
    2172308 
    2173309function rcube_upload_init() 
    2174310{ 
    2175     global $RCMAIL; 
    2176  
    2177     // Enable upload progress bar 
    2178     if (($seconds = $RCMAIL->config->get('upload_progress')) && ini_get('apc.rfc1867')) { 
    2179         if ($field_name = ini_get('apc.rfc1867_name')) { 
    2180             $RCMAIL->output->set_env('upload_progress_name', $field_name); 
    2181             $RCMAIL->output->set_env('upload_progress_time', (int) $seconds); 
    2182         } 
    2183     } 
    2184  
    2185     // find max filesize value 
    2186     $max_filesize = parse_bytes(ini_get('upload_max_filesize')); 
    2187     $max_postsize = parse_bytes(ini_get('post_max_size')); 
    2188     if ($max_postsize && $max_postsize < $max_filesize) 
    2189         $max_filesize = $max_postsize; 
    2190  
    2191     $RCMAIL->output->set_env('max_filesize', $max_filesize); 
    2192     $max_filesize = show_bytes($max_filesize); 
    2193     $RCMAIL->output->set_env('filesizeerror', rcube_label(array( 
    2194         'name' => 'filesizeerror', 'vars' => array('size' => $max_filesize)))); 
    2195  
    2196     return $max_filesize; 
    2197 } 
    2198  
    2199 /** 
    2200  * Initializes client-side autocompletion 
    2201  */ 
     311    return rcube_ui::upload_init(); 
     312} 
     313 
    2202314function rcube_autocomplete_init() 
    2203315{ 
    2204     global $RCMAIL; 
    2205     static $init; 
    2206  
    2207     if ($init) 
    2208         return; 
    2209  
    2210     $init = 1; 
    2211  
    2212     if (($threads = (int)$RCMAIL->config->get('autocomplete_threads')) > 0) { 
    2213       $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql'); 
    2214       if (count($book_types) > 1) { 
    2215         $RCMAIL->output->set_env('autocomplete_threads', $threads); 
    2216         $RCMAIL->output->set_env('autocomplete_sources', $book_types); 
    2217       } 
    2218     } 
    2219  
    2220     $RCMAIL->output->set_env('autocomplete_max', (int)$RCMAIL->config->get('autocomplete_max', 15)); 
    2221     $RCMAIL->output->set_env('autocomplete_min_length', $RCMAIL->config->get('autocomplete_min_length')); 
    2222     $RCMAIL->output->add_label('autocompletechars', 'autocompletemore'); 
     316    rcube_ui::autocomplete_init(); 
    2223317} 
    2224318 
    2225319function rcube_fontdefs($font = null) 
    2226320{ 
    2227   $fonts = array( 
    2228     'Andale Mono'   => '"Andale Mono",Times,monospace', 
    2229     'Arial'         => 'Arial,Helvetica,sans-serif', 
    2230     'Arial Black'   => '"Arial Black","Avant Garde",sans-serif', 
    2231     'Book Antiqua'  => '"Book Antiqua",Palatino,serif', 
    2232     'Courier New'   => '"Courier New",Courier,monospace', 
    2233     'Georgia'       => 'Georgia,Palatino,serif', 
    2234     'Helvetica'     => 'Helvetica,Arial,sans-serif', 
    2235     'Impact'        => 'Impact,Chicago,sans-serif', 
    2236     'Tahoma'        => 'Tahoma,Arial,Helvetica,sans-serif', 
    2237     'Terminal'      => 'Terminal,Monaco,monospace', 
    2238     'Times New Roman' => '"Times New Roman",Times,serif', 
    2239     'Trebuchet MS'  => '"Trebuchet MS",Geneva,sans-serif', 
    2240     'Verdana'       => 'Verdana,Geneva,sans-serif', 
    2241   ); 
    2242  
    2243   if ($font) 
    2244     return $fonts[$font]; 
    2245  
    2246   return $fonts; 
    2247 } 
     321    return rcube_ui::font_defs($font); 
     322} 
     323 
     324function send_nocacheing_headers() 
     325{ 
     326    rcube_ui::send_nocacheing_headers(); 
     327} 
     328 
     329function show_bytes($bytes) 
     330{ 
     331    return rcube_ui::show_bytes($bytes); 
     332} 
     333 
     334function rc_wordwrap($string, $width=75, $break="\n", $cut=false) 
     335{ 
     336    return rcube_wordwrap($string, $width, $break, $cut); 
     337} 
     338 
     339function rc_request_header($name) 
     340{ 
     341    return rcube_request_header($name); 
     342} 
  • branches/devel-framework/roundcubemail/program/include/rcmail.php

    r5778 r5807  
    756756    $this->session = new rcube_session($this->get_dbh(), $this->config); 
    757757 
    758     $this->session->register_gc_handler('rcmail_temp_gc'); 
     758    $this->session->register_gc_handler(array($this, 'temp_gc')); 
    759759    if ($this->config->get('enable_caching')) 
    760       $this->session->register_gc_handler('rcmail_cache_gc'); 
     760      $this->session->register_gc_handler(array($this, 'cache_gc')); 
    761761 
    762762    // start PHP session (if not in CLI mode) 
     
    17541754  } 
    17551755 
     1756 
     1757    /** 
     1758     * Overwrite action variable 
     1759     * 
     1760     * @param string New action value 
     1761     */ 
     1762    public function overwrite_action($action) 
     1763    { 
     1764        $this->action = $action; 
     1765        $this->output->set_env('action', $action); 
     1766    } 
     1767 
     1768 
     1769    /** 
     1770     * Send the given message using the configured method. 
     1771     * 
     1772     * @param object $message    Reference to Mail_MIME object 
     1773     * @param string $from       Sender address string 
     1774     * @param array  $mailto     Array of recipient address strings 
     1775     * @param array  $smtp_error SMTP error array (reference) 
     1776     * @param string $body_file  Location of file with saved message body (reference), 
     1777     *                           used when delay_file_io is enabled 
     1778     * @param array  $smtp_opts  SMTP options (e.g. DSN request) 
     1779     * 
     1780     * @return boolean Send status. 
     1781     */ 
     1782    public function deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file = null, $smtp_opts = null) 
     1783    { 
     1784        $headers = $message->headers(); 
     1785 
     1786        // send thru SMTP server using custom SMTP library 
     1787        if ($this->config->get('smtp_server')) { 
     1788            // generate list of recipients 
     1789            $a_recipients = array($mailto); 
     1790 
     1791            if (strlen($headers['Cc'])) 
     1792                $a_recipients[] = $headers['Cc']; 
     1793            if (strlen($headers['Bcc'])) 
     1794                $a_recipients[] = $headers['Bcc']; 
     1795 
     1796            // clean Bcc from header for recipients 
     1797            $send_headers = $headers; 
     1798            unset($send_headers['Bcc']); 
     1799            // here too, it because txtHeaders() below use $message->_headers not only $send_headers 
     1800            unset($message->_headers['Bcc']); 
     1801 
     1802            $smtp_headers = $message->txtHeaders($send_headers, true); 
     1803 
     1804            if ($message->getParam('delay_file_io')) { 
     1805                // use common temp dir 
     1806                $temp_dir = $this->config->get('temp_dir'); 
     1807                $body_file = tempnam($temp_dir, 'rcmMsg'); 
     1808                if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) { 
     1809                    raise_error(array('code' => 650, 'type' => 'php', 
     1810                        'file' => __FILE__, 'line' => __LINE__, 
     1811                        'message' => "Could not create message: ".$mime_result->getMessage()), 
     1812                        TRUE, FALSE); 
     1813                    return false; 
     1814                } 
     1815                $msg_body = fopen($body_file, 'r'); 
     1816            } 
     1817            else { 
     1818                $msg_body = $message->get(); 
     1819            } 
     1820 
     1821            // send message 
     1822            if (!is_object($this->smtp)) { 
     1823                $this->smtp_init(true); 
     1824            } 
     1825 
     1826            $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts); 
     1827            $smtp_response = $this->smtp->get_response(); 
     1828            $smtp_error = $this->smtp->get_error(); 
     1829 
     1830            // log error 
     1831            if (!$sent) { 
     1832                raise_error(array('code' => 800, 'type' => 'smtp', 
     1833                    'line' => __LINE__, 'file' => __FILE__, 
     1834                    'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE); 
     1835            } 
     1836        } 
     1837        // send mail using PHP's mail() function 
     1838        else { 
     1839            // unset some headers because they will be added by the mail() function 
     1840            $headers_enc = $message->headers($headers); 
     1841            $headers_php = $message->_headers; 
     1842            unset($headers_php['To'], $headers_php['Subject']); 
     1843 
     1844            // reset stored headers and overwrite 
     1845            $message->_headers = array(); 
     1846            $header_str = $message->txtHeaders($headers_php); 
     1847 
     1848            // #1485779 
     1849            if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 
     1850                if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) { 
     1851                    $headers_enc['To'] = implode(', ', $m[1]); 
     1852                } 
     1853            } 
     1854 
     1855            $msg_body = $message->get(); 
     1856 
     1857            if (PEAR::isError($msg_body)) { 
     1858                raise_error(array('code' => 650, 'type' => 'php', 
     1859                    'file' => __FILE__, 'line' => __LINE__, 
     1860                    'message' => "Could not create message: ".$msg_body->getMessage()), 
     1861                    TRUE, FALSE); 
     1862            } 
     1863            else { 
     1864                $delim   = $this->config->header_delimiter(); 
     1865                $to      = $headers_enc['To']; 
     1866                $subject = $headers_enc['Subject']; 
     1867                $header_str = rtrim($header_str); 
     1868 
     1869                if ($delim != "\r\n") { 
     1870                    $header_str = str_replace("\r\n", $delim, $header_str); 
     1871                    $msg_body   = str_replace("\r\n", $delim, $msg_body); 
     1872                    $to         = str_replace("\r\n", $delim, $to); 
     1873                    $subject    = str_replace("\r\n", $delim, $subject); 
     1874                } 
     1875 
     1876                if (ini_get('safe_mode')) 
     1877                    $sent = mail($to, $subject, $msg_body, $header_str); 
     1878                else 
     1879                    $sent = mail($to, $subject, $msg_body, $header_str, "-f$from"); 
     1880            } 
     1881        } 
     1882 
     1883        if ($sent) { 
     1884            $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); 
     1885 
     1886            // remove MDN headers after sending 
     1887            unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); 
     1888 
     1889            // get all recipients 
     1890            if ($headers['Cc']) 
     1891                $mailto .= $headers['Cc']; 
     1892            if ($headers['Bcc']) 
     1893                $mailto .= $headers['Bcc']; 
     1894            if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m)) 
     1895                $mailto = implode(', ', array_unique($m[1])); 
     1896 
     1897            if ($this->config->get('smtp_log')) { 
     1898                write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", 
     1899                    $this->user->get_username(), 
     1900                    $_SERVER['REMOTE_ADDR'], 
     1901                    $mailto, 
     1902                    !empty($smtp_response) ? join('; ', $smtp_response) : '')); 
     1903            } 
     1904        } 
     1905 
     1906        if (is_resource($msg_body)) { 
     1907            fclose($msg_body); 
     1908        } 
     1909 
     1910        $message->_headers = array(); 
     1911        $message->headers($headers); 
     1912 
     1913        return $sent; 
     1914    } 
     1915 
     1916 
     1917    /** 
     1918     * Unique Message-ID generator. 
     1919     * 
     1920     * @return string Message-ID 
     1921     */ 
     1922    public function gen_message_id() 
     1923    { 
     1924        $local_part  = md5(uniqid('rcmail'.mt_rand(),true)); 
     1925        $domain_part = $this->user->get_username('domain'); 
     1926 
     1927        // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924) 
     1928        if (!preg_match('/\.[a-z]+$/i', $domain_part)) { 
     1929            foreach (array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']) as $host) { 
     1930                $host = preg_replace('/:[0-9]+$/', '', $host); 
     1931                if ($host && preg_match('/\.[a-z]+$/i', $host)) { 
     1932                    $domain_part = $host; 
     1933                } 
     1934            } 
     1935        } 
     1936 
     1937        return sprintf('<%s@%s>', $local_part, $domain_part); 
     1938    } 
     1939 
     1940 
     1941    /** 
     1942     * Returns RFC2822 formatted current date in user's timezone 
     1943     * 
     1944     * @return string Date 
     1945     */ 
     1946    public function user_date() 
     1947    { 
     1948        // get user's timezone 
     1949        try { 
     1950            $tz   = new DateTimeZone($this->config->get('timezone')); 
     1951            $date = new DateTime('now', $tz); 
     1952        } 
     1953        catch (Exception $e) { 
     1954            $date = new DateTime(); 
     1955        } 
     1956 
     1957        return $date->format('r'); 
     1958    } 
     1959 
     1960 
     1961    /** 
     1962     * Replaces hostname variables. 
     1963     * 
     1964     * @param string $name Hostname 
     1965     * @param string $host Optional IMAP hostname 
     1966     * 
     1967     * @return string Hostname 
     1968     */ 
     1969    public static function parse_host($name, $host = '') 
     1970    { 
     1971        // %n - host 
     1972        $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); 
     1973        // %d - domain name without first part, e.g. %n=mail.domain.tld, %d=domain.tld 
     1974        $d = preg_replace('/^[^\.]+\./', '', $n); 
     1975        // %h - IMAP host 
     1976        $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host; 
     1977        // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld 
     1978        $z = preg_replace('/^[^\.]+\./', '', $h); 
     1979        // %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided 
     1980        if (strpos($name, '%s') !== false) { 
     1981            $user_email = rcube_idn_convert(get_input_value('_user', RCUBE_INPUT_POST), true); 
     1982            $matches    = preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s); 
     1983            if ($matches < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false) { 
     1984                return false; 
     1985            } 
     1986        } 
     1987 
     1988        $name = str_replace(array('%n', '%d', '%h', '%z', '%s'), array($n, $d, $h, $z, $s[2]), $name); 
     1989        return $name; 
     1990    } 
     1991 
     1992 
     1993    /** 
     1994     * E-mail address validation. 
     1995     * 
     1996     * @param string $email Email address 
     1997     * @param boolean $dns_check True to check dns 
     1998     * 
     1999     * @return boolean True on success, False if address is invalid 
     2000     */ 
     2001    public function check_email($email, $dns_check=true) 
     2002    { 
     2003        // Check for invalid characters 
     2004        if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) { 
     2005            return false; 
     2006        } 
     2007 
     2008        // Check for length limit specified by RFC 5321 (#1486453) 
     2009        if (strlen($email) > 254) { 
     2010            return false; 
     2011        } 
     2012 
     2013        $email_array = explode('@', $email); 
     2014 
     2015        // Check that there's one @ symbol 
     2016        if (count($email_array) < 2) { 
     2017            return false; 
     2018        } 
     2019 
     2020        $domain_part = array_pop($email_array); 
     2021        $local_part  = implode('@', $email_array); 
     2022 
     2023        // from PEAR::Validate 
     2024        $regexp = '&^(?: 
     2025                ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")|                                         #1 quoted name 
     2026                ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*))  #2 OR dot-atom (RFC5322) 
     2027                $&xi'; 
     2028 
     2029        if (!preg_match($regexp, $local_part)) { 
     2030            return false; 
     2031        } 
     2032 
     2033        // Check domain part 
     2034        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)) { 
     2035            return true; // IP address 
     2036        } 
     2037        else { 
     2038            // If not an IP address 
     2039            $domain_array = explode('.', $domain_part); 
     2040            // Not enough parts to be a valid domain 
     2041            if (sizeof($domain_array) < 2) { 
     2042                return false; 
     2043            } 
     2044 
     2045            foreach ($domain_array as $part) { 
     2046                if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) { 
     2047                    return false; 
     2048                } 
     2049            } 
     2050 
     2051            if (!$dns_check || !$this->config->get('email_dns_check')) { 
     2052                return true; 
     2053            } 
     2054 
     2055            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { 
     2056                $lookup = array(); 
     2057                @exec("nslookup -type=MX " . escapeshellarg($domain_part) . " 2>&1", $lookup); 
     2058                foreach ($lookup as $line) { 
     2059                    if (strpos($line, 'MX preference')) { 
     2060                        return true; 
     2061                    } 
     2062                } 
     2063                return false; 
     2064            } 
     2065 
     2066            // find MX record(s) 
     2067            if (getmxrr($domain_part, $mx_records)) { 
     2068                return true; 
     2069            } 
     2070 
     2071            // find any DNS record 
     2072            if (checkdnsrr($domain_part, 'ANY')) { 
     2073                return true; 
     2074            } 
     2075        } 
     2076 
     2077        return false; 
     2078    } 
     2079 
     2080 
     2081    /** 
     2082     * Print or write debug messages 
     2083     * 
     2084     * @param mixed Debug message or data 
     2085     */ 
     2086    public static function console() 
     2087    { 
     2088        $args = func_get_args(); 
     2089 
     2090        if (class_exists('rcmail', false)) { 
     2091            $rcmail = rcmail::get_instance(); 
     2092            if (is_object($rcmail->plugins)) { 
     2093                $plugin = $rcmail->plugins->exec_hook('console', array('args' => $args)); 
     2094                if ($plugin['abort']) { 
     2095                    return; 
     2096                } 
     2097               $args = $plugin['args']; 
     2098            } 
     2099        } 
     2100 
     2101        $msg = array(); 
     2102        foreach ($args as $arg) { 
     2103            $msg[] = !is_string($arg) ? var_export($arg, true) : $arg; 
     2104        } 
     2105 
     2106        write_log('console', join(";\n", $msg)); 
     2107    } 
     2108 
     2109 
     2110    /** 
     2111     * Append a line to a logfile in the logs directory. 
     2112     * Date will be added automatically to the line. 
     2113     * 
     2114     * @param $name name of log file 
     2115     * @param line Line to append 
     2116     */ 
     2117    public static function write_log($name, $line) 
     2118    { 
     2119        global $RCMAIL; 
     2120 
     2121        if (!is_string($line)) { 
     2122            $line = var_export($line, true); 
     2123        } 
     2124 
     2125        $date_format = $RCMAIL ? $RCMAIL->config->get('log_date_format') : null; 
     2126        $log_driver  = $RCMAIL ? $RCMAIL->config->get('log_driver') : null; 
     2127 
     2128        if (empty($date_format)) { 
     2129            $date_format = 'd-M-Y H:i:s O'; 
     2130        } 
     2131 
     2132        $date = date($date_format); 
     2133 
     2134        // trigger logging hook 
     2135        if (is_object($RCMAIL) && is_object($RCMAIL->plugins)) { 
     2136            $log  = $RCMAIL->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line)); 
     2137            $name = $log['name']; 
     2138            $line = $log['line']; 
     2139            $date = $log['date']; 
     2140            if ($log['abort']) 
     2141                return true; 
     2142        } 
     2143 
     2144        if ($log_driver == 'syslog') { 
     2145            $prio = $name == 'errors' ? LOG_ERR : LOG_INFO; 
     2146            syslog($prio, $line); 
     2147            return true; 
     2148        } 
     2149 
     2150        // log_driver == 'file' is assumed here 
     2151 
     2152        $line = sprintf("[%s]: %s\n", $date, $line); 
     2153        $log_dir  = $RCMAIL ? $RCMAIL->config->get('log_dir') : null; 
     2154 
     2155        if (empty($log_dir)) { 
     2156            $log_dir = INSTALL_PATH . 'logs'; 
     2157        } 
     2158 
     2159        // try to open specific log file for writing 
     2160        $logfile = $log_dir.'/'.$name; 
     2161 
     2162        if ($fp = @fopen($logfile, 'a')) { 
     2163            fwrite($fp, $line); 
     2164            fflush($fp); 
     2165            fclose($fp); 
     2166            return true; 
     2167        } 
     2168 
     2169        trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING); 
     2170        return false; 
     2171    } 
     2172 
     2173 
     2174    /** 
     2175     * Write login data (name, ID, IP address) to the 'userlogins' log file. 
     2176     */ 
     2177    public function log_login() 
     2178    { 
     2179        if (!$this->config->get('log_logins') || !$this->user) { 
     2180            return; 
     2181        } 
     2182 
     2183        $this->write_log('userlogins', 
     2184            sprintf('Successful login for %s (ID: %d) from %s in session %s', 
     2185                $this->user->get_username(), 
     2186                $this->user->ID, $this->remote_ip(), session_id())); 
     2187    } 
     2188 
     2189 
     2190    /** 
     2191     * Returns remote IP address and forwarded addresses if found 
     2192     * 
     2193     * @return string Remote IP address(es) 
     2194     */ 
     2195    public static function remote_ip() 
     2196    { 
     2197        $address = $_SERVER['REMOTE_ADDR']; 
     2198 
     2199        // append the NGINX X-Real-IP header, if set 
     2200        if (!empty($_SERVER['HTTP_X_REAL_IP'])) { 
     2201            $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP']; 
     2202        } 
     2203        // append the X-Forwarded-For header, if set 
     2204        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 
     2205            $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR']; 
     2206        } 
     2207 
     2208        if (!empty($remote_ip)) { 
     2209            $address .= '(' . implode(',', $remote_ip) . ')'; 
     2210        } 
     2211 
     2212        return $address; 
     2213    } 
     2214 
     2215 
     2216    /** 
     2217     * Check whether the HTTP referer matches the current request 
     2218     * 
     2219     * @return boolean True if referer is the same host+path, false if not 
     2220     */ 
     2221    public static function check_referer() 
     2222    { 
     2223        $uri = parse_url($_SERVER['REQUEST_URI']); 
     2224        $referer = parse_url(rcube_request_header('Referer')); 
     2225        return $referer['host'] == rcube_request_header('Host') && $referer['path'] == $uri['path']; 
     2226    } 
     2227 
     2228 
     2229    /** 
     2230     * Returns current time (with microseconds). 
     2231     * 
     2232     * @return float Current time in seconds since the Unix 
     2233     */ 
     2234    public static function timer() 
     2235    { 
     2236        return microtime(true); 
     2237    } 
     2238 
     2239 
     2240    /** 
     2241     * Logs time difference according to provided timer 
     2242     * 
     2243     * @param float  $timer  Timer (self::timer() result) 
     2244     * @param string $label  Log line prefix 
     2245     * @param string $dest   Log file name 
     2246     * 
     2247     * @see self::timer() 
     2248     */ 
     2249    public static function print_timer($timer, $label = 'Timer', $dest = 'console') 
     2250    { 
     2251        static $print_count = 0; 
     2252 
     2253        $print_count++; 
     2254        $now = rcube_timer(); 
     2255        $diff = $now-$timer; 
     2256 
     2257        if (empty($label)) { 
     2258            $label = 'Timer '.$print_count; 
     2259        } 
     2260 
     2261        self::write_log($dest, sprintf("%s: %0.4f sec", $label, $diff)); 
     2262    } 
     2263 
     2264 
     2265    /** 
     2266     * Garbage collector function for temp files. 
     2267     * Remove temp files older than two days 
     2268     */ 
     2269    public function temp_gc() 
     2270    { 
     2271        $tmp = unslashify($this->config->get('temp_dir')); 
     2272        $expire = mktime() - 172800;  // expire in 48 hours 
     2273 
     2274        if ($dir = opendir($tmp)) { 
     2275            while (($fname = readdir($dir)) !== false) { 
     2276                if ($fname{0} == '.') { 
     2277                    continue; 
     2278                } 
     2279 
     2280                if (filemtime($tmp.'/'.$fname) < $expire) { 
     2281                    @unlink($tmp.'/'.$fname); 
     2282                } 
     2283            } 
     2284 
     2285            closedir($dir); 
     2286        } 
     2287    } 
     2288 
     2289 
     2290    /** 
     2291     * Garbage collector for cache entries. 
     2292     * Remove all expired message cache records 
     2293     */ 
     2294    public function cache_gc() 
     2295    { 
     2296        $db = $this->get_dbh(); 
     2297 
     2298        // get target timestamp 
     2299        $ts = get_offset_time($this->config->get('message_cache_lifetime', '30d'), -1); 
     2300 
     2301        $db->query("DELETE FROM ".get_table_name('cache_messages') 
     2302            ." WHERE changed < " . $db->fromunixtime($ts)); 
     2303 
     2304        $db->query("DELETE FROM ".get_table_name('cache_index') 
     2305            ." WHERE changed < " . $db->fromunixtime($ts)); 
     2306 
     2307        $db->query("DELETE FROM ".get_table_name('cache_thread') 
     2308            ." WHERE changed < " . $db->fromunixtime($ts)); 
     2309 
     2310        $db->query("DELETE FROM ".get_table_name('cache') 
     2311            ." WHERE created < " . $db->fromunixtime($ts)); 
     2312    } 
     2313 
    17562314} 
  • branches/devel-framework/roundcubemail/program/include/rcube_mdb2.php

    r5529 r5807  
    805805    } 
    806806 
    807 }  // end class rcube_db 
     807 
     808    /** 
     809     * Return correct name for a specific database table 
     810     * 
     811     * @param string $table Table name 
     812     * 
     813     * @return string Translated table name 
     814     */ 
     815    public function table_name($table) 
     816    { 
     817        $rcmail = rcmail::get_instance(); 
     818 
     819        // return table name if configured 
     820        $config_key = 'db_table_'.$table; 
     821 
     822        if ($name = $rcmail->config->get($config_key)) { 
     823            return $name; 
     824        } 
     825 
     826        return $table; 
     827    } 
     828 
     829 
     830    /** 
     831     * Return correct name for a specific database sequence 
     832     * (used for Postgres only) 
     833     * 
     834     * @param string $sequence Secuence name 
     835     * 
     836     * @return string Translated sequence name 
     837     */ 
     838    public function sequence_name($sequence) 
     839    { 
     840        $rcmail = rcmail::get_instance(); 
     841 
     842        // return sequence name if configured 
     843        $config_key = 'db_sequence_'.$sequence; 
     844 
     845        if ($name = $rcmail->config->get($config_key)) { 
     846            return $name; 
     847        } 
     848 
     849        return $sequence; 
     850    } 
     851 
     852} 
  • branches/devel-framework/roundcubemail/program/include/rcube_session.php

    r5521 r5807  
    320320  public function gc() 
    321321  { 
    322     foreach ($this->gc_handlers as $fct) 
     322    foreach ($this->gc_handlers as $fct) { 
    323323      call_user_func($fct); 
     324    } 
    324325  } 
    325326 
     
    330331   * @param mixed Callback function 
    331332   */ 
    332   public function register_gc_handler($func_name) 
    333   { 
    334     if ($func_name && !in_array($func_name, $this->gc_handlers)) 
    335       $this->gc_handlers[] = $func_name; 
     333  public function register_gc_handler($func) 
     334  { 
     335    foreach ($this->gc_handlers as $handler) { 
     336      if ($handler == $func) { 
     337        return; 
     338      } 
     339    } 
     340 
     341    $this->gc_handlers[] = $func; 
    336342  } 
    337343 
  • branches/devel-framework/roundcubemail/program/include/rcube_shared.inc

    r5776 r5807  
    2929 
    3030/** 
    31  * Send HTTP headers to prevent caching this page 
    32  */ 
    33 function send_nocacheing_headers() 
    34 { 
    35   global $OUTPUT; 
    36  
    37   if (headers_sent()) 
    38     return; 
    39  
    40   header("Expires: ".gmdate("D, d M Y H:i:s")." GMT"); 
    41   header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); 
    42   // Request browser to disable DNS prefetching (CVE-2010-0464) 
    43   header("X-DNS-Prefetch-Control: off"); 
    44  
    45   // We need to set the following headers to make downloads work using IE in HTTPS mode. 
    46   if ($OUTPUT->browser->ie && rcube_https_check()) { 
    47     header('Pragma: private'); 
    48     header("Cache-Control: private, must-revalidate"); 
    49   } else { 
    50     header("Cache-Control: private, no-cache, must-revalidate, post-check=0, pre-check=0"); 
    51     header("Pragma: no-cache"); 
    52   } 
    53 } 
    54  
    55  
    56 /** 
    57  * Send header with expire date 30 days in future 
    58  * 
    59  * @param int Expiration time in seconds 
    60  */ 
    61 function send_future_expire_header($offset=2600000) 
    62 { 
    63   if (headers_sent()) 
    64     return; 
    65  
    66   header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+$offset)." GMT"); 
    67   header("Cache-Control: max-age=$offset"); 
    68   header("Pragma: "); 
    69 } 
    70  
    71  
    72 /** 
    7331 * Similar function as in_array() but case-insensitive 
    7432 * 
     
    13896} 
    13997 
    140 /** 
    141  * Create a human readable string for a number of bytes 
    142  * 
    143  * @param int Number of bytes 
    144  * @return string Byte string 
    145  */ 
    146 function show_bytes($bytes) 
    147 { 
    148   if ($bytes >= 1073741824) 
    149   { 
    150     $gb = $bytes/1073741824; 
    151     $str = sprintf($gb>=10 ? "%d " : "%.1f ", $gb) . rcube_label('GB'); 
    152   } 
    153   else if ($bytes >= 1048576) 
    154   { 
    155     $mb = $bytes/1048576; 
    156     $str = sprintf($mb>=10 ? "%d " : "%.1f ", $mb) . rcube_label('MB'); 
    157   } 
    158   else if ($bytes >= 1024) 
    159     $str = sprintf("%d ",  round($bytes/1024)) . rcube_label('KB'); 
    160   else 
    161     $str = sprintf('%d ', $bytes) . rcube_label('B'); 
    162  
    163   return $str; 
    164 } 
    16598 
    16699/** 
    167100 * Wrapper function for wordwrap 
    168101 */ 
    169 function rc_wordwrap($string, $width=75, $break="\n", $cut=false) 
     102function rcube_wordwrap($string, $width=75, $break="\n", $cut=false) 
    170103{ 
    171104  $para = explode($break, $string); 
     
    215148} 
    216149 
     150 
    217151/** 
    218152 * Read a specific HTTP request header 
     
    222156 * @return mixed  Header value or null if not available 
    223157 */ 
    224 function rc_request_header($name) 
     158function rcube_request_header($name) 
    225159{ 
    226160  if (function_exists('getallheaders')) 
     
    346280 
    347281/** 
    348  * A method to guess the mime_type of an attachment. 
    349  * 
    350  * @param string $path      Path to the file. 
    351  * @param string $name      File name (with suffix) 
    352  * @param string $failover  Mime type supplied for failover. 
    353  * @param string $is_stream Set to True if $path contains file body 
    354  * 
    355  * @return string 
    356  * @author Till Klampaeckel <till@php.net> 
    357  * @see    http://de2.php.net/manual/en/ref.fileinfo.php 
    358  * @see    http://de2.php.net/mime_content_type 
    359  */ 
    360 function rc_mime_content_type($path, $name, $failover = 'application/octet-stream', $is_stream=false) 
    361 { 
    362     $mime_type = null; 
    363     $mime_magic = rcmail::get_instance()->config->get('mime_magic'); 
    364     $mime_ext = @include(RCMAIL_CONFIG_DIR . '/mimetypes.php'); 
    365     $suffix = $name ? substr($name, strrpos($name, '.')+1) : '*'; 
    366  
    367     // use file name suffix with hard-coded mime-type map 
    368     if (is_array($mime_ext)) { 
    369         $mime_type = $mime_ext[$suffix]; 
    370     } 
    371     // try fileinfo extension if available 
    372     if (!$mime_type && function_exists('finfo_open')) { 
    373         if ($finfo = finfo_open(FILEINFO_MIME, $mime_magic)) { 
    374             if ($is_stream) 
    375                 $mime_type = finfo_buffer($finfo, $path); 
    376             else 
    377                 $mime_type = finfo_file($finfo, $path); 
    378             finfo_close($finfo); 
    379         } 
    380     } 
    381     // try PHP's mime_content_type 
    382     if (!$mime_type && !$is_stream && function_exists('mime_content_type')) { 
    383       $mime_type = @mime_content_type($path); 
    384     } 
    385     // fall back to user-submitted string 
    386     if (!$mime_type) { 
    387         $mime_type = $failover; 
    388     } 
    389     else { 
    390         // Sometimes (PHP-5.3?) content-type contains charset definition, 
    391         // Remove it (#1487122) also "charset=binary" is useless 
    392         $mime_type = array_shift(preg_split('/[; ]/', $mime_type)); 
    393     } 
    394  
    395     return $mime_type; 
    396 } 
    397  
    398  
    399 /** 
    400  * Detect image type of the given binary data by checking magic numbers 
    401  * 
    402  * @param string  Binary file content 
    403  * @return string Detected mime-type or jpeg as fallback 
    404  */ 
    405 function rc_image_content_type($data) 
    406 { 
    407     $type = 'jpeg'; 
    408     if      (preg_match('/^\x89\x50\x4E\x47/', $data)) $type = 'png'; 
    409     else if (preg_match('/^\x47\x49\x46\x38/', $data)) $type = 'gif'; 
    410     else if (preg_match('/^\x00\x00\x01\x00/', $data)) $type = 'ico'; 
    411 //  else if (preg_match('/^\xFF\xD8\xFF\xE0/', $data)) $type = 'jpeg'; 
    412  
    413     return 'image/' . $type; 
    414 } 
    415  
    416  
    417 /** 
    418282 * Explode quoted string 
    419283 *  
     
    462326 
    463327/** 
     328 * Remove all non-ascii and non-word chars except ., -, _ 
     329 */ 
     330function asciiwords($str, $css_id = false, $replace_with = '') 
     331{ 
     332    $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : ''); 
     333    return preg_replace("/[^$allowed]/i", $replace_with, $str); 
     334} 
     335 
     336 
     337/** 
     338 * Remove single and double quotes from given string 
     339 * 
     340 * @param string Input value 
     341 * 
     342 * @return string Dequoted string 
     343 */ 
     344function strip_quotes($str) 
     345{ 
     346    return str_replace(array("'", '"'), '', $str); 
     347} 
     348 
     349 
     350/** 
     351 * Remove new lines characters from given string 
     352 * 
     353 * @param string Input value 
     354 * 
     355 * @return string Stripped string 
     356 */ 
     357function strip_newlines($str) 
     358{ 
     359    return preg_replace('/[\r\n]/', '', $str); 
     360} 
     361 
     362 
     363/** 
     364 * Improved equivalent to strtotime() 
     365 * 
     366 * @param string Date string 
     367 * 
     368 * @return int Unix timestamp 
     369 */ 
     370function rcube_strtotime($date) 
     371{ 
     372    // check for MS Outlook vCard date format YYYYMMDD 
     373    if (preg_match('/^([12][90]\d\d)([01]\d)(\d\d)$/', trim($date), $matches)) { 
     374        return mktime(0,0,0, intval($matches[2]), intval($matches[3]), intval($matches[1])); 
     375    } 
     376    else if (is_numeric($date)) { 
     377        return $date; 
     378    } 
     379 
     380    // support non-standard "GMTXXXX" literal 
     381    $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); 
     382 
     383    // if date parsing fails, we have a date in non-rfc format. 
     384    // remove token from the end and try again 
     385    while ((($ts = @strtotime($date)) === false) || ($ts < 0)) { 
     386        $d = explode(' ', $date); 
     387        array_pop($d); 
     388        if (!$d) { 
     389            break; 
     390        } 
     391        $date = implode(' ', $d); 
     392    } 
     393 
     394    return $ts; 
     395} 
     396 
     397 
     398/** 
     399 * Compose a valid representation of name and e-mail address 
     400 * 
     401 * @param string E-mail address 
     402 * @param string Person name 
     403 * 
     404 * @return string Formatted string 
     405 */ 
     406function format_email_recipient($email, $name='') 
     407{ 
     408    if ($name && $name != $email) { 
     409        // Special chars as defined by RFC 822 need to in quoted string (or escaped). 
     410        return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, trim($email)); 
     411    } 
     412 
     413    return trim($email); 
     414} 
     415 
     416 
     417/** 
    464418 * mbstring replacement functions 
    465419 */ 
    466  
    467420if (!extension_loaded('mbstring')) 
    468421{ 
     
    546499} 
    547500 
     501 
     502/* 
     503 * Idn_to_ascii wrapper. 
     504 * Intl/Idn modules version of this function doesn't work with e-mail address 
     505 */ 
     506function rcube_idn_to_ascii($str) 
     507{ 
     508    return rcube_idn_convert($str, true); 
     509} 
     510 
     511/* 
     512 * Idn_to_ascii wrapper. 
     513 * Intl/Idn modules version of this function doesn't work with e-mail address 
     514 */ 
     515function rcube_idn_to_utf8($str) 
     516{ 
     517    return rcube_idn_convert($str, false); 
     518} 
     519 
     520function rcube_idn_convert($input, $is_utf=false) 
     521{ 
     522    if ($at = strpos($input, '@')) { 
     523        $user   = substr($input, 0, $at); 
     524        $domain = substr($input, $at+1); 
     525    } 
     526    else { 
     527        $domain = $input; 
     528    } 
     529 
     530    $domain = $is_utf ? idn_to_ascii($domain) : idn_to_utf8($domain); 
     531 
     532    if ($domain === false) { 
     533        return ''; 
     534    } 
     535 
     536    return $at ? $user . '@' . $domain : $domain; 
     537} 
     538 
     539 
     540/** 
     541 * Use PHP5 autoload for dynamic class loading 
     542 * 
     543 * @todo Make Zend, PEAR etc play with this 
     544 * @todo Make our classes conform to a more straight forward CS. 
     545 */ 
     546function rcube_autoload($classname) 
     547{ 
     548    $filename = preg_replace( 
     549        array( 
     550            '/MDB2_(.+)/', 
     551            '/Mail_(.+)/', 
     552            '/Net_(.+)/', 
     553            '/Auth_(.+)/', 
     554            '/^html_.+/', 
     555            '/^utf8$/', 
     556        ), 
     557        array( 
     558            'MDB2/\\1', 
     559            'Mail/\\1', 
     560            'Net/\\1', 
     561            'Auth/\\1', 
     562            'html', 
     563            'utf8.class', 
     564        ), 
     565        $classname 
     566    ); 
     567 
     568    if ($fp = @fopen("$filename.php", 'r', true)) { 
     569        fclose($fp); 
     570        include_once("$filename.php"); 
     571        return true; 
     572    } 
     573 
     574    return false; 
     575} 
     576 
     577/** 
     578 * Local callback function for PEAR errors 
     579 */ 
     580function rcube_pear_error($err) 
     581{ 
     582    error_log(sprintf("%s (%s): %s", 
     583        $err->getMessage(), 
     584        $err->getCode(), 
     585        $err->getUserinfo()), 0); 
     586} 
Note: See TracChangeset for help on using the changeset viewer.