From e70b3b24fc8ac7b54a820ae87ce8f4af4043125e Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Thu, 09 Oct 2008 02:25:43 -0400
Subject: [PATCH] - send set_unread_count() only when changing /Seen status

---
 program/include/rcube_template.php |  314 ++++++++++++++++++++++++++++++++++------------------
 1 files changed, 206 insertions(+), 108 deletions(-)

diff --git a/program/include/rcube_template.php b/program/include/rcube_template.php
index 20b55ca..2108ed7 100755
--- a/program/include/rcube_template.php
+++ b/program/include/rcube_template.php
@@ -30,8 +30,8 @@
  */
 class rcube_template extends rcube_html_page
 {
+    var $app;
     var $config;
-    var $task = '';
     var $framed = false;
     var $pagetitle = '';
     var $env = array();
@@ -39,19 +39,28 @@
     var $js_commands = array();
     var $object_handlers = array();
 
+    public $type = 'html';
     public $ajax_call = false;
 
     /**
      * Constructor
      *
      * @todo   Use jQuery's $(document).ready() here.
+     * @todo   Replace $this->config with the real rcube_config object
      */
-    public function __construct(&$config, $task)
+    public function __construct($task, $framed = false)
     {
         parent::__construct();
 
-        $this->task = $task;
-        $this->config = $config;
+        $this->app = rcmail::get_instance();
+        $this->config = $this->app->config->all();
+        $this->browser = new rcube_browser();
+        
+        //$this->framed = $framed;
+        $this->set_env('task', $task);
+
+        // load the correct skin (in case user-defined)
+        $this->set_skin($this->config['skin']);
 
         // add common javascripts
         $javascript = 'var '.JS_OBJECT_NAME.' = new rcube_webmail();';
@@ -98,6 +107,54 @@
         $this->pagetitle = $title;
     }
 
+
+    /**
+     * Getter for the current page title
+     *
+     * @return string The page title
+     */
+    public function get_pagetitle()
+    {
+        if (!empty($this->pagetitle)) {
+            $title = $this->pagetitle;
+        }
+        else if ($this->env['task'] == 'login') {
+            $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name'])));
+        }
+        else {
+            $title = ucfirst($this->env['task']);
+        }
+        
+        return $title;
+    }
+
+
+    /**
+     * Set skin
+     */
+    public function set_skin($skin)
+    {
+        if (!empty($skin) && is_dir('skins/'.$skin) && is_readable('skins/'.$skin))
+            $skin_path = 'skins/'.$skin;
+        else
+            $skin_path = $this->config['skin_path'] ? $this->config['skin_path'] : 'skins/default';
+
+        $this->app->config->set('skin_path', $skin_path);
+        $this->config['skin_path'] = $skin_path;
+    }
+
+    /**
+     * Check if a specific template exists
+     *
+     * @param string Template name
+     * @return boolean True if template exists
+     */
+    public function template_exists($name)
+    {
+        $filename = $this->config['skin_path'] . '/templates/' . $name . '.html';
+
+        return (is_file($filename) && is_readable($filename));
+    }
 
     /**
      * Register a template object handler
@@ -185,13 +242,27 @@
      * @uses   self::$js_commands
      * @uses   self::$object_handlers
      */
-    public public function reset()
+    public function reset()
     {
         $this->env = array();
         $this->js_env = array();
         $this->js_commands = array();
         $this->object_handlers = array();
         parent::reset();
+    }
+
+
+    /**
+     * Redirect to a certain url
+     *
+     * @param mixed Either a string with the action or url parameters as key-value pairs
+     * @see rcmail::url()
+     */
+    public function redirect($p = array())
+    {
+        $location = $this->app->url($p);
+        header('Location: ' . $location);
+        exit;
     }
 
 
@@ -252,28 +323,19 @@
     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();
+        // read template file
+        if (($templ = @file_get_contents($path)) === false) {
             raise_error(array(
                 'code' => 501,
                 'type' => 'php',
                 'line' => __LINE__,
                 'file' => __FILE__,
-                'message' => 'Error loading template for '.$name.': '.$message
+                'message' => 'Error loading template for '.$name
                 ), true, true);
             return false;
         }
-        $templ = fread($fp, filesize($path));
-        fclose($fp);
 
         // parse for specialtags
         $output = $this->parse_conditions($templ);
@@ -281,9 +343,9 @@
 
         // 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">
+            $this->add_footer('<div style="position:absolute;top:5px;left:5px;width:405px;padding:2px;background:white;opacity:0.8;filter:alpha(opacity=80);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>'
+                <form action="/" name="debugform" style="display:inline"><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);
@@ -318,13 +380,7 @@
             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;
     }
 
@@ -348,7 +404,7 @@
      */
     private function parse_with_globals($input)
     {
-        $GLOBALS['__comm_path'] = Q($GLOBALS['COMM_PATH']);
+        $GLOBALS['__comm_path'] = Q($this->app->comm_path);
         return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input);
     }
 
@@ -409,26 +465,38 @@
      * @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
