thomascube
2007-08-07 6d969b4d9020560d3491d19a5b0487e325e9bce4
Documentation, code style and cleanup

2 files added
13 files modified
1 files deleted
3732 ■■■■ changed files
.htaccess 2 ●●● patch | view | raw | blame | history
bin/makedoc.sh 18 ●●●●● patch | view | raw | blame | history
index.php 1 ●●●● patch | view | raw | blame | history
program/include/bugs.inc 90 ●●●● patch | view | raw | blame | history
program/include/cache.inc 106 ●●●●● patch | view | raw | blame | history
program/include/main.inc 515 ●●●● patch | view | raw | blame | history
program/include/rcmail_template.inc 308 ●●●●● patch | view | raw | blame | history
program/include/rcube_contacts.inc 9 ●●●● patch | view | raw | blame | history
program/include/rcube_db.inc 2 ●●● patch | view | raw | blame | history
program/include/rcube_html.inc 671 ●●●●● patch | view | raw | blame | history
program/include/rcube_imap.inc 377 ●●●●● patch | view | raw | blame | history
program/include/rcube_ldap.inc 41 ●●●●● patch | view | raw | blame | history
program/include/rcube_mdb2.inc 6 ●●●● patch | view | raw | blame | history
program/include/rcube_shared.inc 1523 ●●●● patch | view | raw | blame | history
program/include/rcube_smtp.inc 11 ●●●● patch | view | raw | blame | history
program/include/rcube_sqlite.inc 52 ●●●●● patch | view | raw | blame | history
.htaccess
@@ -4,7 +4,7 @@
php_value    error_log    logs/errors
php_value    upload_max_filesize    2M
<FilesMatch "(\.inc|\~)$|^_">
<FilesMatch "(\.inc|\~)$">
  Order allow,deny
  Deny from all
</FilesMatch>
bin/makedoc.sh
New file
@@ -0,0 +1,18 @@
#!/bin/bash
TITLE="RoundCube Classes"
PACKAGES="Core"
PATH_PROJECT=$PWD/program/include
PATH_DOCS=$PWD/doc/phpdoc
PATH_PHPDOC=/usr/local/php5/bin/phpdoc
OUTPUTFORMAT=HTML
CONVERTER=frames
TEMPLATE=earthli
PRIVATE=off
# make documentation
$PATH_PHPDOC -d $PATH_PROJECT -t $PATH_DOCS -ti "$TITLE" -dn $PACKAGES \
-o $OUTPUTFORMAT:$CONVERTER:$TEMPLATE -pp $PRIVATE
index.php
@@ -81,7 +81,6 @@
require_once('include/rcube_imap.inc');
require_once('include/bugs.inc');
require_once('include/main.inc');
require_once('include/cache.inc');
require_once('PEAR.php');
program/include/bugs.inc
@@ -4,8 +4,8 @@
 +-----------------------------------------------------------------------+
 | program/include/bugs.inc                                              |
 |                                                                       |
 | This file is part of the BQube Webmail client                         |
 | Copyright (C) 2005, BQube Dev - Switzerland                           |
 | This file is part of the RoudCube Webmail client                      |
 | Copyright (C) 2005-2007, RoudCube Dev - Switzerland                   |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | PURPOSE:                                                              |
@@ -20,19 +20,29 @@
*/
// throw system error and show error page
function raise_error($arg=array(), $log=FALSE, $terminate=FALSE)
/**
 * Error handling and logging functions
 *
 * @package Core
 */
/**
 * Throw system error and show error page
 *
 * @param array Named parameters
 *  - code: Error code (required)
 *  - type: Error type [php|db|imap|javascript] (required)
 *  - message: Error message
 *  - file: File where error occured
 *  - line: Line where error occured
 * @param boolean True to log the error
 * @param boolean Terminate script execution
 */
function raise_error($arg=array(), $log=false, $terminate=false)
  {
  global $__page_content, $CONFIG, $OUTPUT, $ERROR_CODE, $ERROR_MESSAGE;
  
  /* $arg keys:
       int     code
       string  type (php, xpath, db, imap, javascript)
       string  message
       sring   file
       int     line
  */
  // report bug (if not incompatible browser)
  if ($log && $arg['type'] && $arg['message'])
    log_bug($arg);
@@ -48,61 +58,53 @@
  }
// report error
/**
 * Report error according to configured debug_level
 *
 * @param array Named parameters
 * @see raise_error()
 */
function log_bug($arg_arr)
  {
{
  global $CONFIG, $INSTALL_PATH;
  $program = $arg_arr['type']=='xpath' ? 'XPath' : strtoupper($arg_arr['type']);
  // write error to local log file
  if ($CONFIG['debug_level'] & 1)
    {
    $log_entry = sprintf("[%s] %s Error: %s in %s on line %d\n",
                 date("d-M-Y H:i:s O", mktime()),
                 $program,
                 $arg_arr['message'],
                 $arg_arr['file'],
                 $arg_arr['line']);
  {
    $log_entry = sprintf(
      "[%s] %s Error: %s in %s on line %d\n",
      date("d-M-Y H:i:s O", mktime()),
      $program,
      $arg_arr['message'],
      $arg_arr['file'],
      $arg_arr['line']);
                 
    if (empty($CONFIG['log_dir']))
      $CONFIG['log_dir'] = $INSTALL_PATH.'logs';
      
    // try to open specific log file for writing
    if ($fp = @fopen($CONFIG['log_dir'].'/errors', 'a'))
      {
    {
      fwrite($fp, $log_entry);
      fclose($fp);
      }
    }
    else
      {
    {
      // send error to PHPs error handler
      trigger_error($arg_arr['message']);
      }
    }
  }
/*
  // resport the bug to the global bug reporting system
  if ($CONFIG['debug_level'] & 2)
    {
    $delm = '%AC';
    http_request(sprintf('http://roundcube.net/log/bug.php?_type=%s&_domain=%s&_server_ip=%s&_client_ip=%s&_useragent=%s&_url=%s%%3A//%s&_errors=%s%s%s%s%s',
                 $arg_arr['type'],
                 $GLOBALS['HTTP_HOST'],
                 $GLOBALS['SERVER_ADDR'],
                 $GLOBALS['REMOTE_ADDR'],
                 rawurlencode($GLOBALS['HTTP_USER_AGENT']),
                    $GLOBALS['SERVER_PORT']==43 ? 'https' : 'http',
                    $GLOBALS['HTTP_HOST'].$GLOBALS['REQUEST_URI'],
                    $arg_arr['file'], $delm,
                 $arg_arr['line'], $delm,
                 rawurlencode($arg_arr['message'])));
    }
*/
  {
    // TODO: Send error via HTTP
  }
  // show error if debug_mode is on
  if ($CONFIG['debug_level'] & 4)
    {
  {
    print "<b>$program Error";
    if (!empty($arg_arr['file']) && !empty($arg_arr['line']))
@@ -112,7 +114,7 @@
    print nl2br($arg_arr['message']);
    print '<br />';
    flush();
    }
  }
}
?>
program/include/cache.inc
File was deleted
program/include/main.inc
@@ -19,6 +19,13 @@
*/
/**
 * RoundCube Webmail common functions
 *
 * @package Core
 * @author Thomas Bruederli <roundcube@gmail.com>
 */
require_once('lib/des.inc');
require_once('lib/utf7.inc');
require_once('lib/utf8.class.php');
@@ -31,7 +38,12 @@
define('RCUBE_INPUT_GPC', 0x0103);
// register session and connect to server
/**
 * Initial startup function
 * to register session, create database and imap connections
 *
 * @param string Current task
 */
function rcmail_startup($task='mail')
  {
  global $sess_id, $sess_user_lang;
@@ -48,9 +60,11 @@
    ini_set('session.gc_maxlifetime', ($CONFIG['session_lifetime']) * 120);
  // prepare DB connection
  require_once('include/rcube_'.(empty($CONFIG['db_backend']) ? 'db' : $CONFIG['db_backend']).'.inc');
  $dbwrapper = empty($CONFIG['db_backend']) ? 'db' : $CONFIG['db_backend'];
  $dbclass = "rcube_" . $dbwrapper;
  require_once("include/$dbclass.inc");
  
  $DB = new rcube_db($CONFIG['db_dsnw'], $CONFIG['db_dsnr'], $CONFIG['db_persistent']);
  $DB = new $dbclass($CONFIG['db_dsnw'], $CONFIG['db_dsnr'], $CONFIG['db_persistent']);
  $DB->sqlite_initials = $INSTALL_PATH.'SQL/sqlite.initial.sql';
  $DB->db_connect('w');
@@ -101,7 +115,11 @@
  }
// load roundcube configuration into global var
/**
 * Load roundcube configuration array
 *
 * @return array Named configuration parameters
 */
function rcmail_load_config()
  {
  global $INSTALL_PATH;
@@ -139,7 +157,12 @@
  }
// load a host-specific config file if configured
/**
 * Load a host-specific config file if configured
 * This will merge the host specific configuration with the given one
 *
 * @param array Global configuration parameters
 */
function rcmail_load_host_config(&$config)
  {
  $fname = NULL;
@@ -157,7 +180,13 @@
  }
// create authorization hash
/**
 * Create unique authorization hash
 *
 * @param string Session ID
 * @param int Timestamp
 * @return string The generated auth hash
 */
function rcmail_auth_hash($sess_id, $ts)
  {
  global $CONFIG;
@@ -175,7 +204,11 @@
  }
// compare the auth hash sent by the client with the local session credentials
/**
 * Check the auth hash sent by the client against the local session credentials
 *
 * @return boolean True if valid, False if not
 */
function rcmail_authenticate_session()
  {
  global $CONFIG, $SESS_CLIENT_IP, $SESS_CHANGED;
@@ -206,7 +239,11 @@
  }
// create IMAP object and connect to server
/**
 * Create global IMAP object and connect to server
 *
 * @param boolean True if connection should be established
 */
function rcmail_imap_init($connect=FALSE)
  {
  global $CONFIG, $DB, $IMAP, $OUTPUT;
@@ -235,8 +272,10 @@
  }
// set root dir and last stored mailbox
// this must be done AFTER connecting to the server
/**
 * Set root dir and last stored mailbox
 * This must be done AFTER connecting to the server!
 */
function rcmail_set_imap_prop()
  {
  global $CONFIG, $IMAP;
@@ -255,7 +294,9 @@
  }
// do these things on script shutdown
/**
 * Do these things on script shutdown
 */
function rcmail_shutdown()
  {
  global $IMAP;
@@ -271,7 +312,9 @@
  }
// destroy session data and remove cookie
/**
 * Destroy session data and remove cookie
 */
function rcmail_kill_session()
  {
  // save user preferences
@@ -292,7 +335,12 @@
  }
// return correct name for a specific database table
/**
 * Return correct name for a specific database table
 *
 * @param string Table name
 * @return string Translated table name
 */
function get_table_name($table)
  {
  global $CONFIG;
@@ -307,8 +355,13 @@
  }
// return correct name for a specific database sequence
// (used for Postres only)
/**
 * Return correct name for a specific database sequence
 * (used for Postres only)
 *
 * @param string Secuence name
 * @return string Translated sequence name
 */
function get_sequence_name($sequence)
  {
  global $CONFIG;
@@ -323,7 +376,13 @@
  }
// check the given string and returns language properties
/**
 * Check the given string and returns language properties
 *
 * @param string Language code
 * @param string Peropert name
 * @return string Property value
 */
function rcube_language_prop($lang, $prop='lang')
  {
  global $INSTALL_PATH;
@@ -360,7 +419,11 @@
  }
  
// init output object for GUI and add common scripts
/**
 * Init output object for GUI and add common scripts.
 * This will instantiate a rcmail_template object and set
 * environment vars according to the current session and configuration
 */
function rcmail_load_gui()
  {
  global $CONFIG, $OUTPUT, $sess_user_lang;
@@ -399,7 +462,10 @@
  }
// set localization charset based on the given language
/**
 * Set localization charset based on the given language.
 * This also creates a global property for mbstring usage.
 */
function rcmail_set_locale($lang)
  {
  global $OUTPUT, $MBSTRING;
@@ -418,7 +484,11 @@
  }
// auto-select IMAP host based on the posted login information
/**
 * Auto-select IMAP host based on the posted login information
 *
 * @return string Selected IMAP host
 */
function rcmail_autoselect_host()
  {
  global $CONFIG;
@@ -446,7 +516,15 @@
  }
// perfom login to the IMAP server and to the webmail service
/**
 * Perfom login to the IMAP server and to the webmail service.
 * This will also create a new user entry if auto_create_user is configured.
 *
 * @param string IMAP user name
 * @param string IMAP password
 * @param string IMAP host
 * @return boolean True on success, False on failure
 */
function rcmail_login($user, $pass, $host=NULL)
  {
  global $CONFIG, $IMAP, $DB, $sess_user_lang;
@@ -575,7 +653,13 @@
  }
// create new entry in users and identities table
/**
 * Create new entry in users and identities table
 *
 * @param string User name
 * @param string IMAP host
 * @return mixed New user ID or False on failure
 */
function rcmail_create_user($user, $host)
{
  global $DB, $CONFIG, $IMAP;
@@ -646,7 +730,11 @@
}
// load virtuser table in array
/**
 * Load virtuser table in array
 *
 * @return array Virtuser table entries
 */
function rcmail_getvirtualfile()
  {
  global $CONFIG;
@@ -659,7 +747,12 @@
  }
// find matches of the given pattern in virtuser table
/**
 * Find matches of the given pattern in virtuser table
 *
 * @param string Regular expression to search for
 * @return array Matching entries
 */
function rcmail_findinvirtual($pattern)
  {
  $result = array();
@@ -682,7 +775,12 @@
  }
// resolve username with virtuser table
/**
 * Resolve username using a virtuser table
 *
 * @param string E-mail address to resolve
 * @return string Resolved IMAP username
 */
function rcmail_email2user($email)
  {
  $user = $email;
@@ -703,7 +801,12 @@
  }
// resolve e-mail address with virtuser table
/**
 * Resolve e-mail address from virtuser table
 *
 * @param string User name
 * @return string Resolved e-mail address
 */
function rcmail_user2email($user)
  {
  $email = "";
@@ -724,6 +827,12 @@
  } 
/**
 * Write the given user prefs to the user's record
 *
 * @param mixed User prefs to save
 * @return boolean True on success, False on failure
 */
function rcmail_save_user_prefs($a_user_prefs)
  {
  global $DB, $CONFIG, $sess_user_lang;
@@ -747,7 +856,11 @@
  }
// overwrite action variable
/**
 * Overwrite action variable
 *
 * @param string New action value
 */
function rcmail_overwrite_action($action)
  {
  global $OUTPUT;
@@ -789,7 +902,12 @@
  }
// encrypt IMAP password using DES encryption
/**
 * Encrypt IMAP password using DES encryption
 *
 * @param string Password to encrypt
 * @return string Encryprted string
 */
function encrypt_passwd($pass)
  {
  $cypher = des(get_des_key(), $pass, 1, 0, NULL);
@@ -797,7 +915,12 @@
  }
// decrypt IMAP password using DES encryption
/**
 * Decrypt IMAP password using DES encryption
 *
 * @param string Encrypted password
 * @return string Plain password
 */
function decrypt_passwd($cypher)
  {
  $pass = des(get_des_key(), base64_decode($cypher), 0, 0, NULL);
@@ -805,7 +928,11 @@
  }
// return a 24 byte key for the DES encryption
/**
 * Return a 24 byte key for the DES encryption
 *
 * @return string DES encryption key
 */
function get_des_key()
  {
  $key = !empty($GLOBALS['CONFIG']['des_key']) ? $GLOBALS['CONFIG']['des_key'] : 'rcmail?24BitPwDkeyF**ECB';
@@ -821,7 +948,11 @@
  }
// read directory program/localization/ and return a list of available languages
/**
 * Read directory program/localization and return a list of available languages
 *
 * @return array List of available localizations
 */
function rcube_list_languages()
  {
  global $CONFIG, $INSTALL_PATH;
@@ -848,7 +979,9 @@
  }
// add a localized label to the client environment
/**
 * Add a localized label to the client environment
 */
function rcube_add_label()
  {
  global $OUTPUT;
@@ -859,7 +992,10 @@
  }
// remove temp files older than two day
/**
 * Garbage collector function for temp files.
 * Remove temp files older than two days
 */
function rcmail_temp_gc()
  {
  $tmp = unslashify($CONFIG['temp_dir']);
@@ -881,7 +1017,10 @@
  }
// remove all expired message cache records
/**
 * Garbage collector for cache entries.
 * Remove all expired message cache records
 */
function rcmail_message_cache_gc()
  {
  global $DB, $CONFIG;
@@ -1054,8 +1193,11 @@
  }
  
/**
 * Quote a given string. Alias function for rep_specialchars_output
 * @see rep_specialchars_output
 * Quote a given string.
 * Shortcut function for rep_specialchars_output
 *
 * @return string HTML-quoted string
 * @see rep_specialchars_output()
 */
function Q($str, $mode='strict', $newlines=TRUE)
  {
@@ -1063,8 +1205,11 @@
  }
/**
 * Quote a given string. Alias function for rep_specialchars_output
 * @see rep_specialchars_output
 * Quote a given string for javascript output.
 * Shortcut function for rep_specialchars_output
 *
 * @return string JS-quoted string
 * @see rep_specialchars_output()
 */
function JQ($str)
  {
@@ -1116,16 +1261,24 @@
    return $value;
  }
/**
 * Remove single and double quotes from given string
 *
 * @param string Input value
 * @return string Dequoted string
 */
function strip_quotes($str)
{
  return preg_replace('/[\'"]/', '', $str);
}
/**
 * Remove new lines characters from given string
 *
 * @param string Input value
 * @return string Stripped string
 */
function strip_newlines($str)
{
@@ -1133,7 +1286,12 @@
}
// return boolean if a specific template exists
/**
 * Check if a specific template exists
 *
 * @param string Template name
 * @return boolean True if template exists
 */
function template_exists($name)
  {
  global $CONFIG;
@@ -1144,15 +1302,25 @@
  }
// Wrapper for rcmail_template::parse()
// @deprecated
/**
 * Wrapper for rcmail_template::parse()
 * @deprecated
 */
function parse_template($name='main', $exit=true)
  {
  $GLOBALS['OUTPUT']->parse($name, $exit);
  }
/**
 * Create a HTML table based on the given data
 *
 * @param  array  Named table attributes
 * @param  mixed  Table row data. Either a two-dimensional array or a valid SQL result set
 * @param  array  List of cols to show
 * @param  string Name of the identifier col
 * @return string HTML table code
 */
function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col)
  {
  global $DB;
@@ -1254,7 +1422,12 @@
  }
// return the mail domain configured for the given host
/**
 * Return the mail domain configured for the given host
 *
 * @param string IMAP host
 * @return string Resolved SMTP host
 */
function rcmail_mail_domain($host)
  {
  global $CONFIG;
@@ -1272,7 +1445,13 @@
  }
// compose a valid attribute string for HTML tags
/**
 * Compose a valid attribute string for HTML tags
 *
 * @param array Named tag attributes
 * @param array List of allowed attributes
 * @return string HTML formatted attribute string
 */
function create_attrib_string($attrib, $allowed_attribs=array('id', 'class', 'style'))
  {
  // allow the following attributes to be added to the <iframe> tag
@@ -1285,7 +1464,12 @@
  }
// convert a HTML attribute string attributes to an associative array (name => value)
/**
 * Convert a HTML attribute string attributes to an associative array (name => value)
 *
 * @param string Input string
 * @return array Key-value pairs of parsed attributes
 */
function parse_attrib_string($str)
  {
  $attrib = array();
@@ -1300,6 +1484,14 @@
  }
/**
 * Convert the given date to a human readable form
 * This uses the date formatting properties from config
 *
 * @param mixed Date representation (string or timestamp)
 * @param string Date format to use
 * @return string Formatted date string
 */
function format_date($date, $format=NULL)
  {
  global $CONFIG, $sess_user_lang;
@@ -1371,6 +1563,13 @@
  }
/**
 * Compose a valid representaion of name and e-mail address
 *
 * @param string E-mail address
 * @param string Person name
 * @return string Formatted string
 */
function format_email_recipient($email, $name='')
  {
  if ($name && $name != $email)
@@ -1379,206 +1578,6 @@
    return $email;
  }
// ************** functions delivering gui objects **************
function rcmail_message_container($attrib)
  {
  global $OUTPUT;
  if (!$attrib['id'])
    $attrib['id'] = 'rcmMessageContainer';
  // allow the following attributes to be added to the <table> tag
  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
  $out = '<div' . $attrib_str . "></div>";
  $OUTPUT->add_gui_object('message', $attrib['id']);
  return $out;
  }
// return the IMAP username of the current session
function rcmail_current_username($attrib)
  {
  global $DB;
  static $s_username;
  // alread fetched
  if (!empty($s_username))
    return $s_username;
  // get e-mail address form default identity
  $sql_result = $DB->query("SELECT email AS mailto
                            FROM ".get_table_name('identities')."
                            WHERE  user_id=?
                            AND    standard=1
                            AND    del<>1",
                            $_SESSION['user_id']);
  if ($DB->num_rows($sql_result))
    {
    $sql_arr = $DB->fetch_assoc($sql_result);
    $s_username = $sql_arr['mailto'];
    }
  else if (strstr($_SESSION['username'], '@'))
    $s_username = $_SESSION['username'];
  else
    $s_username = $_SESSION['username'].'@'.$_SESSION['imap_host'];
  return $s_username;
  }
// return code for the webmail login form
function rcmail_login_form($attrib)
  {
  global $CONFIG, $OUTPUT, $SESS_HIDDEN_FIELD;
  $labels = array();
  $labels['user'] = rcube_label('username');
  $labels['pass'] = rcube_label('password');
  $labels['host'] = rcube_label('server');
  $input_user = new textfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30, 'autocomplete' => 'off'));
  $input_pass = new passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30));
  $input_action = new hiddenfield(array('name' => '_action', 'value' => 'login'));
  $fields = array();
  $fields['user'] = $input_user->show(get_input_value('_user', RCUBE_INPUT_POST));
  $fields['pass'] = $input_pass->show();
  $fields['action'] = $input_action->show();
  if (is_array($CONFIG['default_host']))
    {
    $select_host = new select(array('name' => '_host', 'id' => 'rcmloginhost'));
    foreach ($CONFIG['default_host'] as $key => $value)
    {
      if (!is_array($value))
        $select_host->add($value, (is_numeric($key) ? $value : $key));
      else
        {
        unset($select_host);
        break;
        }
    }
    $fields['host'] = isset($select_host) ? $select_host->show($_POST['_host']) : null;
    }
  else if (!strlen($CONFIG['default_host']))
    {
    $input_host = new textfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30));
    $fields['host'] = $input_host->show($_POST['_host']);
    }
  $form_name = strlen($attrib['form']) ? $attrib['form'] : 'form';
  $form_start = !strlen($attrib['form']) ? '<form name="form" action="./" method="post">' : '';
  $form_end = !strlen($attrib['form']) ? '</form>' : '';
  if ($fields['host'])
    $form_host = <<<EOF
