From 47124c2279382714afd8dbe4a867a867ea179199 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Sat, 12 Apr 2008 09:54:45 -0400
Subject: [PATCH] Changed codebase to PHP5 with autoloader + added some new classes from the devel-vnext branch

---
 INSTALL                                   |    2 
 program/include/main.inc                  |   89 
 program/steps/mail/compose.inc            |   38 
 installer/check.php                       |    2 
 program/include/rcube_json_output.php     |  237 +++
 bin/msgimport.sh                          |    8 
 program/include/rcube_mail_mime.php       |   63 
 program/steps/mail/show.inc               |   23 
 installer/welcome.html                    |    2 
 program/include/iniset.php                |   98 +
 program/steps/settings/manage_folders.inc |   12 
 index.php                                 |  157 -
 program/include/rcube_shared.inc          |   12 
 program/include/rcube_result_set.php      |   74 +
 program/steps/mail/func.inc               |    3 
 program/steps/settings/func.inc           |   24 
 installer/test.php                        |   36 
 program/include/rcube_db.php              |   11 
 bin/modcss.php                            |    6 
 program/steps/mail/addcontact.inc         |    2 
 program/steps/settings/identities.inc     |    2 
 CHANGELOG                                 |   19 
 program/include/html.php                  |  642 +++++++++
 program/lib/html2text.php                 |    0 
 program/steps/addressbook/edit.inc        |    6 
 program/include/rcube_ldap.php            |    6 
 program/steps/addressbook/func.inc        |    7 
 program/include/rcube_user.php            |    0 
 program/include/bugs.inc                  |    4 
 config/main.inc.php.dist                  |    3 
 program/include/rcube_browser.php         |   75 +
 program/steps/mail/sendmail.inc           |   13 
 program/steps/mail/sendmdn.inc            |    2 
 program/steps/settings/edit_identity.inc  |    4 
 /dev/null                                 |  667 ----------
 program/include/rcube_mdb2.php            |   11 
 program/steps/error.inc                   |    2 
 installer/config.php                      |   77 
 program/include/rcube_imap.php            |    5 
 README                                    |    4 
 program/steps/mail/get.inc                |    2 
 program/include/rcube_template.php        | 1004 +++++++++++++++
 bin/html2text.php                         |   18 
 program/js/app.js                         |   35 
 bin/msgexport.sh                          |    8 
 installer/index.php                       |   23 
 program/include/rcube_contacts.php        |   57 
 program/include/rcube_html_page.php       |  256 +++
 48 files changed, 2,698 insertions(+), 1,153 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index c5e49fc..00502ab 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,14 +1,19 @@
 CHANGELOG RoundCube Webmail
 ---------------------------
 
-2008/04/11 (alec)
+2008/04/12 (thomasb)
+----------
+- Changed codebase to PHP5 with autoloader
+- Added some new classes from devel-vnext branch
 