+     * @return boolean True if condition is met, False if not
      */
     private function check_condition($condition)
     {
-        $condition = preg_replace(
+            return eval("return (".$this->parse_expression($condition).");");
+    }
+
+
+    /**
+     * Parses expression and replaces variables
+     *
+     * @param  string Expression statement
+     * @return string Expression statement
+     */
+    private function parse_expression($expression)
+    {
+        return preg_replace(
             array(
                 '/session:([a-z0-9_]+)/i',
-                '/config:([a-z0-9_]+)/i',
+                '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i',
                 '/env:([a-z0-9_]+)/i',
-                '/request:([a-z0-9_]+)/ie'
+                '/request:([a-z0-9_]+)/i',
+                '/cookie:([a-z0-9_]+)/i'
             ),
             array(
                 "\$_SESSION['\\1']",
-                "\$this->config['\\1']",
+                "\$this->app->config->get('\\1',get_boolean('\\3'))",
                 "\$this->env['\\1']",
-                "get_input_value('\\1', RCUVE_INPUT_GPC)"
+                "get_input_value('\\1', RCUBE_INPUT_GPC)",
+                "\$_COOKIE['\\1']"
             ),
-            $condition);
-            
-            return eval("return (".$condition.");");
+            $expression);
     }
 
 
@@ -438,11 +506,28 @@
      *
      * @param  string Input string to parse
      * @return string Altered input string
+     * @todo   Use DOM-parser to traverse template HTML
      * @todo   Maybe a cache.
      */
     private function parse_xml($input)
     {
-        return preg_replace('/<roundcube:([-_a-z]+)\s+([^>]+)>/Uie', "\$this->xml_command('\\1', '\\2')", $input);
+        return preg_replace_callback('/<roundcube:([-_a-z]+)\s+([^>]+)>/Ui', array($this, 'xml_command_callback'), $input);
+    }
+
+
+    /**
+     * This is a callback function for preg_replace_callback (see #1485286)
+     * It's only purpose is to reconfigure parameters for xml_command, so that the signature isn't disturbed
+     */
+    private function xml_command_callback($matches)
+    {
+        $str_attrib = isset($matches[2]) ? $matches[2] : '';
+        $add_attrib = isset($matches[3]) ? $matches[3] : array();
+
+        $command = $matches[1];
+        //matches[0] is the entire matched portion of the string
+
+        return $this->xml_command($command, $str_attrib, $add_attrib);
     }
 
 
@@ -482,14 +567,13 @@
             // include a file
             case 'include':
                 $path = realpath($this->config['skin_path'].$attrib['file']);
-                if ($fsize = filesize($path)) {
+                if (is_readable($path)) {
                     if ($this->config['skin_include_php']) {
                         $incl = $this->include_php($path);
                     }
-                    else if ($fp = fopen($path, 'r')) {
-                        $incl = fread($fp, $fsize);
-                        fclose($fp);
-                    }
+                    else {
+		        $incl = file_get_contents($path);
+		    }
                     return $this->parse_xml($incl);
                 }
                 break;
@@ -529,25 +613,27 @@
                     return Q($name);
                 }
                 if ($object=='version') {
-                    return (string)RCMAIL_VERSION;
+                    $ver = (string)RCMAIL_VERSION;
+                    if (is_file(INSTALL_PATH . '.svn/entries')) {
+                        if (preg_match('/Revision:\s(\d+)/', @shell_exec('svn info'), $regs))
+                          $ver .= ' [SVN r'.$regs[1].']';
+                    }
+                    return $ver;
+                }
+                if ($object=='steptitle') {
+                  return Q($this->get_pagetitle());
                 }
                 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);
-                    }
-
+                    $title .= $this->get_pagetitle();
                     return Q($title);
                 }
                 break;
+
+            // return code for a specified eval expression
+            case 'exp':
+        	$value = $this->parse_expression($attrib['expression']);
+                return eval("return Q($value);");
             
             // return variable
             case 'var':
@@ -570,6 +656,9 @@
                         break;
                     case 'session':
                         $value = $_SESSION[$name];
+                        break;
+                    case 'cookie':
+                        $value = htmlspecialchars($_COOKIE[$name]);
                         break;
                 }
 
@@ -599,7 +688,6 @@
         return $out;
     }
 