</tr><tr>
<td class="title"><label for="rcmloginhost">$labels[host]</label></td>
<td>$fields[host]</td>
EOF;
  $OUTPUT->add_gui_object('loginform', $form_name);
  $out = <<<EOF
$form_start
$SESS_HIDDEN_FIELD
$fields[action]
<table><tr>
<td class="title"><label for="rcmloginuser">$labels[user]</label></td>
<td>$fields[user]</td>
</tr><tr>
<td class="title"><label for="rcmloginpwd">$labels[pass]</label></td>
<td>$fields[pass]</td>
$form_host
</tr></table>
$form_end
EOF;
  return $out;
  }
function rcmail_charset_selector($attrib)
  {
  global $OUTPUT;
  // pass the following attributes to the form class
  $field_attrib = array('name' => '_charset');
  foreach ($attrib as $attr => $value)
    if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex')))
      $field_attrib[$attr] = $value;
  $charsets = array(
    'US-ASCII'     => 'ASCII (English)',
    'EUC-JP'       => 'EUC-JP (Japanese)',
    'EUC-KR'       => 'EUC-KR (Korean)',
    'BIG5'         => 'BIG5 (Chinese)',
    'GB2312'       => 'GB2312 (Chinese)',
    'ISO-2022-JP'  => 'ISO-2022-JP (Japanese)',
    'ISO-8859-1'   => 'ISO-8859-1 (Latin-1)',
    'ISO-8859-2'   => 'ISO-8895-2 (Central European)',
    'ISO-8859-7'   => 'ISO-8859-7 (Greek)',
    'ISO-8859-9'   => 'ISO-8859-9 (Turkish)',
    'Windows-1251' => 'Windows-1251 (Cyrillic)',
    'Windows-1252' => 'Windows-1252 (Western)',
    'Windows-1255' => 'Windows-1255 (Hebrew)',
    'Windows-1256' => 'Windows-1256 (Arabic)',
    'Windows-1257' => 'Windows-1257 (Baltic)',
    'UTF-8'        => 'UTF-8'
    );
  $select = new select($field_attrib);
  $select->add(array_values($charsets), array_keys($charsets));
  $set = $_POST['_charset'] ? $_POST['_charset'] : $OUTPUT->get_charset();
  return $select->show($set);
  }
// return code for search function
function rcmail_search_form($attrib)
  {
  global $OUTPUT;
  // add some labels to client
  rcube_add_label('searching');
  $attrib['name'] = '_q';
  if (empty($attrib['id']))
    $attrib['id'] = 'rcmqsearchbox';
  $input_q = new textfield($attrib);
  $out = $input_q->show();
  $OUTPUT->add_gui_object('qsearchbox', $attrib['id']);
  // add form tag around text field
  if (empty($attrib['form']))
    $out = sprintf(
      '<form name="rcmqsearchform" action="./" '.
      'onsubmit="%s.command(\'search\');return false" style="display:inline;">%s</form>',
      JS_OBJECT_NAME,
      $out);
  return $out;
  }
/****** debugging functions ********/
@@ -1637,6 +1636,9 @@
  }
/**
 * @access private
 */
function rcube_timer()
  {
  list($usec, $sec) = explode(" ", microtime());
@@ -1644,6 +1646,9 @@
  }
  
/**
 * @access private
 */
function rcube_print_time($timer, $label='Timer')
  {
  static $print_count = 0;
@@ -1659,7 +1664,12 @@
  }
// return the mailboxlist in HTML
/**
 * Return the mailboxlist in HTML
 *
 * @param array Named parameters
 * @return string HTML code for the gui object
 */
function rcmail_mailbox_list($attrib)
  {
  global $IMAP, $CONFIG, $OUTPUT, $COMM_PATH;
@@ -1729,7 +1739,10 @@
// create a hierarchical array of the mailbox list
/**
 * Create a hierarchical array of the mailbox list
 * @access private
 */
function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='')
  {
  $pos = strpos($folder, $delm);
@@ -1758,7 +1771,10 @@
  }
  
// return html for a structured list <ul> for the mailbox tree
/**
 * Return html for a structured list &lt;ul&gt; for the mailbox tree
 * @access private
 */
function rcmail_render_folder_tree_html(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0)
  {
  global $COMM_PATH, $IMAP, $CONFIG, $OUTPUT;
@@ -1839,7 +1855,10 @@
  }
// return html for a flat list <select> for the mailbox tree
/**
 * Return html for a flat list <select> for the mailbox tree
 * @access private
 */