+2008/04/11 (alec)
+----------
 - Mark as read in one action with message preview (#1484972)
 - Delete redundant quota reads (#1484972)
 - Add options for empty trash and expunge inbox on logout (#1483863)
 
 2008/04/10 (alec)
-
+----------
 - Add rows highlighting in onmousemove on ksearch list
 - Remove lines wrapping when displaying message
 - Fix month localization
@@ -16,7 +21,7 @@
 - Fix debug (ajax) console 
 
 2008/04/02 (alec)
-
+----------
 - Updated timezones list (#1484908)
 - Fix design in Settings (#1484799)
 - Fix deleting messages after clicking on "All" (#1484838)
@@ -24,21 +29,21 @@
 - Fix creating a new folder w/a comma in its name (#1484681)
 
 2008/04/01 (thomasb)
-
+----------
 - Fix Enter problem on login (#1484839)
 - Make the http-received header in outgoing mails configurable
 
 2008/03/30 (till)
-
+----------
 - Fix Firefox problem with ob_gzhandler (#1484932)
 - Improve message previewpane - less loading (#1484316)
 
 2008/03/28 (thomasb)
-
+----------
 - Disable installer by default; add config option to enable it again 
 
 2008/03/24 (till)
-
+----------
 - Don't send mark requests for already marked messages (#1484906)
 - Fix "quote inside a quote" (#1484783)
 
diff --git a/INSTALL b/INSTALL
index a88f4f9..098e886 100644
--- a/INSTALL
+++ b/INSTALL
@@ -11,7 +11,7 @@
 
 * The Apache or Lighttpd Webserver
 * .htaccess support allowing overrides for DirectoryIndex
-* PHP Version 4.3.1 or greater including
+* PHP Version 5.2 or greater including
    - PCRE (perl compatible regular expression)
    - libiconv (recommended)
    - mbstring (optional)
diff --git a/README b/README
index 6b2313a..1129cf5 100644
--- a/README
+++ b/README
@@ -4,8 +4,8 @@
 ATTENTION
 ---------
 This is just a snapshot of the current SVN repository and is NOT A STABLE
-version of RoundCube. There have been major changes since the latest release
-so please read the update instructions carefully. It's not recommended to
+version of RoundCube. Unlike the latest release this version requires PHP 5
+and does not work on a webserver with PHP 4. It's not recommended to
 replace an existing installation of RoundCube with this version. Also using
 a separate database or this installation is highly recommended.
 
diff --git a/bin/html2text.php b/bin/html2text.php
index 7f74ac6..0f0e6ae 100644
--- a/bin/html2text.php
+++ b/bin/html2text.php
@@ -1,21 +1,11 @@
 <?php
 
-require_once('../program/lib/html2text.inc');
+define('INSTALL_PATH', realpath('./../') . '/');
+require INSTALL_PATH.'program/include/iniset.php';
 
-$htmlText = $HTTP_RAW_POST_DATA;
-$converter = new html2text($htmlText);
+$converter = new html2text($HTTP_RAW_POST_DATA);
 
 header('Content-Type: text/plain; charset=UTF-8');
-$plaintext = $converter->get_text();
-
-$phpver = explode('.', phpversion());
-$vernum = $phpver[0] . $phpver[1] . $phpver[2];
-
-# html_entity_decode doesn't handle UTF character sets in PHP 4.x
-
-if (($vernum >= 500) && function_exists('html_entity_decode'))
-	print html_entity_decode($plaintext, ENT_COMPAT, 'UTF-8');
-else
-	print $plaintext;
+print html_entity_decode($converter->get_text(), ENT_COMPAT, 'UTF-8');
 
 ?>
diff --git a/bin/modcss.php b/bin/modcss.php
index e482389..e97b8ec 100644
--- a/bin/modcss.php
+++ b/bin/modcss.php
@@ -19,10 +19,8 @@
 
 */
 
-$INSTALL_PATH = realpath("./../") . "/";
-ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$INSTALL_PATH.'program'.PATH_SEPARATOR.ini_get('include_path'));
-
-require 'include/main.inc';
+define('INSTALL_PATH', realpath('./../') . '/');
+require INSTALL_PATH.'program/include/iniset.php';
 
 $source = "";
 if ($url = preg_replace('/[^a-z0-9.-_\?\$&=%]/i', '', $_GET['u']))
diff --git a/bin/msgexport.sh b/bin/msgexport.sh
index 6168955..890d48a 100755
--- a/bin/msgexport.sh
+++ b/bin/msgexport.sh
@@ -1,14 +1,10 @@
 #!/usr/bin/php -qC 
 <?php
 
-$CWD = $INSTALL_PATH = preg_replace('/bin\/$/', '', getcwd() . '/');
-ini_set('include_path',  ini_get('include_path') . PATH_SEPARATOR . $CWD.'program/');
+define('INSTALL_PATH', preg_replace('/bin\/$/', '', getcwd()) . '/');
 ini_set('memory_limit', -1);
 
-require_once('include/rcube_shared.inc');
-require_once('include/rcube_imap.inc');
-require_once('include/main.inc');
-require_once('include/bugs.inc');
+require_once INSTALL_PATH.'program/include/iniset.php';
 
 /**
  * Parse commandline arguments into a hash array
diff --git a/bin/msgimport b/bin/msgimport.sh
similarity index 88%
rename from bin/msgimport
rename to bin/msgimport.sh
index fd5afae..98a0389 100755
--- a/bin/msgimport
+++ b/bin/msgimport.sh
@@ -1,14 +1,10 @@
 #!/usr/bin/php -qC 
 <?php
 
-$CWD = $INSTALL_PATH = preg_replace('/bin\/$/', '', getcwd() . '/');
-ini_set('include_path',  ini_get('include_path') . PATH_SEPARATOR . $CWD.'program/');
+define('INSTALL_PATH', preg_replace('/bin\/$/', '', getcwd()) . '/');
 ini_set('memory_limit', -1);
 
-require_once('include/rcube_shared.inc');
-require_once('include/rcube_imap.inc');
-require_once('include/main.inc');
-require_once('include/bugs.inc');
+require_once INSTALL_PATH.'program/include/iniset.php';
 
 /**
  * Parse commandline arguments into a hash array
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 527210d..8adb4cf 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -240,9 +240,6 @@
 // don't allow these settings to be overriden by the user
 $rcmail_config['dont_override'] = array();
 
-// list of configuration option names that need to be available in Javascript.
-$rcmail_config['javascript_config'] = array('read_when_deleted', 'flag_for_deletion');
-
 // try to load host-specific configuration
 $rcmail_config['include_host_config'] = false;
 
diff --git a/index.php b/index.php
index b160dd6..aa8d8bb 100644
--- a/index.php
+++ b/index.php
@@ -40,54 +40,12 @@
 
 */
 
-// application constants
-define('RCMAIL_VERSION', '0.1-trunk');
-define('RCMAIL_CHARSET', 'UTF-8');
-define('JS_OBJECT_NAME', 'rcmail');
+// include environment
+require_once 'program/include/iniset.php';
 
 // define global vars
 $OUTPUT_TYPE = 'html';
-$INSTALL_PATH = dirname(__FILE__);
 $MAIN_TASKS = array('mail','settings','addressbook','logout');
-
-if (empty($INSTALL_PATH))
-  $INSTALL_PATH = './';
-else
-  $INSTALL_PATH .= '/';
-
-
-// make sure path_separator is defined
-if (!defined('PATH_SEPARATOR'))
-  define('PATH_SEPARATOR', (eregi('win', PHP_OS) ? ';' : ':'));
-
-
-// RC include folders MUST be included FIRST to avoid other
-// possible not compatible libraries (i.e PEAR) to be included
-// instead the ones provided by RC
-ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$INSTALL_PATH.'program'.PATH_SEPARATOR.$INSTALL_PATH.'program/lib'.PATH_SEPARATOR.ini_get('include_path'));
-
-ini_set('session.name', 'roundcube_sessid');
-ini_set('session.use_cookies', 1);
-ini_set('session.gc_maxlifetime', 21600);
-ini_set('session.gc_divisor', 500);
-ini_set('error_reporting', E_ALL&~E_NOTICE); 
-set_magic_quotes_runtime(0);
-
-// increase maximum execution time for php scripts
-// (does not work in safe mode)
-if (!ini_get('safe_mode')) @set_time_limit(120);
-
-// include base files
-require_once('include/rcube_shared.inc');
-require_once('include/rcube_imap.inc');
-require_once('include/bugs.inc');
-require_once('include/main.inc');
-require_once('PEAR.php');
-
-
-// set PEAR error handling
-// PEAR::setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_NOTICE);
-
 
 // catch some url/post parameters
 $_task = strip_quotes(get_input_value('_task', RCUBE_INPUT_GPC));
@@ -100,17 +58,16 @@
 
 
 // set output buffering
-if ($_action != 'get' && $_action != 'viewsource')
-{
+if ($_action != 'get' && $_action != 'viewsource') {
   // use gzip compression if supported
   if (function_exists('ob_gzhandler')
-    && !ini_get('zlib.output_compression')
-    && ini_get('output_handler') != 'ob_gzhandler')
-  {
+      && !ini_get('zlib.output_compression')
+      && ini_get('output_handler') != 'ob_gzhandler') {
     ob_start('ob_gzhandler');
   }
-  else
+  else {
     ob_start();
+  }
 }
 
 
@@ -123,20 +80,23 @@
 
 
 // add framed parameter
-if ($_framed)
-{
+if ($_framed) {
   $COMM_PATH .= '&_framed=1';
   $SESS_HIDDEN_FIELD .= "\n".'<input type="hidden" name="_framed" value="1" />';
 }
 
 
-// init necessary objects for GUI
-rcmail_load_gui();
+// init output class
+if (!empty($_GET['_remote']) || !empty($_POST['_remote'])) {
+  rcmail_init_json();
+}
+else {
+  rcmail_load_gui();
+}
 
 
 // check DB connections and exit on failure
-if ($err_str = $DB->is_error())
-{
+if ($err_str = $DB->is_error()) {
   raise_error(array(
     'code' => 603,
     'type' => 'db',
@@ -145,24 +105,21 @@
 
 
 // error steps
-if ($_action=='error' && !empty($_GET['_code']))
+if ($_action=='error' && !empty($_GET['_code'])) {
   raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE);
-
+}
 
 // try to log in
-if ($_action=='login' && $_task=='mail')
-{
+if ($_action=='login' && $_task=='mail') {
   $host = rcmail_autoselect_host();
   
   // check if client supports cookies
-  if (empty($_COOKIE))
-  {
+  if (empty($_COOKIE)) {
     $OUTPUT->show_message("cookiesdisabled", 'warning');
   }
   else if ($_SESSION['temp'] && !empty($_POST['_user']) && isset($_POST['_pass']) &&
            rcmail_login(trim(get_input_value('_user', RCUBE_INPUT_POST), ' '),
-              get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host))
-  {
+              get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host)) {
     // create new session ID
     unset($_SESSION['temp']);
     sess_regenerate_id();
@@ -174,26 +131,22 @@
     header("Location: $COMM_PATH");
     exit;
   }
-  else
-  {
+  else {
     $OUTPUT->show_message($IMAP->error_code == -1 ? 'imaperror' : 'loginfailed', 'warning');
     rcmail_kill_session();
   }
 }
 
 // end session
-else if (($_task=='logout' || $_action=='logout') && isset($_SESSION['user_id']))
-{
+else if (($_task=='logout' || $_action=='logout') && isset($_SESSION['user_id'])) {
   $OUTPUT->show_message('loggedout');
   rcmail_logout_actions();
   rcmail_kill_session();
 }
 
 // check session and auth cookie
-else if ($_action != 'login' && $_SESSION['user_id'] && $_action != 'send')
-{
-  if (!rcmail_authenticate_session())
-  {
+else if ($_action != 'login' && $_SESSION['user_id'] && $_action != 'send') {
+  if (!rcmail_authenticate_session()) {
     $OUTPUT->show_message('sessionerror', 'error');
     rcmail_kill_session();
   }
@@ -201,22 +154,20 @@
 
 
 // log in to imap server
-if (!empty($USER->ID) && $_task=='mail')
-{
+if (!empty($USER->ID) && $_task=='mail') {
   $conn = $IMAP->connect($_SESSION['imap_host'], $_SESSION['username'], decrypt_passwd($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl']);
-  if (!$conn)
-  {
+  if (!$conn) {
     $OUTPUT->show_message($IMAP->error_code == -1 ? 'imaperror' : 'sessionerror', 'error');
     rcmail_kill_session();
   }
-  else
+  else {
     rcmail_set_imap_prop();
+  }
 }
 
 
 // not logged in -> set task to 'login
-if (empty($USER->ID))
-{
+if (empty($USER->ID)) {
   if ($OUTPUT->ajax_call)
     $OUTPUT->remote_response("setTimeout(\"location.href='\"+this.env.comm_path+\"'\", 2000);");
   
@@ -225,10 +176,8 @@
 
 
 // check client X-header to verify request origin
-if ($OUTPUT->ajax_call)
-{
-  if (empty($CONFIG['devel_mode']) && !rc_request_header('X-RoundCube-Referer'))
-  {
+if ($OUTPUT->ajax_call) {
+  if (empty($CONFIG['devel_mode']) && !rc_request_header('X-RoundCube-Referer')) {
     header('HTTP/1.1 404 Not Found');
     die("Invalid Request");
   }
@@ -237,24 +186,25 @@
 
 // set task and action to client
 $OUTPUT->set_env('task', $_task);
-if (!empty($_action))
+if (!empty($_action)) {
   $OUTPUT->set_env('action', $_action);
+}
 
 
 
 // not logged in -> show login page
-if (empty($USER->ID))
-{
+if (empty($USER->ID)) {
   // check if installer is still active
-  if ($CONFIG['enable_installer'] && is_readable('./installer/index.php'))
-    $OUTPUT->add_footer('
-  <div style="background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em">
-  <h2 style="margin-top:0.2em">Installer script is still accessible</h2>
-  <p>The install script of your RoundCube installation is still stored in its default location!</p>
-  <p>Please <b>remove</b> the whole <tt>installer</tt> folder from the RoundCube directory because
-  these files may expose sensitive configuration data like server passwords and encryption keys
-  to the public. Make sure you cannot access the <a href="./installer/">installer script</a> from your browser.</p>
-  </div>');
+  if ($CONFIG['enable_installer'] && is_readable('./installer/index.php')) {
+    $OUTPUT->add_footer(html::div(array('style' => "background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em"),
+      html::tag('h2', array('style' => "margin-top:0.2em"), "Installer script is still accessible") .
+      html::p(null, "The install script of your RoundCube installation is still stored in its default location!") .
+      html::p(null, "Please <b>remove</b> the whole <tt>installer</tt> folder from the RoundCube directory because .
+        these files may expose sensitive configuration data like server passwords and encryption keys
+        to the public. Make sure you cannot access the <a href=\"./installer/\">installer script</a> from your browser.")
+      )
+    );
+  }
   
   $OUTPUT->task = 'login';
   $OUTPUT->send('login');
@@ -263,16 +213,14 @@
 
 
 // handle keep-alive signal
-if ($_action=='keep-alive')
-{
+if ($_action=='keep-alive') {
   $OUTPUT->reset();
   $OUTPUT->send('');
   exit;
 }
 
 // include task specific files
-if ($_task=='mail')
-{
+if ($_task=='mail') {
   include_once('program/steps/mail/func.inc');
   
   if ($_action=='show' || $_action=='preview' || $_action=='print')
@@ -327,13 +275,12 @@
     include('program/steps/mail/rss.inc');
     
   // make sure the message count is refreshed
-  $IMAP->messagecount($_SESSION['mbox'], 'ALL', TRUE);
+  $IMAP->messagecount($_SESSION['mbox'], 'ALL', true);
 }
 
 
 // include task specific files
-if ($_task=='addressbook')
-{
+if ($_task=='addressbook') {
   include_once('program/steps/addressbook/func.inc');
 
   if ($_action=='save')
@@ -363,8 +310,7 @@
 
 
 // include task specific files
-if ($_task=='settings')
-{
+if ($_task=='settings') {
   include_once('program/steps/settings/func.inc');
 
   if ($_action=='save-identity')
@@ -385,7 +331,6 @@
   if ($_action=='folders' || $_action=='subscribe' || $_action=='unsubscribe' ||
       $_action=='create-folder' || $_action=='rename-folder' || $_action=='delete-folder')
     include('program/steps/settings/manage_folders.inc');
-
 }
 
 
@@ -399,6 +344,6 @@
   'type' => 'php',
   'line' => __LINE__,
   'file' => __FILE__,
-  'message' => "Invalid request"), TRUE, TRUE);
+  'message' => "Invalid request"), true, true);
                       
 ?>
diff --git a/installer/check.php b/installer/check.php
index 2afa7da..7ca982f 100644
--- a/installer/check.php
+++ b/installer/check.php
@@ -37,7 +37,7 @@
 <h3>Checking PHP version</h3>
 <?php
 
-define('MIN_PHP_VERSION', '4.3.1');
+define('MIN_PHP_VERSION', '5.2.0');
 if (version_compare(PHP_VERSION, MIN_PHP_VERSION, '>=')) {
     $RCI->pass('Version', 'PHP ' . PHP_VERSION . ' detected');
 } else {
diff --git a/installer/config.php b/installer/config.php
index dc85faa..d6b5526 100644
--- a/installer/config.php
+++ b/installer/config.php
@@ -2,9 +2,6 @@
 <input type="hidden" name="_step" value="2" />
 <?php
 
-ini_set('display_errors', 1);
-require_once 'include/rcube_html.inc';
-
 // also load the default config to fill in the fields
 $RCI->load_defaults();
 
@@ -29,7 +26,7 @@
   echo ' within the <tt>config/</tt> directory of your RoundCube installation.<br/>';
   echo ' Make sure that there are no characters outside the <tt>&lt;?php ?&gt;</tt> brackets when saving the files.</p>';
   
-  $textbox = new textarea(array('rows' => 16, 'cols' => 60, 'class' => "configfile"));
+  $textbox = new html_textarea(array('rows' => 16, 'cols' => 60, 'class' => "configfile"));
   
   echo '<div><em>main.inc.php</em></div>';
   echo $textbox->show($RCI->create_config('main'));
@@ -56,7 +53,7 @@
 <?php
 /*
 $value = $RCI->getprop('debug_level');
-$check_debug = new checkbox(array('name' => '_debug_level[]'));
+$check_debug = new html_checkbox(array('name' => '_debug_level[]'));
 echo $check_debug->show(($value & 1) ? 1 : 0 , array('value' => 1, 'id' => 'cfgdebug1'));
 echo '<label for="cfgdebug1">Log errors</label><br />';
 
@@ -74,7 +71,7 @@
 <dd>
 <?php
 
-$input_prodname = new textfield(array('name' => '_product_name', 'size' => 30, 'id' => "cfgprodname"));
+$input_prodname = new html_inputfield(array('name' => '_product_name', 'size' => 30, 'id' => "cfgprodname"));
 echo $input_prodname->show($RCI->getprop('product_name'));
 
 ?>
@@ -85,7 +82,7 @@
 <dd>
 <?php
 
-$input_skinpath = new textfield(array('name' => '_skin_path', 'size' => 30, 'id' => "cfgskinpath"));
+$input_skinpath = new html_inputfield(array('name' => '_skin_path', 'size' => 30, 'id' => "cfgskinpath"));
 echo $input_skinpath->show($RCI->getprop('skin_path'));
 
 ?>
@@ -96,7 +93,7 @@
 <dd>
 <?php
 
-$input_tempdir = new textfield(array('name' => '_temp_dir', 'size' => 30, 'id' => "cfgtempdir"));
+$input_tempdir = new html_inputfield(array('name' => '_temp_dir', 'size' => 30, 'id' => "cfgtempdir"));
 echo $input_tempdir->show($RCI->getprop('temp_dir'));
 
 ?>
@@ -107,7 +104,7 @@
 <dd>
 <?php
 
-$input_logdir = new textfield(array('name' => '_log_dir', 'size' => 30, 'id' => "cfglogdir"));
+$input_logdir = new html_inputfield(array('name' => '_log_dir', 'size' => 30, 'id' => "cfglogdir"));
 echo $input_logdir->show($RCI->getprop('log_dir'));
 
 ?>
@@ -118,7 +115,7 @@
 <dd>
 <?php
 
-$check_ipcheck = new checkbox(array('name' => '_ip_check', 'id' => "cfgipcheck"));
+$check_ipcheck = new html_checkbox(array('name' => '_ip_check', 'id' => "cfgipcheck"));
 echo $check_ipcheck->show(intval($RCI->getprop('ip_check')), array('value' => 1));
 
 ?>
@@ -131,7 +128,7 @@
 <dd>
 <?php
 
-$input_deskey = new textfield(array('name' => '_des_key', 'size' => 30, 'id' => "cfgdeskey"));
+$input_deskey = new html_inputfield(array('name' => '_des_key', 'size' => 30, 'id' => "cfgdeskey"));
 echo $input_deskey->show($RCI->getprop('des_key'));
 
 ?>
@@ -144,7 +141,7 @@
 <dd>
 <?php
 
-$check_caching = new checkbox(array('name' => '_enable_caching', 'id' => "cfgcache"));
+$check_caching = new html_checkbox(array('name' => '_enable_caching', 'id' => "cfgcache"));
 echo $check_caching->show(intval($RCI->getprop('enable_caching')), array('value' => 1));
 
 ?>
@@ -155,7 +152,7 @@
 <dd>
 <?php
 
-$check_caching = new checkbox(array('name' => '_enable_spellcheck', 'id' => "cfgspellcheck"));
+$check_caching = new html_checkbox(array('name' => '_enable_spellcheck', 'id' => "cfgspellcheck"));
 echo $check_caching->show(intval($RCI->getprop('enable_spellcheck')), array('value' => 1));
 
 ?>
@@ -168,7 +165,7 @@
 <dd>
 <?php
 
-$select_mdnreq = new select(array('name' => '_mdn_requests', 'id' => "cfgmdnreq"));
+$select_mdnreq = new html_select(array('name' => '_mdn_requests', 'id' => "cfgmdnreq"));
 $select_mdnreq->add(array('ask the user', 'send automatically', 'ignore'), array(0, 1, 2));
 echo $select_mdnreq->show(intval($RCI->getprop('mdn_requests')));
 
@@ -192,17 +189,17 @@
 $supported_dbs = array('MySQL' => 'mysql', 'MySQLi' => 'mysqli',
     'PgSQL' => 'pgsql', 'SQLite' => 'sqlite');
 
-$select_dbtype = new select(array('name' => '_dbtype', 'id' => "cfgdbtype"));
+$select_dbtype = new html_select(array('name' => '_dbtype', 'id' => "cfgdbtype"));
 foreach ($supported_dbs AS $database => $ext) {
     if (extension_loaded($ext)) {
         $select_dbtype->add($database, $ext);
     }
 }
 
-$input_dbhost = new textfield(array('name' => '_dbhost', 'size' => 20, 'id' => "cfgdbhost"));
-$input_dbname = new textfield(array('name' => '_dbname', 'size' => 20, 'id' => "cfgdbname"));
-$input_dbuser = new textfield(array('name' => '_dbuser', 'size' => 20, 'id' => "cfgdbuser"));
-$input_dbpass = new textfield(array('name' => '_dbpass', 'size' => 20, 'id' => "cfgdbpass"));
+$input_dbhost = new html_inputfield(array('name' => '_dbhost', 'size' => 20, 'id' => "cfgdbhost"));
+$input_dbname = new html_inputfield(array('name' => '_dbname', 'size' => 20, 'id' => "cfgdbname"));
+$input_dbuser = new html_inputfield(array('name' => '_dbuser', 'size' => 20, 'id' => "cfgdbuser"));
+$input_dbpass = new html_inputfield(array('name' => '_dbpass', 'size' => 20, 'id' => "cfgdbpass"));
 
 $dsnw = DB::parseDSN($RCI->getprop('db_dsnw'));
 
@@ -228,7 +225,7 @@
 @include_once 'DB.php';
 @include_once 'MDB2.php';
 
-$select_dbba = new select(array('name' => '_db_backend', 'id' => "cfgdbba"));
+$select_dbba = new html_select(array('name' => '_db_backend', 'id' => "cfgdbba"));
 
 if (class_exists('DB'))
   $select_dbba->add('DB', 'db');
@@ -254,7 +251,7 @@
 <div id="defaulthostlist">
 <?php
 
-$text_imaphost = new textfield(array('name' => '_default_host[]', 'size' => 30));
+$text_imaphost = new html_inputfield(array('name' => '_default_host[]', 'size' => 30));
 $default_hosts = $RCI->get_hostlist();
 
 if (empty($default_hosts))
@@ -279,7 +276,7 @@
 <dd>
 <?php
 
-$text_imapport = new textfield(array('name' => '_default_port', 'size' => 6, 'id' => "cfgimapport"));
+$text_imapport = new html_inputfield(array('name' => '_default_port', 'size' => 6, 'id' => "cfgimapport"));
 echo $text_imapport->show($RCI->getprop('default_port'));
 
 ?>
@@ -290,7 +287,7 @@
 <dd>
 <?php
 
-$text_userdomain = new textfield(array('name' => '_username_domain', 'size' => 30, 'id' => "cfguserdomain"));
+$text_userdomain = new html_inputfield(array('name' => '_username_domain', 'size' => 30, 'id' => "cfguserdomain"));
 echo $text_userdomain->show($RCI->getprop('username_domain'));
 
 ?>
@@ -303,7 +300,7 @@
 <dd>
 <?php
 
-$check_autocreate = new checkbox(array('name' => '_auto_create_user', 'id' => "cfgautocreate"));
+$check_autocreate = new html_checkbox(array('name' => '_auto_create_user', 'id' => "cfgautocreate"));
 echo $check_autocreate->show(intval($RCI->getprop('auto_create_user')), array('value' => 1));
 
 ?>
@@ -320,7 +317,7 @@
 <dd>
 <?php
 
-$text_sentmbox = new textfield(array('name' => '_sent_mbox', 'size' => 20, 'id' => "cfgsentmbox"));
+$text_sentmbox = new html_inputfield(array('name' => '_sent_mbox', 'size' => 20, 'id' => "cfgsentmbox"));
 echo $text_sentmbox->show($RCI->getprop('sent_mbox'));
 
 ?>
@@ -333,7 +330,7 @@
 <dd>
 <?php
 
-$text_trashmbox = new textfield(array('name' => '_trash_mbox', 'size' => 20, 'id' => "cfgtrashmbox"));
+$text_trashmbox = new html_inputfield(array('name' => '_trash_mbox', 'size' => 20, 'id' => "cfgtrashmbox"));
 echo $text_trashmbox->show($RCI->getprop('trash_mbox'));
 
 ?>
@@ -346,7 +343,7 @@
 <dd>
 <?php
 
-$text_draftsmbox = new textfield(array('name' => '_drafts_mbox', 'size' => 20, 'id' => "cfgdraftsmbox"));
+$text_draftsmbox = new html_inputfield(array('name' => '_drafts_mbox', 'size' => 20, 'id' => "cfgdraftsmbox"));
 echo $text_draftsmbox->show($RCI->getprop('drafts_mbox'));
 
 ?>
@@ -364,7 +361,7 @@
 <dd>
 <?php
 
-$text_smtphost = new textfield(array('name' => '_smtp_server', 'size' => 30, 'id' => "cfgsmtphost"));
+$text_smtphost = new html_inputfield(array('name' => '_smtp_server', 'size' => 30, 'id' => "cfgsmtphost"));
 echo $text_smtphost->show($RCI->getprop('smtp_server'));
 
 ?>
@@ -377,7 +374,7 @@
 <dd>
 <?php
 
-$text_smtpport = new textfield(array('name' => '_smtp_port', 'size' => 6, 'id' => "cfgsmtpport"));
+$text_smtpport = new html_inputfield(array('name' => '_smtp_port', 'size' => 6, 'id' => "cfgsmtpport"));
 echo $text_smtpport->show($RCI->getprop('smtp_port'));
 
 ?>
@@ -388,8 +385,8 @@
 <dd>
 <?php
 
-$text_smtpuser = new textfield(array('name' => '_smtp_user', 'size' => 20, 'id' => "cfgsmtpuser"));
-$text_smtppass = new textfield(array('name' => '_smtp_pass', 'size' => 20, 'id' => "cfgsmtppass"));
+$text_smtpuser = new html_inputfield(array('name' => '_smtp_user', 'size' => 20, 'id' => "cfgsmtpuser"));
+$text_smtppass = new html_inputfield(array('name' => '_smtp_pass', 'size' => 20, 'id' => "cfgsmtppass"));
 echo $text_smtpuser->show($RCI->getprop('smtp_user'));
 echo $text_smtppass->show($RCI->getprop('smtp_pass'));
 
@@ -398,7 +395,7 @@
 <p>
 <?php
 
-$check_smtpuser = new checkbox(array('name' => '_smtp_user_u', 'id' => "cfgsmtpuseru"));
+$check_smtpuser = new html_checkbox(array('name' => '_smtp_user_u', 'id' => "cfgsmtpuseru"));
 echo $check_smtpuser->show($RCI->getprop('smtp_user') == '%u' || $_POST['_smtp_user_u'] ? 1 : 0, array('value' => 1));
 
 ?>
@@ -410,7 +407,7 @@
 <dd>
 <?php
 /*
-$select_smtpauth = new select(array('name' => '_smtp_auth_type', 'id' => "cfgsmtpauth"));
+$select_smtpauth = new html_select(array('name' => '_smtp_auth_type', 'id' => "cfgsmtpauth"));
 $select_smtpauth->add(array('(auto)', 'PLAIN', 'DIGEST-MD5', 'CRAM-MD5', 'LOGIN'), array('0', 'PLAIN', 'DIGEST-MD5', 'CRAM-MD5', 'LOGIN'));
 echo $select_smtpauth->show(intval($RCI->getprop('smtp_auth_type')));
 */
@@ -422,7 +419,7 @@
 <dd>
 <?php
 
-$check_smtplog = new checkbox(array('name' => '_smtp_log', 'id' => "cfgsmtplog"));
+$check_smtplog = new html_checkbox(array('name' => '_smtp_log', 'id' => "cfgsmtplog"));
 echo $check_smtplog->show(intval($RCI->getprop('smtp_log')), array('value' => 1));
 
 ?>
@@ -441,7 +438,7 @@
 <dd>
 <?php
 
-$input_locale = new textfield(array('name' => '_locale_string', 'size' => 6, 'id' => "cfglocale"));
+$input_locale = new html_inputfield(array('name' => '_locale_string', 'size' => 6, 'id' => "cfglocale"));
 echo $input_locale->show($RCI->getprop('locale_string'));
 
 ?>
@@ -453,7 +450,7 @@
 <dd>
 <?php
 
-$input_pagesize = new textfield(array('name' => '_pagesize', 'size' => 6, 'id' => "cfgpagesize"));
+$input_pagesize = new html_inputfield(array('name' => '_pagesize', 'size' => 6, 'id' => "cfgpagesize"));
 echo $input_pagesize->show($RCI->getprop('pagesize'));
 
 ?>
@@ -464,7 +461,7 @@
 <dd>
 <?php
 
-$check_htmlview = new checkbox(array('name' => '_prefer_html', 'id' => "cfghtmlview", 'value' => 1));
+$check_htmlview = new html_checkbox(array('name' => '_prefer_html', 'id' => "cfghtmlview", 'value' => 1));
 echo $check_htmlview->show(intval($RCI->getprop('prefer_html')));
 
 ?>
@@ -475,7 +472,7 @@
 <dd>
 <?php
 
-$check_prevpane = new checkbox(array('name' => '_preview_pane', 'id' => "cfgprevpane", 'value' => 1));
+$check_prevpane = new html_checkbox(array('name' => '_preview_pane', 'id' => "cfgprevpane", 'value' => 1));
 echo $check_prevpane->show(intval($RCI->getprop('preview_pane')));
 
 ?>
@@ -486,7 +483,7 @@
 <dd>
 <?php
 
-$check_htmlcomp = new checkbox(array('name' => '_htmleditor', 'id' => "cfghtmlcompose", 'value' => 1));
+$check_htmlcomp = new html_checkbox(array('name' => '_htmleditor', 'id' => "cfghtmlcompose", 'value' => 1));
 echo $check_htmlcomp->show(intval($RCI->getprop('htmleditor')));
 
 ?>
@@ -498,7 +495,7 @@
 <label for="cfgautosave">Save compose message every</label>
 <?php
 
-$select_autosave = new select(array('name' => '_draft_autosave', 'id' => 'cfgautosave'));
+$select_autosave = new html_select(array('name' => '_draft_autosave', 'id' => 'cfgautosave'));
 $select_autosave->add('never', 0);
 foreach (array(3, 5, 10) as $i => $min)
   $select_autosave->add("$min min", $min*60);
diff --git a/installer/index.php b/installer/index.php
index cb5f3fe..f6fa479 100644
--- a/installer/index.php
+++ b/installer/index.php
@@ -3,7 +3,25 @@
 ini_set('error_reporting', E_ALL&~E_NOTICE);
 ini_set('display_errors', 1);
 
+define('INSTALL_PATH', realpath(dirname(__FILE__) . '/../').'/');
+$include_path  = INSTALL_PATH . 'program/lib' . PATH_SEPARATOR . INSTALL_PATH . 'program' . PATH_SEPARATOR . INSTALL_PATH . 'program/include' . PATH_SEPARATOR . ini_get('include_path');
+set_include_path($include_path);
+
 session_start();
+
+/**
+ * Use PHP5 autoload for dynamic class loading
+ * (copy from program/incllude/iniset.php)
+ */
+function __autoload($classname)
+{
+  $filename = preg_replace(
+      array('/MDB2_(.+)/', '/Mail_(.+)/', '/^html_.+/', '/^utf8$/'),
+      array('MDB2/\\1', 'Mail/\\1', 'html', 'utf8.class'),
+      $classname
+  );
+  include_once $filename. '.php';
+}
 
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
@@ -32,11 +50,6 @@
 
 <?php
 
-  $docroot = realpath(dirname(__FILE__) . '/../');
-  $include_path  = $docroot . '/program/lib' . PATH_SEPARATOR . $docroot . '/program' . PATH_SEPARATOR . ini_get('include_path');
-  set_include_path($include_path);
-
-  require_once 'rcube_install.php';
   $RCI = rcube_install::get_instance();
   $RCI->load_config();
 
diff --git a/installer/test.php b/installer/test.php
index 5be343a..bdaf3ee 100644
--- a/installer/test.php
+++ b/installer/test.php
@@ -3,10 +3,8 @@
 <h3>Check config files</h3>
 <?php
 
-require_once 'include/rcube_html.inc';
-
-$read_main = is_readable('../config/main.inc.php');
-$read_db = is_readable('../config/db.inc.php');
+$read_main = is_readable(INSTALL_PATH.'config/main.inc.php');
+$read_db = is_readable(INSTALL_PATH.'config/db.inc.php');
 
 if ($read_main && !empty($RCI->config)) {
   $RCI->pass('main.inc.php');
@@ -38,7 +36,7 @@
 if ($RCI->configured) {
     $pass = false;
     foreach (array($RCI->config['temp_dir'],$RCI->config['log_dir']) as $dir) {
-        $dirpath = $dir{0} == '/' ? $dir : $docroot . '/' . $dir;
+        $dirpath = $dir{0} == '/' ? $dir : INSTALL_PATH . $dir;
         if (is_writable(realpath($dirpath))) {
             $RCI->pass($dir);
             $pass = true;
@@ -68,10 +66,9 @@
         echo 'Backend: ';
         echo 'PEAR::' . strtoupper($RCI->config['db_backend']) . '<br />';
 
-        $_class = 'rcube_' . strtolower($RCI->config['db_backend']);
-        require_once 'include/' . $_class . '.inc';
+        $dbclass = 'rcube_' . strtolower($RCI->config['db_backend']);
 
-        $DB = new $_class($RCI->config['db_dsnw'], '', false);
+        $DB = new $dbclass($RCI->config['db_dsnw'], '', false);
         $DB->db_connect('w');
         if (!($db_error_msg = $DB->is_error())) {
             $RCI->pass('DSN (write)');
@@ -164,11 +161,11 @@
   $pass = $RCI->getprop('smtp_pass', '(none)');
   
   if ($user == '%u') {
-    $user_field = new textfield(array('name' => '_smtp_user'));
+    $user_field = new html_inputfield(array('name' => '_smtp_user'));
     $user = $user_field->show($_POST['_smtp_user']);
   }
   if ($pass == '%p') {
-    $pass_field = new passwordfield(array('name' => '_smtp_pass'));
+    $pass_field = new html_passwordfield(array('name' => '_smtp_pass'));
     $pass = $pass_field->show();
   }
   
@@ -176,8 +173,8 @@
   echo "Password: $pass<br />";
 }
 
-$from_field = new textfield(array('name' => '_from', 'id' => 'sendmailfrom'));
-$to_field = new textfield(array('name' => '_to', 'id' => 'sendmailto'));
+$from_field = new html_inputfield(array('name' => '_from', 'id' => 'sendmailfrom'));
+$to_field = new html_inputfield(array('name' => '_to', 'id' => 'sendmailto'));
 
 ?>
 </p>
@@ -186,8 +183,7 @@
 
 if (isset($_POST['sendmail']) && !empty($_POST['_from']) && !empty($_POST['_to'])) {
   
-  require_once 'lib/rc_mail_mime.inc';
-  require_once 'include/rcube_smtp.inc';
+  require_once 'rcube_smtp.inc';
   
   echo '<p>Trying to send email...<br />';
   
@@ -214,7 +210,7 @@
         $CONFIG['smtp_pass'] = $_POST['_smtp_pass'];
       }
 
-      $mail_object  = new rc_mail_mime();
+      $mail_object  = new rcube_mail_mime();
       $send_headers = $mail_object->headers($headers);
       
       $status = smtp_mail($headers['From'], $headers['To'],
@@ -271,15 +267,15 @@
 
 $default_hosts = $RCI->get_hostlist();
 if (!empty($default_hosts)) {
-  $host_field = new select(array('name' => '_host', 'id' => 'imaphost'));
+  $host_field = new html_select(array('name' => '_host', 'id' => 'imaphost'));
   $host_field->add($default_hosts);
 }
 else {
-  $host_field = new textfield(array('name' => '_host', 'id' => 'imaphost'));
+  $host_field = new html_inputfield(array('name' => '_host', 'id' => 'imaphost'));
 }
 
-$user_field = new textfield(array('name' => '_user', 'id' => 'imapuser'));
-$pass_field = new passwordfield(array('name' => '_pass', 'id' => 'imappass'));
+$user_field = new html_inputfield(array('name' => '_user', 'id' => 'imapuser'));
+$pass_field = new html_passwordfield(array('name' => '_pass', 'id' => 'imappass'));
 
 ?>
 
@@ -307,8 +303,6 @@
 <?php
 
 if (isset($_POST['imaptest']) && !empty($_POST['_host']) && !empty($_POST['_user'])) {
-  
-  require_once 'include/rcube_imap.inc';
   
   echo '<p>Connecting to ' . Q($_POST['_host']) . '...<br />';
   
diff --git a/installer/welcome.html b/installer/welcome.html
index 200f680..bfec233 100644
--- a/installer/welcome.html
+++ b/installer/welcome.html
@@ -6,7 +6,7 @@
 
 <p>The basic requirements are:</p>
 <ul>
-  <li>PHP Version 4.3.1 or greater including
+  <li>PHP Version 5.2.0 or greater including
     <ul>
       <li>PCRE (perl compatible regular expression)</li>
       <li>Session support</li>
diff --git a/program/include/bugs.inc b/program/include/bugs.inc
index 9d98ef4..78808c3 100644
--- a/program/include/bugs.inc
+++ b/program/include/bugs.inc
@@ -66,7 +66,7 @@
  */
 function log_bug($arg_arr)
 {
-  global $CONFIG, $INSTALL_PATH;
+  global $CONFIG;
   $program = $arg_arr['type']=='xpath' ? 'XPath' : strtoupper($arg_arr['type']);
 
   // write error to local log file
@@ -81,7 +81,7 @@
       $arg_arr['line']);
                  
     if (empty($CONFIG['log_dir']))
-      $CONFIG['log_dir'] = $INSTALL_PATH.'logs';
+      $CONFIG['log_dir'] = INSTALL_PATH.'logs';
       
     // try to open specific log file for writing
     if ($fp = @fopen($CONFIG['log_dir'].'/errors', 'a'))
diff --git a/program/include/html.php b/program/include/html.php
new file mode 100644
index 0000000..8af1b1f
--- /dev/null
+++ b/program/include/html.php
@@ -0,0 +1,642 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/html.php                                              |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2005-2008, RoundCube Dev, - Switzerland                 |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Helper class to create valid XHTML code                             |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+ */
+
+
+/**
+ * Class for HTML code creation
+ *
+ * @package HTML
+ */
+class html
+{
+    protected $tagname;
+    protected $attrib = array();
+    protected $allowed;
+    protected $content;
+
+    protected static $common_attrib = array('id','class','style','title','align');
+    public static $containers = array('div','span','p','h1','h2','h3','form','textarea');
+    public static $lc_tags = true;
+
+    /**
+     * Constructor
+     *
+     * @param array Hash array with tag attributes
+     */
+    public function __construct($attrib = array())
+    {
+        if (is_array($attrib)) {
+            $this->attrib = $attrib;
+        }
+    }
+
+    /**
+     * Return the tag code
+     *
+     * @return string The finally composed HTML tag
+     */
+    public function show()
+    {
+        return self::tag($this->tagname, $this->attrib, $this->content, $this->allowed);
+    }
+
+    /****** STATIC METHODS *******/
+
+    /**
+     * Generic method to create a HTML tag
+     *
+     * @param string Tag name
+     * @param array  Tag attributes as key/value pairs
+     * @param string Optinal Tag content (creates a container tag)
+     * @param array  List with allowed attributes, omit to allow all
+     * @return string The XHTML tag
+     */
+    public static function tag($tagname, $attrib = array(), $content = null, $allowed_attrib = null)
+    {
+        $inline_tags = array('a','span','img');
+        $suffix = $attrib['nl'] || ($content && $attrib['nl'] !== false && !in_array($tagname, $inline_tags)) ? "\n" : '';
+
+        $tagname = self::$lc_tags ? strtolower($tagname) : $tagname;
+        if ($content || in_array($tagname, self::$containers)) {
+            $templ = $attrib['noclose'] ? "<%s%s>%s" : "<%s%s>%s</%s>%s";
+            unset($attrib['noclose']);
+            return sprintf($templ, $tagname, self::attrib_string($attrib, $allowed_attrib), $content, $tagname, $suffix);
+        }
+        else {
+            return sprintf("<%s%s />%s", $tagname, self::attrib_string($attrib, $allowed_attrib), $suffix);
+        }
+    }
+
+    /**
+     * Derrived method for <div> containers
+     *
+     * @param mixed  Hash array with tag attributes or string with class name
+     * @param string Div content
+     * @return string HTML code
+     * @see html::tag()
+     */
+    public static function div($attr = null, $cont = null)
+    {
+        if (is_string($attr)) {
+            $attr = array('class' => $attr);
+        }
+        return self::tag('div', $attr, $cont, self::$common_attrib);
+    }
+
+    /**
+     * Derrived method for <p> blocks
+     *
+     * @param mixed  Hash array with tag attributes or string with class name
+     * @param string Paragraph content
+     * @return string HTML code
+     * @see html::tag()
+     */
+    public static function p($attr = null, $cont = null)
+    {
+        if (is_string($attr)) {
+            $attr = array('class' => $attr);
+        }
+        return self::tag('p', $attr, $cont, self::$common_attrib);
+    }
+
+    /**
+     * Derrived method to create <img />
+     *
+     * @param mixed Hash array with tag attributes or string with image source (src)
+     * @return string HTML code
+     * @see html::tag()
+     */
+    public static function img($attr = null)
+    {
+        if (is_string($attr)) {
+            $attr = array('src' => $attr);
+        }
+        return self::tag('img', $attr + array('alt' => ''), null, array_merge(self::$common_attrib, array('src','alt','width','height','border','usemap')));
+    }
+
+    /**
+     * Derrived method for link tags
+     *
+     * @param mixed  Hash array with tag attributes or string with link location (href)
+     * @param string Link content
+     * @return string HTML code
+     * @see html::tag()
+     */
+    public static function a($attr, $cont)
+    {
+        if (is_string($attr)) {
+            $attr = array('href' => $attr);
+        }
+        return self::tag('a', $attr, $cont, array_merge(self::$common_attrib, array('href','target','name','onclick','onmouseover','onmouseout')));
+    }
+
+    /**
+     * Derrived method for inline span tags
+     *
+     * @param mixed  Hash array with tag attributes or string with class name
+     * @param string Tag content
+     * @return string HTML code
+     * @see html::tag()
+     */
+    public static function span($attr, $cont)
+    {
+        if (is_string($attr)) {
+            $attr = array('class' => $attr);
+        }
+        return self::tag('span', $attr, $cont, self::$common_attrib);
+    }
+
+    /**
+     * Derrived method for form element labels
+     *
+     * @param mixed  Hash array with tag attributes or string with 'for' attrib
+     * @param string Tag content
+     * @return string HTML code
+     * @see html::tag()
+     */
+    public static function label($attr, $cont)
+    {
+        if (is_string($attr)) {
+            $attr = array('for' => $attr);
+        }
+        return self::tag('label', $attr, $cont, array_merge(self::$common_attrib, array('for')));
+    }
+
+    /**
+     * Derrived method for line breaks
+     *
+     * @return string HTML code
+     * @see html::tag()
+     */
+    public static function br()
+    {
+        return self::tag('br');
+    }
+
+    /**
+     * Create string with attributes
+     *
+     * @param array Associative arry with tag attributes
+     * @param array List of allowed attributes
+     * @return string Valid attribute string
+     */
+    public static function attrib_string($attrib = array(), $allowed = null)
+    {
+        if (empty($attrib)) {
+            return '';
+        }
+
+        $allowed_f = array_flip((array)$allowed);
+        $attrib_arr = array();
+        foreach ($attrib as $key => $value) {
+            // skip size if not numeric
+            if (($key=='size' && !is_numeric($value))) {
+                continue;
+            }
+
+            // ignore "internal" or not allowed attributes
+            if ($key == 'nl' || ($allowed && !isset($allowed_f[$key])) || $value === null) {
+                continue;
+            }
+
+            // skip empty eventhandlers
+            if (preg_match('/^on[a-z]+/', $key) && !$value) {
+                continue;
+            }
+
+            // attributes with no value
+            if (in_array($key, array('checked', 'multiple', 'disabled', 'selected'))) {
+                if ($value) {
+                    $attrib_arr[] = sprintf('%s="%s"', $key, $key);
+                }
+            }
+            else if ($key=='value') {
+                $attrib_arr[] = sprintf('%s="%s"', $key, Q($value, 'strict', false));
+            }
+            else {
+                $attrib_arr[] = sprintf('%s="%s"', $key, Q($value));
+            }
+        }
+        return count($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
+    }
+}
+
+/**
+ * Class to create an HTML input field
+ *
+ * @package HTML
+ */
+class html_inputfield extends html
+{
+    protected $tagname = 'input';
+    protected $type = 'text';
+
+    public function __construct($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 attributes to override
+     * @return string HTML output
+     */
+    public 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;
+        }
+        // set type
+        $this->attrib['type'] = $this->type;
+        return parent::show();
+    }
+}
+
+/**
+ * Class to create an HTML password field
+ *
+ * @package HTML
+ */
+class html_passwordfield extends html_inputfield
+{
+    protected $type = 'password';
+}
+
+/**
+ * Class to create an hidden HTML input field
+ *
+ * @package HTML
+ */
+
+class html_hiddenfield extends html_inputfield
+{
+    protected $type = 'hidden';
+    protected $fields_arr = array();
+    protected $newline = true;
+
+    /**
+     * Constructor
+     *
+     * @param array Named tag attributes
+     */
+    public function __construct($attrib = null)
+    {
+        if (is_array($attrib)) {
+            $this->add($attrib);
+        }
+    }
+
+    /**
+     * Add a hidden field to this instance
+     *
+     * @param array Named tag attributes
+     */
+    public function add($attrib)
+    {
+        $this->fields_arr[] = $attrib;
+    }
+
+    /**
+     * Create HTML code for the hidden fields
+     *
+     * @return string Final HTML code
+     */
+    public function show()
+    {
+        $out = '';
+        foreach ($this->fields_arr as $attrib) {
+            $out .= self::tag($this->tagname, array('type' => $this->type) + $attrib);
+        }
+        return $out;
+    }
+}
+
+/**
+ * Class to create HTML radio buttons
+ *
+ * @package HTML
+ */
+class html_radiobutton extends html_inputfield
+{
+    protected $type = 'radio';
+
+    /**
+     * Get HTML code for this object
+     *
+     * @param string Value of the checked field
+     * @param array Additional attributes to override
+     * @return string HTML output
+     */
+    public function show($value = '', $attrib = null)
+    {
+        // overwrite object attributes
+        if (is_array($attrib)) {
+            $this->attrib = array_merge($this->attrib, $attrib);
+        }
+
+        // set value attribute
+        $this->attrib['checked'] = ($value && (string)$value == (string)$this->attrib['value']);
+
+        return parent::show();
+    }
+}
+
+/**
+ * Class to create HTML checkboxes
+ *
+ * @package HTML
+ */
+class html_checkbox extends html_inputfield
+{
+    protected $type = 'checkbox';
+
+    /**
+     * Get HTML code for this object
+     *
+     * @param string Value of the checked field
+     * @param array Additional attributes to override
+     * @return string HTML output
+     */
+    public function show($value = '', $attrib = null)
+    {
+        // overwrite object attributes
+        if (is_array($attrib)) {
+            $this->attrib = array_merge($this->attrib, $attrib);
+        }
+
+        // set value attribute
+        $this->attrib['checked'] = ($value && (string)$value == (string)$this->attrib['value']);
+
+        return parent::show();
+    }
+}
+
+/**
+ * Class to create an HTML textarea
+ *
+ * @package HTML
+ */
+class html_textarea extends html
+{
+    protected $tagname = 'textarea';
+    protected $allowed_attrib = array('name','rows','cols','wrap');
+
+    /**
+     * Get HTML code for this object
+     *
+     * @param string Textbox value
+     * @param array Additional attributes to override
+     * @return string HTML output
+     */
+    public 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 self::tag($this->tagname, $this->attrib, Q($value), array_merge(self::$common_attrib, $this->allowed_attrib));
+    }
+}
+
+/**
+ * Builder for HTML drop-down menus
+ * Syntax:<pre>
+ * // create instance. arguments are used to set attributes of select-tag
+ * $select = new html_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 html_select extends html
+{
+    protected $tagname = 'select';
+    protected $options = array();
+    
+    /**
+     * Add a new option to this drop-down
+     *
+     * @param mixed Option name or array with option names
+     * @param mixed Option value or array with option values
+     */
+    public function add($names, $values = null)
+    {
+        if (is_array($names)) {
+            foreach ($names as $i => $text) {
+                $this->options[] = array('text' => $text, 'value' => $values[$i]);
+            }
+        }
+        else {
+            $this->options[] = array('text' => $names, 'value' => $values);
+        }
+    }
+
+
+    /**
+     * Get HTML code for this object
+     *
+     * @param string Value of the selection option
+     * @param array Additional attributes to override
+     * @return string HTML output
+     */
+    public function show($select = array(), $attrib = null)
+    {
+        // overwrite object attributes
+        if (is_array($attrib)) {
+            $this->attrib = array_merge($this->attrib, $attrib);
+        }
+
+        $this->content = "\n";
+        $select = (array)$select;
+        foreach ($this->options as $option) {
+            $attr = array(
+                'value' => $option['value'],
+                'selected' => ((!empty($option['value']) && in_array($option['value'], $select, true)) ||
+            (in_array($option['text'], $select, TRUE))) ? 1 : null);
+
+            $this->content .= self::tag('option', $attr, Q($option['text']));
+        }
+        return parent::show();
+    }
+}
+
+
+/**
+ * Class to build an HTML table
+ *
+ * @package HTML
+ */
+class html_table extends html
+{
+    protected $tagname = 'table';
+    protected $allowed = array('id','class','style','width','summary','cellpadding','cellspacing','border');
+    private $header = array();
+    private $rows = array();
+    private $rowindex = 0;
+    private $colindex = 0;
+
+
+    public function __construct($attrib = array())
+    {
+        $this->attrib = array_merge($attrib, array('summary' => '', 'border' => 0));
+    }
+
+    /**
+     * Add a table cell
+     *
+     * @param array Cell attributes
+     * @param string Cell content
+     */
+    public function add($attr, $cont)
+    {
+        if (is_string($attr)) {
+            $attr = array('class' => $attr);
+        }
+
+        $cell = new stdClass;
+        $cell->attrib = $attr;
+        $cell->content = $cont;
+
+        $this->rows[$this->rowindex]->cells[$this->colindex] = $cell;
+        $this->colindex++;
+
+        if ($this->attrib['cols'] && $this->colindex == $this->attrib['cols']) {
+            $this->add_row();
+        }
+    }
+
+    /**
+     * Add a table header cell
+     *
+     * @param array Cell attributes
+     * @param string Cell content
+     */
+    private function add_header($attr, $cont)
+    {
+        if (is_string($attr))
+        $attr = array('class' => $attr);
+
+        $cell = new stdClass;
+        $cell->attrib = $attr;
+        $cell->content = $cont;
+        $this->header[] = $cell;
+    }
+
+    /**
+     * Jump to next row
+     *
+     * @param array Row attributes
+     */
+    private function add_row($attr = array())
+    {
+        $this->rowindex++;
+        $this->colindex = 0;
+        $this->rows[$this->rowindex] = new stdClass;
+        $this->rows[$this->rowindex]->attrib = $attr;
+        $this->rows[$this->rowindex]->cells = array();
+    }
+
+
+    /**
+     * Build HTML output of the table data
+     *
+     * @param array Table attributes
+     * @return string The final table HTML code
+     */
+    public function show($attr = array())
+    {
+        $this->attrib = array_merge($this->attrib, $attr);
+        $thead = $tbody = "";
+
+        // include <thead>
+        if (!empty($this->header)) {
+            $rowcontent = '';
+            foreach ($this->header as $c => $col) {
+                $rowcontent .= self::tag('th', $col->attrib, $col->content);
+            }
+            $thead = self::tag('thead', null, self::tag('tr', null, $rowcontent));
+        }
+
+        foreach ($this->rows as $r => $row) {
+            $rowcontent = '';
+            foreach ($row->cells as $c => $col) {
+                $rowcontent .= self::tag('td', $col->attrib, $col->content);
+            }
+
+            if ($r < $this->rowindex || count($row->cells)) {
+                $tbody .= self::tag('tr', $rows->attrib, $rowcontent);
+            }
+        }
+
+        if ($this->attrib['rowsonly']) {
+            return $tbody;
+        }
+
+        // add <tbody>
+        $this->content = $thead . self::tag('tbody', null, $tbody);
+
+        unset($this->attrib['cols'], $this->attrib['rowsonly']);
+        return parent::show();
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/program/include/iniset.php b/program/include/iniset.php
new file mode 100755
index 0000000..926b282
--- /dev/null
+++ b/program/include/iniset.php
@@ -0,0 +1,98 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/iniset.inc                                            |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2008, RoundCube Dev, - Switzerland                      |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Setup the application envoronment required to process               |
+ |   any request.                                                        |
+ +-----------------------------------------------------------------------+
+ | Author: Till Klampaeckel <till@php.net>                               |
+ |         Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id: cache.inc 88 2005-12-03 16:54:12Z roundcube $
+
+*/
+
+
+// application constants
+define('RCMAIL_VERSION', '0.1-trunk');
+define('RCMAIL_CHARSET', 'UTF-8');
+define('JS_OBJECT_NAME', 'rcmail');
+
+if (!defined('INSTALL_PATH')) {
+  define('INSTALL_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/');
+}
+
+// make sure path_separator is defined
+if (!defined('PATH_SEPARATOR')) {
+  define('PATH_SEPARATOR', (eregi('win', PHP_OS) ? ';' : ':'));
+}
+
+// RC include folders MUST be included FIRST to avoid other
+// possible not compatible libraries (i.e PEAR) to be included
+// instead the ones provided by RC
+$include_path = INSTALL_PATH . PATH_SEPARATOR;
+$include_path.= INSTALL_PATH . 'program' . PATH_SEPARATOR;
+$include_path.= INSTALL_PATH . 'program/lib' . PATH_SEPARATOR;
+$include_path.= INSTALL_PATH . 'program/include' . PATH_SEPARATOR;
+$include_path.= ini_get('include_path');
+
+if (set_include_path($include_path) === false) {
+  die('Fatal error: ini_set/set_include_path does not work.');
+}
+
+ini_set('session.name', 'roundcube_sessid');
+ini_set('session.use_cookies', 1);
+ini_set('session.gc_maxlifetime', 21600);
+ini_set('session.gc_divisor', 500);
+ini_set('error_reporting', E_ALL&~E_NOTICE);
+set_magic_quotes_runtime(0);
+
+// increase maximum execution time for php scripts
+// (does not work in safe mode)
+if (!ini_get('safe_mode')) {
+  set_time_limit(120);
+}
+
+/**
+ * Use PHP5 autoload for dynamic class loading
+ * 
+ * @todo Make Zend, PEAR etc play with this
+ */
+function __autoload($classname)
+{
+  $filename = preg_replace(
+      array('/MDB2_(.+)/', '/Mail_(.+)/', '/^html_.+/', '/^utf8$/'),
+      array('MDB2/\\1', 'Mail/\\1', 'html', 'utf8.class'),
+      $classname
+  );
+  include_once $filename. '.php';
+}
+
+/**
+ * Local callback function for PEAR errors
+ */
+function rcube_pear_error($err)
+{
+  error_log(sprintf("%s (%s): %s",
+    $err->getMessage(),
+    $err->getCode(),
+    $err->getUserinfo()), 0);
+}
+
+// include global functions
+require_once 'include/bugs.inc';
+require_once 'include/main.inc';
+require_once 'include/rcube_shared.inc';
+
+
+// set PEAR error handling (will also load the PEAR main class)
+PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
+
diff --git a/program/include/main.inc b/program/include/main.inc
index 649dd25..6d548d8 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -27,9 +27,7 @@
  */
 
 require_once('lib/utf7.inc');
-require_once('include/rcube_user.inc');
 require_once('include/rcube_shared.inc');
-require_once('include/rcmail_template.inc');
 
 // fallback if not PHP modules are available
 @include_once('lib/des.inc');
@@ -50,14 +48,11 @@
 function rcmail_startup($task='mail')
   {
   global $sess_id, $sess_user_lang;
-  global $CONFIG, $INSTALL_PATH, $BROWSER, $OUTPUT, $_SESSION, $IMAP, $DB, $USER;
+  global $CONFIG, $OUTPUT, $IMAP, $DB, $USER;
 
   // start output buffering, we don't need any output yet, 
   // it'll be cleared after reading of config files, etc.
   ob_start();
-
-  // check client
-  $BROWSER = rcube_browser();
 
   // load configuration
   $CONFIG = rcmail_load_config();
@@ -74,10 +69,9 @@
   // prepare DB connection
   $dbwrapper = empty($CONFIG['db_backend']) ? 'db' : $CONFIG['db_backend'];
   $dbclass = "rcube_" . $dbwrapper;
-  require_once("include/$dbclass.inc");
   
   $DB = new $dbclass($CONFIG['db_dsnw'], $CONFIG['db_dsnr'], $CONFIG['db_persistent']);
-  $DB->sqlite_initials = $INSTALL_PATH.'SQL/sqlite.initial.sql';
+  $DB->sqlite_initials = INSTALL_PATH.'SQL/sqlite.initial.sql';
   $DB->set_debug((bool)$CONFIG['sql_debug']);
   $DB->db_connect('w');
 
@@ -136,8 +130,6 @@
  */
 function rcmail_load_config()
   {
-  global $INSTALL_PATH;
-
   // load config file
   include_once('config/main.inc.php');
   $conf = is_array($rcmail_config) ? $rcmail_config : array();
@@ -152,7 +144,7 @@
   $conf = array_merge($conf, $rcmail_config);
 
   if (empty($conf['log_dir']))
-    $conf['log_dir'] = $INSTALL_PATH.'logs';
+    $conf['log_dir'] = INSTALL_PATH.'logs';
   else
     $conf['log_dir'] = unslashify($conf['log_dir']);
 
@@ -427,11 +419,10 @@
  */
 function rcube_language_prop($lang, $prop='lang')
   {
-  global $INSTALL_PATH;
   static $rcube_languages, $rcube_language_aliases, $rcube_charsets;
 
   if (empty($rcube_languages))
-    @include($INSTALL_PATH.'program/localization/index.inc');
+    @include(INSTALL_PATH.'program/localization/index.inc');
     
   // check if we have an alias for that language
   if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang]))
@@ -451,7 +442,7 @@
   if (isset($rcube_charsets[$lang]))
     $charset = $rcube_charsets[$lang];
   else
-    $charset = 'UTF-8';    
+    $charset = 'UTF-8';
 
 
   if ($prop=='charset')
@@ -467,18 +458,15 @@
  * environment vars according to the current session and configuration
  */
 function rcmail_load_gui()
-  {
+{
   global $CONFIG, $OUTPUT, $sess_user_lang;
 
   // init output page
-  $OUTPUT = new rcmail_template($CONFIG, $GLOBALS['_task']);
+  $OUTPUT = new rcube_template($CONFIG, $GLOBALS['_task']);
   $OUTPUT->set_env('comm_path', $GLOBALS['COMM_PATH']);
 
-  if (is_array($CONFIG['javascript_config']))
-  {
-    foreach ($CONFIG['javascript_config'] as $js_config_var)
-      $OUTPUT->set_env($js_config_var, $CONFIG[$js_config_var]);
-  }
+  foreach (array('read_when_deleted', 'flag_for_deletion') as $js_config_var)
+    $OUTPUT->set_env($js_config_var, $CONFIG[$js_config_var]);
 
   if (!empty($GLOBALS['_framed']))
     $OUTPUT->set_env('framed', true);
@@ -490,19 +478,23 @@
   if (!empty($CONFIG['charset']))
     $OUTPUT->set_charset($CONFIG['charset']);
     
-  // register common UI objects
-  $OUTPUT->add_handlers(array(
-    'loginform' => 'rcmail_login_form',
-    'username'  => 'rcmail_current_username',
-    'message' => 'rcmail_message_container',
-    'charsetselector' => 'rcmail_charset_selector',
-  ));
-
   // add some basic label to client
-  if (!$OUTPUT->ajax_call)
-    rcube_add_label('loading', 'movingmessage');
-  }
+  $OUTPUT->add_label('loading', 'movingmessage');
+}
 
+/**
+ * Create an output object for JSON responses
+ */
+function rcmail_init_json()
+{
+  global $CONFIG, $OUTPUT;
+  
+  // init output object
+  $OUTPUT = new rcube_json_output($CONFIG, $GLOBALS['_task']);
+
+  // set locale setting
+  rcmail_set_locale($sess_user_lang);
+}
 
 /**
  * Set localization charset based on the given language.
@@ -878,18 +870,18 @@
  */
 function rcube_list_languages()
   {
-  global $CONFIG, $INSTALL_PATH;
+  global $CONFIG;
   static $sa_languages = array();
 
   if (!sizeof($sa_languages))
     {
-    @include($INSTALL_PATH.'program/localization/index.inc');
+    @include(INSTALL_PATH.'program/localization/index.inc');
 
-    if ($dh = @opendir($INSTALL_PATH.'program/localization'))
+    if ($dh = @opendir(INSTALL_PATH.'program/localization'))
       {
       while (($name = readdir($dh)) !== false)
         {
-        if ($name{0}=='.' || !is_dir($INSTALL_PATH.'program/localization/'.$name))
+        if ($name{0}=='.' || !is_dir(INSTALL_PATH.'program/localization/'.$name))
           continue;
 
         if ($label = $rcube_languages[$name])
@@ -904,6 +896,7 @@
 
 /**
  * Add a localized label to the client environment
+ * @deprecated
  */
 function rcube_add_label()
   {
@@ -911,7 +904,7 @@
   
   $arg_list = func_get_args();
   foreach ($arg_list as $i => $name)
-    $OUTPUT->command('add_label', $name, rcube_label($name));
+    $OUTPUT->add_label($name);
   }
 
 
@@ -1135,7 +1128,7 @@
     if ($OUTPUT->get_charset()!='UTF-8')
       $str = rcube_charset_convert($str, RCMAIL_CHARSET, $OUTPUT->get_charset());
       
-    return preg_replace(array("/\r?\n/", "/\r/"), array('\n', '\n'), addslashes(strtr($str, $js_rep_table)));
+    return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), addslashes(strtr($str, $js_rep_table)));
     }
 
   // no encoding given -> return original string
@@ -1261,16 +1254,6 @@
 
 
 /**
- * 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
@@ -1360,15 +1343,15 @@
   if ($type=='checkbox')
     {
     $attrib['value'] = '1';
-    $input = new checkbox($attrib);
+    $input = new html_checkbox($attrib);
     }
   else if ($type=='textarea')
     {
     $attrib['cols'] = $attrib['size'];
-    $input = new textarea($attrib);
+    $input = new html_textarea($attrib);
     }
   else
-    $input = new textfield($attrib);
+    $input = new html_inputfield($attrib);
 
   // use value from post
   if (!empty($_POST[$fname]))
@@ -1645,7 +1628,7 @@
  */
 function write_log($name, $line)
   {
-  global $CONFIG, $INSTALL_PATH;
+  global $CONFIG;
 
   if (!is_string($line))
     $line = var_export($line, true);
@@ -1655,7 +1638,7 @@
                  $line);
                  
   if (empty($CONFIG['log_dir']))
-    $CONFIG['log_dir'] = $INSTALL_PATH.'logs';
+    $CONFIG['log_dir'] = INSTALL_PATH.'logs';
       
   // try to open specific log file for writing
   if ($fp = @fopen($CONFIG['log_dir'].'/'.$name, 'a'))    
diff --git a/program/include/rcmail_template.inc b/program/include/rcmail_template.inc
deleted file mode 100644
index 301b3f2..0000000
--- a/program/include/rcmail_template.inc
+++ /dev/null
@@ -1,948 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | program/include/rcmail_template.inc                                   |
- |                                                                       |
- | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2007, RoundCube Dev. - Switzerland                      |
- | Licensed under the GNU GPL                                            |
- |                                                                       |
- | PURPOSE:                                                              |
- |   Class to handle HTML page output using a skin template.             |
- |   Extends rcube_html_page class from rcube_html.inc                   |
- |                                                                       |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com>                        |
- +-----------------------------------------------------------------------+
-
- $Id:  $
-
-*/
-
-
-/**
- * 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;
-  var $task = '';
-  var $framed = false;
-  var $ajax_call = false;
-  var $pagetitle = '';
-  var $env = array();
-  var $js_env = array();
-  var $js_commands = array();
-  var $object_handlers = array();
-
-
-  /**
-   * Constructor
-   *
-   * @param array Configuration array
-   * @param string Current task
-   */
-  function __construct(&$config, $task)
-  {
-    $this->task = $task;
-    $this->config = $config;
-    $this->ajax_call = !empty($_GET['_remote']) || !empty($_POST['_remote']);
-    
-    // add common javascripts
-    if (!$this->ajax_call)
-    {
-      $javascript = "var ".JS_OBJECT_NAME." = new rcube_webmail();";
-
-      // don't wait for page onload. Call init at the bottom of the page (delayed)
-      $javascript_foot = "if (window.call_init)\n call_init('".JS_OBJECT_NAME."');";
-
-      $this->add_script($javascript, 'head_top');
-      $this->add_script($javascript_foot, 'foot');
-      $this->scripts_path = 'program/js/';
-      $this->include_script('common.js');
-      $this->include_script('app.js');
-    }
-  }
-
-  /**
-   * PHP 4 compatibility
-   * @see rcmail_template::__construct()
-   */
-  function rcmail_template(&$config, $task)
-  {
-    $this->__construct($config, $task);
-  }
-  
-  
-  /**
-   * 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)
-  {
-    $this->env[$name] = $value;
-    if ($addtojs || isset($this->js_env[$name]))
-      $this->js_env[$name] = $value;
-  }
-
-
-  /**
-   * Set page title variable
-   */
-  function set_pagetitle($title)
-  {
-    $this->pagetitle = $title;
-  }
-
-
-  /**
-   * Register a template object handler
-   *
-   * @param string Object name
-   * @param string Function name to call
-   */
-  function add_handler($obj, $func)
-  {
-    $this->object_handlers[$obj] = $func;
-  }
-
-  /**
-   * Register a list of template object handlers
-   *
-   * @param array Hash array with object=>handler pairs
-   */
-  function add_handlers($arr)
-  {
-    $this->object_handlers = array_merge($this->object_handlers, $arr);
-  }
-
-  /**
-   * Register a GUI object to the client script
-   *
-   * @param string Object name
-   * @param string Object ID
-   */
-  function add_gui_object($obj, $id)
-  {
-    $this->add_script(JS_OBJECT_NAME.".gui_object('$obj', '$id');");
-  }
-
-
-  /**
-   * Call a client method
-   *
-   * @param string Method to call
-   * @param ... Additional arguments
-   */
-  function command()
-  {
-    $this->js_commands[] = func_get_args();
-  }
-
-
-  /**
-   * 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)
-  {
-    $this->command(
-      'display_message',
-      rcube_label(array('name' => $message, 'vars' => $vars)),
-      $type);
-  }
-
-
-  /**
-   * Delete all stored env variables and commands
-   */
-  function reset()
-  {
-    $this->env = array();
-    $this->js_env = array();
-    $this->js_commands = array();
-    $this->object_handlers = array();    
-    parent::reset();
-  }
-
-  /**
-   * Send the request output to the client.
-   * This will either parse a skin tempalte or send an AJAX response
-   *
-   * @param string  Template name
-   * @param boolean True if script should terminate (default)
-   */
-  function send($templ=null, $exit=true)
-  {
-    if ($this->ajax_call)
-      $this->remote_response('', !$exit);
-    else if ($templ != 'iframe')
-      $this->parse($templ, false);
-    else
-    {
-      $this->framed = $templ == 'iframe' ? true : $this->framed;
-      $this->write();
-    }
-    
-    if ($exit)
-      exit;
-  }
-
-
-  /**
-   * Send an AJAX response with executable JS code
-   * 
-   * @param string  Additional JS code
-   * @param boolean True if output buffer should be flushed
-   */
-  function remote_response($add='', $flush=false)
-  {
-    static $s_header_sent = FALSE;
-
-    if (!$s_header_sent)
-    {
-      $s_header_sent = TRUE;
-      send_nocacheing_headers();
-      header('Content-Type: application/x-javascript; charset='.RCMAIL_CHARSET);
-      print '/** ajax response ['.date('d/M/Y h:i:s O')."] **/\n";
-    }
-    
-    // unset default env vars
-    unset($this->js_env['task'], $this->js_env['action'], $this->js_env['comm_path']);
-
-    // send response code
-    print rcube_charset_convert($this->get_js_commands() . $add, RCMAIL_CHARSET, $this->get_charset());
-
-    if ($flush)  // flush the output buffer
-      flush();
-  }
-  
-  
-  /**
-   * Process template and write to stdOut
-   *
-   * @param string HTML template
-   * @see rcube_html_page::write()
-   */
-  function write($template='')
-  {
-    // unlock interface after iframe load
-    if ($this->framed)
-      array_unshift($this->js_commands, array('set_busy', false));
-    
-    // write all env variables to client
-    $js = $this->framed ? "if(window.parent) {\n" : '';
-    $js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
-    $this->add_script($js, 'head_top');
-
-    // call super method
-    parent::write($template, $this->config['skin_path']);
-  }
-
-
-  /**
-   * Parse a specific skin template and deliver to stdout
-   *
-   * @param string  Template name
-   * @param boolean Exit script
-   */  
-  function parse($name='main', $exit=true)
-  {
-    $skin_path = $this->config['skin_path'];
-
-    // read template file
-    $templ = '';
-    $path = "$skin_path/templates/$name.html";
-
-    if($fp = @fopen($path, 'r'))
-    {
-      $templ = fread($fp, filesize($path));
-      fclose($fp);
-    }
-    else
-    {
-      raise_error(array(
-        'code' => 501,
-        'type' => 'php',
-        'line' => __LINE__,
-        'file' => __FILE__,
-        'message' => "Error loading template for '$name'"), TRUE, TRUE);
-      return FALSE;
-    }
-
-    // parse for specialtags
-    $output = $this->parse_xml($this->parse_conditions($templ));
-
-    // add debug console
-    if ($this->config['debug_level'] & 8)
-      $this->add_footer('<div style="position:absolute;top:5px;left:5px;width:400px;padding:0.2em;background:white;opacity:0.8;z-index:9000">
-        <a href="#toggle" onclick="con=document.getElementById(\'dbgconsole\');con.style.display=(con.style.display==\'none\'?\'block\':\'none\');return false">console</a>
-        <form action="/" name="debugform"><textarea name="console" id="dbgconsole" rows="20" cols="40" wrap="off" style="display:none;width:400px;border:none;font-size:x-small"></textarea></form></div>');
-
-    $this->write(trim($this->parse_with_globals($output)), $skin_path);
-
-    if ($exit)
-      exit;
-  }
-
-
-  /**
-   * Return executable javascript code for all registered commands
-   * @access private
-   */
-  function get_js_commands()
-  {
-    $out = '';
-    if (!$this->framed && !empty($this->js_env))
-      $out .= ($this->ajax_call ? 'this' : JS_OBJECT_NAME) . '.set_env('.json_serialize($this->js_env).");\n";
-    
-    // add command to set page title
-    if ($this->ajax_call && !empty($this->pagetitle))
-      $out .= sprintf(
-        "this.set_pagetitle('%s');\n",
-        JQ((!empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '') . $this->pagetitle)
-      );
-
-    foreach ($this->js_commands as $i => $args)
-    {
-      $method = array_shift($args);
-      foreach ($args as $i => $arg)
-        $args[$i] = json_serialize($arg);
-
-      $parent = $this->framed || preg_match('/^parent\./', $method);
-      $out .= sprintf(
-        "%s.%s(%s);\n",
-        $this->ajax_call ? 'this' : ($parent ? 'parent.' : '') . JS_OBJECT_NAME,
-        preg_replace('/^parent\./', '', $method),
-        join(',', $args));
-    }
-    
-
-    
-    return $out;
-  }
-  
-  /**
-   * Make URLs starting with a slash point to skin directory
-   * @access private
-   */
-  function abs_url($str)
-  {
-    return preg_replace('/^\//', $this->config['skin_path'].'/', $str);
-  }
-
-
-
-  /*****  Template parsing methods  *****/
-  
-  /**
-   * Replace all strings ($varname)
-   * with the content of the according global variable.
-   * @access private
-   */
-  function parse_with_globals($input)
-  {
-    $GLOBALS['__comm_path'] = Q($GLOBALS['COMM_PATH']);
-    return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input);
-  }
-  
-  
-  /**
-   * Parse for conditional tags
-   * @access private
-   */
-  function parse_conditions($input)
-  {
-    if (($matches = preg_split('/<roundcube:(if|elseif|else|endif)\s+([^>]+)>/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE)) && count($matches)==4)
-    {
-      if (preg_match('/^(else|endif)$/i', $matches[1]))
-        return $matches[0] . $this->parse_conditions($matches[3]);
-      else
-      {
-        $attrib = parse_attrib_string($matches[2]);
-        if (isset($attrib['condition']))
-        {
-          $condmet = $this->check_condition($attrib['condition']);
-          $submatches = preg_split('/<roundcube:(elseif|else|endif)\s+([^>]+)>/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE);
-
-          if ($condmet)
-            $result = $submatches[0] . ($submatches[1] != 'endif' ? preg_replace('/.*<roundcube:endif\s+[^>]+>/Uis', '', $submatches[3], 1) : $submatches[3]);
-          else
-            $result = "<roundcube:$submatches[1] $submatches[2]>" . $submatches[3];
-
-          return $matches[0] . $this->parse_conditions($result);
-        }
-        else
-        {
-          raise_error(array('code' => 500, 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__,
-                            'message' => "Unable to parse conditional tag " . $matches[2]), TRUE, FALSE);
-        }
-      }
-    }
-
-    return $input;
-  }
-
-
-  /**
-   * Determines if a given condition is met
-   *
-   * @return True if condition is valid, False is not
-   * @access private
-   */
-  function check_condition($condition)
-  {
-    $condition = preg_replace(
-        array('/session:([a-z0-9_]+)/i', '/config:([a-z0-9_]+)/i', '/env:([a-z0-9_]+)/i', '/request:([a-z0-9_]+)/ie'),
-        array("\$_SESSION['\\1']", "\$this->config['\\1']", "\$this->env['\\1']", "get_input_value('\\1', RCUBE_INPUT_GPC)"),
-        $condition);
-
-    return @eval("return (".$condition.");");
-  }
-
-
-  /**
-   * Search for special tags in input and replace them
-   * with the appropriate content
-   *
-   * @param string Input string to parse
-   * @return Altered input string
-   * @access private
-   */
-  function parse_xml($input)
-  {
-    return preg_replace('/<roundcube:([-_a-z]+)\s+([^>]+)>/Uie', "\$this->xml_command('\\1', '\\2')", $input);
-  }
-
-
-  /**
-   * Convert a xml command tag into real content
-   *
-   * @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;
-
-    // empty output if required condition is not met
-    if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition']))
-      return '';
-
-    // execute command
-    switch ($command)
-    {
-      // return a button
-      case 'button':
-        return $this->button($attrib);
-        break;
-
-      // show a label
-      case 'label':
-        if ($attrib['name'] || $attrib['command'])
-          return Q(rcube_label($attrib + array('vars' => array('product' => $this->config['product_name']))));
-        break;
-
-      // include a file 
-      case 'include':
-        $path = realpath($this->config['skin_path'].$attrib['file']);
-        if (filesize($path))
-        {
-          if ($this->config['skin_include_php'])
-            $incl = $this->include_php($path);
-          else if ($fp = @fopen($path, 'r'))
-          {
-            $incl = fread($fp, filesize($path));
-            fclose($fp);
-          }
-          return $this->parse_xml($incl);
-        }
-        break;
-
-      // return code for a specific application object
-      case 'object':
-        $object = strtolower($attrib['name']);
-
-        // execute object handler function
-        if ($this->object_handlers[$object] && function_exists($this->object_handlers[$object]))
-          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'].' :: ' : '';
-
-          if (!empty($this->pagetitle))
-            $title .= $this->pagetitle;
-          else if ($task == 'login')
-            $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name'])));
-          else
-            $title .= ucfirst($task);
-
-          return Q($title);
-        }
-
-        break;
-      
-      // return variable
-      case 'var':
-        $var = explode(':', $attrib['name']);
-        $name = $var[1];
-        $value = '';
-        
-        switch ($var[0])
-        {
-          case 'env':
-            $value = $this->env[$name];
-            break;
-          case 'config':
-            $value = $this->config[$name];
-            if (is_array($value) && $value[$_SESSION['imap_host']])
-              $value = $value[$_SESSION['imap_host']];
-            break;
-          case 'request':
-            $value = get_input_value($name, RCUBE_INPUT_GPC);
-            break;
-          case 'session':
-            $value = $_SESSION[$name];
-            break;
-        }
-        
-        if (is_array($value))
-          $value = join(", ", $value);
-        
-        return Q($value);
-    }
-
-    return '';
-  }
-
-
-  /**
-   * Include a specific file and return it's contents
-   *
-   * @param string File path
-   * @return string Contents of the processed file
-   */
-  function include_php($file)
-  {
-    ob_start();
-    @include($file);
-    $out = ob_get_contents();
-    ob_end_clean();
-    
-    return $out;
-  }
-
-
-  /**
-   * Create and register a button
-   *
-   * @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;
-
-    // these commands can be called directly via url
-    $a_static_commands = array('compose', 'list');
-
-    $skin_path = $this->config['skin_path'];
-
-    if (!($attrib['command'] || $attrib['name'] || $attrib['onclick']))
-      return '';
-
-    // try to find out the button type
-    if ($attrib['type'])
-      $attrib['type'] = strtolower($attrib['type']);
-    else
-      $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link';
-
-    $command = $attrib['command'];
-
-    // take the button from the stack
-    if($attrib['name'] && $sa_buttons[$attrib['name']])
-      $attrib = $sa_buttons[$attrib['name']];
-
-    // add button to button stack
-    else if($attrib['image'] || $attrib['imageact'] || $attrib['imagepas'] || $attrib['class'])
-    {
-      if (!$attrib['name'])
-        $attrib['name'] = $command;
-
-      if (!$attrib['image'])
-        $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact'];
-
-      $sa_buttons[$attrib['name']] = $attrib;
-    }
-
-    // get saved button for this command/name
-    else if ($command && $sa_buttons[$command])
-      $attrib = $sa_buttons[$command];
-
-    //else
-    //  return '';
-
-
-    // set border to 0 because of the link arround the button
-    if ($attrib['type']=='image' && !isset($attrib['border']))
-      $attrib['border'] = 0;
-
-    if (!$attrib['id'])
-      $attrib['id'] =  sprintf('rcmbtn%d', $s_button_count++);
-
-    // get localized text for labels and titles
-    if ($attrib['title'])
-      $attrib['title'] = Q(rcube_label($attrib['title']));
-    if ($attrib['label'])
-      $attrib['label'] = Q(rcube_label($attrib['label']));
-
-    if ($attrib['alt'])
-      $attrib['alt'] = Q(rcube_label($attrib['alt']));
-
-    // set title to alt attribute for IE browsers
-    if ($BROWSER['ie'] && $attrib['title'] && !$attrib['alt'])
-    {
-      $attrib['alt'] = $attrib['title'];
-      unset($attrib['title']);
-    }
-
-    // add empty alt attribute for XHTML compatibility
-    if (!isset($attrib['alt']))
-      $attrib['alt'] = '';
-
-
-    // register button in the system
-    if ($attrib['command'])
-    {
-      $this->add_script(sprintf(
-        "%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');",
-        JS_OBJECT_NAME,
-        $command,
-        $attrib['id'],
-        $attrib['type'],
-        $attrib['imageact'] ? $skin_path.$attrib['imageact'] : $attrib['classact'],
-        $attrib['imagesel'] ? $skin_path.$attrib['imagesel'] : $attrib['classsel'],
-        $attrib['imageover'] ? $skin_path.$attrib['imageover'] : '')
-      );
-
-      // make valid href to specific buttons
-      if (in_array($attrib['command'], $MAIN_TASKS))
-        $attrib['href'] = Q(rcmail_url(null, null, $attrib['command']));
-      else if (in_array($attrib['command'], $a_static_commands))
-        $attrib['href'] = Q(rcmail_url($attrib['command']));
-    }
-
-    // overwrite attributes
-    if (!$attrib['href'])
-      $attrib['href'] = '#';
-
-    if ($command)
-      $attrib['onclick'] = sprintf("return %s.command('%s','%s',this)", JS_OBJECT_NAME, $command, $attrib['prop']);
-
-    if ($command && $attrib['imageover'])
-    {
-      $attrib['onmouseover'] = sprintf("return %s.button_over('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
-      $attrib['onmouseout'] = sprintf("return %s.button_out('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
-    }
-
-    if ($command && $attrib['imagesel'])
-    {
-      $attrib['onmousedown'] = sprintf("return %s.button_sel('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
-      $attrib['onmouseup'] = sprintf("return %s.button_out('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
-    }
-
-    $out = '';
-
-    // generate image tag
-    if ($attrib['type']=='image')
-    {
-      $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'align', 'alt'));
-      $img_tag = sprintf('<img src="%%s"%s />', $attrib_str);
-      $btn_content = sprintf($img_tag, $skin_path.$attrib['image']);
-      if ($attrib['label'])
-        $btn_content .= ' '.$attrib['label'];
-
-      $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title');
-    }
-    else if ($attrib['type']=='link')
-    {
-      $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command'];
-      $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style');
-    }
-    else if ($attrib['type']=='input')
-    {
-      $attrib['type'] = 'button';
-
-      if ($attrib['label'])
-        $attrib['value'] = $attrib['label'];
-
-      $attrib_str = create_attrib_string($attrib, array('type', 'value', 'onclick', 'id', 'class', 'style'));
-      $out = sprintf('<input%s disabled="disabled" />', $attrib_str);
-    }
-
-    // generate html code for button
-    if ($btn_content)
-    {
-      $attrib_str = create_attrib_string($attrib, $link_attrib);
-      $out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content);
-    }
-
-    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 $USER;
-  static $s_username;
-
-  // alread fetched  
-  if (!empty($s_username))
-    return $s_username;
-
-  if ($sql_arr = $USER->get_identity())
-    $s_username = $sql_arr['email'];
-  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) + $attrib);
-  $input_pass = new passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30) + $attrib);
-  $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(get_input_value('_host', RCUBE_INPUT_POST)) : null;
-    }
-  else if (!strlen($CONFIG['default_host']))
-    {
-    $input_host = new textfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30));
-    $fields['host'] = $input_host->show(get_input_value('_host', RCUBE_INPUT_POST));
-    }
-
-  $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;
-  } 
-
-
-?>
diff --git a/program/include/rcube_browser.php b/program/include/rcube_browser.php
new file mode 100644
index 0000000..af393d6
--- /dev/null
+++ b/program/include/rcube_browser.php
@@ -0,0 +1,75 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_browser.php                                     |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2007-2008, RoundCube Dev. - Switzerland                 |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Class representing the client browser's properties                  |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id: rcube_browser.php 328 2006-08-30 17:41:21Z thomasb $
+
+*/
+
+/** 
+ * rcube_browser
+ * 
+ * Provide details about the client's browser based on the User-Agent header
+ *
+ * @package Core
+ */
+class rcube_browser
+{
+    function __construct()
+    {
+        $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
+
+        $this->ver = 0;
+        $this->win = stristr($HTTP_USER_AGENT, 'win');
+        $this->mac = stristr($HTTP_USER_AGENT, 'mac');
+        $this->linux = stristr($HTTP_USER_AGENT, 'linux');
+        $this->unix  = stristr($HTTP_USER_AGENT, 'unix');
+
+        $this->ns4 = stristr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie');
+        $this->ns  = ($this->ns4 || stristr($HTTP_USER_AGENT, 'netscape'));
+        $this->ie  = stristr($HTTP_USER_AGENT, 'msie');
+        $this->mz  = stristr($HTTP_USER_AGENT, 'mozilla/5');
+        $this->opera = stristr($HTTP_USER_AGENT, 'opera');
+        $this->safari = stristr($HTTP_USER_AGENT, 'safari');
+
+        if ($this->ns) {
+            $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+            $this->ver = $test ? (float)$regs[1] : 0;
+        }
+        if ($this->mz) {
+            $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+            $this->ver = $test ? (float)$regs[1] : 0;
+        }
+        if($this->ie) {
+            $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+            $this->ver = $test ? (float)$regs[1] : 0;
+        }
+        if ($this->opera) {
+            $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
+            $this->ver = $test ? (float)$regs[1] : 0;
+        }
+
+        if (eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs))
+            $this->lang =  $regs[1];
+        else
+            $this->lang =  'en';
+
+        $this->dom = ($this->mz || $this->safari || ($this->ie && $this->ver>=5) || ($this->opera && $this->ver>=7));
+        $this->pngalpha = $this->mz || $this->safari || ($this->ie && $this->ver>=5.5) ||
+            ($this->ie && $this->ver>=5 && $this->mac) || ($this->opera && $this->ver>=7) ? true : false;
+    }
+  }
+
diff --git a/program/include/rcube_contacts.inc b/program/include/rcube_contacts.php
similarity index 91%
rename from program/include/rcube_contacts.inc
rename to program/include/rcube_contacts.php
index 6a48656..a9d1614 100644
--- a/program/include/rcube_contacts.inc
+++ b/program/include/rcube_contacts.php
@@ -2,10 +2,10 @@
 
 /*
  +-----------------------------------------------------------------------+
- | program/include/rcube_contacts.inc                                    |
+ | program/include/rcube_contacts.php                                    |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2006-2007, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2006-2008, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -403,56 +403,3 @@
 }
 
 
-/**
- * RoundCube result set class.
- * Representing an address directory result set.
- */
-class rcube_result_set
-{
-  var $count = 0;
-  var $first = 0;
-  var $current = 0;
-  var $records = array();
-  
-  function __construct($c=0, $f=0)
-  {
-    $this->count = (int)$c;
-    $this->first = (int)$f;
-  }
-  
-  function rcube_result_set($c=0, $f=0)
-  {
-    $this->__construct($c, $f);
-  }
-  
-  function add($rec)
-  {
-    $this->records[] = $rec;
-  }
-  
-  function iterate()
-  {
-    return $this->records[$this->current++];
-  }
-  
-  function first()
-  {
-    $this->current = 0;
-    return $this->records[$this->current++];
-  }
-  
-  // alias
-  function next()
-  {
-    return $this->iterate();
-  }
-  
-  function seek($i)
-  {
-    $this->current = $i;
-  }
-  
-}
-
-
-?>
\ No newline at end of file
diff --git a/program/include/rcube_db.inc b/program/include/rcube_db.php
similarity index 98%
rename from program/include/rcube_db.inc
rename to program/include/rcube_db.php
index 63c6759..8fa34e6 100644
--- a/program/include/rcube_db.inc
+++ b/program/include/rcube_db.php
@@ -2,10 +2,10 @@
 
 /*
  +-----------------------------------------------------------------------+
- | program/include/rcube_db.inc                                          |
+ | program/include/rcube_db.php                                          |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -21,11 +21,6 @@
 
 */
 
-
-/**
- * Obtain the PEAR::DB class that is used for abstraction
- */
-require_once 'DB.php';
 
 /**
  * Database independent query interface
@@ -605,4 +600,4 @@
 
   }  // end class rcube_db
 
-?>
+
diff --git a/program/include/rcube_html.inc b/program/include/rcube_html.inc
deleted file mode 100644
index d23760a..0000000
--- a/program/include/rcube_html.inc
+++ /dev/null
@@ -1,667 +0,0 @@
-<?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;
-
-      // attributes with no value
-      if (in_array($key, array('checked', 'multiple', 'disabled', 'selected', 'nowrap')))
-      {
-        if ($value)
-          $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $key);
-      }
-      // don't convert size of value attribute
-      else if ($key=='value')
-        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), Q($value, 'strict', false));
-        
-      // regular tag attributes
-      else
-        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case(Q($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' => $values[$i]);
-    }
-    else
-      $this->options[] = array('text' => $names, 'value' => $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($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="selected"', 'attrib') : '';
-                   
-      $options_str .= sprintf("<%s%s%s>%s</%s>\n",
-                             $this->_conv_case('option', 'tag'),
-                             isset($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" : ""));    
-  }
-}
-
-
-?>
diff --git a/program/include/rcube_html_page.php b/program/include/rcube_html_page.php
new file mode 100644
index 0000000..42036f6
--- /dev/null
+++ b/program/include/rcube_html_page.php
@@ -0,0 +1,256 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_html_page.php                                   |
+ |                                                                       |
+ | This file is part of the RoundCube PHP suite                          |
+ | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland                 |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | CONTENTS:                                                             |
+ |   Class to build XHTML page output                                    |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id:  $
+
+*/
+
+/**
+ * Class for HTML page creation
+ *
+ * @package HTML
+ */
+class rcube_html_page
+{
+    protected $scripts_path = '';
+    protected $script_files = array();
+    protected $external_scripts = array();
+    protected $scripts = array();
+    protected $charset = 'UTF-8';
+
+    protected $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
+    protected $script_tag      = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
+    protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
+    protected $tag_format_external_script = "<script type=\"text/javascript\" src=\"%s\"></script>\n";
+
+    protected $title = '';
+    protected $header = '';
+    protected $footer = '';
+    protected $body = '';
+
+
+    /** Constructor */
+    public function __construct() {}
+
+    /**
+     * Link an external script file
+     *
+     * @param string File URL
+     * @param string Target position [head|foot]
+     */
+    public 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]
+     */
+    public 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
+     */
+    public function add_header($str)
+    {
+        $this->header .= "\n".$str;
+    }
+
+    /**
+     * Add HTML code to the page footer
+     * To be added right befor </body>
+     */
+    public function add_footer($str)
+    {
+        $this->footer .= "\n".$str;
+    }
+
+    /**
+     * Setter for page title
+     */
+    public function set_title($t)
+    {
+        $this->title = $t;
+    }
+
+    /**
+     * Setter for output charset.
+     * To be specified in a meta tag and sent as http-header
+     */
+    public function set_charset($charset)
+    {
+        $this->charset = $charset;
+    }
+
+    /**
+     * Getter for output charset
+     */
+    public function get_charset()
+    {
+        return $this->charset;
+    }
+
+    /**
+     * Reset all saved properties
+     */
+    public 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
+     */
+    public 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)) {
+            if (!headers_sent()) {
+                header('Content-Type: text/html; charset=' . $this->charset);
+            }
+            $__page_header = '<meta http-equiv="content-type"';
+            $__page_header.= ' content="text/html; charset=';
+            $__page_header.= $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 = strrpos($output_lc, '</body>')) || ($fpos = strrpos($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);
+    }
+}
+
diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.php
similarity index 99%
rename from program/include/rcube_imap.inc
rename to program/include/rcube_imap.php
index 9a59485..04bb7bf 100644
--- a/program/include/rcube_imap.inc
+++ b/program/include/rcube_imap.php
@@ -2,10 +2,10 @@
 
 /*
  +-----------------------------------------------------------------------+
- | program/include/rcube_imap.inc                                        |
+ | program/include/rcube_imap.php                                        |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -2929,4 +2929,3 @@
   }
 
 
-?>
diff --git a/program/include/rcube_json_output.php b/program/include/rcube_json_output.php
new file mode 100644
index 0000000..6bf4f8a
--- /dev/null
+++ b/program/include/rcube_json_output.php
@@ -0,0 +1,237 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_json_output.php                                 |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2008, RoundCube Dev. - Switzerland                      |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Class to handle HTML page output using a skin template.             |
+ |   Extends rcube_html_page class from rcube_shared.inc                 |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id:  $
+
+*/
+
+
+/**
+ * View class to produce JSON responses
+ *
+ * @package View
+ */
+class rcube_json_output
+{
+    private $config;
+    private $charset = 'UTF-8';
+    private $env = array();
+    private $texts = array();
+    private $commands = array();
+
+    public $task = '';
+    public $ajax_call = true;
+    
+    
+    /**
+     * Constructor
+     */
+    public function __construct(&$config, $task)
+    {
+        $this->task   = $task;
+        $this->config = $config;
+    }
+    
+    
+    /**
+     * Set environment variable
+     *
+     * @param string Property name
+     * @param mixed Property value
+     */
+    public function set_env($name, $value)
+    {
+        $this->env[$name] = $value;
+    }
+    
+    /**
+     * @ignore
+     */
+    public function set_pagetitle($title)
+    {
+        // ignore
+    }
+
+    /**
+     * @ignore
+     */
+    function set_charset($charset)
+    {
+        // ignore: $this->charset = $charset;
+    }
+
+
+    /**
+     * Get charset for output
+     *
+     * @return string Output charset
+     */
+    function get_charset()
+    {
+        return $this->charset;
+    }
+
+
+    /**
+     * Register a template object handler
+     *
+     * @param  string Object name
+     * @param  string Function name to call
+     * @return void
+     */
+    public function add_handler($obj, $func)
+    {
+        // ignore
+    }
+
+    /**
+     * Register a list of template object handlers
+     *
+     * @param  array Hash array with object=>handler pairs
+     * @return void
+     */
+    public function add_handlers($arr)
+    {
+        // ignore
+    }
+    
+    
+    /**
+     * Call a client method
+     *
+     * @param string Method to call
+     * @param ... Additional arguments
+     */
+    public function command()
+    {
+        $this->commands[] = func_get_args();
+    }
+    
+    
+    /**
+     * Add a localized label to the client environment
+     */
+    public function add_label()
+    {
+        $arg_list = func_get_args();
+        foreach ($arg_list as $i => $name) {
+            $this->texts[$name] = rcube::gettext($name);
+        }
+    }
+    
+
+    /**
+     * 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
+     * @uses self::command()
+     */
+    public function show_message($message, $type='notice', $vars=null)
+    {
+        $this->command(
+            'display_message',
+            rcube::gettext(array('name' => $message, 'vars' => $vars)),
+            $type
+        );
+    }
+    
+    /**
+     * Delete all stored env variables and commands
+     */
+    public public function reset()
+    {
+        $this->env = array();
+        $this->texts = array();
+        $this->commands = array();
+    }
+    
+    
+    /**
+     * Send an AJAX response to the client.
+     */
+    public function send()
+    {
+        $this->remote_response();
+        exit;
+    }
+    
+    
+    /**
+     * Send an AJAX response with executable JS code
+     *
+     * @param  string  Additional JS code
+     * @param  boolean True if output buffer should be flushed
+     * @return void
+     * @deprecated
+     */
+    public function remote_response($add='', $flush=false)
+    {
+        static $s_header_sent = false;
+
+        if (!$s_header_sent) {
+            $s_header_sent = true;
+            send_nocacheing_headers();
+            header('Content-Type: application/x-javascript; charset=' . $this->get_charset());
+            print '/** ajax response ['.date('d/M/Y h:i:s O')."] **/\n";
+        }
+
+        // unset default env vars
+        unset($this->env['task'], $this->env['action'], $this->env['comm_path']);
+
+        // send response code
+        echo $this->get_js_commands() . $add;
+
+        // flush the output buffer
+        if ($flush)
+            flush();
+    }
+    
+    
+    /**
+     * Return executable javascript code for all registered commands
+     *
+     * @return string $out
+     */
+    private function get_js_commands()
+    {
+        $out = 'this.set_env('.json_serialize($this->env).");\n";
+        
+        foreach($this->texts as $name => $text) {
+            $out .= sprintf("this.add_label('%s', '%s');\n", $name, JQ($text));
+        }
+
+        foreach ($this->commands as $i => $args) {
+            $method = array_shift($args);
+            foreach ($args as $i => $arg) {
+                $args[$i] = json_serialize($arg);
+            }
+
+            $out .= sprintf(
+                "this.%s(%s);\n",
+                preg_replace('/^parent\./', '', $method),
+                implode(',', $args)
+            );
+        }
+        
+        return $out;
+    }
+}
+
+
diff --git a/program/include/rcube_ldap.inc b/program/include/rcube_ldap.php
similarity index 98%
rename from program/include/rcube_ldap.inc
rename to program/include/rcube_ldap.php
index 969101b..4d0574e 100644
--- a/program/include/rcube_ldap.inc
+++ b/program/include/rcube_ldap.php
@@ -1,10 +1,10 @@
 <?php
 /*
  +-----------------------------------------------------------------------+
- | program/include/rcube_ldap.inc                                        |
+ | program/include/rcube_ldap.php                                        |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2006-2007, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2006-2008, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -456,4 +456,4 @@
 
 }
 
-?>
+
diff --git a/program/lib/rc_mail_mime.inc b/program/include/rcube_mail_mime.php
similarity index 85%
rename from program/lib/rc_mail_mime.inc
rename to program/include/rcube_mail_mime.php
index ca4d0bf..866786b 100644
--- a/program/lib/rc_mail_mime.inc
+++ b/program/include/rcube_mail_mime.php
@@ -2,10 +2,10 @@
 
 /*
  +-----------------------------------------------------------------------+
- | program/lib/rc_mime.inc                                               |
+ | program/include/rcube_mail_mime.php                                   |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2007, RoundCube Dev. - Switzerland                      |
+ | Copyright (C) 2007-2008, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -19,19 +19,22 @@
 
 */
 
-// require Mail_mime class 1.4.0
-require_once('Mail/mime.php');
 
-
-class rc_mail_mime extends Mail_mime
+/**
+ * Replacement PEAR:Mail_mime with some additional or overloaded methods
+ *
+ * @package Mail
+ */
+class rcube_mail_mime extends Mail_mime
 {
   /**
    * Set build parameters
    */
   function setParam($param)
   {
-    if (is_array($param))
+    if (is_array($param)) {
       $this->_build_params = array_merge($this->_build_params, $param);
+    }
   }
   
   /**
@@ -51,16 +54,20 @@
   function addHTMLImage($file, $c_type='application/octet-stream', $name = '', $isfilename = true, $contentid = '')
   {
     $filedata = ($isfilename === true) ? $this->_file2str($file) : $file;
-    if ($isfilename === true)
+    if ($isfilename === true) {
       $filename = ($name == '' ? $file : $name);
-    else
+    }
+    else {
       $filename = $name;
+    }
 
-    if (PEAR::isError($filedata))
+    if (PEAR::isError($filedata)) {
         return $filedata;
+    }
 
-    if ($contentid == '')
+    if ($contentid == '') {
        $contentid = md5(uniqid(time()));
+    }
 
     $this->_html_images[] = array(
       'body'   => $filedata,
@@ -117,31 +124,29 @@
     foreach ($input as $hdr_name => $hdr_value)
     {
       // if header contains e-mail addresses
-      if (preg_match('/\s<.+@[a-z0-9\-\.]+\.[a-z]+>/U', $hdr_value))
+      if (preg_match('/\s<.+@[a-z0-9\-\.]+\.[a-z]+>/U', $hdr_value)) {
         $chunks = $this->_explode_quoted_string(',', $hdr_value);
-      else
+      }
+      else {
         $chunks = array($hdr_value);
+      }
 
       $hdr_value = '';
       $line_len = 0;
 
-      foreach ($chunks as $i => $value)
-      {
+      foreach ($chunks as $i => $value) {
         $value = trim($value);
 
         //This header contains non ASCII chars and should be encoded.
-        if (preg_match('#[\x80-\xFF]{1}#', $value))
-        {
+        if (preg_match('#[\x80-\xFF]{1}#', $value)) {
           $suffix = '';
           // Don't encode e-mail address
-          if (preg_match('/(.+)\s(<.+@[a-z0-9\-\.]+>)$/Ui', $value, $matches))
-          {
+          if (preg_match('/(.+)\s(<.+@[a-z0-9\-\.]+>)$/Ui', $value, $matches)) {
             $value = $matches[1];
             $suffix = ' '.$matches[2];
           }
 
-          switch ($params['head_encoding'])
-          {
+          switch ($params['head_encoding']) {
             case 'base64':
             // Base64 encoding has been selected.
             $mode = 'B';
@@ -162,13 +167,11 @@
 
         // add chunk to output string by regarding the header maxlen
         $len = strlen($value);
-        if ($i == 0 || $line_len + $len < $maxlen)
-        {
+        if ($i == 0 || $line_len + $len < $maxlen) {
           $hdr_value .= ($i>0?', ':'') . $value;
           $line_len += $len + ($i>0?2:0);
         }
-        else
-        {
+        else {
           $hdr_value .= ($i>0?', ':'') . "\n " . $value;
           $line_len = $len;
         }
@@ -185,12 +188,11 @@
   {
     $result = array();
     $strlen = strlen($string);
-    for ($q=$p=$i=0; $i < $strlen; $i++)
-    {
-      if ($string{$i} == "\"" && $string{$i-1} != "\\")
+    for ($q=$p=$i=0; $i < $strlen; $i++) {
+      if ($string{$i} == "\"" && $string{$i-1} != "\\") {
         $q = $q ? false : true;
-      else if (!$q && $string{$i} == $delimiter)
-      {
+      }
+      else if (!$q && $string{$i} == $delimiter) {
         $result[] = substr($string, $p, $i - $p);
         $p = $i + 1;
       }
@@ -202,4 +204,3 @@
 
 }
 
-?>
\ No newline at end of file
diff --git a/program/include/rcube_mdb2.inc b/program/include/rcube_mdb2.php
similarity index 98%
rename from program/include/rcube_mdb2.inc
rename to program/include/rcube_mdb2.php
index 72d9066..f2845d3 100644
--- a/program/include/rcube_mdb2.inc
+++ b/program/include/rcube_mdb2.php
@@ -2,10 +2,10 @@
 
 /*
  +-----------------------------------------------------------------------+
- | program/include/rcube_mdb2.inc                                        |
+ | program/include/rcube_mdb2.php                                        |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -19,12 +19,6 @@
  $Id$
 
 */
-
-
-/**
- * Obtain the PEAR::DB class that is used for abstraction
- */
-require_once('MDB2.php');
 
 
 /**
@@ -617,4 +611,3 @@
 }
 
 
-?>
diff --git a/program/include/rcube_result_set.php b/program/include/rcube_result_set.php
new file mode 100644
index 0000000..7e968cd
--- /dev/null
+++ b/program/include/rcube_result_set.php
@@ -0,0 +1,74 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_result_set.php                                  |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2006-2008, RoundCube Dev. - Switzerland                 |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Class representing an address directory result set                  |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id: rcube_result_set.php 328 2006-08-30 17:41:21Z thomasb $
+
+*/
+
+
+/**
+ * RoundCube result set class.
+ * Representing an address directory result set.
+ *
+ * @package Addressbook
+ */
+class rcube_result_set
+{
+  var $count = 0;
+  var $first = 0;
+  var $current = 0;
+  var $records = array();
+  
+  function __construct($c=0, $f=0)
+  {
+    $this->count = (int)$c;
+    $this->first = (int)$f;
+  }
+  
+  function rcube_result_set($c=0, $f=0)
+  {
+    $this->__construct($c, $f);
+  }
+  
+  function add($rec)
+  {
+    $this->records[] = $rec;
+  }
+  
+  function iterate()
+  {
+    return $this->records[$this->current++];
+  }
+  
+  function first()
+  {
+    $this->current = 0;
+    return $this->records[$this->current++];
+  }
+  
+  // alias
+  function next()
+  {
+    return $this->iterate();
+  }
+  
+  function seek($i)
+  {
+    $this->current = $i;
+  }
+  
+}
\ No newline at end of file
diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc
index 8153311..c9cf4fb 100644
--- a/program/include/rcube_shared.inc
+++ b/program/include/rcube_shared.inc
@@ -91,7 +91,7 @@
  */
 function rcube_label($attrib)
 {
-  global $sess_user_lang, $INSTALL_PATH, $OUTPUT;
+  global $sess_user_lang, $OUTPUT;
   static $sa_text_data, $s_language, $utf8_decode;
 
   // extract attributes
@@ -111,8 +111,8 @@
     $sa_text_data = array();
     
     // get english labels (these should be complete)
-    @include($INSTALL_PATH.'program/localization/en_US/labels.inc');
-    @include($INSTALL_PATH.'program/localization/en_US/messages.inc');
+    @include(INSTALL_PATH.'program/localization/en_US/labels.inc');
+    @include(INSTALL_PATH.'program/localization/en_US/messages.inc');
 
     if (is_array($labels))
       $sa_text_data = $labels;
@@ -120,10 +120,10 @@
       $sa_text_data = array_merge($sa_text_data, $messages);
     
     // include user language files
-    if ($sess_user_lang!='en' && is_dir($INSTALL_PATH.'program/localization/'.$sess_user_lang))
+    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');
+      include_once(INSTALL_PATH.'program/localization/'.$sess_user_lang.'/labels.inc');
+      include_once(INSTALL_PATH.'program/localization/'.$sess_user_lang.'/messages.inc');
 
       if (is_array($labels))
         $sa_text_data = array_merge($sa_text_data, $labels);
diff --git a/program/include/rcube_template.php b/program/include/rcube_template.php
new file mode 100755
index 0000000..2002a62
--- /dev/null
+++ b/program/include/rcube_template.php
@@ -0,0 +1,1004 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_template.php                                    |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2006-2008, RoundCube Dev. - Switzerland                 |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Class to handle HTML page output using a skin template.             |
+ |   Extends rcube_html_page class from rcube_shared.inc                 |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+ */
+
+
+/**
+ * Class to create HTML page output using a skin template
+ *
+ * @package View
+ * @todo Documentation
+ * @uses rcube_html_page
+ */
+class rcube_template extends rcube_html_page
+{
+    var $config;
+    var $task = '';
+    var $framed = false;
+    var $pagetitle = '';
+    var $env = array();
+    var $js_env = array();
+    var $js_commands = array();
+    var $object_handlers = array();
+
+    public $ajax_call = false;
+
+    /**
+     * Constructor
+     *
+     * @todo   Use jQuery's $(document).ready() here.
+     */
+    public function __construct(&$config, $task)
+    {
+        parent::__construct();
+
+        $this->task = $task;
+        $this->config = $config;
+
+        // add common javascripts
+        $javascript = 'var '.JS_OBJECT_NAME.' = new rcube_webmail();';
+
+        // don't wait for page onload. Call init at the bottom of the page (delayed)
+        $javascript_foot = "if (window.call_init)\n call_init('".JS_OBJECT_NAME."');";
+
+        $this->add_script($javascript, 'head_top');
+        $this->add_script($javascript_foot, 'foot');
+        $this->scripts_path = 'program/js/';
+        $this->include_script('common.js');
+        $this->include_script('app.js');
+
+        // register common UI objects
+        $this->add_handlers(array(
+            'loginform'       => array($this, 'login_form'),
+            'username'        => array($this, 'current_username'),
+            'message'         => array($this, 'message_container'),
+            'charsetselector' => array($this, 'charset_selector'),
+        ));
+    }
+
+    /**
+     * Set environment variable
+     *
+     * @param string Property name
+     * @param mixed Property value
+     * @param boolean True if this property should be added to client environment
+     */
+    public function set_env($name, $value, $addtojs = true)
+    {
+        $this->env[$name] = $value;
+        if ($addtojs || isset($this->js_env[$name])) {
+            $this->js_env[$name] = $value;
+        }
+    }
+
+
+    /**
+     * Set page title variable
+     */
+    public function set_pagetitle($title)
+    {
+        $this->pagetitle = $title;
+    }
+
+
+    /**
+     * Register a template object handler
+     *
+     * @param  string Object name
+     * @param  string Function name to call
+     * @return void
+     */
+    public function add_handler($obj, $func)
+    {
+        $this->object_handlers[$obj] = $func;
+    }
+
+    /**
+     * Register a list of template object handlers
+     *
+     * @param  array Hash array with object=>handler pairs
+     * @return void
+     */
+    public function add_handlers($arr)
+    {
+        $this->object_handlers = array_merge($this->object_handlers, $arr);
+    }
+
+    /**
+     * Register a GUI object to the client script
+     *
+     * @param  string Object name
+     * @param  string Object ID
+     * @return void
+     */
+    public function add_gui_object($obj, $id)
+    {
+        $this->add_script(JS_OBJECT_NAME.".gui_object('$obj', '$id');");
+    }
+
+    /**
+     * Call a client method
+     *
+     * @param string Method to call
+     * @param ... Additional arguments
+     */
+    public function command()
+    {
+        $this->js_commands[] = func_get_args();
+    }
+
+
+    /**
+     * Add a localized label to the client environment
+     */
+    public function add_label()
+    {
+        $arg_list = func_get_args();
+        foreach ($arg_list as $i => $name) {
+            $this->command('add_label', $name, rcube_label($name));
+        }
+    }
+
+
+    /**
+     * 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
+     * @uses self::command()
+     */
+    public function show_message($message, $type='notice', $vars=NULL)
+    {
+        $this->command(
+            'display_message',
+            rcube_label(array('name' => $message, 'vars' => $vars)),
+            $type);
+    }
+
+
+    /**
+     * Delete all stored env variables and commands
+     *
+     * @return void
+     * @uses   rcube_html::reset()
+     * @uses   self::$env
+     * @uses   self::$js_env
+     * @uses   self::$js_commands
+     * @uses   self::$object_handlers
+     */
+    public public function reset()
+    {
+        $this->env = array();
+        $this->js_env = array();
+        $this->js_commands = array();
+        $this->object_handlers = array();
+        parent::reset();
+    }
+
+
+    /**
+     * Send the request output to the client.
+     * This will either parse a skin tempalte or send an AJAX response
+     *
+     * @param string  Template name
+     * @param boolean True if script should terminate (default)
+     */
+    public function send($templ = null, $exit = true)
+    {
+        if ($templ != 'iframe') {
+            $this->parse($templ, false);
+        }
+        else {
+            $this->framed = $templ == 'iframe' ? true : $this->framed;
+            $this->write();
+        }
+
+        if ($exit) {
+            exit;
+        }
+    }
+
+    /**
+     * Process template and write to stdOut
+     *
+     * @param string HTML template
+     * @see rcube_html_page::write()
+     * @override
+     */
+    public function write($template = '')
+    {
+        // unlock interface after iframe load
+        if ($this->framed) {
+            array_unshift($this->js_commands, array('set_busy', false));
+        }
+        // write all env variables to client
+        $js = $this->framed ? "if(window.parent) {\n" : '';
+        $js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
+        $this->add_script($js, 'head_top');
+
+        // call super method
+        parent::write($template, $this->config['skin_path']);
+    }
+
+    /**
+     * Parse a specific skin template and deliver to stdout
+     *
+     * Either returns nothing, or exists hard (exit();)
+     *
+     * @param  string  Template name
+     * @param  boolean Exit script
+     * @return void
+     * @link   http://php.net/manual/en/function.exit.php
+     */
+    private function parse($name = 'main', $exit = true)
+    {
+        $skin_path = $this->config['skin_path'];
+
+        // read template file
+        $templ = '';
+        $path = "$skin_path/templates/$name.html";
+
+        if (($fp = fopen($path, 'r')) === false) {
+            $message = '';
+            ob_start();
+            fopen($path, 'r');
+            $message.= ob_get_contents();
+            ob_end_clean();
+            rcube_error::raise(array(
+                'code' => 501,
+                'type' => 'php',
+                'line' => __LINE__,
+                'file' => __FILE__,
+                'message' => 'Error loading template for '.$name.': '.$message
+                ), true, true);
+            return false;
+        }
+        $templ = fread($fp, filesize($path));
+        fclose($fp);
+
+        // parse for specialtags
+        $output = $this->parse_conditions($templ);
+        $output = $this->parse_xml($output);
+
+        // add debug console
+        if ($this->config['debug_level'] & 8) {
+            $this->add_footer('<div style="position:absolute;top:5px;left:5px;width:400px;padding:0.2em;background:white;opacity:0.8;z-index:9000">
+                <a href="#toggle" onclick="con=document.getElementById(\'dbgconsole\');con.style.display=(con.style.display==\'none\'?\'block\':\'none\');return false">console</a>
+                <form action="/" name="debugform"><textarea name="console" id="dbgconsole" rows="20" cols="40" wrap="off" style="display:none;width:400px;border:none;font-size:x-small"></textarea></form></div>'
+            );
+        }
+        $output = $this->parse_with_globals($output);
+        $this->write(trim($output), $skin_path);
+        if ($exit) {
+            exit;
+        }
+    }
+
+
+    /**
+     * Return executable javascript code for all registered commands
+     *
+     * @return string $out
+     */
+    private function get_js_commands()
+    {
+        $out = '';
+        if (!$this->framed && !empty($this->js_env)) {
+            $out .= JS_OBJECT_NAME . '.set_env('.json_serialize($this->js_env).");\n";
+        }
+        foreach ($this->js_commands as $i => $args) {
+            $method = array_shift($args);
+            foreach ($args as $i => $arg) {
+                $args[$i] = json_serialize($arg);
+            }
+            $parent = $this->framed || preg_match('/^parent\./', $method);
+            $out .= sprintf(
+                "%s.%s(%s);\n",
+            ($parent ? 'parent.' : '') . JS_OBJECT_NAME,
+            preg_replace('/^parent\./', '', $method),
+            implode(',', $args)
+            );
+        }
+        // add command to set page title
+        if ($this->ajax_call && !empty($this->pagetitle)) {
+            $out .= sprintf(
+                "this.set_pagetitle('%s');\n",
+                JQ((!empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '') . $this->pagetitle)
+            );
+        }
+        return $out;
+    }
+
+    /**
+     * Make URLs starting with a slash point to skin directory
+     *
+     * @param  string Input string
+     * @return string
+     */
+    public function abs_url($str)
+    {
+        return preg_replace('/^\//', $this->config['skin_path'].'/', $str);
+    }
+
+
+    /*****  Template parsing methods  *****/
+
+    /**
+     * Replace all strings ($varname)
+     * with the content of the according global variable.
+     */
+    private function parse_with_globals($input)
+    {
+        $GLOBALS['__comm_path'] = Q($GLOBALS['COMM_PATH']);
+        return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input);
+    }
+
+    /**
+     * Public wrapper to dipp into template parsing.
+     *
+     * @param  string $input
+     * @return string
+     * @uses   rcube_template::parse_xml()
+     * @since  0.1-rc1
+     */
+    public function just_parse($input)
+    {
+        return $this->parse_xml($input);
+    }
+
+    /**
+     * Parse for conditional tags
+     *
+     * @param  string $input
+     * @return string
+     */
+    private function parse_conditions($input)
+    {
+        $matches = preg_split('/<roundcube:(if|elseif|else|endif)\s+([^>]+)>/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE);
+        if ($matches && count($matches) == 4) {
+            if (preg_match('/^(else|endif)$/i', $matches[1])) {
+                return $matches[0] . $this->parse_conditions($matches[3]);
+            }
+            $attrib = parse_attrib_string($matches[2]);
+            if (isset($attrib['condition'])) {
+                $condmet = $this->check_condition($attrib['condition']);
+                $submatches = preg_split('/<roundcube:(elseif|else|endif)\s+([^>]+)>/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE);
+                if ($condmet) {
+                    $result = $submatches[0];
+                    $result.= ($submatches[1] != 'endif' ? preg_replace('/.*<roundcube:endif\s+[^>]+>/Uis', '', $submatches[3], 1) : $submatches[3]);
+                }
+                else {
+                    $result = "<roundcube:$submatches[1] $submatches[2]>" . $submatches[3];
+                }
+                return $matches[0] . $this->parse_conditions($result);
+            }
+            rcube_error::raise(array(
+                'code' => 500,
+                'type' => 'php',
+                'line' => __LINE__,
+                'file' => __FILE__,
+                'message' => "Unable to parse conditional tag " . $matches[2]
+            ), true, false);
+        }
+        return $input;
+    }
+
+
+    /**
+     * Determines if a given condition is met
+     *
+     * @todo   Get rid off eval() once I understand what this does.
+     * @todo   Extend this to allow real conditions, not just "set"
+     * @param  string Condition statement
+     * @return boolean True if condition is met, False is not
+     */
+    private function check_condition($condition)
+    {
+        $condition = preg_replace(
+            array(
+                '/session:([a-z0-9_]+)/i',
+                '/config:([a-z0-9_]+)/i',
+                '/env:([a-z0-9_]+)/i',
+                '/request:([a-z0-9_]+)/ie'
+            ),
+            array(
+                "\$_SESSION['\\1']",
+                "\$this->config['\\1']",
+                "\$this->env['\\1']",
+                "get_input_value('\\1', RCUVE_INPUT_GPC)"
+            ),
+            $condition);
+            
+            return eval("return (".$condition.");");
+    }
+
+
+    /**
+     * Search for special tags in input and replace them
+     * with the appropriate content
+     *
+     * @param  string Input string to parse
+     * @return string Altered input string
+     * @todo   Maybe a cache.
+     */
+    private function parse_xml($input)
+    {
+        return preg_replace('/<roundcube:([-_a-z]+)\s+([^>]+)>/Uie', "\$this->xml_command('\\1', '\\2')", $input);
+    }
+
+
+    /**
+     * Convert a xml command tag into real content
+     *
+     * @param  string Tag command: object,button,label, etc.
+     * @param  string Attribute string
+     * @return string Tag/Object content
+     */
+    private function xml_command($command, $str_attrib, $add_attrib = array())
+    {
+        $command = strtolower($command);
+        $attrib  = parse_attrib_string($str_attrib) + $add_attrib;
+
+        // empty output if required condition is not met
+        if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) {
+            return '';
+        }
+
+        // execute command
+        switch ($command) {
+            // return a button
+            case 'button':
+                if ($attrib['command']) {
+                    return $this->button($attrib);
+                }
+                break;
+
+            // show a label
+            case 'label':
+                if ($attrib['name'] || $attrib['command']) {
+                    return Q(rcube_label($attrib + array('vars' => array('product' => $this->config['product_name']))));
+                }
+                break;
+
+            // include a file
+            case 'include':
+                $path = realpath($this->config['skin_path'].$attrib['file']);
+                if ($fsize = filesize($path)) {
+                    if ($this->config['skin_include_php']) {
+                        $incl = $this->include_php($path);
+                    }
+                    else if ($fp = fopen($path, 'r')) {
+                        $incl = fread($fp, $fsize);
+                        fclose($fp);
+                    }
+                    return $this->parse_xml($incl);
+                }
+                break;
+
+            case 'plugin.include':
+                //rcube::tfk_debug(var_export($this->config['skin_path'], true));
+                $path = realpath($this->config['skin_path'].$attrib['file']);
+                if (!$path) {
+                    //rcube::tfk_debug("Does not exist:");
+                    //rcube::tfk_debug($this->config['skin_path']);
+                    //rcube::tfk_debug($attrib['file']);
+                    //rcube::tfk_debug($path);
+                }
+                $incl = file_get_contents($path);
+                if ($incl) {
+                    return $this->parse_xml($incl);
+                }
+                break;
+
+            // return code for a specific application object
+            case 'object':
+                $object = strtolower($attrib['name']);
+
+                // we are calling a class/method
+                if (($handler = $this->object_handlers[$object]) && is_array($handler)) {
+                    if ((is_object($handler[0]) && method_exists($handler[0], $handler[1])) ||
+                    (is_string($handler[0]) && class_exists($handler[0])))
+                    return call_user_func($handler, $attrib);
+                }
+                else if (function_exists($handler)) {
+                    // execute object handler function
+                    return call_user_func($handler, $attrib);
+                }
+
+                if ($object=='productname') {
+                    $name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail';
+                    return Q($name);
+                }
+                if ($object=='version') {
+                    return (string)RCMAIL_VERSION;
+                }
+                if ($object=='pagetitle') {
+                    $task  = $this->task;
+                    $title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '';
+
+                    if (!empty($this->pagetitle)) {
+                        $title .= $this->pagetitle;
+                    }
+                    else if ($task == 'login') {
+                        $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name'])));
+                    }
+                    else {
+                        $title .= ucfirst($task);
+                    }
+
+                    return Q($title);
+                }
+                break;
+            
+            // return variable
+            case 'var':
+                $var = explode(':', $attrib['name']);
+                $name = $var[1];
+                $value = '';
+
+                switch ($var[0]) {
+                    case 'env':
+                        $value = $this->env[$name];
+                        break;
+                    case 'config':
+                        $value = $this->config[$name];
+                        if (is_array($value) && $value[$_SESSION['imap_host']]) {
+                            $value = $value[$_SESSION['imap_host']];
+                        }
+                        break;
+                    case 'request':
+                        $value = get_input_value($name, RCUBE_INPUT_GPC);
+                        break;
+                    case 'session':
+                        $value = $_SESSION[$name];
+                        break;
+                }
+
+                if (is_array($value)) {
+                    $value = implode(', ', $value);
+                }
+
+                return Q($value);
+                break;
+        }
+        return '';
+    }
+
+    /**
+     * Include a specific file and return it's contents
+     *
+     * @param string File path
+     * @return string Contents of the processed file
+     */
+    private function include_php($file)
+    {
+        ob_start();
+        include $file;
+        $out = ob_get_contents();
+        ob_end_clean();
+
+        return $out;
+    }
+
+
+    /**
+     * Create and register a button
+     *
+     * @param  array Named button attributes
+     * @return string HTML button
+     * @todo   Remove all inline JS calls and use jQuery instead.
+     * @todo   Remove all sprintf()'s - they are pretty, but also slow.
+     */
+    private function button($attrib)
+    {
+        global $CONFIG, $OUTPUT, $MAIN_TASKS;
+        static $sa_buttons = array();
+        static $s_button_count = 100;
+
+        // these commands can be called directly via url
+        $a_static_commands = array('compose', 'list');
+
+        $browser   = new rcube_browser();
+        $skin_path = $this->config['skin_path'];
+
+        if (!($attrib['command'] || $attrib['name'])) {
+            return '';
+        }
+        // try to find out the button type
+        if ($attrib['type']) {
+            $attrib['type'] = strtolower($attrib['type']);
+        }
+        else {
+            $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link';
+        }
+        $command = $attrib['command'];
+
+        // take the button from the stack
+        if ($attrib['name'] && $sa_buttons[$attrib['name']]) {
+            $attrib = $sa_buttons[$attrib['name']];
+        }
+        else if($attrib['image'] || $attrib['imageact'] || $attrib['imagepas'] || $attrib['class']) {
+            // add button to button stack
+            if (!$attrib['name']) {
+                $attrib['name'] = $command;
+            }
+            if (!$attrib['image']) {
+                $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact'];
+            }
+            $sa_buttons[$attrib['name']] = $attrib;
+        }
+        else if ($command && $sa_buttons[$command]) {
+            // get saved button for this command/name
+            $attrib = $sa_buttons[$command];
+        }
+
+        // set border to 0 because of the link arround the button
+        if ($attrib['type']=='image' && !isset($attrib['border'])) {
+            $attrib['border'] = 0;
+        }
+        if (!$attrib['id']) {
+            $attrib['id'] =  sprintf('rcmbtn%d', $s_button_count++);
+        }
+        // get localized text for labels and titles
+        if ($attrib['title']) {
+            $attrib['title'] = Q(rcube_label($attrib['title']));
+        }
+        if ($attrib['label']) {
+            $attrib['label'] = Q(rcube_label($attrib['label']));
+        }
+        if ($attrib['alt']) {
+            $attrib['alt'] = Q(rcube_label($attrib['alt']));
+        }
+        // set title to alt attribute for IE browsers
+        if ($browser->ie && $attrib['title'] && !$attrib['alt']) {
+            $attrib['alt'] = $attrib['title'];
+            unset($attrib['title']);
+        }
+
+        // add empty alt attribute for XHTML compatibility
+        if (!isset($attrib['alt'])) {
+            $attrib['alt'] = '';
+        }
+
+        // register button in the system
+        if ($attrib['command']) {
+            $this->add_script(sprintf(
+                "%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');",
+                JS_OBJECT_NAME,
+                $command,
+                $attrib['id'],
+                $attrib['type'],
+                $attrib['imageact'] ? $skin_path.$attrib['imageact'] : $attrib['classact'],
+                $attrib['imagesel'] ? $skin_path.$attrib['imagesel'] : $attrib['classsel'],
+                $attrib['imageover'] ? $skin_path.$attrib['imageover'] : ''
+            ));
+
+            // make valid href to specific buttons
+            if (in_array($attrib['command'], $MAIN_TASKS)) {
+                $attrib['href'] = Q(rcmail_url(null, null, $attrib['command']));
+            }
+            else if (in_array($attrib['command'], $a_static_commands)) {
+                $attrib['href'] = Q(rcmail_url($attrib['command']));
+            }
+        }
+
+        // overwrite attributes
+        if (!$attrib['href']) {
+            $attrib['href'] = '#';
+        }
+        if ($command) {
+            $attrib['onclick'] = sprintf(
+                "return %s.command('%s','%s',this)",
+                JS_OBJECT_NAME,
+                $command,
+                $attrib['prop']
+            );
+        }
+        if ($command && $attrib['imageover']) {
+            $attrib['onmouseover'] = sprintf(
+                "return %s.button_over('%s','%s')",
+                JS_OBJECT_NAME,
+                $command,
+                $attrib['id']
+            );
+            $attrib['onmouseout'] = sprintf(
+                "return %s.button_out('%s','%s')",
+                JS_OBJECT_NAME,
+                $command,
+                $attrib['id']
+            );
+        }
+
+        if ($command && $attrib['imagesel']) {
+            $attrib['onmousedown'] = sprintf(
+                "return %s.button_sel('%s','%s')",
+                JS_OBJECT_NAME,
+                $command,
+                $attrib['id']
+            );
+            $attrib['onmouseup'] = sprintf(
+                "return %s.button_out('%s','%s')",
+                JS_OBJECT_NAME,
+                $command,
+                $attrib['id']
+            );
+        }
+
+        $out = '';
+
+        // generate image tag
+        if ($attrib['type']=='image') {
+            $attrib_str = html::attrib_string(
+                $attrib,
+                array(
+                    'style', 'class', 'id', 'width',
+                    'height', 'border', 'hspace',
+                    'vspace', 'align', 'alt',
+                )
+            );
+            $img_tag = sprintf('<img src="%%s"%s />', $attrib_str);
+            $btn_content = sprintf($img_tag, $skin_path.$attrib['image']);
+            if ($attrib['label']) {
+                $btn_content .= ' '.$attrib['label'];
+            }
+            $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title');
+        }
+        else if ($attrib['type']=='link') {
+            $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command'];
+            $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style');
+        }
+        else if ($attrib['type']=='input') {
+            $attrib['type'] = 'button';
+
+            if ($attrib['label']) {
+                $attrib['value'] = $attrib['label'];
+            }
+
+            $attrib_str = html::attrib_string(
+                $attrib,
+                array(
+                    'type', 'value', 'onclick',
+                    'id', 'class', 'style'
+                )
+            );
+            $out = sprintf('<input%s disabled="disabled" />', $attrib_str);
+        }
+
+        // generate html code for button
+        if ($btn_content) {
+            $attrib_str = html::attrib_string($attrib, $link_attrib);
+            $out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content);
+        }
+
+        return $out;
+    }
+
+
+    /*  ************* common functions delivering gui objects **************  */
+
+
+    /**
+     * 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
+     */
+    static function current_username($attrib)
+    {
+        global $USER;
+        static $username;
+
+        // alread fetched
+        if (!empty($username)) {
+            return $username;
+        }
+
+        // get e-mail address form default identity
+        if ($sql_arr = $USER->get_identity()) {
+          $s_username = $sql_arr['email'];
+        }
+        else if (strstr($_SESSION['username'], '@')) {
+            $username = $_SESSION['username'];
+        }
+        else {
+            $username = $_SESSION['username'].'@'.$_SESSION['imap_host'];
+        }
+
+        return $username;
+    }
+
+
+    /**
+     * GUI object 'loginform'
+     * Returns code for the webmail login form
+     *
+     * @param array Named parameters
+     * @return string HTML code for the gui object
+     */
+    private function login_form($attrib)
+    {
+        global $CONFIG, $SESS_HIDDEN_FIELD;
+        $default_host = $CONFIG['default_host'];
+
+        $_SESSION['temp'] = true;
+
+        $input_user   = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30, 'autocomplete' => 'off'));
+        $input_pass   = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30));
+        $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login'));
+        $input_host   = null;
+
+        if (is_array($default_host)) {
+            $input_host = new html_select(array('name' => '_host', 'id' => 'rcmloginhost'));
+
+            foreach ($default_host as $key => $value) {
+                if (!is_array($value)) {
+                    $input_host->add($value, (is_numeric($key) ? $value : $key));
+                }
+                else {
+                    $input_host = null;
+                    break;
+                }
+            }
+        }
+        else if (!strlen($default_host)) {
+            $input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30));
+        }
+
+        $form_name  = !empty($attrib['form']) ? $attrib['form'] : 'form';
+        $this->add_gui_object('loginform', $form_name);
+
+        // create HTML table with two cols
+        $table = new html_table(array('cols' => 2));
+
+        $table->add('title', html::label('rcmloginuser', Q(rcube_label('username'))));
+        $table->add(null, $input_user->show(get_input_value('_user', RCUVE_INPUT_POST)));
+
+        $table->add('title', html::label('rcmloginpwd', Q(rcube_label('password'))));
+        $table->add(null, $input_pass->show());
+
+        // add host selection row
+        if (is_object($input_host)) {
+            $table->add('title', html::label('rcmloginhost', Q(rcube_label('server'))));
+            $table->add(null, $input_host->show(get_input_value('_host', RCUVE_INPUT_POST)));
+        }
+
+        $out = $SESS_HIDDEN_FIELD;
+        $out .= $input_action->show();
+        $out .= $table->show();
+
+        // surround html output with a form tag
+        if (empty($attrib['form'])) {
+            $out = html::tag(
+                'form',
+                array(
+                    'name' => $form_name,
+                    'action' => "./",
+                    'method' => "post"
+                ),
+            $out);
+        }
+
+        return $out;
+    }
+
+
+    /**
+     * GUI object 'searchform'
+     * Returns code for search function
+     *
+     * @param array Named parameters
+     * @return string HTML code for the gui object
+     */
+    private function search_form($attrib)
+    {
+        // add some labels to client
+        $this->add_label('searching');
+
+        $attrib['name'] = '_q';
+
+        if (empty($attrib['id'])) {
+            $attrib['id'] = 'rcmqsearchbox';
+        }
+        $input_q = new html_inputfield($attrib);
+        $out = $input_q->show();
+
+        $this->add_gui_object('qsearchbox', $attrib['id']);
+
+        // add form tag around text field
+        if (empty($attrib['form'])) {
+            $out = html::tag(
+                'form',
+                array(
+                    'name' => "rcmqsearchform",
+                    'action' => "./",
+                    'onsubmit' => JS_OBJECT_NAME . ".command('search');return false;",
+                    'style' => "display:inline",
+                ),
+            $out);
+        }
+
+        return $out;
+    }
+
+
+    /**
+     * Builder for GUI object 'message'
+     *
+     * @param array Named tag parameters
+     * @return string HTML code for the gui object
+     */
+    private function message_container($attrib)
+    {
+        if (isset($attrib['id']) === false) {
+            $attrib['id'] = 'rcmMessageContainer';
+        }
+
+        $this->add_gui_object('message', $attrib['id']);
+        return html::div($attrib, "");
+    }
+
+
+    /**
+     * GUI object 'charsetselector'
+     *
+     * @param array Named parameters for the select tag
+     * @return string HTML code for the gui object
+     */
+    static function charset_selector($attrib)
+    {
+        // 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 html_select($field_attrib);
+            $select->add(array_values($charsets), array_keys($charsets));
+
+            $set = $_POST['_charset'] ? $_POST['_charset'] : $this->get_charset();
+            return $select->show($set);
+    }
+
+}  // end class rcube_template
+
+
diff --git a/program/include/rcube_user.inc b/program/include/rcube_user.php
similarity index 100%
rename from program/include/rcube_user.inc
rename to program/include/rcube_user.php
diff --git a/program/js/app.js b/program/js/app.js
index 02c1cf5..a62d8d8 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -1581,11 +1581,11 @@
         parent.rcmail.set_classname(rows[uid].obj, 'unread', false);
 
         if (rows[uid].replied && parent.rcmail.env.repliedicon)
-    	  icn_src = parent.rcmail.env.repliedicon;
+          icn_src = parent.rcmail.env.repliedicon;
         else if (parent.rcmail.env.messageicon)
           icn_src = parent.rcmail.env.messageicon;
       
-	if (rows[uid].icon && icn_src)
+        if (rows[uid].icon && icn_src)
           rows[uid].icon.src = icn_src;
       }
   }
@@ -3502,28 +3502,27 @@
           this.message_list.init();
 
       case 'purge':
-      case 'expunge':      
-	if (!this.env.messagecount)
-    	  {
-	    // clear preview pane content
-	    if (this.env.contentframe)
-	      this.show_contentframe(false);
-	    // disable commands useless when mailbox is empty
-	    this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource',
-	      'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', false);
-	  }
+      case 'expunge':
+        if (!this.env.messagecount)
+        {
+          // clear preview pane content
+          if (this.env.contentframe)
+            this.show_contentframe(false);
+          // disable commands useless when mailbox is empty
+          this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource',
+          'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', false);
+        }
 
-	break;
+      break;
 
       case 'list':
-	this.msglist_select(this.message_list);
+        this.msglist_select(this.message_list);
 
       case 'check-recent':
       case 'getunread':
-	this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0));
-	this.enable_command('purge', (this.env.messagecount && (this.env.mailbox==this.env.trash_mailbox || this.env.mailbox==this.env.junk_mailbox)));
-
-	break;
+        this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0));
+        this.enable_command('purge', (this.env.messagecount && (this.env.mailbox==this.env.trash_mailbox || this.env.mailbox==this.env.junk_mailbox)));
+        break;
 
       }
 
diff --git a/program/lib/html2text.inc b/program/lib/html2text.php
similarity index 100%
rename from program/lib/html2text.inc
rename to program/lib/html2text.php
diff --git a/program/steps/addressbook/edit.inc b/program/steps/addressbook/edit.inc
index 47db719..e3218a3 100644
--- a/program/steps/addressbook/edit.inc
+++ b/program/steps/addressbook/edit.inc
@@ -89,7 +89,7 @@
   $form_start = '';
   if (!strlen($EDIT_FORM))
     {
-    $hiddenfields = new hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
+    $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
     $hiddenfields->add(array('name' => '_action', 'value' => 'save', 'source' => get_input_value('_source', RCUBE_INPUT_GPC)));
     
     if (($result = $CONTACTS->get_result()) && ($record = $result->first()))
@@ -114,8 +114,8 @@
 
 
 if (!$CONTACTS->get_result() && template_exists('addcontact'))
-  parse_template('addcontact');
+  $OUTPUT->send('addcontact');
 
 // this will be executed if no template for addcontact exists
-parse_template('editcontact');
+$OUTPUT->send('editcontact');
 ?>
\ No newline at end of file
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index b916ad7..28b540a 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -19,9 +19,6 @@
 
 */
 
-require_once('include/rcube_contacts.inc');
-require_once('include/rcube_ldap.inc');
-
 // instantiate a contacts object according to the given source
 if (($source = get_input_value('_source', RCUBE_INPUT_GPC)) && isset($CONFIG['ldap_public'][$source]))
   $CONTACTS = new rcube_ldap($CONFIG['ldap_public'][$source]);
@@ -157,7 +154,7 @@
     
     // format each col
     foreach ($a_show_cols as $col)
-      $a_row_cols[$col] = $row[$col];
+      $a_row_cols[$col] = Q($row[$col]);
     
     $OUTPUT->command($prefix.'add_contact_row', $row['ID'], $a_row_cols);
     }
@@ -231,7 +228,7 @@
   'addresslist' => 'rcmail_contacts_list',
   'addressframe' => 'rcmail_contact_frame',
   'recordscountdisplay' => 'rcmail_rowcount_display',
-  'searchform' => 'rcmail_search_form'
+  'searchform' => array($OUTPUT, 'search_form')
 ));
 
 ?>
diff --git a/program/steps/error.inc b/program/steps/error.inc
index afe5a28..4a151d4 100644
--- a/program/steps/error.inc
+++ b/program/steps/error.inc
@@ -101,7 +101,7 @@
   {
   $OUTPUT->scripts = array();
   $OUTPUT->script_files = array();
-  parse_template('error');
+  $OUTPUT->send('error');
   }
 
 
diff --git a/program/steps/mail/addcontact.inc b/program/steps/mail/addcontact.inc
index 2cf1903..0ad1031 100644
--- a/program/steps/mail/addcontact.inc
+++ b/program/steps/mail/addcontact.inc
@@ -19,8 +19,6 @@
 
 */
 
-require_once('include/rcube_contacts.inc');
-
 $done = false;
 
 if (!empty($_POST['_address']))
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index fd3743e..aaeca24 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -19,9 +19,6 @@
 
 */
 
-require_once('Mail/mimeDecode.php');
-require_once('lib/html2text.inc');
-
 // define constants for message compose mode
 define('RCUBE_COMPOSE_REPLY', 0x0106);
 define('RCUBE_COMPOSE_FORWARD', 0x0107);
@@ -159,14 +156,14 @@
       }
         
       $allow_attrib = array('id', 'class', 'style', 'cols', 'rows', 'tabindex');
-      $field_type = 'textarea';            
+      $field_type = 'html_textarea';
       break;
 
     case 'replyto':
     case 'reply-to':
       $fname = '_replyto';
       $allow_attrib = array('id', 'class', 'style', 'size', 'tabindex');
-      $field_type = 'textfield';
+      $field_type = 'html_inputfield';
       break;    
   }
  
@@ -231,7 +228,7 @@
 
     // create teaxtarea object
     $input = new $field_type($field_attrib);
-    $out = $input->show($fvalue);    
+    $out = $input->show($fvalue);
   }
   
   if ($form_start)
@@ -285,7 +282,7 @@
     $a_signatures = array();
 
     $field_attrib['onchange'] = JS_OBJECT_NAME.".change_identity(this)";
-    $select_from = new select($field_attrib);
+    $select_from = new html_select($field_attrib);
 
     while ($sql_arr = $DB->fetch_assoc($sql_result))
     {
@@ -327,7 +324,7 @@
   }
   else
   {
-    $input_from = new textfield($field_attrib);
+    $input_from = new html_inputfield($field_attrib);
     $out = $input_from->show($_POST['_from']);
   }
   
@@ -419,19 +416,19 @@
 
   $out = $form_start ? "$form_start\n" : '';
 
-  $saveid = new hiddenfield(array('name' => '_draft_saveid', 'value' => $compose_mode==RCUBE_COMPOSE_DRAFT ? str_replace(array('<','>'), "", $MESSAGE['headers']->messageID) : ''));
+  $saveid = new html_hiddenfield(array('name' => '_draft_saveid', 'value' => $compose_mode==RCUBE_COMPOSE_DRAFT ? str_replace(array('<','>'), "", $MESSAGE['headers']->messageID) : ''));
   $out .= $saveid->show();
 
-  $drafttoggle = new hiddenfield(array('name' => '_draft', 'value' => 'yes'));
+  $drafttoggle = new html_hiddenfield(array('name' => '_draft', 'value' => 'yes'));
   $out .= $drafttoggle->show();
 
-  $msgtype = new hiddenfield(array('name' => '_is_html', 'value' => ($isHtml?"1":"0")));
+  $msgtype = new html_hiddenfield(array('name' => '_is_html', 'value' => ($isHtml?"1":"0")));
   $out .= $msgtype->show();
 
   // If desired, set this text area to be editable by TinyMCE
   if ($isHtml)
     $attrib['mce_editable'] = "true";
-  $textarea = new textarea($attrib);
+  $textarea = new html_textarea($attrib);
   $out .= $textarea->show($body);
   $out .= $form_end ? "\n$form_end" : '';
 
@@ -622,7 +619,7 @@
   unset($attrib['form']);
   
   $attrib['name'] = '_subject';
-  $textfield = new textfield($attrib);
+  $textfield = new html_inputfield($attrib);
 
   $subject = '';
 
@@ -750,7 +747,7 @@
   unset($attrib['form']);
   
   $attrib['name'] = '_priority';
-  $selector = new select($attrib);
+  $selector = new html_select($attrib);
 
   $selector->add(array(rcube_label('lowest'),
                        rcube_label('low'),
@@ -781,7 +778,7 @@
 
   $attrib['name'] = '_receipt';
   $attrib['value'] = '1';
-  $checkbox = new checkbox($attrib);
+  $checkbox = new html_checkbox($attrib);
 
   $out = $form_start ? "$form_start\n" : '';
   $out .= $checkbox->show($MESSAGE['headers']->mdn_to ? 1 : 0);
@@ -828,7 +825,7 @@
       unset($attrib['checked']);
 
     $attrib['id'] = '_' . $value;
-    $rb = new radiobutton($attrib);
+    $rb = new html_radiobutton($attrib);
     $selector .= sprintf("%s<label for=\"%s\">%s</label>",
                          $rb->show($value),
                          $attrib['id'],
@@ -846,7 +843,7 @@
   $form_start = '';
   if (!strlen($MESSAGE_FORM))
   {
-    $hiddenfields = new hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
+    $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
     $hiddenfields->add(array('name' => '_action', 'value' => 'send'));
 
     $form_start = empty($attrib['form']) ? '<form name="form" action="./" method="post">' : '';
@@ -862,7 +859,7 @@
   
   $MESSAGE_FORM = $form_name;
 
-  return array($form_start, $form_end);  
+  return array($form_start, $form_end);
 }
 
 
@@ -880,9 +877,6 @@
 ));
 
 /****** get contacts for this user and add them to client scripts ********/
-
-require_once('include/rcube_contacts.inc');
-require_once('include/rcube_ldap.inc'); 
 
 $CONTACTS = new rcube_contacts($DB, $USER->ID);
 $CONTACTS->set_pagesize(1000);
@@ -928,5 +922,5 @@
   { 
  	$OUTPUT->set_env('contacts', $a_contacts); 
   } 
-parse_template('compose');
+$OUTPUT->send('compose');
 ?>
\ No newline at end of file
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 393fcaa..205db2f 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -19,7 +19,6 @@
 
 */
 
-require_once('lib/html2text.inc');
 require_once('lib/enriched.inc');
 require_once('include/rcube_smtp.inc');
 
@@ -1541,7 +1540,7 @@
   'messagecontentframe' => 'rcmail_messagecontent_frame',
   'messagepartframe' => 'rcmail_message_part_frame',
   'messagepartcontrols' => 'rcmail_message_part_controls',
-  'searchform' => 'rcmail_search_form'
+  'searchform' => array($OUTPUT, 'search_form'),
 ));
 
 ?>
diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc
index 6aca131..06c22ec 100644
--- a/program/steps/mail/get.inc
+++ b/program/steps/mail/get.inc
@@ -49,7 +49,7 @@
 // show part page
 if ($_GET['_frame'])
   {
-  parse_template('messagepart');
+  $OUTPUT->send('messagepart');
   exit;
   }
 
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index 5466d71..2281a97 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -5,7 +5,7 @@
  | program/steps/mail/sendmail.inc                                       |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -19,11 +19,6 @@
  $Id$
 
 */
-
-
-//require_once('lib/smtp.inc');
-require_once('lib/html2text.inc');
-require_once('lib/rc_mail_mime.inc');
 
 
 if (!isset($_SESSION['compose']['id']))
@@ -70,7 +65,7 @@
  */
 function rcmail_attach_emoticons(&$mime_message)
 {
-  global $CONFIG, $INSTALL_PATH;
+  global $CONFIG;
 
   $htmlContents = $mime_message->getHtmlBody();
 
@@ -100,7 +95,7 @@
     if (! in_array($image_name, $included_images))
       {
       // add the image to the MIME message
-      $img_file = $INSTALL_PATH . '/' . $searchstr . $image_name;
+      $img_file = INSTALL_PATH . '/' . $searchstr . $image_name;
       if(! $mime_message->addHTMLImage($img_file, 'image/gif', '', true, '_' . $image_name))
         $OUTPUT->show_message("emoticonerror", 'error');
 
@@ -237,7 +232,7 @@
 $isHtml = ($isHtmlVal == "1");
 
 // create extended PEAR::Mail_mime instance
-$MAIL_MIME = new rc_mail_mime(rcmail_header_delm());
+$MAIL_MIME = new rcube_mail_mime(rcmail_header_delm());
 
 // For HTML-formatted messages, construct the MIME message with both
 // the HTML part and the plain-text part
diff --git a/program/steps/mail/sendmdn.inc b/program/steps/mail/sendmdn.inc
index 530dcac..191f950 100644
--- a/program/steps/mail/sendmdn.inc
+++ b/program/steps/mail/sendmdn.inc
@@ -19,8 +19,6 @@
 
 */
 
-require_once('lib/rc_mail_mime.inc');
-
 
 if (!empty($_POST['_uid'])) {
   $sent = rcmail_send_mdn(get_input_value('_uid', RCUBE_INPUT_POST));
diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc
index 94e4c61..cc16700 100644
--- a/program/steps/mail/show.inc
+++ b/program/steps/mail/show.inc
@@ -19,9 +19,6 @@
 
 */
 
-require_once('Mail/mimeDecode.php');
-require_once('lib/rc_mail_mime.inc');
-
 $PRINT_MODE = $_action=='print' ? TRUE : FALSE;
 
 // similar code as in program/steps/mail/get.inc
@@ -39,7 +36,7 @@
     {
     $OUTPUT->show_message('messageopenerror', 'error');
     if ($_action=='preview' && template_exists('messagepreview'))
-        parse_template('messagepreview');
+        $OUTPUT->send('messagepreview');
     else
       {
       $_action = 'list';
@@ -79,14 +76,14 @@
 
   // mark message as read
   if (!$MESSAGE['headers']->seen)
+  {
+    $marked = $IMAP->set_flag($MESSAGE['UID'], 'SEEN');
+    if($_action == 'preview' && $marked != -1)
     {
-      $marked = $IMAP->set_flag($MESSAGE['UID'], 'SEEN');
-      if($_action == 'preview' && $marked != -1)
-	{
-	$OUTPUT->command('set_unread_count_from_preview', $mbox_name, $IMAP->messagecount($mbox_name, 'UNSEEN'), ($mbox_name == 'INBOX'));
-	$OUTPUT->command('mark_as_read_from_preview', $MESSAGE['UID']);
-	}
+      $OUTPUT->command('set_unread_count_from_preview', $mbox_name, $IMAP->messagecount($mbox_name, 'UNSEEN'), ($mbox_name == 'INBOX'));
+      $OUTPUT->command('mark_as_read_from_preview', $MESSAGE['UID']);
     }
+  }
 
   // give message uid to the client
   $OUTPUT->set_env('uid', $MESSAGE['UID']);
@@ -207,9 +204,9 @@
 
 
 if ($_action=='print' && template_exists('printmessage'))
-  parse_template('printmessage');
+  $OUTPUT->send('printmessage');
 else if ($_action=='preview' && template_exists('messagepreview'))
-    parse_template('messagepreview');
+    $OUTPUT->send('messagepreview');
 else
-  parse_template('message');
+  $OUTPUT->send('message');
 ?>
diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc
index 7497d8a..7309d4b 100644
--- a/program/steps/settings/edit_identity.inc
+++ b/program/steps/settings/edit_identity.inc
@@ -130,7 +130,7 @@
 $OUTPUT->add_handler('identityform', 'rcube_identity_form');
 
 if ($_action=='add-identity' && template_exists('addidentity'))
-  parse_template('addidentity');
+  $OUTPUT->send('addidentity');
 
-parse_template('editidentity');
+$OUTPUT->send('editidentity');
 ?>
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index 3edced4..81da0a2 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -50,7 +50,7 @@
     asort($a_lang);
   
     $field_id = 'rcmfd_lang';
-    $select_lang = new select(array('name' => '_language', 'id' => $field_id));
+    $select_lang = new html_select(array('name' => '_language', 'id' => $field_id));
     $select_lang->add(array_values($a_lang), array_keys($a_lang));
   
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
@@ -64,7 +64,7 @@
   if (!isset($no_override['timezone']))
     {
     $field_id = 'rcmfd_timezone';
-    $select_timezone = new select(array('name' => '_timezone', 'id' => $field_id));
+    $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id));
     $select_timezone->add('(GMT -11:00) Midway Island, Samoa', '-11');
     $select_timezone->add('(GMT -10:00) Hawaii', '-10');
     $select_timezone->add('(GMT -9:30) Marquesas Islands', '-9.5');
@@ -116,7 +116,7 @@
   if (!isset($no_override['dst_active']))
     {
     $field_id = 'rcmfd_dst';
-    $input_dst = new checkbox(array('name' => '_dst_active', 'id' => $field_id, 'value' => 1));
+    $input_dst = new html_checkbox(array('name' => '_dst_active', 'id' => $field_id, 'value' => 1));
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
                     Q(rcube_label('dstactive')),
@@ -127,7 +127,7 @@
   if (!isset($no_override['pagesize']))
     {
     $field_id = 'rcmfd_pgsize';
-    $input_pagesize = new textfield(array('name' => '_pagesize', 'id' => $field_id, 'size' => 5));
+    $input_pagesize = new html_inputfield(array('name' => '_pagesize', 'id' => $field_id, 'size' => 5));
 
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
@@ -139,7 +139,7 @@
   if (!isset($no_override['prettydate']))
     {
     $field_id = 'rcmfd_prettydate';
-    $input_prettydate = new checkbox(array('name' => '_pretty_date', 'id' => $field_id, 'value' => 1));
+    $input_prettydate = new html_checkbox(array('name' => '_pretty_date', 'id' => $field_id, 'value' => 1));
 
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
@@ -151,7 +151,7 @@
   if (!isset($no_override['prefer_html']))
     {
     $field_id = 'rcmfd_htmlmsg';
-    $input_pagesize = new checkbox(array('name' => '_prefer_html', 'id' => $field_id, 'value' => 1));
+    $input_pagesize = new html_checkbox(array('name' => '_prefer_html', 'id' => $field_id, 'value' => 1));
 
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
@@ -163,7 +163,7 @@
   if (!isset($no_override['htmleditor']))
     {
     $field_id = 'rcmfd_htmleditor';
-    $input_htmleditor = new checkbox(array('name' => '_htmleditor', 'id' => $field_id, 'value' => 1));
+    $input_htmleditor = new html_checkbox(array('name' => '_htmleditor', 'id' => $field_id, 'value' => 1));
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
                     Q(rcube_label('htmleditor')),
@@ -174,7 +174,7 @@
   if (!isset($no_override['preview_pane']))
     {
     $field_id = 'rcmfd_preview';
-    $input_preview = new checkbox(array('name' => '_preview_pane', 'id' => $field_id, 'value' => 1));
+    $input_preview = new html_checkbox(array('name' => '_preview_pane', 'id' => $field_id, 'value' => 1));
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
                     Q(rcube_label('previewpane')),
@@ -184,7 +184,7 @@
   if (!empty($CONFIG['drafts_mbox']) && !isset($no_override['draft_autosave']))
     {
     $field_id = 'rcmfd_autosave';
-    $select_autosave = new select(array('name' => '_draft_autosave', 'id' => $field_id));
+    $select_autosave = new html_select(array('name' => '_draft_autosave', 'id' => $field_id));
     $select_autosave->add(rcube_label('never'), 0);
     foreach (array(3, 5, 10) as $i => $min)
       $select_autosave->add(rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))), $min*60);
@@ -199,7 +199,7 @@
   if (!isset($no_override['logout_purge']))
     {
     $field_id = 'rcmfd_logout_purge';
-    $input_purge = new checkbox(array('name' => '_logout_purge', 'id' => $field_id, 'value' => 1));
+    $input_purge = new html_checkbox(array('name' => '_logout_purge', 'id' => $field_id, 'value' => 1));
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
                     Q(rcube_label('logoutclear')),
@@ -210,7 +210,7 @@
   if (!isset($no_override['logout_expunge']))
     {
     $field_id = 'rcmfd_logout_expunge';
-    $input_expunge = new checkbox(array('name' => '_logout_expunge', 'id' => $field_id, 'value' => 1));
+    $input_expunge = new html_checkbox(array('name' => '_logout_expunge', 'id' => $field_id, 'value' => 1));
     $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
                     $field_id,
                     Q(rcube_label('logoutcompact')),
@@ -254,7 +254,7 @@
   $form_start = '';
   if (!strlen($EDIT_FORM))
     {
-    $hiddenfields = new hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
+    $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
     $hiddenfields->add(array('name' => '_action', 'value' => $action));
     
     if ($add_hidden)
diff --git a/program/steps/settings/identities.inc b/program/steps/settings/identities.inc
index 9284e52..fe53ecc 100644
--- a/program/steps/settings/identities.inc
+++ b/program/steps/settings/identities.inc
@@ -45,5 +45,5 @@
 
 $OUTPUT->add_handler('identityframe', 'rcmail_identity_frame');
 
-parse_template('identities');
+$OUTPUT->send('identities');
 ?>
\ No newline at end of file
diff --git a/program/steps/settings/manage_folders.inc b/program/steps/settings/manage_folders.inc
index 9cf188a..4356c9f 100644
--- a/program/steps/settings/manage_folders.inc
+++ b/program/steps/settings/manage_folders.inc
@@ -174,7 +174,7 @@
   $delimiter = $IMAP->get_hierarchy_delimiter();
   $a_js_folders = array();
  
-  $checkbox_subscribe = new checkbox(array('name' => '_subscribed[]', 'onclick' => JS_OBJECT_NAME.".command(this.checked?'subscribe':'unsubscribe',this.value)"));
+  $checkbox_subscribe = new html_checkbox(array('name' => '_subscribed[]', 'onclick' => JS_OBJECT_NAME.".command(this.checked?'subscribe':'unsubscribe',this.value)"));
   
   if (!empty($attrib['deleteicon']))
     $del_button = sprintf('<img src="%s%s" alt="%s" border="0" />', $CONFIG['skin_path'], $attrib['deleteicon'], rcube_label('delete'));
@@ -251,12 +251,12 @@
   // return the complete edit form as table
   $out = "$form_start\n";
 
-  $input = new textfield(array('name' => '_folder_name'));
+  $input = new html_inputfield(array('name' => '_folder_name'));
   $out .= $input->show();
   
   if (get_boolean($attrib['button']))
     {
-    $button = new input_field(array('type' => 'button',
+    $button = new html_inputfield(array('type' => 'button',
                                     'value' => rcube_label('create'),
                                     'onclick' => JS_OBJECT_NAME.".command('create-folder',this.form)"));
     $out .= $button->show();
@@ -278,7 +278,7 @@
   $out = "$form_start\n";
 
   $a_unsubscribed = $IMAP->list_unsubscribed();
-  $select_folder = new select(array('name' => '_folder_oldname', 'id' => 'rcmfd_oldfolder'));
+  $select_folder = new html_select(array('name' => '_folder_oldname', 'id' => 'rcmfd_oldfolder'));
 
   foreach ($a_unsubscribed as $i => $folder)
     {
@@ -291,12 +291,12 @@
   $out .= $select_folder->show();
 
   $out .= " to ";
-  $inputtwo = new textfield(array('name' => '_folder_newname'));
+  $inputtwo = new html_inputfield(array('name' => '_folder_newname'));
   $out .= $inputtwo->show();
 
   if (get_boolean($attrib['button']))
     {
-    $button = new input_field(array('type' => 'button',
+    $button = new html_inputfield(array('type' => 'button',
                                     'value' => rcube_label('rename'),
                                     'onclick' => JS_OBJECT_NAME.".command('rename-folder',this.form)"));
     $out .= $button->show();

--
Gitblit v1.9.1