-
     /**
      * Create and register a button
      *
@@ -608,21 +696,18 @@
      * @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)
+    public 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']);
@@ -669,7 +754,7 @@
             $attrib['alt'] = Q(rcube_label($attrib['alt']));
         }
         // set title to alt attribute for IE browsers
-        if ($browser->ie && $attrib['title'] && !$attrib['alt']) {
+        if ($this->browser->ie && $attrib['title'] && !$attrib['alt']) {
             $attrib['alt'] = $attrib['title'];
             unset($attrib['title']);
         }
@@ -687,17 +772,20 @@
                 $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'] : ''
+                $attrib['imageact'] ? $this->abs_url($attrib['imageact']) : $attrib['classact'],
+                $attrib['imagesel'] ? $this->abs_url($attrib['imagesel']) : $attrib['classsel'],
+                $attrib['imageover'] ? $this->abs_url($attrib['imageover']) : ''
             ));
 
             // make valid href to specific buttons
-            if (in_array($attrib['command'], $MAIN_TASKS)) {
-                $attrib['href'] = Q(rcmail_url(null, null, $attrib['command']));
+            if (in_array($attrib['command'], rcmail::$main_tasks)) {
+                $attrib['href'] = rcmail_url(null, null, $attrib['command']);
             }
             else if (in_array($attrib['command'], $a_static_commands)) {
-                $attrib['href'] = Q(rcmail_url($attrib['command']));
+                $attrib['href'] = rcmail_url($attrib['command']);
+            }
+            else if ($attrib['command'] == 'permaurl' && !empty($this->env['permaurl'])) {
+                $attrib['href'] = $this->env['permaurl'];
             }
         }
 
@@ -752,19 +840,18 @@
                 array(
                     'style', 'class', 'id', 'width',
                     'height', 'border', 'hspace',
-                    'vspace', 'align', 'alt',
+                    'vspace', 'align', 'alt', 'tabindex'
                 )
             );
-            $img_tag = sprintf('<img src="%%s"%s />', $attrib_str);
-            $btn_content = sprintf($img_tag, $skin_path.$attrib['image']);
+            $btn_content = sprintf('<img src="%s"%s />', $this->abs_url($attrib['image']), $attrib_str);
             if ($attrib['label']) {
                 $btn_content .= ' '.$attrib['label'];
             }
-            $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title');
+            $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title', 'target');
         }
         else if ($attrib['type']=='link') {
             $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command'];
-            $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style');
+            $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style', 'tabindex', 'target');
         }
         else if ($attrib['type']=='input') {
             $attrib['type'] = 'button';
@@ -777,7 +864,7 @@
                 $attrib,
                 array(
                     'type', 'value', 'onclick',
-                    'id', 'class', 'style'
+                    'id', 'class', 'style', 'tabindex'
                 )
             );
             $out = sprintf('<input%s disabled="disabled" />', $attrib_str);
@@ -797,15 +884,36 @@
 
 
     /**
+     * Create a form tag with the necessary hidden fields
+     *
+     * @param array Named tag parameters
+     * @return string HTML code for the form
+     */
+    public function form_tag($attrib, $content = null)
+    {
+      if ($this->framed) {
+        $hiddenfield = new html_hiddenfield(array('name' => '_framed', 'value' => '1'));
+        $hidden = $hiddenfield->show();
+      }
+      
+      if (!$content)
+        $attrib['noclose'] = true;
+      
+      return html::tag('form',
+        $attrib + array('action' => "./", 'method' => "get"),
+        $hidden . $content);
+    }
+
+
+    /**
      * 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)
+    public function current_username($attrib)
     {
-        global $USER;
         static $username;
 
         // alread fetched
@@ -814,14 +922,11 @@
         }
 
         // 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'];
+        if ($sql_arr = $this->app->user->get_identity()) {
+            $username = $sql_arr['email'];
         }
         else {
-            $username = $_SESSION['username'].'@'.$_SESSION['imap_host'];
+            $username = $this->app->user->get_username();
         }
 
         return $username;
@@ -837,14 +942,14 @@
      */
     private function login_form($attrib)
     {
-        global $CONFIG, $SESS_HIDDEN_FIELD;
-        $default_host = $CONFIG['default_host'];
+        $default_host = $this->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_user   = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30) + $attrib);
+        $input_pass   = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30) + $attrib);
         $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login'));
+        $input_tzone  = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_'));
         $input_host   = null;
 
         if (is_array($default_host)) {
@@ -860,7 +965,7 @@
                 }
             }
         }
-        else if (!strlen($default_host)) {
+        else if (empty($default_host)) {
             $input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30));
         }
 
@@ -871,7 +976,7 @@
         $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(null, $input_user->show(get_input_value('_user', RCUBE_INPUT_POST)));
 
         $table->add('title', html::label('rcmloginpwd', Q(rcube_label('password'))));
         $table->add(null, $input_pass->show());
@@ -879,23 +984,16 @@
         // 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)));
+            $table->add(null, $input_host->show(get_input_value('_host', RCUBE_INPUT_POST)));
         }
 
-        $out = $SESS_HIDDEN_FIELD;
-        $out .= $input_action->show();
+        $out = $input_action->show();
+        $out .= $input_tzone->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);
+            $out = $this->form_tag(array('name' => $form_name, 'method' => "post"), $out);
         }
 
         return $out;
@@ -919,6 +1017,10 @@
         if (empty($attrib['id'])) {
             $attrib['id'] = 'rcmqsearchbox';
         }
+        if ($attrib['type'] == 'search' && !$this->browser->khtml) {
+          unset($attrib['type'], $attrib['results']);
+        }
+        
         $input_q = new html_inputfield($attrib);
         $out = $input_q->show();
 
@@ -926,15 +1028,11 @@
 
         // 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);
+            $out = $this->form_tag(array(
+                'name' => "rcmqsearchform",
+                'onsubmit' => JS_OBJECT_NAME . ".command('search');return false;",
+                'style' => "display:inline"),
+              $out);
         }
 
         return $out;

--
Gitblit v1.9.1