function rcmail_render_folder_tree_select(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0)
  {
  global $IMAP, $OUTPUT;
program/include/rcmail_template.inc
@@ -10,7 +10,7 @@
 |                                                                       |
 | PURPOSE:                                                              |
 |   Class to handle HTML page output using a skin template.             |
 |   Extends rcube_html_page class from rcube_shared.inc                 |
 |   Extends rcube_html_page class from rcube_html.inc                   |
 |                                                                       |
 +-----------------------------------------------------------------------+
 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
@@ -20,9 +20,19 @@
*/
require_once('include/rcube_shared.inc');
/**
 * Classes and functions for HTML output
 *
 * @package View
 */
require_once('include/rcube_html.inc');
/**
 * Class to create HTML page output using a skin template
 */
class rcmail_template extends rcube_html_page
{
  var $config;
@@ -36,11 +46,14 @@
  var $object_handlers = array();
  // PHP 5 constructor
  /**
   * Constructor
   *
   * @param array Configuration array
   * @param string Current task
   */
  function __construct(&$config, $task)
  {
    parent::__construct();
    $this->task = $task;
    $this->config = $config;
    $this->ajax_call = !empty($_GET['_remote']) || !empty($_POST['_remote']);
@@ -61,7 +74,10 @@
    }
  }
  // PHP 4 compatibility
  /**
   * PHP 4 compatibility
   * @see rcmail_template::__construct()
   */
  function rcmail_template(&$config, $task)
  {
    $this->__construct($config, $task);
@@ -70,6 +86,10 @@
  
  /**
   * Set environment variable
   *
   * @param string Property name
   * @param mixed Property value
   * @param boolean True if this property should be added to client environment
   */
  function set_env($name, $value, $addtojs=true)
  {
@@ -135,6 +155,10 @@
  /**
   * Invoke display_message command
   *
   * @param string Message to display
   * @param string Message type [notice|confirm|error]
   * @param array Key-value pairs to be replaced in localized text
   */
  function show_message($message, $type='notice', $vars=NULL)
  {
@@ -211,7 +235,10 @@
  
  
  /**
   * @override
   * Process template and write to stdOut
   *
   * @param string HTML template
   * @see rcube_html_page::write()
   */
  function write($template='')
  {
@@ -273,7 +300,7 @@
  /**
   * Return executable javascript code for all registered commands
   * @private
   * @access private
   */
  function get_js_commands()
  {
@@ -300,6 +327,7 @@
  
  /**
   * Make URLs starting with a slash point to skin directory
   * @access private
   */
  function abs_url($str)
  {
@@ -311,8 +339,9 @@
  /*****  Template parsing methods  *****/
  
  /**
   * Replace all strings ($varname) with the content
   * of the according global variable.
   * Replace all strings ($varname)
   * with the content of the according global variable.
   * @access private
   */
  function parse_with_globals($input)
  {
@@ -323,6 +352,7 @@
  
  /**
   * Parse for conditional tags
   * @access private
   */
  function parse_conditions($input)
  {
@@ -361,6 +391,7 @@
   * Determines if a given condition is met
   *
   * @return True if condition is valid, False is not
   * @access private
   */
  function check_condition($condition)
  {
@@ -379,6 +410,7 @@
   *
   * @param string Input string to parse
   * @return Altered input string
   * @access private
   */
  function parse_xml($input)
  {
@@ -392,9 +424,10 @@
   * @param string Tag command: object,button,label, etc.
   * @param string Attribute string
   * @return Tag/Object content string
   * @access private
   */
  function xml_command($command, $str_attrib, $add_attrib=array())
    {
  {
    $command = strtolower($command);
    $attrib = parse_attrib_string($str_attrib) + $add_attrib;
@@ -437,16 +470,16 @@
          return call_user_func($this->object_handlers[$object], $attrib);
        else if ($object=='productname')
          {
        {
          $name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail';
          return Q($name);
          }
        }
        else if ($object=='version')
          {
        {
          return (string)RCMAIL_VERSION;
          }
        }
        else if ($object=='pagetitle')
          {
        {
          $task = $this->task;
          $title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '';
@@ -458,13 +491,13 @@
            $title .= ucfirst($task);
          return Q($title);
          }
        }
        break;
      }
    return '';
    }
  }
  /**
@@ -472,9 +505,10 @@
   *
   * @param array Button attributes
   * @return HTML button
   * @access private
   */
  function button($attrib)
    {
  {
    global $CONFIG, $OUTPUT, $BROWSER, $MAIN_TASKS;
    static $sa_buttons = array();
    static $s_button_count = 100;
@@ -626,6 +660,238 @@
    return $out;
  }
}
}  // end class rcmail_template
?>
// ************** common functions delivering gui objects **************
/**
 * Builder for GUI object 'message'
 *
 * @param array Named tag parameters
 * @return string HTML code for the gui object
 */
function rcmail_message_container($attrib)
  {
  global $OUTPUT;
  if (!$attrib['id'])
    $attrib['id'] = 'rcmMessageContainer';
  // allow the following attributes to be added to the <table> tag
  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
  $out = '<div' . $attrib_str . "></div>";
  $OUTPUT->add_gui_object('message', $attrib['id']);
  return $out;
  }
/**
 * GUI object 'username'
 * Showing IMAP username of the current session
 *
 * @param array Named tag parameters (currently not used)
 * @return string HTML code for the gui object
 */
function rcmail_current_username($attrib)
  {
  global $DB;
  static $s_username;
  // alread fetched
  if (!empty($s_username))
    return $s_username;
  // get e-mail address form default identity
  $sql_result = $DB->query(
    "SELECT email AS mailto
     FROM ".get_table_name('identities')."
     WHERE  user_id=?
     AND    standard=1
     AND    del<>1",
    $_SESSION['user_id']);
  if ($DB->num_rows($sql_result))
    {
    $sql_arr = $DB->fetch_assoc($sql_result);
    $s_username = $sql_arr['mailto'];
    }
  else if (strstr($_SESSION['username'], '@'))
    $s_username = $_SESSION['username'];
  else
    $s_username = $_SESSION['username'].'@'.$_SESSION['imap_host'];
  return $s_username;
  }
/**
 * GUI object 'loginform'
 * Returns code for the webmail login form
 *
 * @param array Named parameters
 * @return string HTML code for the gui object
 */
function rcmail_login_form($attrib)
  {
  global $CONFIG, $OUTPUT, $SESS_HIDDEN_FIELD;
  $labels = array();
  $labels['user'] = rcube_label('username');
  $labels['pass'] = rcube_label('password');
  $labels['host'] = rcube_label('server');
  $input_user = new textfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30, 'autocomplete' => 'off'));
  $input_pass = new passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30));
  $input_action = new hiddenfield(array('name' => '_action', 'value' => 'login'));
  $fields = array();
  $fields['user'] = $input_user->show(get_input_value('_user', RCUBE_INPUT_POST));
  $fields['pass'] = $input_pass->show();
  $fields['action'] = $input_action->show();
  if (is_array($CONFIG['default_host']))
    {
    $select_host = new select(array('name' => '_host', 'id' => 'rcmloginhost'));
    foreach ($CONFIG['default_host'] as $key => $value)
    {
      if (!is_array($value))
        $select_host->add($value, (is_numeric($key) ? $value : $key));
      else
        {
        unset($select_host);
        break;
        }
    }
    $fields['host'] = isset($select_host) ? $select_host->show($_POST['_host']) : null;
    }
  else if (!strlen($CONFIG['default_host']))
    {
    $input_host = new textfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30));
    $fields['host'] = $input_host->show($_POST['_host']);
    }
  $form_name = strlen($attrib['form']) ? $attrib['form'] : 'form';
  $form_start = !strlen($attrib['form']) ? '<form name="form" action="./" method="post">' : '';
  $form_end = !strlen($attrib['form']) ? '</form>' : '';
  if ($fields['host'])
    $form_host = <<<EOF
</tr><tr>
<td class="title"><label for="rcmloginhost">$labels[host]</label></td>
<td>$fields[host]</td>
EOF;
  $OUTPUT->add_gui_object('loginform', $form_name);
  $out = <<<EOF
$form_start
$SESS_HIDDEN_FIELD
$fields[action]
<table><tr>
<td class="title"><label for="rcmloginuser">$labels[user]</label></td>
<td>$fields[user]</td>
</tr><tr>
<td class="title"><label for="rcmloginpwd">$labels[pass]</label></td>
<td>$fields[pass]</td>
$form_host
</tr></table>
$form_end
EOF;
  return $out;
  }
/**
 * GUI object 'charsetselector'
 *
 * @param array Named parameters for the select tag
 * @return string HTML code for the gui object
 */
function rcmail_charset_selector($attrib)
  {
  global $OUTPUT;
  // pass the following attributes to the form class
  $field_attrib = array('name' => '_charset');
  foreach ($attrib as $attr => $value)
    if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex')))
      $field_attrib[$attr] = $value;
  $charsets = array(
    'US-ASCII'     => 'ASCII (English)',
    'EUC-JP'       => 'EUC-JP (Japanese)',
    'EUC-KR'       => 'EUC-KR (Korean)',
    'BIG5'         => 'BIG5 (Chinese)',
    'GB2312'       => 'GB2312 (Chinese)',
    'ISO-2022-JP'  => 'ISO-2022-JP (Japanese)',
    'ISO-8859-1'   => 'ISO-8859-1 (Latin-1)',
    'ISO-8859-2'   => 'ISO-8895-2 (Central European)',
    'ISO-8859-7'   => 'ISO-8859-7 (Greek)',
    'ISO-8859-9'   => 'ISO-8859-9 (Turkish)',
    'Windows-1251' => 'Windows-1251 (Cyrillic)',
    'Windows-1252' => 'Windows-1252 (Western)',
    'Windows-1255' => 'Windows-1255 (Hebrew)',
    'Windows-1256' => 'Windows-1256 (Arabic)',
    'Windows-1257' => 'Windows-1257 (Baltic)',
    'UTF-8'        => 'UTF-8'
    );
  $select = new select($field_attrib);
  $select->add(array_values($charsets), array_keys($charsets));
  $set = $_POST['_charset'] ? $_POST['_charset'] : $OUTPUT->get_charset();
  return $select->show($set);
  }
/**
 * GUI object 'searchform'
 * Returns code for search function
 *
 * @param array Named parameters
 * @return string HTML code for the gui object
 */
function rcmail_search_form($attrib)
  {
  global $OUTPUT;
  // add some labels to client
  rcube_add_label('searching');
  $attrib['name'] = '_q';
  if (empty($attrib['id']))
    $attrib['id'] = 'rcmqsearchbox';
  $input_q = new textfield($attrib);
  $out = $input_q->show();
  $OUTPUT->add_gui_object('qsearchbox', $attrib['id']);
  // add form tag around text field
  if (empty($attrib['form']))
    $out = sprintf(
      '<form name="rcmqsearchform" action="./" '.
      'onsubmit="%s.command(\'search\');return false" style="display:inline;">%s</form>',
      JS_OBJECT_NAME,
      $out);
  return $out;
  }
?>
program/include/rcube_contacts.inc
@@ -19,6 +19,12 @@
*/
/**
 * Model class for the local address book database
 *
 * @package Addressbook
 */
class rcube_contacts
{
  var $db = null;
@@ -55,7 +61,7 @@
  /**
   * PHP 4 object constructor
   *
   * @see  rcube_contacts::__construct
   * @see rcube_contacts::__construct()
   */
  function rcube_contacts($dbconn, $user)
  {
@@ -125,6 +131,7 @@
   * List the current set of contact records
   *
   * @param  array  List of cols to show
   * @param  int    Only return this number of records, use negative values for tail
   * @return array  Indexed list of contact records, each a hash array
   */
  function list_records($cols=null, $subset=0)
program/include/rcube_db.inc
@@ -33,7 +33,7 @@
 *
 * This is a wrapper for the PEAR::DB class
 *
 * @package    RoundCube Webmail
 * @package    Database
 * @author     David Saez Padros <david@ols.es>
 * @author     Thomas Bruederli <roundcube@gmail.com>
 * @version    1.17
program/include/rcube_html.inc
New file
@@ -0,0 +1,671 @@
<?php
/*
 +-----------------------------------------------------------------------+
 | rcube_html.inc                                                        |
 |                                                                       |
 | This file is part of the RoundCube PHP suite                          |
 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | CONTENTS:                                                             |
 |   Common Classes to create HTML output                                |
 |                                                                       |
 +-----------------------------------------------------------------------+
 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
 +-----------------------------------------------------------------------+
 $Id:  $
*/
/**
 * HTML page builder class
 *
 * @package HTML
 */
class rcube_html_page
{
  var $scripts_path = '';
  var $script_files = array();
  var $scripts = array();
  var $charset = 'UTF-8';
  var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
  var $script_tag      = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
  var $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
  var $title = 'RoundCube Mail';
  var $header = '';
  var $footer = '';
  var $body = '';
  var $body_attrib = array();
  var $meta_tags = array();
  /**
   * Link an external script file
   *
   * @param string File URL
   * @param string Target position [head|foot]
   */
  function include_script($file, $position='head')
  {
    static $sa_files = array();
    if (in_array($file, $sa_files))
      return;
    if (!is_array($this->script_files[$position]))
      $this->script_files[$position] = array();
    $this->script_files[$position][] = $file;
  }
  /**
   * Add inline javascript code
   *
   * @param string JS code snippet
   * @param string Target position [head|head_top|foot]
   */
  function add_script($script, $position='head')
  {
    if (!isset($this->scripts[$position]))
      $this->scripts[$position] = "\n".rtrim($script);
    else
      $this->scripts[$position] .= "\n".rtrim($script);
  }
  /**
   * Add HTML code to the page header
   */
  function add_header($str)
  {
    $this->header .= "\n".$str;
  }
  /**
   * Add HTML code to the page footer
   * To be added right befor </body>
   */
  function add_footer($str)
  {
    $this->footer .= "\n".$str;
  }
  /**
   * Setter for page title
   */
  function set_title($t)
  {
    $this->title = $t;
  }
  /**
   * Setter for output charset.
   * To be specified in a meta tag and sent as http-header
   */
  function set_charset($charset)
  {
    global $MBSTRING;
    $this->charset = $charset;
    if ($MBSTRING && function_exists("mb_internal_encoding"))
      {
      if(!@mb_internal_encoding($charset))
        $MBSTRING = FALSE;
      }
  }
  /**
   * Getter for output charset
   */
  function get_charset()
  {
    return $this->charset;
  }
  /**
   * Reset all saved properties
   */
  function reset()
  {
    $this->script_files = array();
    $this->scripts = array();
    $this->title = '';
    $this->header = '';
    $this->footer = '';
  }
  /**
   * Process template and write to stdOut
   *
   * @param string HTML template
   * @param string Base for absolute paths
   */
  function write($templ='', $base_path='')
  {
    $output = empty($templ) ? $this->default_template : trim($templ);
    // replace specialchars in content
    $__page_title = Q($this->title, 'show', FALSE);
    $__page_header = $__page_body = $__page_footer = '';
    // include meta tag with charset
    if (!empty($this->charset))
    {
      header('Content-Type: text/html; charset='.$this->charset, true);
      $__page_header = '<meta http-equiv="content-type" content="text/html; charset='.$this->charset.'" />'."\n";
    }
    // definition of the code to be placed in the document header and footer
    if (is_array($this->script_files['head']))
      foreach ($this->script_files['head'] as $file)
        $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file);
    $head_script = $this->scripts['head_top'] . $this->scripts['head'];
    if (!empty($head_script))
      $__page_header .= sprintf($this->script_tag, $head_script);
    if (!empty($this->header))
      $__page_header .= $this->header;
    if (is_array($this->script_files['foot']))
      foreach ($this->script_files['foot'] as $file)
        $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file);
    if (!empty($this->scripts['foot']))
      $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']);
    if (!empty($this->footer))
      $__page_footer .= $this->footer;
    // find page header
    if ($hpos = strpos(strtolower($output), '</head>'))
      $__page_header .= "\n";
    else
    {
      if (!is_numeric($hpos))
        $hpos = strpos(strtolower($output), '<body');
      if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html')))
      {
        while($output[$hpos]!='>')
          $hpos++;
        $hpos++;
      }
      $__page_header = "<head>\n<title>$__page_title</title>\n$__page_header\n</head>\n";
    }
    // add page hader
    if ($hpos)
      $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output));
    else
      $output = $__page_header . $output;
    // find page body
    if($bpos = strpos(strtolower($output), '<body'))
    {
      while($output[$bpos]!='>') $bpos++;
      $bpos++;
    }
    else
      $bpos = strpos(strtolower($output), '</head>')+7;
    // add page body
    if($bpos && $__page_body)
      $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output));
    // find and add page footer
    $output_lc = strtolower($output);
    if(($fpos = strrstr($output_lc, '</body>')) ||
       ($fpos = strrstr($output_lc, '</html>')))
      $output = substr($output, 0, $fpos) . "$__page_footer\n" . substr($output, $fpos);
    else
      $output .= "\n$__page_footer";
    // reset those global vars
    $__page_header = $__page_footer = '';
    // correct absolute paths in images and other tags
    $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output);
    $output = str_replace('$__skin_path', $base_path, $output);
    print rcube_charset_convert($output, 'UTF-8', $this->charset);
  }
}  // end class rcube_html_page
/**
 * Base class to build a HTML for element
 *
 * @package HTML
 */
class rcube_form_element
  {
  var $uppertags = FALSE;
  var $upperattribs = FALSE;
  var $upperprops = FALSE;
  var $newline = FALSE;
  var $attrib = array();
  /**
   * Create string with saved attributes
   *
   * @return string HTML formatted tag attributes
   */
  function create_attrib_string()
  {
    if (!sizeof($this->attrib))
      return '';
    if ($this->name!='')
      $this->attrib['name'] = $this->name;
    $attrib_arr = array();
    foreach ($this->attrib as $key => $value)
    {
      // don't output some internally used attributes
      if (in_array($key, array('form', 'quicksearch')))
        continue;
      // skip if size if not numeric
      if (($key=='size' && !is_numeric($value)))
        continue;
      // skip empty eventhandlers
      if ((strpos($key,'on')===0 && $value==''))
        continue;
      // encode textarea content
      if ($key=='value')
        $value = Q($value, 'strict', FALSE);
      // attributes with no value
      if (in_array($key, array('checked', 'multiple', 'disabled', 'selected')))
      {
        if ($value)
          $attrib_arr[] = $key;
      }
      // don't convert size of value attribute
      else if ($key=='value')
        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $value, 'value');
      // regular tag attributes
      else
        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case($value, 'value'));
    }
    return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
  }
  /**
   * Convert tags and attributes to upper-/lowercase
   *
   * @param string Input string
   * @param string Value type (can either be "tag" or "attrib")
   * @return string Converted output string
   * @access private
   */
  function _conv_case($str, $type='attrib')
    {
    if ($type == 'tag')
      return $this->uppertags ? strtoupper($str) : strtolower($str);
    else if ($type == 'attrib')
      return $this->upperattribs ? strtoupper($str) : strtolower($str);
    else if ($type == 'value')
      return $this->upperprops ? strtoupper($str) : strtolower($str);
    }
  }
