Index: inc/core/class.dc.blog.php
===================================================================
--- inc/core/class.dc.blog.php	(revision 2318)
+++ inc/core/class.dc.blog.php	(revision 2468)
@@ -4,5 +4,5 @@
 # This file is part of Dotclear 2.
 #
-# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
 # Licensed under the GPL version 2.0 license.
 # See LICENSE file or
@@ -81,5 +81,5 @@
 			$this->desc = $b->blog_desc;
 			$this->url = $b->blog_url;
-			$this->host = http::getHostFromURL($this->url);
+			$this->host = preg_replace('|^([a-z]{3,}://)(.*?)/.*$|','$1$2',$this->url);
 			$this->creadt = strtotime($b->blog_creadt);
 			$this->upddt = strtotime($b->blog_upddt);
@@ -865,5 +865,5 @@
 		
 		if (!empty($params['user_id'])) {
-			$strReq .= "AND U.user_id = '".$this->con->escape($params['user_id'])."' ";
+			$strReq .= "AND U.user_id ".$this->con->in($params['user_id'])." ";
 		}
 		
@@ -963,8 +963,7 @@
 				$strReq .= 'ORDER BY post_dt DESC ';
 			}
-		}
-		
-		if (!$count_only && !empty($params['limit'])) {
-			$strReq .= $this->con->limit($params['limit']);
+			if (!empty($params['limit'])) {
+				$strReq .= $this->con->limit($params['limit']);
+			}
 		}
 		