/**
 * Builder for an <input> field
 *
 * @package HTML
 */
class input_field extends rcube_form_element
{
  var $type = 'text';
  /**
   * Constructor
   * @param array Named tag attributes
   */
  function input_field($attrib=array())
  {
    if (is_array($attrib))
      $this->attrib = $attrib;
    if ($attrib['type'])
      $this->type = $attrib['type'];
    if ($attrib['newline'])
      $this->newline = TRUE;
  }
  /**
   * Compose input tag
   *
   * @param string Field value
   * @param array  Additional tag attributes
   * @return string Final HTML code
   */
  function show($value=NULL, $attrib=NULL)
  {
    // overwrite object attributes
    if (is_array($attrib))
      $this->attrib = array_merge($this->attrib, $attrib);
    // set value attribute
    if ($value!==NULL)
      $this->attrib['value'] = $value;
    $this->attrib['type'] = $this->type;
    // return final tag
    return sprintf(
      '<%s%s />%s',
      $this->_conv_case('input', 'tag'),
      $this->create_attrib_string(),
      ($this->newline ? "\n" : ""));
  }
}
/**
 * Builder for a <input type="text"> field
 *
 * @package HTML
 */
class textfield extends input_field
{
  var $type = 'text';
}
/**
 * Builder for a <input type="password"> field
 *
 * @package HTML
 */
class passwordfield extends input_field
{
  var $type = 'password';
}
/**
 * Builder for <input type="radio"> fields
 *
 * @package HTML
 */
class radiobutton extends input_field
{
  var $type = 'radio';
}
/**
 * Builder for <input type="checkbox"> fields
 *
 * @package HTML
 */
class checkbox extends input_field
{
  var $type = 'checkbox';
  /**
   * Compose input tag
   *
   * @param string Field value
   * @param array  Additional tag attributes
   * @return string Final HTML code
   */
  function show($value='', $attrib=NULL)
  {
    // overwrite object attributes
    if (is_array($attrib))
      $this->attrib = array_merge($this->attrib, $attrib);
    $this->attrib['type'] = $this->type;
    if ($value && (string)$value==(string)$this->attrib['value'])
      $this->attrib['checked'] = TRUE;
    else
      $this->attrib['checked'] = FALSE;
    // return final tag
    return sprintf(
      '<%s%s />%s',
      $this->_conv_case('input', 'tag'),
      $this->create_attrib_string(),
      ($this->newline ? "\n" : ""));
  }
}
/**
 * Builder for a <textarea> field
 *
 * @package HTML
 */
class textarea extends rcube_form_element
  {
  /**
   * Constructor
   * @param array Named tag attributes
   */
  function textarea($attrib=array())
  {
    $this->attrib = $attrib;
    if ($attrib['newline'])
      $this->newline = TRUE;
  }
  /**
   * Create HTML representation for this field
   *
   * @param string Field value
   * @param array  Additional tag attributes
   * @return string Final HTML code
   */
  function show($value='', $attrib=NULL)
  {
    // overwrite object attributes
    if (is_array($attrib))
      $this->attrib = array_merge($this->attrib, $attrib);
    // take value attribute as content
    if ($value=='')
      $value = $this->attrib['value'];
    // make shure we don't print the value attribute
    if (isset($this->attrib['value']))
      unset($this->attrib['value']);
    if (!empty($value) && !isset($this->attrib['mce_editable']))
      $value = Q($value, 'strict', FALSE);
    // return final tag
    return sprintf(
      '<%s%s>%s</%s>%s',
      $this->_conv_case('textarea', 'tag'),
      $this->create_attrib_string(),
      $value,
      $this->_conv_case('textarea', 'tag'),
      ($this->newline ? "\n" : ""));
  }
}
/**
 * Builder for group of hidden form fields
 *
 * @package HTML
 */
class hiddenfield extends rcube_form_element
{
  var $fields_arr = array();
  var $newline = TRUE;
  /**
   * Constructor
   *
   * @param array Named tag attributes
   */
  function hiddenfield($attrib=NULL)
  {
    if (is_array($attrib))
      $this->add($attrib);
  }
  /**
   * Add a hidden field to this instance
   * @param array Named tag attributes
   */
  function add($attrib)
  {
    $this->fields_arr[] = $attrib;
  }
  /**
   * Create HTML code for the hidden fields
   *
   * @return string Final HTML code
   */
  function show()
  {
    $out = '';
    foreach ($this->fields_arr as $attrib)
    {
      $this->attrib = $attrib;
      $this->attrib['type'] = 'hidden';
      $out .= sprintf(
        '<%s%s />%s',
        $this->_conv_case('input', 'tag'),
        $this->create_attrib_string(),
        ($this->newline ? "\n" : ""));
    }
    return $out;
  }
}
/**
 * Builder for HTML drop-down menus
 * Syntax:<pre>
 * // create instance. arguments are used to set attributes of select-tag
 * $select = new select(array('name' => 'fieldname'));
 *
 * // add one option
 * $select->add('Switzerland', 'CH');
 *
 * // add multiple options
 * $select->add(array('Switzerland','Germany'), array('CH','DE'));
 *
 * // generate pulldown with selection 'Switzerland'  and return html-code
 * // as second argument the same attributes available to instanciate can be used
 * print $select->show('CH');
 * </pre>
 *
 * @package HTML
 */
class select extends rcube_form_element
{
  var $options = array();
  /**
   * Constructor
   *
   * @param array Named tag attributes
   */
  function select($attrib=NULL)
  {
    if (is_array($attrib))
      $this->attrib = $attrib;
    if ($attrib['newline'])
      $this->newline = TRUE;
  }
  /**
   * Add one ore more menu options
   *
   * @param mixed Array with names or single option name
   * @param mixed Array with values or single option value
   */
  function add($names, $values=NULL)
  {
    if (is_array($names))
    {
      foreach ($names as $i => $text)
        $this->options[] = array('text' => $text, 'value' => (string)$values[$i]);
    }
    else
      $this->options[] = array('text' => $names, 'value' => (string)$values);
  }
  /**
   * Generate HTML code for this drop-down menu
   *
   * @param string Value of the selected option
   * @param array Additional tag attributes
   * @return string Final HTML code
   */
  function show($select=array(), $attrib=NULL)
  {
    $options_str = "\n";
    $value_str = $this->_conv_case(' value="%s"', 'attrib');
    if (!is_array($select))
      $select = array((string)$select);
    foreach ($this->options as $option)
    {
      $selected = ((isset($option['value']) &&
                    in_array($option['value'], $select, TRUE)) ||
                   (in_array($option['text'], $select, TRUE))) ?
        $this->_conv_case(' selected', 'attrib') : '';
      $options_str .= sprintf("<%s%s%s>%s</%s>\n",
                             $this->_conv_case('option', 'tag'),
                             !empty($option['value']) ? sprintf($value_str, Q($option['value'])) : '',
                             $selected,
                             Q($option['text'], 'strict', FALSE),
                             $this->_conv_case('option', 'tag'));
    }
    // return final tag
    return sprintf('<%s%s>%s</%s>%s',
                   $this->_conv_case('select', 'tag'),
                   $this->create_attrib_string(),
                   $options_str,
                   $this->_conv_case('select', 'tag'),
                   ($this->newline ? "\n" : ""));
  }
}
?>
program/include/rcube_imap.inc
@@ -21,7 +21,7 @@
*/
/**
/*
 * Obtain classes from the Iloha IMAP library
 */
require_once('lib/imap.inc');
@@ -33,13 +33,13 @@
 *
 * This is a wrapper that implements the Iloha IMAP Library (IIL)
 *
 * @package    RoundCube Webmail
 * @package    Mail
 * @author     Thomas Bruederli <roundcube@gmail.com>
 * @version    1.36
 * @link       http://ilohamail.org
 */