Index: inc/core/class.dc.context.php
===================================================================
--- inc/core/class.dc.context.php	(revision 1507)
+++ inc/core/class.dc.context.php	(revision 1507)
@@ -0,0 +1,340 @@
+<?php
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+if (!defined('DC_RC_PATH')) { return; }
+
+/**
+ * @ingroup DC_CORE
+ * @brief Template extension for public context
+ *
+ * This extends template environment with tools required in context.
+ * Admin context and public context should extend this class.
+ */
+class dcContext extends Twig_Extension
+{
+	protected $core;
+	protected $globals = array();
+	protected $protected_globals = array();
+	protected $memory = array();
+	protected $timestamp_messages = true;
+	
+	public function __construct($core)
+	{
+		$this->core = $core;
+		
+		# Globals editable via context
+		$this->globals = array();
+		
+		# Globals not editable via context
+		$this->protected_globals = array(
+			'messages' => array(
+				'static' => array(),
+				'lists' => array(),
+				'alert' => '',
+				'errors' => array()
+			),
+			
+			'version' 		=> DC_VERSION,
+			'vendor_name' 	=> DC_VENDOR_NAME,
+			
+			'safe_mode' 	=> isset($_SESSION['sess_safe_mode']) && $_SESSION['sess_safe_mode'],
+			'debug_mode'	=> DC_DEBUG
+		);
+	}
+	
+	/**
+	 * Prevent call crash from template on method that return this class
+	 */
+	public function __toString()
+	{
+		return '';
+	}
+	
+	/**
+	 * Test a global variable
+	 *
+	 * @param string $name Name of the variable to test
+	 * @return boolean
+	 */
+	public function __isset($name)
+	{
+		return isset($this->globals[$name]);
+	}
+	
+	/**
+	 * Add a global variable
+	 *
+	 * @param string $name Name of the variable
+	 * @param mixed $value Value of the variable
+	 */
+	public function __set($name,$value)
+	{
+/*
+		# Overload protect
+		if ($value === null && isset($this->globals[$name])) {
+			unset($this->globals[$name]);
+		}
+		elseif (!isset($this->globals[$name])) {
+			throw new Exception('Modification of overloaded globals has no effect');
+		}
+//*/
+		$this->globals[$name] = $value;
+	}
+	
+	/**
+	 * Get a global variable
+	 *
+	 * @param string $name Name of the variable
+	 * @return mixed Value of the variable or null
+	 */
+	public function __get($name)
+	{
+		return isset($this->globals[$name]) ? $this->globals[$name] : null;
+	}
+	
+	/**
+	 * Returns a list of filters to add to the existing list.
+	 *
+	 * @return array An array of filters
+	 */
+	public function getFilters()
+	{
+		return array(
+			'trans' => new Twig_Filter_Function("__", array('is_safe' => array('html')))
+		);
+	}
+	
+	/**
+	 * Returns a list of functions to add to the existing list.
+	 * 
+	 * @return array An array of functions
+	 */
+	public function getFunctions()
+	{
+		return array(
+			'__' 		=> new Twig_Function_Function("__", array('is_safe' => array('html'))),
+			'debug_info' => new Twig_Function_Method($this, 'getDebugInfo', array('is_safe' => array('html'))),
+			'memorize' => new Twig_Function_Method($this, 'setMemory', array('is_safe' => array('html'))),
+			'memorized' => new Twig_Function_Method($this, 'getMemory', array('is_safe' => array('html')))
+		);
+	}
+	
+	/**
+	 * Returns a list of global variables to add to the existing list.
+	 *
+	 * This merges overloaded variables with defined variables.
+	 *
+	 * @return array An array of global variables
+	 */
+	public function getGlobals()
+	{
+		# Keep protected globals safe
+		return array_merge($this->globals,$this->protected_globals);
+	}
+	
+	/**
+	 * Returns the name of the extension.
+	 *
+	 * @return string The extension name
+	 */
+	public function getName()
+	{
+		return 'dcContext';
+	}
+	
+	
+	/**
+	 * Add an informational message
+	 *
+	 * @param string $message A message
+	 * @return object self
+	 */
+	public function setSafeMode($safe_mode)
+	{
+		$this->protected_globals['safe_mode'] = (boolean) $safe_mode;
+		return $this;
+	}
+	
+	/**
+	 * Add an informational message
+	 *
+	 * @param string $message A message
+	 * @return object self
+	 */
+	public function addMessageStatic($message)
+	{
+		$this->protected_globals['messages']['static'][] = $this->timeStamp($message);
+		return $this;
+	}
+	
+	/**
+	 * Add a list of informational messages
+	 *
+	 * @param string $message A title
+	 * @param array $message A list of messages
+	 * @return object self
+	 */
+	public function addMessagesList($title,$messages)
+	{
+		$this->protected_globals['messages']['lists'][$title] = $this->timeStamp($messages);
+		return $this;
+	}
+	
+	/**
+	 * Set an important message
+	 *
+	 * @param string $message A message
+	 * @return object self
+	 */
+	public function setAlert($message)
+	{
+		$this->protected_globals['messages']['alert'] = $this->timeStamp($message);
+		return $this;
+	}
+	
+	/**
+	 * Add an error message
+	 *
+	 * @param string Error message
+	 * @return object self
+	 */
+	public function addError($error)
+	{
+		$this->protected_globals['messages']['errors'][] = $this->timeStamp($error);
+		return $this;
+	}
+	
+	/**
+	 * Check if there is an error message
+	 * 
+	 * @return boolean
+	 */
+	public function hasError()
+	{
+		return !empty($this->protected_globals['messages']['errors']);
+	}
+	
+	/**
+	 * Set use of timestamp on messages
+	 *
+	 * @param boolean $add Add timestamp to messages
+	 * @return object self
+	 */
+	public function setTimestamp($add=true)
+	{
+		$this->timestamp_messages;
+		return $this;
+	}
+	
+	/**
+	 * Prepend message with a timestamp
+	 *
+	 * @param string|array $message Message(s)
+	 * @return string|array Timestamp message(s)
+	 */
+	public function timeStamp($message)
+	{
+		if (!$this->timestamp_messages) {
+			return $message;
+		}
+		
+		$tz = @$this->core->auth->getInfo('user_tz');
+		if (!$tz) {
+			$tz = $this->core->blog->settings->system->blog_timezone;
+		}
+		$dt = dt::str(__('%H:%M:%S:'),null,$tz);
+		
+		if (!is_array($message)) {
+			return $dt.' '.$message;
+		} else {
+			foreach($message as $k => $v)
+			{
+				$message[$k] = $dt.' '.$v;
+			}
+			return $message;
+		}
+	}
+	
+	/**
+	 * Get an array of debug/dev infos
+	 */
+	public function getDebugInfo()
+	{
+		if (!DC_DEBUG) {
+			return array();
+		}
+		
+		$di = array(
+			'global_vars' => implode(', ',array_keys($GLOBALS)),
+			'memory' => array(
+				'usage' => memory_get_usage(),
+				'size' => files::size(memory_get_usage())
+			),
+			'xdebug' => array()
+		);
+		
+		if (function_exists('xdebug_get_profiler_filename')) {
+		
+			$url = http::getSelfURI();
+			$url .= strpos($url,'?') === false ? '?' : '&';
+			$url .= 'XDEBUG_PROFILE';
+			
+			$di['xdebug'] = array(
+				'elapse_time' => xdebug_time_index(),
+				'profiler_file' => xdebug_get_profiler_filename(),
+				'profiler_url' =>  $url
+			);
+			
+			/* xdebug configuration:
+			zend_extension = /.../xdebug.so
+			xdebug.auto_trace = On
+			xdebug.trace_format = 0
+			xdebug.trace_options = 1
+			xdebug.show_mem_delta = On
+			xdebug.profiler_enable = 0
+			xdebug.profiler_enable_trigger = 1
+			xdebug.profiler_output_dir = /tmp
+			xdebug.profiler_append = 0
+			xdebug.profiler_output_name = timestamp
+			*/
+		}
+		
+		return $di;
+	}
+	
+	/**
+	 * Add a value in a namespace memory
+	 *
+	 * This help keep variable when recalling Twig macros
+	 *
+	 * @param string $ns A namespace
+	 * @param string $str A value to memorize in this namespace
+	 */
+	public function setMemory($ns,$str)
+	{
+		if (!array_key_exists($ns,$this->memory) || !in_array($str,$this->memory[$ns])) {
+			$this->memory[$ns][] = $str;
+		}
+	}
+	
+	/**
+	 * Check if a value is previously memorized in a namespace
+	 *
+	 * @param string $ns A namespace
+	 * @param string $str A value to search in this namespace
+	 * @return array True if exists
+	 */
+	public function getMemory($ns,$str)
+	{
+		return array_key_exists($ns,$this->memory) && in_array($str,$this->memory[$ns]);
+	}
+}
+?>
Index: inc/core/class.dc.core.php
===================================================================
--- inc/core/class.dc.core.php	(revision 2198)
+++ inc/core/class.dc.core.php	(revision 2313)
@@ -4,5 +4,5 @@
 # This file is part of Dotclear 2.
 #
-# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
 # Licensed under the GPL version 2.0 license.
 # See LICENSE file or
@@ -39,4 +39,5 @@
 	public $rest;		///< <b>dcRestServer</b>	dcRestServer object
 	public $log;		///< <b>dcLog</b>			dcLog object
+	public $tpl;		///< <b>Twig_Environment</b>	Twig_Environment object
 	
 	private $versions = null;
@@ -97,4 +98,5 @@
 		$this->addFormater('xhtml', create_function('$s','return $s;'));
 		$this->addFormater('wiki', array($this,'wikiTransform'));
+		$this->loadTemplateEnvironment();
 	}
 	
@@ -120,4 +122,39 @@
 	}
 	
+	/**
+	Create template environment (Twig_Environment instance)
+	
+	default-templates path must be added from admin|public/prepend.php with:
+	$core->tpl->getLoader()->addPath('PATH_TO/default-templates');
+	Selected theme path must be added with:
+	$core->tpl->getLoader()->prependPath('PATH_TO/MY_THEME');
+	*/
+	public function loadTemplateEnvironment()
+	{
+		$cache_dir = path::real(DC_TPL_CACHE.'/twtpl',false);
+		if (!is_dir($cache_dir)) {
+			try {
+				files::makeDir($cache_dir);
+			} catch (Exception $e) {
+				$cache_dir = false;
+			}
+		}
+		
+		$this->tpl = new Twig_Environment(
+			new Twig_Loader_Filesystem(dirname(__FILE__).'/../swf'),
+			array(
+				'auto_reload' => true,
+				'autoescape' => false,
+				'base_template_class' => 'Twig_Template',
+				'cache' => $cache_dir, 
+				'charset' => 'UTF-8',
+				'debug' => DC_DEBUG,
+				'optimizations' => -1,
+				'strict_variables' => 0 //DC_DEBUG // Please fix undefined variables!
+			)
+		);
+		$this->tpl->addExtension(new dcFormExtension($this));
+		$this->tpl->addExtension(new dcTabExtension($this));
+	}
 	
 	/// @name Blog init methods
Index: inc/core/class.dc.template.php
===================================================================
--- inc/core/class.dc.template.php	(revision 1128)
+++ inc/core/class.dc.template.php	(revision 1128)
@@ -0,0 +1,241 @@
+<?php
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+if (!defined('DC_RC_PATH')) { return; }
+
+/**
+ * @ingroup DC_CORE
+ * @brief Template environment.
+ *
+ * This class provides same Twig environment for both admin and public side. 
+ * It adds methods for backwards compatibility with old template engine.
+ *
+ * default-templates path must be added from admin|public/prepend.php with:
+ * $core->tpl->getLoader()->addPath('PATH_TO/default-templates');
+ * Selected theme path must be added with:
+ * $core->tpl->getLoader()->prependPath('PATH_TO/MY_THEME');
+ */
+class dcTemplate extends Twig_Environment
+{
+	protected $dc_blocks = array();
+	protected $dc_values = array();
+	
+	private $core;
+	
+	/**
+	 * Create template environment (Twig_Environment instance).
+	 * 
+	 * We keep same signature as the old dcTemplate class.
+	 */
+	public function __construct($cache_dir,$self_name,$core)
+	{
+		$this->core =& $core;
+		
+		# Check cache directory
+		$cache_dir = path::real($cache_dir.'/twtpl',false);
+		if (!is_dir($cache_dir)) {
+			try {
+				files::makeDir($cache_dir);
+			} catch (Exception $e) {
+				$cache_dir = false;
+			}
+		}
+		
+		# Create Twig environment
+		parent::__construct(
+			new Twig_Loader_Filesystem(dirname(__FILE__).'/../swf'),
+			array(
+				'auto_reload' => true,
+				'autoescape' => false,
+				'base_template_class' => 'Twig_Template',
+				'cache' => $cache_dir, 
+				'charset' => 'UTF-8',
+				'debug' => DC_DEBUG,
+				'optimizations' => -1,
+				'strict_variables' => 0 //DC_DEBUG // Please fix undefined variables!
+			)
+		);
+		
+		# Add extensions
+		$this->addExtension(new dcFormExtension($this));
+		$this->addExtension(new dcTabExtension($this));
+	}
+	
+	/// @name Old template engine compatibility methods
+	//@{
+	/**
+	 * Old style to add a template block.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function addBlock($name,$callback)
+	{
+		if (!is_callable($callback)) {
+			throw new Exception('No valid callback for '.$name);
+		}
+		
+		$this->dc_blocks[$name] = $callback;
+	}
+	
+	/**
+	 * Old style to add a template value.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function addValue($name,$callback)
+	{
+		if (!is_callable($callback)) {
+			throw new Exception('No valid callback for '.$name);
+		}
+		
+		$this->dc_values[$name] = $callback;
+	}
+	
+	/**
+	 * Old style to check if a template block exists.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function blockExists($name)
+	{
+		return isset($this->dc_blocks[$name]);
+	}
+	
+	
+	/**
+	 * Old style to check if a template value exists.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function valueExists($name)
+	{
+		return isset($this->dc_values[$name]);
+	}
+	
+	
+	/**
+	 * Old style to check if a template tag exists.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function tagExists($name)
+	{
+		return $this->blockExists($name) || $this->valueExists($name);
+	}
+	
+	
+	/**
+	 * Old style to get a template value callback.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function getValueCallback($name)
+	{
+		if ($this->valueExists($name))
+		{
+			return $this->dc_values[$name];
+		}
+		
+		return false;
+	}
+	
+	/**
+	 * Old style to get a template block callback.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function getBlockCallback($name)
+	{
+		if ($this->blockExists($name))
+		{
+			return $this->dc_blocks[$name];
+		}
+		
+		return false;
+	}
+	
+	/**
+	 * Old style to get list of template blocks.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function getBlocksList()
+	{
+		return array_keys($this->dc_blocks);
+	}
+	
+	/**
+	 * Old style to get list of template values.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function getValuesList()
+	{
+		return array_keys($this->dc_values);
+	}
+	
+	/**
+	 * Old style to add template path.
+	 *
+	 * Many plugins and themes use this method, so we keep it.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function setPath()
+	{
+		$path = array();
+		
+		foreach (func_get_args() as $v)
+		{
+			if (is_array($v)) {
+				$path = array_merge($path,array_values($v));
+			} else {
+				$path[] = $v;
+			}
+		}
+		
+		foreach ($path as $k => $v)
+		{
+			if (($v = path::real($v)) === false) {
+				unset($path[$k]);
+			}
+		}
+		
+		$path = array_unique($path);
+		
+		$this->getLoader()->setPaths($path);
+	}
+	
+	/**
+	 * Old style to get template path.
+	 *
+	 * Many plugins and themes use this method, so we keep it.
+	 *
+	 * @ignore
+	 * @deprecated
+	 */
+	public function getPath()
+	{
+		return $this->getLoader()->getPaths();
+	}
+	//@}
+}
+?>
Index: inc/core/class.dc.twig.page.php
===================================================================
--- inc/core/class.dc.twig.page.php	(revision 1014)
+++ inc/core/class.dc.twig.page.php	(revision 1014)
@@ -0,0 +1,65 @@
+<?php
+
+// common to public and admin sides @see inc/admin/prepend.php
+class dcTwigPage extends Twig_Environment
+{
+	protected $core;
+	protected $context = null;
+	
+	public function __construct($default_tpl_dir,$cache_dir,$context,$core)
+	{
+		$this->core =& $core;
+		
+		# Twig Loader
+		$loader = new Twig_Loader_Filesystem($this->checkDefaultTemplateDir($default_tpl_dir));
+		
+		# Twig Environment options
+		$options = array(
+			'auto_reload' => true,
+			'base_template_class' => 'Twig_Template',
+			'cache' => $this->setCacheDir($cache_dir),
+			'charset' => 'UTF-8',
+			'debug' => DC_DEBUG,
+			'optimizations' => -1
+		);
+		
+		# Twig Environment
+		parent::__construct($loader,$options);
+		
+		# Add context helper (public vs admin)
+		if ($context instanceof Twig_ExtensionInterface) {
+			$this->context = $context;
+			$this->addExtension($context);
+		}
+		
+		# Add form helper
+		$this->addExtension(new dcFormExtension($core));
+		
+		$this->clearCacheFiles();
+	}
+	
+	protected function checkDefaultTemplateDir($dir)
+	{
+		$dir = path::real($dir,false);
+		
+		return is_dir($dir) ? $dir : false;
+	}
+	
+	protected function setCacheDir($dir)
+	{
+		try {
+			$dir = path::real($dir,false);
+			files::makeDir($dir,true);
+			return $dir;
+		}
+		catch(Exception $e) { }
+		
+		return false;
+	}
+	
+	public function getContext()
+	{
+		return $this->context;
+	}
+}
+?>