class rcube_imap
  {
{
  var $db;
  var $conn;
  var $root_ns = '';
@@ -70,7 +70,7 @@
  /**
   * Object constructor
   *
   * @param  object  Database connection
   * @param object DB Database connection
   */
  function __construct($db_conn)
    {
@@ -294,6 +294,7 @@
  /**
   * Return the saved search set as hash array
   * @return array Search set
   */
  function get_search_set()
    {
@@ -382,8 +383,8 @@
   * Private method for mailbox listing
   *
   * @return  array   List of mailboxes/folders
   * @see     rcube_imap::list_mailboxes()
   * @access  private
   * @see     rcube_imap::list_mailboxes
   */
  function _list_mailboxes($root='', $filter='*')
    {
@@ -413,8 +414,8 @@
   * @param   string   Mailbox/folder name
   * @param   string   Mode for count [ALL|UNSEEN|RECENT]
   * @param   boolean  Force reading from server and update cache
   * @return  number   Number of messages
   * @access  public
   * @return  int      Number of messages
   * @access  public
   */
  function messagecount($mbox_name='', $mode='ALL', $force=FALSE)
    {
@@ -427,7 +428,7 @@
   * Private method for getting nr of messages
   *
   * @access  private
   * @see     rcube_imap::messagecount
   * @see     rcube_imap::messagecount()
   */
  function _messagecount($mailbox='', $mode='ALL', $force=FALSE)
    {
@@ -496,7 +497,7 @@
   * convert mailbox name with root dir first
   *
   * @param   string   Mailbox/folder name
   * @param   number   Current page to list
   * @param   int      Current page to list
   * @param   string   Header field to sort by
   * @param   string   Sort order [ASC|DESC]
   * @return  array    Indexed array with message header objects
@@ -616,7 +617,7 @@
   *
   * @param   string   Mailbox/folder name
   * @param   array    List of message ids to list
   * @param   number   Current page to list
   * @param   int      Current page to list
   * @param   string   Header field to sort by
   * @param   string   Sort order [ASC|DESC]
   * @return  array    Indexed array with message header objects
@@ -633,7 +634,7 @@
   * Private method for listing a set of message headers
   *
   * @access  private
   * @see     rcube_imap::list_header_set
   * @see     rcube_imap::list_header_set()
   */
  function _list_header_set($mailbox, $msgs, $page=NULL, $sort_field=NULL, $sort_order=NULL)
    {
@@ -671,7 +672,7 @@
  /**
   * Helper function to get first and last index of the requested set
   *
   * @param  number  message count
   * @param  int     message count
   * @param  mixed   page number to show, or string 'all'
   * @return array   array with two values: first index, last index
   * @access private
@@ -713,7 +714,7 @@
   * @param  string  Message index to fetch
   * @param  array   Reference to message headers array
   * @param  array   Array with cache index
   * @return number  Number of deleted messages
   * @return int     Number of deleted messages
   * @access private
   */
  function _fetch_headers($mailbox, $msgs, &$a_msg_headers, $cache_key)
@@ -815,6 +816,9 @@
    }
  /**
   * @access private
   */
  function sync_header_index($mailbox)
    {
    $cache_key = $mailbox.'.msg';
@@ -927,6 +931,8 @@
  
  /**
   * Refresh saved search set
   *
   * @return array Current search set
   */
  function refresh_search()
    {
@@ -973,8 +979,8 @@
   * Fetch body structure from the IMAP server and build
   * an object structure similar to the one generated by PEAR::Mail_mimeDecode
   *
   * @param Int Message UID to fetch
   * @return object Standard object tree or False on failure
   * @param int Message UID to fetch
   * @return object stdClass Message part tree or False on failure
   */
  function &get_structure($uid)
    {
@@ -1136,7 +1142,7 @@
  /**
   * Return a flat array with references to all parts, indexed by part numbers
   *
   * @param object Message body structure
   * @param object rcube_message_part Message body structure
   * @return Array with part number -> object pairs
   */
  function get_mime_numbers(&$structure)
@@ -1150,7 +1156,7 @@
  /**
   * Helper method for recursive calls
   *
   * @access
   * @access private
   */
  function _get_part_numbers(&$part, &$a_parts)
    {
@@ -1168,9 +1174,9 @@
   *
   * @param  int    Message UID
   * @param  string Part number
   * @param  object Part object created by get_structure()
   * @param  object rcube_message_part Part object created by get_structure()
   * @param  mixed  True to print part, ressource to write part contents in
   * @return Message/part body if not printed
   * @return string Message/part body if not printed
   */
  function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL)
    {
@@ -1223,8 +1229,8 @@
   * Fetch message body of a specific message from the server
   *
   * @param  int    Message UID
   * @return Message/part body
   * @see    ::get_message_part()
   * @return string Message/part body
   * @see    rcube_imap::get_message_part()
   */
  function &get_body($uid, $part=1)
    {
@@ -1236,15 +1242,15 @@
   * Returns the whole message source as string
   *
   * @param int  Message UID
   * @return Message source string
   * @return string Message source string
   */
  function &get_raw_body($uid)
    {
    if (!($msg_id = $this->_uid2id($uid)))
      return FALSE;
    $body = iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL);
    $body .= iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 1);
    $body = iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL);
    $body .= iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 1);
    return $body;    
    }
@@ -1260,9 +1266,9 @@
    if (!($msg_id = $this->_uid2id($uid)))
      return FALSE;
    print iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL);
    flush();
    iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 2);
    print iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL);
    flush();
    iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 2);
    }
@@ -1271,7 +1277,7 @@
   *
   * @param mixed  Message UIDs as array or as comma-separated string
   * @param string Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT
   * @return True on success, False on failure
   * @return boolean True on success, False on failure
   */
  function set_flag($uids, $flag)
    {
@@ -1324,7 +1330,13 @@
    }
  // append a mail message (source) to a specific mailbox
  /**
   * Append a mail message (source) to a specific mailbox
   *
   * @param string Target mailbox
   * @param string Message source
   * @return boolean True on success, False on error
   */
  function save_message($mbox_name, &$message)
    {
    $mbox_name = stripslashes($mbox_name);
@@ -1344,7 +1356,14 @@
    }
  // move a message from one mailbox to another
  /**
   * Move a message from one mailbox to another
   *
   * @param string List of UIDs to move, separated by comma
   * @param string Target mailbox
   * @param string Source mailbox
   * @return boolean True on success, False on error
   */
  function move_message($uids, $to_mbox, $from_mbox='')
    {
    $to_mbox = stripslashes($to_mbox);
@@ -1408,7 +1427,13 @@
    }
  // mark messages as deleted and expunge mailbox
  /**
   * Mark messages as deleted and expunge mailbox
   *
   * @param string List of UIDs to move, separated by comma
   * @param string Source mailbox
   * @return boolean True on success, False on error
   */
  function delete_message($uids, $mbox_name='')
    {
    $mbox_name = stripslashes($mbox_name);
@@ -1460,7 +1485,12 @@
    }
  // clear all messages in a specific mailbox
  /**
   * Clear all messages in a specific mailbox
   *
   * @param string Mailbox name
   * @return int Above 0 on success
   */
  function clear_mailbox($mbox_name=NULL)
    {
    $mbox_name = stripslashes($mbox_name);
@@ -1487,7 +1517,13 @@
    }
  // send IMAP expunge command and clear cache
  /**
   * Send IMAP expunge command and clear cache
   *
   * @param string Mailbox name
   * @param boolean False if cache should not be cleared
   * @return boolean True on success
   */
  function expunge($mbox_name='', $clear_cache=TRUE)
    {
    $mbox_name = stripslashes($mbox_name);
@@ -1496,7 +1532,12 @@
    }
  // send IMAP expunge command and clear cache
  /**
   * Send IMAP expunge command and clear cache
   *
   * @see rcube_imap::expunge()
   * @access private
   */
  function _expunge($mailbox, $clear_cache=TRUE)
    {
    $result = iil_C_Expunge($this->conn, $mailbox);
@@ -1520,7 +1561,7 @@
   * Get a list of all folders available on the IMAP server
   * 
   * @param string IMAP root dir
   * @return array Inbdexed array with folder names
   * @return array Indexed array with folder names
   */
  function list_unsubscribed($root='')
    {
@@ -1547,8 +1588,10 @@
  /**
   * Get quota
   * Get mailbox quota information
   * added by Nuny
   *
   * @return mixed Quota info or False if not supported
   */
  function get_quota()
    {
@@ -1560,9 +1603,12 @@
  /**
   * subscribe to a specific mailbox(es)
   * Subscribe to a specific mailbox(es)
   *
   * @param string Mailbox name(s)
   * @return boolean True on success
   */ 
  function subscribe($mbox_name, $mode='subscribe')
  function subscribe($mbox_name)
    {
    if (is_array($mbox_name))
      $a_mboxes = $mbox_name;
@@ -1575,7 +1621,10 @@
  /**
   * unsubscribe mailboxes
   * Unsubscribe mailboxes
   *
   * @param string Mailbox name(s)
   * @return boolean True on success
   */
  function unsubscribe($mbox_name)
    {
@@ -1625,7 +1674,7 @@
   *
   * @param string Mailbox to rename (as utf-7 string)
   * @param string New mailbox name (as utf-7 string)
   * @param string Name of the renames mailbox, false on error
   * @return string Name of the renames mailbox, False on error
   */
  function rename_mailbox($mbox_name, $new_name)
    {
@@ -1668,7 +1717,10 @@
  /**
   * remove mailboxes from server
   * Remove mailboxes from server
   *
   * @param string Mailbox name
   * @return boolean True on success
   */
  function delete_mailbox($mbox_name)
    {
@@ -1736,7 +1788,9 @@
   *   internal caching methods
   * --------------------------------*/
  /**
   * @access private
   */
  function set_caching($set)
    {
    if ($set && is_object($this->db))
@@ -1745,7 +1799,9 @@
      $this->caching_enabled = FALSE;
    }
  /**
   * @access private
   */
  function get_cache($key)
    {
    // read cache
@@ -1758,7 +1814,9 @@
    return $this->cache[$key];
    }
  /**
   * @access private
   */
  function update_cache($key, $data)
    {
    $this->cache[$key] = $data;
@@ -1766,7 +1824,9 @@
    $this->cache_changes[$key] = TRUE;
    }
  /**
   * @access private
   */
  function write_cache()
    {
    if ($this->caching_enabled && $this->cache_changed)
@@ -1779,7 +1839,9 @@
      }    
    }
  /**
   * @access private
   */
  function clear_cache($key=NULL)
    {
    if ($key===NULL)
@@ -1799,8 +1861,9 @@
      }
    }
  /**
   * @access private
   */
  function _read_cache_record($key)
    {
    $cache_data = FALSE;
@@ -1823,10 +1886,12 @@
        }
      }
    return $cache_data;
    return $cache_data;
    }
  /**
   * @access private
   */
  function _write_cache_record($key, $data)
    {
    if (!$this->db)
@@ -1875,7 +1940,9 @@
      }
    }
  /**
   * @access private
   */
  function _clear_cache_record($key)
    {
    $this->db->query(
@@ -1893,8 +1960,13 @@
   * --------------------------------*/
   
  // checks if the cache is up-to-date
  // return: -3 = off, -2 = incomplete, -1 = dirty
  /**
   * Checks if the cache is up-to-date
   *
   * @param string Mailbox name
   * @param string Internal cache key
   * @return int -3 = off, -2 = incomplete, -1 = dirty
   */
  function check_cache_status($mailbox, $cache_key)
    {
    if (!$this->caching_enabled)
@@ -1926,8 +1998,9 @@
      return -2;
    }
  /**
   * @access private
   */
  function get_message_cache($key, $from, $to, $sort_field, $sort_order)
    {
    $cache_key = "$key:$from:$to:$sort_field:$sort_order";
@@ -1961,7 +2034,9 @@
    return $this->cache[$cache_key];
    }
  /**
   * @access private
   */
  function &get_cached_message($key, $uid, $struct=false)
    {
    if (!$this->caching_enabled)
@@ -1993,7 +2068,9 @@
    return $this->cache[$internal_key][$uid];
    }
  /**
   * @access private
   */
  function get_message_cache_index($key, $force=FALSE, $sort_col='idx', $sort_order='ASC')
    {
    static $sa_message_index = array();
@@ -2021,7 +2098,9 @@
    return $sa_message_index[$key];
    }
  /**
   * @access private
   */
  function add_message_cache($key, $index, $headers, $struct=null)
    {
    if (!$this->caching_enabled || empty($key) || !is_object($headers) || empty($headers->uid))
@@ -2073,7 +2152,9 @@
      }
    }
    
  /**
   * @access private
   */
  function remove_message_cache($key, $index)
    {
    $this->db->query(
@@ -2086,7 +2167,9 @@
      $index);
    }
  /**
   * @access private
   */
  function clear_message_cache($key, $start_index=1)
    {
    $this->db->query(
@@ -2106,7 +2189,14 @@
   *   encoding/decoding methods
   * --------------------------------*/
  /**
   * Split an address list into a structured array list
   *
   * @param string  Input string
   * @param int     List only this number of addresses
   * @param boolean Decode address strings
   * @return array  Indexed list of addresses
   */
  function decode_address_list($input, $max=null, $decode=true)
    {
    $a = $this->_parse_address_list($input, $decode);
@@ -2142,6 +2232,13 @@
    }
  /**
   * Decode a message header value
   *
   * @param string  Header value
   * @param boolean Remove quotes if necessary
   * @return string Decoded string
   */
  function decode_header($input, $remove_quotes=FALSE)
    {
    $str = $this->decode_mime_string((string)$input);
@@ -2155,7 +2252,10 @@
  /**
   * Decode a mime-encoded string to internal charset
   *
   * @access static
   * @param string  Header value
   * @param string  Fallback charset if none specified
   * @return string Decoded string
   * @static
   */
  function decode_mime_string($input, $fallback=null)
    {
@@ -2187,7 +2287,7 @@
  /**
   * Decode a part of a mime-encoded string
   *
   * @access static
   * @access private
   */
  function _decode_mime_string_part($str)
    {
@@ -2215,6 +2315,14 @@
    }
  /**
   * Decode a mime part
   *
   * @param string Input string
   * @param string Part encoding
   * @return string Decoded string
   * @access private
   */
  function mime_decode($input, $encoding='7bit')
    {
    switch (strtolower($encoding))
@@ -2237,25 +2345,13 @@
    }
  function mime_encode($input, $encoding='7bit')
    {
    switch ($encoding)
      {
      case 'quoted-printable':
        return quoted_printable_encode($input);
        break;
      case 'base64':
        return base64_encode($input);
        break;
      default:
        return $input;
      }
    }
  // convert body chars according to the ctype_parameters
  /**
   * Convert body charset to UTF-8 according to the ctype_parameters
   *
   * @param string Part body to decode
   * @param string Charset to convert from
   * @return string Content converted to internal charset
   */
  function charset_decode($body, $ctype_param)
    {
    if (is_array($ctype_param) && !empty($ctype_param['charset']))
@@ -2266,6 +2362,33 @@
    }
  /**
   * Translate UID to message ID
   *
   * @param int    Message UID
   * @param string Mailbox name
   * @return int   Message ID
   */
  function get_id($uid, $mbox_name=NULL)
    {
      $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
      return $this->_uid2id($uid, $mailbox);
    }
  /**
   * Translate message number to UID
   *
   * @param int    Message ID
   * @param string Mailbox name
   * @return int   Message UID
   */
  function get_uid($id,$mbox_name=NULL)
    {
      $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
      return $this->_id2uid($id, $mailbox);
    }
  /* --------------------------------
@@ -2273,6 +2396,9 @@
   * --------------------------------*/
  /**
   * @access private
   */
  function _mod_mailbox($mbox_name, $mode='in')
    {
    if ((!empty($this->root_ns) && $this->root_ns == $mbox_name) || $mbox_name == 'INBOX')
@@ -2287,7 +2413,10 @@
    }
  // sort mailboxes first by default folders and then in alphabethical order
  /**
   * Sort mailboxes first by default folders and then in alphabethical order
   * @access private
   */
  function _sort_mailbox_list($a_folders)
    {
    $a_out = $a_defaults = array();
@@ -2296,10 +2425,10 @@
    foreach($a_folders as $i => $folder)
      {
      if ($folder{0}=='.')
          continue;
        continue;
      if (($p = array_search(strtolower($folder), $this->default_folders_lc))!==FALSE)
          $a_defaults[$p] = $folder;
        $a_defaults[$p] = $folder;
      else
        $a_out[] = $folder;
      }
@@ -2310,18 +2439,9 @@
    return array_merge($a_defaults, $a_out);
    }
  function get_id($uid, $mbox_name=NULL)
    {
      $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
      return $this->_uid2id($uid, $mailbox);
    }
  function get_uid($id,$mbox_name=NULL)
    {
      $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
      return $this->_id2uid($id, $mailbox);
    }
  /**
   * @access private
   */
  function _uid2id($uid, $mbox_name=NULL)
    {
    if (!$mbox_name)
@@ -2333,6 +2453,9 @@
    return $this->uid_id_map[$mbox_name][$uid];
    }
  /**
   * @access private
   */
  function _id2uid($id, $mbox_name=NULL)
    {
    if (!$mbox_name)
@@ -2342,7 +2465,10 @@
    }
  // parse string or array of server capabilities and put them in internal array
  /**
   * Parse string or array of server capabilities and put them in internal array
   * @access private
   */
  function _parse_capability($caps)
    {
    if (!is_array($caps))
@@ -2369,7 +2495,10 @@
    }
  // subscribe/unsubscribe a list of mailboxes and update local cache
  /**
   * Subscribe/unsubscribe a list of mailboxes and update local cache
   * @access private
   */
  function _change_subscription($a_mboxes, $mode)
    {
    $updated = FALSE;
@@ -2410,7 +2539,10 @@
    }
  // increde/decrese messagecount for a specific mailbox
  /**
   * Increde/decrese messagecount for a specific mailbox
   * @access private
   */
  function _set_messagecount($mbox_name, $mode, $increment)
    {
    $a_mailbox_cache = FALSE;
@@ -2436,7 +2568,10 @@
    }
  // remove messagecount of a specific mailbox from cache
  /**
   * Remove messagecount of a specific mailbox from cache
   * @access private
   */
  function _clear_messagecount($mbox_name='')
    {
    $a_mailbox_cache = FALSE;
@@ -2452,7 +2587,10 @@
    }
  // split RFC822 header string into an associative array
  /**
   * Split RFC822 header string into an associative array
   * @access private
   */
  function _parse_headers($headers)
    {
    $a_headers = array();
@@ -2473,6 +2611,9 @@
    }
  /**
   * @access private
   */
  function _parse_address_list($str, $decode=true)
    {
    // remove any newlines and carriage returns before
@@ -2501,6 +2642,9 @@
    }
  /**
   * @access private
   */
  function _explode_quoted_string($delimiter, $string)
    {
    $result = array();
@@ -2519,11 +2663,14 @@
    $result[] = substr($string, $p);
    return $result;
    }
  }
}  // end class rcube_imap
/**
 * Class representing a message part
 *
 * @package Mail
 */
class rcube_message_part
{
@@ -2544,10 +2691,9 @@
/**
 * rcube_header_sorter
 *
 * Class for sorting an array of iilBasicHeader objects in a predetermined order.
 *
 * @package Mail
 * @author Eric Stadtherr
 */
class rcube_header_sorter
@@ -2555,9 +2701,9 @@
   var $sequence_numbers = array();
   
   /**
    * set the predetermined sort order.
    * Set the predetermined sort order.
    *
    * @param array $seqnums numerically indexed array of IMAP message sequence numbers
    * @param array Numerically indexed array of IMAP message sequence numbers
    */
   function set_sequence_numbers($seqnums)
   {
@@ -2565,9 +2711,9 @@
   }
 
   /**
    * sort the array of header objects
    * Sort the array of header objects
    *
    * @param array $headers array of iilBasicHeader objects indexed by UID
    * @param array Array of iilBasicHeader objects indexed by UID
    */
   function sort_headers(&$headers)
   {
@@ -2582,9 +2728,10 @@
   }
 
   /**
    * get the position of a message sequence number in my sequence_numbers array
    * Get the position of a message sequence number in my sequence_numbers array
    *
    * @param integer $seqnum message sequence number contained in sequence_numbers
    * @param int Message sequence number contained in sequence_numbers
    * @return int Position, -1 if not found
    */
   function position_of($seqnum)
   {
@@ -2620,10 +2767,10 @@
/**
 * Add quoted-printable encoding to a given string
 * 
 * @param string  $input      string to encode
 * @param int     $line_max   add new line after this number of characters
 * @param boolena $space_conf true if spaces should be converted into =20
 * @return encoded string
 * @param string   String to encode
 * @param int      Add new line after this number of characters
 * @param boolean  True if spaces should be converted into =20
 * @return string Encoded string
 */
function quoted_printable_encode($input, $line_max=76, $space_conv=false)
  {
program/include/rcube_ldap.inc
@@ -19,6 +19,12 @@
*/
/**
 * Model class to access an LDAP address directory
 *
 * @package Addressbook
 */
class rcube_ldap
{
  var $conn;
@@ -59,7 +65,7 @@
  /**
   * PHP 4 object constructor
   *
   * @see  rcube_ldap::__construct
   * @see  rcube_ldap::__construct()
   */
  function rcube_ldap($p)
  {
@@ -105,6 +111,10 @@
  /**
   * Bind connection with DN and password
   *
   * @param string Bind DN
   * @param string Bind password
   * @return boolean True on success, False on error
   */
  function bind($dn, $pass)
  {
@@ -163,7 +173,7 @@
  /**
   * Save a search string for future listings
   *
   * @param string ??
   * @param string Filter string
   */
  function set_search_set($filter)
  {
@@ -197,6 +207,7 @@
   * List the current set of contact records
   *
   * @param  array  List of cols to show
   * @param  int    Only return this number of records (not implemented)
   * @return array  Indexed list of contact records, each a hash array
   */
  function list_records($cols=null, $subset=0)
@@ -229,7 +240,7 @@
   * @param array   List of fields to search in
   * @param string  Search value
   * @param boolean True if results are requested, False if count only
   * @return Indexed list of contact records and 'count' value
   * @return array  Indexed list of contact records and 'count' value
   */
  function search($fields, $value, $strict=false, $select=true)
  {
@@ -283,7 +294,7 @@
  /**
   * Count number of available contacts in database
   *
   * @return Result array with values for 'count' and 'first'
   * @return object rcube_result_set Resultset with values for 'count' and 'first'
   */
  function count()
  {
@@ -298,7 +309,7 @@
  /**
   * Return the last result set
   *
   * @return Result array or NULL if nothing selected yet
   * @return object rcube_result_set Current resultset or NULL if nothing selected yet
   */
  function get_result()
  {
@@ -309,8 +320,9 @@
  /**
   * Get a specific contact record
   *
   * @param mixed record identifier
   * @return Hash array with all record fields or False if not found
   * @param mixed   Record identifier
   * @param boolean Return as associative array
   * @return mixed  Hash array or rcube_result_set with all record fields
   */
  function get_record($dn, $assoc=false)
  {
@@ -335,8 +347,8 @@
  /**
   * Create a new contact record
   *
   * @param array Assoziative array with save data
   * @return The create record ID on success, False on error
   * @param array    Hash array with save data
   * @return boolean The create record ID on success, False on error
   */
  function insert($save_cols)
  {
@@ -349,8 +361,8 @@
   * Update a specific contact record
   *
   * @param mixed Record identifier
   * @param array Assoziative array with save data
   * @return True on success, False on error
   * @param array Hash array with save data
   * @return boolean True on success, False on error
   */
  function update($id, $save_cols)
  {
@@ -363,6 +375,7 @@
   * Mark one or more contact records as deleted
   *
   * @param array  Record identifiers
   * @return boolean True on success, False on error
   */
  function delete($ids)
  {
@@ -374,7 +387,7 @@
  /**
   * Execute the LDAP search based on the stored credentials
   *
   * @private
   * @access private
   */
  function _exec_search()
  {
@@ -390,7 +403,7 @@
  
  
  /**
   * @private
   * @access private
   */
  function _ldap2result($rec)
  {
@@ -410,7 +423,7 @@
  
  
  /**
   * @private
   * @access private
   */
  function _map_field($field)
  {
program/include/rcube_mdb2.inc
@@ -32,14 +32,14 @@
 *
 * This is a wrapper for the PEAR::MDB2 class
 *
 * @package    RoundCube Webmail
 * @package    Database
 * @author     David Saez Padros <david@ols.es>
 * @author     Thomas Bruederli <roundcube@gmail.com>
 * @author     Lukas Kahwe Smith <smith@pooteeweet.org>
 * @version    1.16
 * @link       http://pear.php.net/package/MDB2
 */
class rcube_db
class rcube_mdb2
  {
  var $db_dsnw;               // DSN for write operations
  var $db_dsnr;               // DSN for read operations
@@ -76,7 +76,7 @@
  /**
   * PHP 4 object constructor
   *
   * @see  rcube_MDB2::__construct
   * @see  rcube_mdb2::__construct
   */
  function rcube_db($db_dsnw,$db_dsnr='')
    {
program/include/rcube_shared.inc
@@ -20,1039 +20,20 @@
*/
// ********* round cube schared classes *********
/**
 * RoundCube shared functions
 *
 * @package Core
 */
class rcube_html_page
  {
  var $css;
  var $scripts_path = '';
  var $script_files = array();
  var $external_scripts = array();
  var $scripts = array();
  var $charset = 'ISO-8859-1';
  var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
  var $script_tag      = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
  var $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
  var $tag_format_external_script = "<script type=\"text/javascript\" src=\"%s\"></script>\n";
  var $title = '';
  var $header = '';
  var $footer = '';
  var $body = '';
  var $body_attrib = array();
  var $meta_tags = array();
  // PHP 5 constructor
  function __construct()
    {
    $this->css = new rcube_css();
    }
  // PHP 4 compatibility
  function rcube_html_page()
    {
    $this->__construct();
    }
  function include_script($file, $position='head')
    {
    static $sa_files = array();
    if (in_array($file, $sa_files))
      return;
    if (!is_array($this->script_files[$position]))
      $this->script_files[$position] = array();
    $this->script_files[$position][] = $file;
    }
  function include_external_script($script_location, $position='head')
  {
     if (!is_array($this->external_scripts[$position]))
     {
        $this->external_scripts[$position] = array();
     }
     $this->external_scripts[$position][] = $script_location;
  }
  function add_script($script, $position='head')
    {
    if (!isset($this->scripts[$position]))
      $this->scripts[$position] = "\n".rtrim($script);
    else
      $this->scripts[$position] .= "\n".rtrim($script);
    }
  function add_header($str)
    {
    $this->header .= "\n".$str;
    }
  function add_footer($str)
    {
    $this->footer .= "\n".$str;
    }
  function set_title($t)
    {
    $this->title = $t;
    }
  function set_charset($charset)
    {
    global $MBSTRING;
    $this->charset = $charset;
    if ($MBSTRING && function_exists("mb_internal_encoding"))
      {
      if(!@mb_internal_encoding($charset))
        $MBSTRING = FALSE;
      }
    }
  function get_charset()
    {
    return $this->charset;
    }
  function reset()
    {
    $this->css = new rcube_css();
    $this->script_files = array();
    $this->scripts = array();
    $this->title = '';
    $this->header = '';
    $this->footer = '';
    }
  function write($templ='', $base_path='')
    {
    $output = empty($templ) ? $this->default_template : trim($templ);
    // set default page title
    if (empty($this->title))
      $this->title = 'RoundCube Mail';
    // replace specialchars in content
    $__page_title = Q($this->title, 'show', FALSE);
    $__page_header = $__page_body = $__page_footer = '';
    // include meta tag with charset
    if (!empty($this->charset))
      {
      header('Content-Type: text/html; charset='.$this->charset);
      $__page_header = '<meta http-equiv="content-type" content="text/html; charset='.$this->charset.'" />'."\n";
      }
    // definition of the code to be placed in the document header and footer
    if (is_array($this->script_files['head']))
      foreach ($this->script_files['head'] as $file)
        $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file);
    if (is_array($this->external_scripts['head']))
      foreach ($this->external_scripts['head'] as $xscript)
        $__page_header .= sprintf($this->tag_format_external_script, $xscript);
    $head_script = $this->scripts['head_top'] . $this->scripts['head'];
    if (!empty($head_script))
      $__page_header .= sprintf($this->script_tag, $head_script);
    if (!empty($this->header))
      $__page_header .= $this->header;
    if (is_array($this->script_files['foot']))
      foreach ($this->script_files['foot'] as $file)
        $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file);
    if (!empty($this->scripts['foot']))
      $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']);
    if (!empty($this->footer))
      $__page_footer .= $this->footer;
    $__page_header .= $this->css->show();
    // find page header
    if($hpos = strpos(strtolower($output), '</head>'))
      $__page_header .= "\n";
    else
      {
      if (!is_numeric($hpos))
        $hpos = strpos(strtolower($output), '<body');
      if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html')))
        {
        while($output[$hpos]!='>')
        $hpos++;
        $hpos++;
        }
      $__page_header = "<head>\n<title>$__page_title</title>\n$__page_header\n</head>\n";
      }
    // add page hader
    if($hpos)
      $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output));
    else
      $output = $__page_header . $output;
    // find page body
    if($bpos = strpos(strtolower($output), '<body'))
      {
      while($output[$bpos]!='>') $bpos++;
      $bpos++;
      }
    else
      $bpos = strpos(strtolower($output), '</head>')+7;
    // add page body
    if($bpos && $__page_body)
      $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output));
    // find and add page footer
    $output_lc = strtolower($output);
    if(($fpos = strrstr($output_lc, '</body>')) ||
       ($fpos = strrstr($output_lc, '</html>')))
      $output = substr($output, 0, $fpos) . "$__page_footer\n" . substr($output, $fpos);
    else
      $output .= "\n$__page_footer";
    // reset those global vars
    $__page_header = $__page_footer = '';
    // correct absolute paths in images and other tags
    $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output);
    $output = str_replace('$__skin_path', $base_path, $output);
    print rcube_charset_convert($output, 'UTF-8', $this->charset);
    }
  function _parse($templ)
    {
    }
  }
class rcube_css
  {
  var $css_data = array();
  var $css_groups = array();
  var $include_files = array();
  var $grouped_output = TRUE;
  var $content_type = 'text/css';
  var $base_path = '';
  var $indent_chars = "\t";
  // add or overwrite a css definition
  // either pass porperty and value as separate arguments
  // or provide an associative array as second argument
  function set_style($selector, $property, $value='')
    {
    $a_elements = $this->_parse_selectors($selector);
    foreach ($a_elements as $element)
      {
      if (!is_array($property))
        $property = array($property => $value);
      foreach ($property as $name => $value)
        $this->css_data[$element][strtolower($name)] = $value;
      }
    // clear goups array
    $this->css_groups = array();
    }
  // unset a style property
  function remove_style($selector, $property)
    {
    if (!is_array($property))
      $property = array($property);
    foreach ($property as $key)
      unset($this->css_data[$selector][strtolower($key)]);
    // clear goups array
    $this->css_groups = array();
    }
  // define base path for external css files
  function set_basepath($path)
    {
    $this->base_path = preg_replace('/\/$/', '', $path);
    }
  // enable/disable grouped output
  function set_grouped_output($grouped)
    {
    $this->grouped_output = $grouped;
    }
  // add a css file as external source
  function include_file($filename, $media='')
    {
    // include multiple files
    if (is_array($filename))
      {
      foreach ($filename as $file)
        $this->include_file($file, $media);
      }
    // add single file
    else if (!in_array($filename, $this->include_files))
      $this->include_files[] = array('file' => $filename,
                                     'media' => $media);
    }
  // parse css code
  function import_string($str)
    {
    $ret = FALSE;
    if (strlen($str))
      $ret = $this->_parse($str);
    return $ret;
    }
  // open and parse a css file
  function import_file($file)
    {
    $ret = FALSE;
    if (!is_file($file))
      return $ret;
    // for php version >= 4.3.0
    if (function_exists('file_get_contents'))
      $ret = $this->_parse(file_get_contents($file));
    // for order php versions
    else if ($fp = fopen($file, 'r'))
      {
      $ret = $this->_parse(fread($fp, filesize($file)));
      fclose($fp);
      }
    return $ret;
    }
  // copy all properties inherited from superior styles to a specific selector
  function copy_inherited_styles($selector)
    {
    // get inherited props from body and tag/class selectors
    $css_props = $this->_get_inherited_styles($selector);
    // write modified props back and clear goups array
    if (sizeof($css_props))
      {
      $this->css_data[$selector] = $css_props;
      $this->css_groups = array();
      }
    }
  // return css definition for embedding in HTML
  function show()
    {
    $out = '';
    // include external css files
    if (sizeof($this->include_files))
      foreach ($this->include_files as $file_arr)
      $out .= sprintf('<link rel="stylesheet" type="%s" href="%s"%s>'."\n",
                        $this->content_type,
                        $this->_get_file_path($file_arr['file']),
                        $file_arr['media'] ? ' media="'.$file_arr['media'].'"' : '');
    // compose css string
    if (sizeof($this->css_data))
      $out .= sprintf("<style type=\"%s\">\n<!--\n\n%s-->\n</style>",
                      $this->content_type,
                      $this->to_string());
    return $out;
    }
  // return valid css code of the current styles grid
  function to_string($selector=NULL)
    {
    // return code for a single selector
    if ($selector)
      {
      $indent_str = $this->indent_chars;
      $this->indent_chars = '';
      $prop_arr = $this->to_array($selector);
      $out = $this->_style2string($prop_arr, TRUE);
      $this->indent_chars = $indent_str;
      }
    // compose css code for complete data grid
    else
      {
      $out = '';
      $css_data = $this->to_array();
      foreach ($css_data as $key => $prop_arr)
        $out .= sprintf("%s {\n%s}\n\n",
                        $key,
                        $this->_style2string($prop_arr, TRUE));
      }
    return $out;
    }
  // return a single-line string of a css definition
  function to_inline($selector)
    {
    if ($this->css_data[$selector])
      return str_replace('"', '\\"', $this->_style2string($this->css_data[$selector], FALSE));
    }
  // return an associative array with selector(s) as key and styles array as value
  function to_array($selector=NULL)
    {
    if (!$selector && $this->grouped_output)
      {
      // build groups if desired
      if (!sizeof($this->css_groups))
        $this->_build_groups();
      // modify group array to get an array(selector => properties)
      $out_arr = array();
      foreach ($this->css_groups as $group_arr)
        {
        $key = join(', ', $group_arr['selectors']);
        $out_arr[$key] = $group_arr['properties'];
        }
      }
    else
      $out_arr = $this->css_data;
    return $selector ? $out_arr[$selector] : $out_arr;
    }
  // create a css file
  function to_file($filepath)
    {
    if ($fp = fopen($filepath, 'w'))
      {
      fwrite($fp, $this->to_string());
      fclose($fp);
      return TRUE;
      }
    return FALSE;
    }
  // alias method for import_string() [DEPRECATED]
  function add($str)
    {
    $this->import_string($str);
    }
  // alias method for to_string() [DEPRECATED]
  function get()
    {
    return $this->to_string();
    }
  // ******** private methods ********
  // parse a string and add styles to internal data grid
  function _parse($str)
    {
    // remove comments
    $str = preg_replace("/\/\*(.*)?\*\//Usi", '', $str);
    // parse style definitions
    if (!preg_match_all ('/([a-z0-9\.#*:_][a-z0-9\.\-_#:*,\[\]\(\)\s\"\'\+\|>~=]+)\s*\{([^\}]*)\}/ims', $str, $matches, PREG_SET_ORDER))
      return FALSE;
    foreach ($matches as $match_arr)
      {
      // split selectors into array
      $a_keys = $this->_parse_selectors(trim($match_arr[1]));
      // parse each property of an element
      $codes = explode(";", trim($match_arr[2]));
      foreach ($codes as $code)
        {
        if (strlen(trim($code))>0)
          {
          // find the property and the value
          if (!($sep = strpos($code, ':')))
            continue;
          $property = strtolower(trim(substr($code, 0, $sep)));
          $value    = trim(substr($code, $sep+1));
          // add the property to the object array
          foreach ($a_keys as $key)
            $this->css_data[$key][$property] = $value;
          }
        }
      }
    // clear goups array
    if (sizeof($matches))
      {
      $this->css_groups = array();
      return TRUE;
      }
    return FALSE;
    }
  // split selector group
  function _parse_selectors($selector)
    {
    // trim selector and remove multiple spaces
    $selector = preg_replace('/\s+/', ' ', trim($selector));
    if (strpos($selector, ','))
      return preg_split('/[\t\s\n\r]*,[\t\s\n\r]*/mi', $selector);
    else
      return array($selector);
    }
  // compare identical styles and make groups
  function _build_groups()
    {
    // clear group array
    $this->css_groups = array();
    $string_group_map = array();
    // bulild css string for each selector and check if the same is already defines
    foreach ($this->css_data as $selector => $prop_arr)
      {
      // make shure to compare props in the same order
      ksort($prop_arr);
      $compare_str = preg_replace('/[\s\t]+/', '', $this->_style2string($prop_arr, FALSE));
      // add selector to extisting group
      if (isset($string_group_map[$compare_str]))
        {
        $group_index = $string_group_map[$compare_str];
        $this->css_groups[$group_index]['selectors'][] = $selector;
        }
      // create new group
      else
        {
        $i = sizeof($this->css_groups);
        $string_group_map[$compare_str] = $i;
        $this->css_groups[$i] = array('selectors' => array($selector),
                                      'properties' => $this->css_data[$selector]);
        }
      }
    }
  // convert the prop array into a valid css definition
  function _style2string($prop_arr, $multiline=TRUE)
    {
    $out = '';
    $delm   = $multiline ? "\n" : '';
    $spacer = $multiline ? ' ' : '';
    $indent = $multiline ? $this->indent_chars : '';
    if (is_array($prop_arr))
      foreach ($prop_arr as $prop => $value)
        if (strlen($value))
          $out .= sprintf('%s%s:%s%s;%s',
                          $indent,
                          $prop,
                          $spacer,
                          $value,
                          $delm);
    return $out;
    }
  // copy all properties inherited from superior styles to a specific selector
  function _get_inherited_styles($selector, $loop=FALSE)
    {
    $css_props = $this->css_data[$selector] ? $this->css_data[$selector] : array();
    // get styles from tag selector
    if (preg_match('/(([a-z0-9]*)(\.[^\s]+)?)$/i', $selector, $regs))
      {
      $sel = $regs[1];
      $tagname = $regs[2];
      $class = $regs[3];
      if ($sel && is_array($this->css_data[$sel]))
        $css_props = $this->_merge_styles($this->css_data[$sel], $css_props);
      if ($class && is_array($this->css_data[$class]))
        $css_props = $this->_merge_styles($this->css_data[$class], $css_props);
      if ($tagname && is_array($this->css_data[$tagname]))
        $css_props = $this->_merge_styles($this->css_data[$tagname], $css_props);
      }
    // analyse inheritance
    if (strpos($selector, ' '))
      {
      $a_hier = split(' ', $selector);
      if (sizeof($a_hier)>1)
        {
        array_pop($a_hier);
        $base_selector = join(' ', $a_hier);
        // call this method recursively
        $new_props = $this->_get_inherited_styles($base_selector, TRUE);
        $css_props = $this->_merge_styles($new_props, $css_props);
        }
      }
    // get body style
    if (!$loop && is_array($this->css_data['body']))
      $css_props = $this->_merge_styles($this->css_data['body'], $css_props);
    return $css_props;
    }
  // merge two arrays with style properties together like a browser would do
  function _merge_styles($one, $two)
    {
    // these properties are additive
    foreach (array('text-decoration') as $prop)
      if ($one[$prop] && $two[$prop])
        {
        // if value contains 'none' it's ignored
        if (strstr($one[$prop], 'none'))
          continue;
        else if (strstr($two[$prop], 'none'))
          unset($two[$prop]);
        $a_values_one = split(' ', $one[$prop]);
        $a_values_two = split(' ', $two[$prop]);
        $two[$prop] = join(' ', array_unique(array_merge($a_values_one, $a_values_two)));
        }
    return array_merge($one, $two);
    }
  // resolve file path
  function _get_file_path($file)
    {
    if (!$this->base_path && $GLOBALS['CSS_PATH'])
      $this->set_basepath($GLOBALS['CSS_PATH']);
    $base = ($file{0}=='/' || $file{0}=='.' || substr($file, 0, 7)=='http://') ? '' :
            ($this->base_path ? $this->base_path.'/' : '');
    return $base.$file;
    }
  }
class base_form_element
  {
  var $uppertags = FALSE;
  var $upperattribs = FALSE;
  var $upperprops = FALSE;
  var $newline = FALSE;
  var $attrib = array();
  // create string with attributes
  function create_attrib_string($tagname='')
    {
    if (!sizeof($this->attrib))
      return '';
    if ($this->name!='')
      $this->attrib['name'] = $this->name;
    $attrib_arr = array();
    foreach ($this->attrib as $key => $value)
      {
      // don't output some internally used attributes
      if (in_array($key, array('form', 'quicksearch')))
        continue;
      // skip if size if not numeric
      if (($key=='size' && !is_numeric($value)))
        continue;
      // skip empty eventhandlers
      if ((strpos($key,'on')===0 && $value==''))
        continue;
      // encode textarea content
      if ($key=='value')
        $value = Q($value, 'strict', FALSE);
      // attributes with no value
      if (in_array($key, array('checked', 'multiple', 'disabled', 'selected')))
        {
        if ($value)
          $attrib_arr[] = $key;
        }
      // don't convert size of value attribute
      else if ($key=='value')
        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $value, 'value');
      // regular tag attributes
      else
        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case($value, 'value'));
      }
    return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
    }
  // convert tags and attributes to upper-/lowercase
  // $type can either be "tag" or "attrib"
  function _conv_case($str, $type='attrib')
    {
    if ($type == 'tag')
      return $this->uppertags ? strtoupper($str) : strtolower($str);
    else if ($type == 'attrib')
      return $this->upperattribs ? strtoupper($str) : strtolower($str);
    else if ($type == 'value')
      return $this->upperprops ? strtoupper($str) : strtolower($str);
    }
  }
class input_field extends base_form_element
  {
  var $type = 'text';
  // PHP 5 constructor
  function __construct($attrib=NULL)
    {
    if (is_array($attrib))
      $this->attrib = $attrib;
    if ($attrib['type'])
      $this->type = $attrib['type'];
    if ($attrib['newline'])
      $this->newline = TRUE;
    }
  // PHP 4 compatibility
  function input_field($attrib=array())
    {
    $this->__construct($attrib);
    }
  // compose input tag
  function show($value=NULL, $attrib=NULL)
    {
    // overwrite object attributes
    if (is_array($attrib))
      $this->attrib = array_merge($this->attrib, $attrib);
    // set value attribute
    if ($value!==NULL)
      $this->attrib['value'] = $value;
    $this->attrib['type'] = $this->type;
    // return final tag
    return sprintf('<%s%s />%s',
                   $this->_conv_case('input', 'tag'),
                   $this->create_attrib_string(),
                   ($this->newline ? "\n" : ""));
    }
  }
class textfield extends input_field
  {
  var $type = 'text';
  }
class passwordfield extends input_field
  {
  var $type = 'password';
  }
class radiobutton extends input_field
  {
  var $type = 'radio';
  }
class checkbox extends input_field
  {
  var $type = 'checkbox';
  function show($value='', $attrib=NULL)
    {
    // overwrite object attributes
    if (is_array($attrib))
      $this->attrib = array_merge($this->attrib, $attrib);
    $this->attrib['type'] = $this->type;
    if ($value && (string)$value==(string)$this->attrib['value'])
      $this->attrib['checked'] = TRUE;
    else
      $this->attrib['checked'] = FALSE;
    // return final tag
    return sprintf('<%s%s />%s',
                   $this->_conv_case('input', 'tag'),
                   $this->create_attrib_string(),
                   ($this->newline ? "\n" : ""));
    }
  }
class textarea extends base_form_element
  {
  // PHP 5 constructor
  function __construct($attrib=array())
    {
    $this->attrib = $attrib;
    if ($attrib['newline'])
      $this->newline = TRUE;
    }
  // PHP 4 compatibility
  function textarea($attrib=array())
    {
    $this->__construct($attrib);
    }
  function show($value='', $attrib=NULL)
    {
    // overwrite object attributes
    if (is_array($attrib))
      $this->attrib = array_merge($this->attrib, $attrib);
    // take value attribute as content
    if ($value=='')
      $value = $this->attrib['value'];
    // make shure we don't print the value attribute
    if (isset($this->attrib['value']))
      unset($this->attrib['value']);
    if (!empty($value) && !isset($this->attrib['mce_editable']))
      $value = Q($value, 'strict', FALSE);
    // return final tag
    return sprintf('<%s%s>%s</%s>%s',
                   $this->_conv_case('textarea', 'tag'),
                   $this->create_attrib_string(),
                   $value,
                   $this->_conv_case('textarea', 'tag'),
                   ($this->newline ? "\n" : ""));
    }
  }
class hiddenfield extends base_form_element
  {
  var $fields_arr = array();
  var $newline = TRUE;
  // PHP 5 constructor
  function __construct($attrib=NULL)
    {
    if (is_array($attrib))
      $this->add($attrib);
    }
  // PHP 4 compatibility
  function hiddenfield($attrib=NULL)
    {
    $this->__construct($attrib);
    }
  // add a hidden field to this instance
  function add($attrib)
    {
    $this->fields_arr[] = $attrib;
    }
  function show()
    {
    $out = '';
    foreach ($this->fields_arr as $attrib)
      {
      $this->attrib = $attrib;
      $this->attrib['type'] = 'hidden';
      $out .= sprintf('<%s%s />%s',
                   $this->_conv_case('input', 'tag'),
                   $this->create_attrib_string(),
                   ($this->newline ? "\n" : ""));
      }
    return $out;
    }
  }
class select extends base_form_element
  {
  var $options = array();
  /*
  syntax:
  -------
  // create instance. arguments are used to set attributes of select-tag
  $select = new select(array('name' => 'fieldname'));
  // add one option
  $select->add('Switzerland', 'CH');
  // add multiple options
  $select->add(array('Switzerland', 'Germany'),
               array('CH', 'DE'));
  // add 10 blank options with 50 chars
  // used to fill with javascript (necessary for 4.x browsers)
  $select->add_blank(10, 50);
  // generate pulldown with selection 'Switzerland'  and return html-code
  // as second argument the same attributes available to instanciate can be used
  print $select->show('CH');
  */
  // PHP 5 constructor
  function __construct($attrib=NULL)
    {
    if (is_array($attrib))
      $this->attrib = $attrib;
    if ($attrib['newline'])
      $this->newline = TRUE;
    }
  // PHP 4 compatibility
  function select($attrib=NULL)
    {
    $this->__construct($attrib);
    }
  function add($names, $values=NULL)
    {
    if (is_array($names))
      {
      foreach ($names as $i => $text)
        $this->options[] = array('text' => $text, 'value' => (string)$values[$i]);
      }
    else
      {
      $this->options[] = array('text' => $names, 'value' => (string)$values);
      }
    }
  function add_blank($nr, $width=0)
    {
    $text = $width ? str_repeat('&nbsp;', $width) : '';
    for ($i=0; $i < $nr; $i++)
      $this->options[] = array('text' => $text);
    }
  function show($select=array(), $attrib=NULL)
    {
    $options_str = "\n";
    $value_str = $this->_conv_case(' value="%s"', 'attrib');
    if (!is_array($select))
      $select = array((string)$select);
    foreach ($this->options as $option)
      {
      $selected = ((isset($option['value']) &&
                    in_array($option['value'], $select, TRUE)) ||
                   (in_array($option['text'], $select, TRUE))) ?
        $this->_conv_case(' selected', 'attrib') : '';
      $options_str .= sprintf("<%s%s%s>%s</%s>\n",
                             $this->_conv_case('option', 'tag'),
                             !empty($option['value']) ? sprintf($value_str, Q($option['value'])) : '',
                             $selected,
                             Q($option['text'], 'strict', FALSE),
                             $this->_conv_case('option', 'tag'));
      }
    // return final tag
    return sprintf('<%s%s>%s</%s>%s',
                   $this->_conv_case('select', 'tag'),
                   $this->create_attrib_string(),
                   $options_str,
                   $this->_conv_case('select', 'tag'),
                   ($this->newline ? "\n" : ""));
    }
  }
// ********* rcube schared functions *********
// provide details about the client's browser
/**
 * Provide details about the client's browser
 *
 * @return array Key-value pairs of browser properties
 */
function rcube_browser()
  {
{
  $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
  $bw['ver'] = 0;
@@ -1069,25 +50,25 @@
  $bw['safari'] = stristr($HTTP_USER_AGENT, 'safari');
  if($bw['ns'])
    {
  {
    $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs);
    $bw['ver'] = $test ? (float)$regs[1] : 0;
    }
  }
  if($bw['mz'])
    {
  {
    $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs);
    $bw['ver'] = $test ? (float)$regs[1] : 0;
    }
  }
  if($bw['ie'])
    {
  {
    $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
    $bw['ver'] = $test ? (float)$regs[1] : 0;
    }
  }
  if($bw['opera'])
    {
  {
    $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
    $bw['ver'] = $test ? (float)$regs[1] : 0;
    }
  }
  if(eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs))
    $bw['lang'] =  $regs[1];
@@ -1099,12 +80,17 @@
                    ($bw['ie'] && $bw['ver']>=5 && $bw['mac']) || ($bw['opera'] && $bw['ver']>=7) ? TRUE : FALSE;
  return $bw;
  }
}
// get text in the desired language from the language file
/**
 * Get localized text in the desired language
 *
 * @param mixed Named parameters array or label name
 * @return string Localized text
 */
function rcube_label($attrib)
  {
{
  global $sess_user_lang, $INSTALL_PATH, $OUTPUT;
  static $sa_text_data, $s_language, $utf8_decode;
@@ -1135,7 +121,7 @@
    
    // include user language files
    if ($sess_user_lang!='en' && is_dir($INSTALL_PATH.'program/localization/'.$sess_user_lang))
      {
    {
      include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/labels.inc');
      include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/messages.inc');
@@ -1143,23 +129,24 @@
        $sa_text_data = array_merge($sa_text_data, $labels);
      if (is_array($messages))
        $sa_text_data = array_merge($sa_text_data, $messages);
      }
    }
      
    $s_language = $sess_user_lang;
    }
  }
  // text does not exist
  if (!($text_item = $sa_text_data[$alias]))
    {
  {
    /*
    raise_error(array('code' => 500,
                      'type' => 'php',
                      'line' => __LINE__,
                      'file' => __FILE__,
                      'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE);
    raise_error(array(
      'code' => 500,
      'type' => 'php',
      'line' => __LINE__,
      'file' => __FILE__,
      'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE);
    */
    return "[$alias]";
    }
  }
  // make text item array 
  $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item);
@@ -1170,14 +157,14 @@
  else if ($nr>0)
    $text = $a_text_item['multiple'];
  else if ($nr==0)
    {
  {
    if ($a_text_item['none'])
      $text = $a_text_item['none'];
    else if ($a_text_item['single'])
      $text = $a_text_item['single'];
    else if ($a_text_item['multiple'])
      $text = $a_text_item['multiple'];
    }
  }
  // default text is single
  if ($text=='')
@@ -1185,10 +172,10 @@
  // replace vars in text
  if (is_array($attrib['vars']))
    {
  {
    foreach ($attrib['vars'] as $var_key=>$var_value)
      $a_replace_vars[substr($var_key, 0, 1)=='$' ? substr($var_key, 1) : $var_key] = $var_value;
    }
  }
  if ($a_replace_vars)
    $text = preg_replace('/\${?([_a-z]{1}[_a-z0-9]*)}?/ei', '$a_replace_vars["\1"]', $text);
@@ -1208,12 +195,14 @@
    return strtolower($text);
  return $text;
  }
}
// send HTTP header for no-cacheing steps
/**
 * Send HTTP headers to prevent caching this page
 */
function send_nocacheing_headers()
  {
{
  if (headers_sent())
    return;
@@ -1221,22 +210,32 @@
  header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
  header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
  header("Pragma: no-cache");
  }
}
// send header with expire date 30 days in future
/**
 * Send header with expire date 30 days in future
 *
 * @param int Expiration time in seconds
 */
function send_future_expire_header($offset=2600000)
  {
{
  if (headers_sent())
    return;
  header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+$offset)." GMT");
  header("Cache-Control: max-age=$offset");
  header("Pragma: ");
  }
}
// check request for If-Modified-Since and send an according response
/**
 * Check request for If-Modified-Since and send an according response.
 * This will terminate the current script if headers match the given values
 *
 * @param int Modified date as unix timestamp
 * @param string Etag value for caching
 */
function send_modified_header($mdate, $etag=null)
{
  if (headers_sent())
@@ -1268,260 +267,311 @@
/**
 * Convert a variable into a javascript notation string
 * Convert a variable into a javascript object notation
 *
 * @param mixed Input value
 * @return string Serialized JSON string
 */
function json_serialize($var)
{
  if (is_object($var))
    $var = get_object_vars($var);
  if (is_array($var))
  {
    if (is_object($var))
      $var = get_object_vars($var);
    if (is_array($var))
    {
      // empty array
      if (!sizeof($var))
        return '[]';
      else
      {
        $keys_arr = array_keys($var);
        $is_assoc = $have_numeric = 0;
        for ($i=0; $i<sizeof($keys_arr); ++$i)
        {
          if (is_numeric($keys_arr[$i]))
            $have_numeric = 1;
          if (!is_numeric($keys_arr[$i]) || $keys_arr[$i] != $i)
            $is_assoc = 1;
          if ($is_assoc && $have_numeric)
            break;
        }
        $brackets = $is_assoc ? '{}' : '[]';
        $pairs = array();
        foreach ($var as $key => $value)
        {
          // enclose key with quotes if it is not variable-name conform
          if (!ereg("^[_a-zA-Z]{1}[_a-zA-Z0-9]*$", $key) /* || is_js_reserved_word($key) */)
            $key = "'$key'";
          $pairs[] = sprintf("%s%s", $is_assoc ? "$key:" : '', json_serialize($value));
        }
        return $brackets{0} . implode(',', $pairs) . $brackets{1};
      }
    }
    else if (is_numeric($var) && strval(intval($var)) === strval($var))
      return $var;
    else if (is_bool($var))
      return $var ? '1' : '0';
    // empty array
    if (!sizeof($var))
      return '[]';
    else
      return "'".JQ($var)."'";
    {
      $keys_arr = array_keys($var);
      $is_assoc = $have_numeric = 0;
      for ($i=0; $i<sizeof($keys_arr); ++$i)
      {
        if (is_numeric($keys_arr[$i]))
          $have_numeric = 1;
        if (!is_numeric($keys_arr[$i]) || $keys_arr[$i] != $i)
          $is_assoc = 1;
        if ($is_assoc && $have_numeric)
          break;
      }
      $brackets = $is_assoc ? '{}' : '[]';
      $pairs = array();
      foreach ($var as $key => $value)
      {
        // enclose key with quotes if it is not variable-name conform
        if (!ereg("^[_a-zA-Z]{1}[_a-zA-Z0-9]*$", $key) /* || is_js_reserved_word($key) */)
          $key = "'$key'";
        $pairs[] = sprintf("%s%s", $is_assoc ? "$key:" : '', json_serialize($value));
      }
      return $brackets{0} . implode(',', $pairs) . $brackets{1};
    }
  }
  else if (is_numeric($var) && strval(intval($var)) === strval($var))
    return $var;
  else if (is_bool($var))
    return $var ? '1' : '0';
  else
    return "'".JQ($var)."'";
}
/**
 * function to convert an array to a javascript array
 * Function to convert an array to a javascript array
 * Actually an alias function for json_serialize()
 * @deprecated
 */
function array2js($arr, $type='')
  {
{
  return json_serialize($arr);
  }
}
/**
 * Similar function as in_array() but case-insensitive
 *
 * @param mixed Needle value
 * @param array Array to search in
 * @return boolean True if found, False if not
 */
function in_array_nocase($needle, $haystack)
  {
{
  foreach ($haystack as $value)
    {
    if (strtolower($needle)===strtolower($value))
      return TRUE;
    }
  return FALSE;
  }
      return true;
  return false;
}
/**
 * Find out if the string content means TRUE or FALSE
 *
 * @param string Input value
 * @return boolean Imagine what!
 */
function get_boolean($str)
  {
{
  $str = strtolower($str);
  if(in_array($str, array('false', '0', 'no', 'nein', ''), TRUE))
    return FALSE;
  else
    return TRUE;
  }
}
// parse a human readable string for a number of bytes
/**
 * Parse a human readable string for a number of bytes
 *
 * @param string Input string
 * @return int Number of bytes
 */
function parse_bytes($str)
  {
{
  if (is_numeric($str))
    return intval($str);
    
  if (preg_match('/([0-9]+)([a-z])/i', $str, $regs))
  {
    $bytes = floatval($regs[1]);
    switch (strtolower($regs[2]))
    {
      $bytes = floatval($regs[1]);
      switch (strtolower($regs[2]))
      {
        case 'g':
          $bytes *= 1073741824;
          break;
        case 'm':
          $bytes *= 1048576;
          break;
        case 'k':
          $bytes *= 1024;
          break;
      }
      case 'g':
        $bytes *= 1073741824;
        break;
      case 'm':
        $bytes *= 1048576;
        break;
      case 'k':
        $bytes *= 1024;
        break;
    }
  }
  return intval($bytes);
  }
}
    
// create a human readable string for a number of bytes
/**
 * Create a human readable string for a number of bytes
 *
 * @param int Number of bytes
 * @return string Byte string
 */
function show_bytes($bytes)
  {
{
  if ($bytes > 1073741824)
    {
  {
    $gb = $bytes/1073741824;
    $str = sprintf($gb>=10 ? "%d GB" : "%.1f GB", $gb);
    }
  }
  else if ($bytes > 1048576)
    {
  {
    $mb = $bytes/1048576;
    $str = sprintf($mb>=10 ? "%d MB" : "%.1f MB", $mb);
    }
  }
  else if ($bytes > 1024)
    $str = sprintf("%d KB",  round($bytes/1024));
  else
    $str = sprintf('%d B', $bytes);
  return $str;
  }
}
// convert paths like ../xxx to an absolute path using a base url
/**
 * Convert paths like ../xxx to an absolute path using a base url
 *
 * @param string Relative path
 * @param string Base URL
 * @return string Absolute URL
 */
function make_absolute_url($path, $base_url)
    {
    $host_url = $base_url;
    $abs_path = $path;
{
  $host_url = $base_url;
  $abs_path = $path;
    // cut base_url to the last directory
    if (strpos($base_url, '/')>7)
  // cut base_url to the last directory
  if (strpos($base_url, '/')>7)
  {
    $host_url = substr($base_url, 0, strpos($base_url, '/'));
    $base_url = substr($base_url, 0, strrpos($base_url, '/'));
  }
  // $path is absolute
  if ($path{0}=='/')
    $abs_path = $host_url.$path;
  else
  {
    // strip './' because its the same as ''
    $path = preg_replace('/^\.\//', '', $path);
    if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER))
      foreach ($matches as $a_match)
      {
      $host_url = substr($base_url, 0, strpos($base_url, '/'));
      $base_url = substr($base_url, 0, strrpos($base_url, '/'));
        if (strrpos($base_url, '/'))
          $base_url = substr($base_url, 0, strrpos($base_url, '/'));
        $path = substr($path, 3);
      }
    // $path is absolute
    if ($path{0}=='/')
      $abs_path = $host_url.$path;
    else
      {
      // strip './' because its the same as ''
      $path = preg_replace('/^\.\//', '', $path);
      if(preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER))
        foreach($matches as $a_match)
          {
          if (strrpos($base_url, '/'))
            $base_url = substr($base_url, 0, strrpos($base_url, '/'));
          $path = substr($path, 3);
          }
      $abs_path = $base_url.'/'.$path;
      }
    return $abs_path;
    }
    $abs_path = $base_url.'/'.$path;
  }
  return $abs_path;
}
// wrapper function for strlen
/**
 * Wrapper function for strlen
 */
function rc_strlen($str)
  {
    if (function_exists('mb_strlen'))
      return mb_strlen($str);
    else
      return strlen($str);
  }
{
  if (function_exists('mb_strlen'))
    return mb_strlen($str);
  else
    return strlen($str);
}
  
// wrapper function for strtolower
/**
 * Wrapper function for strtolower
 */
function rc_strtolower($str)
  {
    if (function_exists('mb_strtolower'))
      return mb_strtolower($str);
    else
      return strtolower($str);
  }
{
  if (function_exists('mb_strtolower'))
    return mb_strtolower($str);
  else
    return strtolower($str);
}
// wrapper function for substr
/**
 * Wrapper function for substr
 */
function rc_substr($str, $start, $len=null)
  {
{
  if (function_exists('mb_substr'))
    return mb_substr($str, $start, $len);
  else
    return substr($str, $start, $len);
  }
}
// wrapper function for strpos
/**
 * Wrapper function for strpos
 */
function rc_strpos($haystack, $needle, $offset=0)
  {
{
  if (function_exists('mb_strpos'))
    return mb_strpos($haystack, $needle, $offset);
  else
    return strpos($haystack, $needle, $offset);
  }
}
// wrapper function for strrpos
/**
 * Wrapper function for strrpos
 */
function rc_strrpos($haystack, $needle, $offset=0)
  {
{
  if (function_exists('mb_strrpos'))
    return mb_strrpos($haystack, $needle, $offset);
  else
    return strrpos($haystack, $needle, $offset);
  }
}
// replace the middle part of a string with ...
// if it is longer than the allowed length
/**
 * Replace the middle part of a string with ...
 * if it is longer than the allowed length
 *
 * @param string Input string
 * @param int    Max. length
 * @param string Replace removed chars with this
 * @return string Abbrevated string
 */
function abbrevate_string($str, $maxlength, $place_holder='...')
  {
{
  $length = rc_strlen($str);
  $first_part_length = floor($maxlength/2) - rc_strlen($place_holder);
  
  if ($length > $maxlength)
    {
  {
    $second_starting_location = $length - $maxlength + $first_part_length + 1;
    $str = rc_substr($str, 0, $first_part_length) . $place_holder . rc_substr($str, $second_starting_location, $length);
    }
  }
  return $str;
  }
}
// make sure the string ends with a slash
/**
 * Make sure the string ends with a slash
 */
function slashify($str)
  {
{
  return unslashify($str).'/';
  }
}
// remove slash at the end of the string
/**
 * Remove slash at the end of the string
 */
function unslashify($str)
  {
{
  return preg_replace('/\/$/', '', $str);
  }
}
  
// delete all files within a folder
/**
 * Delete all files within a folder
 *
 * @param string Path to directory
 * @return boolean True on success, False if directory was not found
 */
function clear_directory($dir_path)
  {
{
  $dir = @opendir($dir_path);
  if(!$dir) return FALSE;
@@ -1531,26 +581,32 @@
  closedir($dir);
  return TRUE;
  }
}
// create a unix timestamp with a specified offset from now
/**
 * Create a unix timestamp with a specified offset from now
 *
 * @param string String representation of the offset (e.g. 20min, 5h, 2days)
 * @param int Factor to multiply with the offset
 * @return int Unix timestamp
 */
function get_offset_time($offset_str, $factor=1)
  {
  if (preg_match('/^([0-9]+)\s*([smhdw])/i', $offset_str, $regs))
    {
  {
    $amount = (int)$regs[1];
    $unit = strtolower($regs[2]);
    }
  }
  else
    {
  {
    $amount = (int)$offset_str;
    $unit = 's';
    }
  }
    
  $ts = mktime();
  switch ($unit)
    {
  {
    case 'w':
      $amount *= 7;
    case 'd':
@@ -1561,37 +617,34 @@
      $amount *= 60;
    case 's':
      $ts += $amount * $factor;
    }
  }
  return $ts;
  }
}
/**
 * strrstr
 * Return the last occurence of a string in another string
 *
 * return the last occurence of a string in another string
 * @param haystack string string in which to search
 * @param needle string string for which to search
 * @return index of needle within haystack, or false if not found
 */
function strrstr($haystack, $needle)
{
  $pver = phpversion();
  if ($pver[0] >= 5)
      return strrpos($haystack, $needle);
  else
  {
    $pver = phpversion();
    if ($pver[0] >= 5)
      {
        return strrpos($haystack, $needle);
      }
    else
      {
        $index = strpos(strrev($haystack), strrev($needle));
        if($index === false) {
            return false;
        }
        $index = strlen($haystack) - strlen($needle) - $index;
        return $index;
      }
    $index = strpos(strrev($haystack), strrev($needle));
    if($index === false)
        return false;
    $index = strlen($haystack) - strlen($needle) - $index;
    return $index;
  }
}
?>
program/include/rcube_smtp.inc
@@ -5,7 +5,7 @@
 | program/include/rcube_smtp.inc                                        |
 |                                                                       |
 | This file is part of the RoundCube Webmail client                     |
 | Copyright (C) 2005, RoundCube Dev. - Switzerland                      |
 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | PURPOSE:                                                              |
@@ -19,6 +19,11 @@
*/
/**
 * SMTP delivery functions
 *
 * @package Mail
 */
// include required PEAR classes
require_once('Net/SMTP.php');
@@ -47,7 +52,6 @@
 * @param string The full text of the message body, including any Mime parts, etc.
 *
 * @return bool  Returns TRUE on success, or FALSE on error
 * @access public
 */
function smtp_mail($from, $recipients, &$headers, &$body, &$response)
  {
@@ -342,6 +346,9 @@
  }
/**
 * @access private
 */
function smtp_explode_quoted_str($delimiter, $string)
  {
  $quotes=explode("\"", $string);
program/include/rcube_sqlite.inc
@@ -20,52 +20,58 @@
*/
/**
 * Callback functions for sqlite database interface
 *
 * @package Database
 */
function rcube_sqlite_from_unixtime($timestamp)
  {
    $timestamp = trim($timestamp);
    if (!preg_match("/^[0-9]+$/is", $timestamp))
      $ret = strtotime($timestamp);
    else
      $ret = $timestamp;
    $ret = date("Y-m-d H:i:s", $ret);
    rcube_sqlite_debug("FROM_UNIXTIME ($timestamp) = $ret");
    return $ret;
  $timestamp = trim($timestamp);
  if (!preg_match("/^[0-9]+$/is", $timestamp))
    $ret = strtotime($timestamp);
  else
    $ret = $timestamp;
  $ret = date("Y-m-d H:i:s", $ret);
  rcube_sqlite_debug("FROM_UNIXTIME ($timestamp) = $ret");
  return $ret;
  }
function rcube_sqlite_unix_timestamp($timestamp="")
  {
    $timestamp = trim($timestamp);
    if (!$timestamp)
      $ret = time();
    else if (!preg_match("/^[0-9]+$/is", $timestamp))
      $ret = strtotime($timestamp);
    else
      $ret = $timestamp;
  $timestamp = trim($timestamp);
  if (!$timestamp)
    $ret = time();
  else if (!preg_match("/^[0-9]+$/is", $timestamp))
    $ret = strtotime($timestamp);
  else
    $ret = $timestamp;
    rcube_sqlite_debug("UNIX_TIMESTAMP ($timestamp) = $ret");
    return $ret;
  rcube_sqlite_debug("UNIX_TIMESTAMP ($timestamp) = $ret");
  return $ret;
  }
function rcube_sqlite_now()
  {
    rcube_sqlite_debug("NOW() = ".date("Y-m-d H:i:s"));
    return date("Y-m-d H:i:s");
  rcube_sqlite_debug("NOW() = ".date("Y-m-d H:i:s"));
  return date("Y-m-d H:i:s");
  }
function rcube_sqlite_md5($str)
  {
    return md5($str);
  return md5($str);
  }
function rcube_sqlite_debug($str)
  {
    //console($str);
  //console($str);
  }
?>