Index: admin/blog_theme.php
===================================================================
--- admin/blog_theme.php	(revision 2196)
+++ admin/blog_theme.php	(revision 2215)
@@ -15,6 +15,5 @@
 dcPage::check('admin');
 
-# --------------------------------------------------
-# @todo Add settings to Dotclear update features
+# -- "First time" settings setup --
 if ($core->blog->settings->system->repository_theme_url === null) {
 	$core->blog->settings->system->put(
@@ -22,5 +21,4 @@
 	);
 }
-# --------------------------------------------------
 
 # -- Loading themes --
@@ -28,44 +26,41 @@
 $core->themes->loadModules($core->blog->themes_path, null);
 
-# -- Repository helper --
-$repository = new dcRepository(
+# -- Page helper --
+$list = new adminThemesList(
 	$core->themes, 
+	$core->blog->themes_path,
 	$core->blog->settings->system->repository_theme_url
 );
-$repository->check();
-
-# -- Page helper --
-$list = new adminThemesList(
-	$core, 
-	$core->blog->themes_path,
-	false
+$list::$distributed_modules = array(
+	'blueSilence',
+	'blowupConfig',
+	'customCSS',
+	'default',
+	'ductile'
 );
 
 # -- Theme screenshot --
-if (!empty($_GET['shot']) && $core->themes->moduleExists($_GET['shot']))
-{
-	if (empty($_GET['src'])) {
-		$f = $core->blog->themes_path.'/'.$_GET['shot'].'/screenshot.jpg';
-	} else {
-		$f = $core->blog->themes_path.'/'.$_GET['shot'].'/'.path::clean($_GET['src']);
-	}
-	
-	$f = path::real($f);
-	
+if (!empty($_GET['shot']) && $list->modules->moduleExists($_GET['shot'])) {
+
+	$f= path::real(empty($_GET['src']) ?
+		$core->blog->themes_path.'/'.$_GET['shot'].'/screenshot.jpg' :
+		$core->blog->themes_path.'/'.$_GET['shot'].'/'.path::clean($_GET['src'])
+	);
+
 	if (!file_exists($f)) {
 		$f = dirname(__FILE__).'/images/noscreenshot.png';
 	}
-	
-	http::cache(array_merge(array($f),get_included_files()));
-	
+
+	http::cache(array_merge(array($f), get_included_files()));
+
 	header('Content-Type: '.files::getMimeType($f));
 	header('Content-Length: '.filesize($f));
 	readfile($f);
-	
+
 	exit;
 }
 
 # -- Display module configuration page --
-if ($list->setConfigurationFile($core->themes, $core->blog->settings->system->theme)) {
+if ($list->setConfigurationFile($core->blog->settings->system->theme)) {
 
 	# Get content before page headers
@@ -105,11 +100,9 @@
 
 # -- Execute actions --
-if (!empty($_POST) && empty($_REQUEST['conf']) && $core->auth->isSuperAdmin() && $list->isPathWritable()) {
-	try {
-		$list->executeAction('themes', $core->themes, $repository);
-	}
-	catch (Exception $e) {
-		$core->error->add($e->getMessage());
-	}
+try {
+	$list->doActions('themes');
+}
+catch (Exception $e) {
+	$core->error->add($e->getMessage());
 }
 
@@ -139,5 +132,5 @@
 
 	# Updated modules from repo
-	$modules = $repository->get(true);
+	$modules = $list->repository->get(true);
 	if (!empty($modules)) {
 		echo 
@@ -168,5 +161,5 @@
 '<div class="multi-part" id="themes" title="'.__('Installed themes').'">';
 
-$modules = $core->themes->getModules();
+$modules = $list->modules->getModules();
 if (!empty($modules)) {
 
@@ -180,10 +173,10 @@
 		->setPageTab('themes')
 		->displayModulesList(
-			/* cols */		array('sshot', 'name', 'config', 'desc', 'author', 'version', 'parent'),
+			/* cols */		array('sshot', 'distrib', 'name', 'config', 'desc', 'author', 'version', 'parent'),
 			/* actions */	array('select', 'deactivate', 'delete')
 		);
 }
 
-$modules = $core->themes->getDisabledModules();
+$modules = $list->modules->getDisabledModules();
 if (!empty($modules)) {
 
@@ -209,43 +202,43 @@
 	# New modules from repo
 	$search = $list->getSearchQuery();
-	$modules = $search ? $repository->search($search) : $repository->get();
-
-	echo
-	'<div class="multi-part" id="new" title="'.__('Add themes from Dotaddict').'">'.
-	'<h3>'.__('Add themes from Dotaddict repository').'</h3>';
-
-	$list
-		->newList('theme-new')
-		->setModules($modules)
-		->setPageTab('new')
-		->displaySearchForm()
-		->displayNavMenu()
-		->displayModulesList(
-			/* cols */		array('expander', 'sshot', 'name', 'config', 'desc', 'author', 'version', 'parent', 'distrib'),
-			/* actions */	array('install'),
-			/* nav limit */	true
-		);
-
-	echo
-	'<p class="info vertical-separator">'.sprintf(
-		__("Visit %s repository, the resources center for Dotclear."),
-		'<a href="http://dotaddict.org/dc2/themes">Dotaddict</a>'
-		).
-	'</p>'.
-
+	$modules = $search ? $list->repository->search($search) : $list->repository->get();
+
+	if (!empty($search) || !empty($modules)) {
+		echo
+		'<div class="multi-part" id="new" title="'.__('Add themes from Dotaddict').'">'.
+		'<h3>'.__('Add themes from Dotaddict repository').'</h3>';
+
+		$list
+			->newList('theme-new')
+			->setModules($modules)
+			->setPageTab('new')
+			->displaySearchForm()
+			->displayNavMenu()
+			->displayModulesList(
+				/* cols */		array('expander', 'sshot', 'name', 'config', 'desc', 'author', 'version', 'parent', 'details', 'support'),
+				/* actions */	array('install'),
+				/* nav limit */	true
+			);
+
+		echo
+		'<p class="info vertical-separator">'.sprintf(
+			__("Visit %s repository, the resources center for Dotclear."),
+			'<a href="http://dotaddict.org/dc2/themes">Dotaddict</a>'
+			).
+		'</p>'.
+
+		'</div>';
+	}
+
+	# Add a new plugin
+	echo
+	'<div class="multi-part" id="addtheme" title="'.__('Install or upgrade manually').'">'.
+	'<p>'.__('You can install themes by uploading or downloading zip files.').'</p>';
+
+	$list->displayManualForm();
+
+	echo
 	'</div>';
-
-	# Add a new plugin
-	echo
-	'<div class="multi-part" id="addtheme" title="'.__('Install or upgrade manually').'">';
-
-	echo '<p>'.__('You can install themes by uploading or downloading zip files.').'</p>';
-	
-	$list->displayManualForm();
-
-	echo
-	'</div>';
 }
 
 dcPage::close();
-?>
Index: admin/index.php
===================================================================
--- admin/index.php	(revision 2175)
+++ admin/index.php	(revision 2215)
@@ -129,5 +129,4 @@
 {
 	$repo = new dcRepository($mod, $url);
-	$repo->check();
 	$upd = $repo->get(true);
 	if (!empty($upd)) {
Index: admin/plugins.php
===================================================================
--- admin/plugins.php	(revision 2182)
+++ admin/plugins.php	(revision 2215)
@@ -15,6 +15,5 @@
 dcPage::check('admin');
 
-# --------------------------------------------------
-# @todo Add settings to Dotclear update features
+# -- "First time" settings setup --
 if ($core->blog->settings->system->plugins_allow_multi_install === null) {
 	$core->blog->settings->system->put(
@@ -27,21 +26,14 @@
 	);
 }
-# --------------------------------------------------
-
-# -- Repository helper --
-$repository = new dcRepository(
+
+# -- Page helper --
+$list = new adminModulesList(
 	$core->plugins, 
+	DC_PLUGINS_ROOT, 
 	$core->blog->settings->system->repository_plugin_url
 );
-$repository->check();
-
-# -- Page helper --
-$list = new adminModulesList(
-	$core, 
-	DC_PLUGINS_ROOT,
-	$core->blog->settings->system->plugins_allow_multi_install
-);
-
-$list::setDistributedModules(array(
+
+$list::$allow_multi_install = $core->blog->settings->system->plugins_allow_multi_install;
+$list::$distributed_modules = array(
 	'aboutConfig',
 	'akismet',
@@ -61,8 +53,8 @@
 	'userPref',
 	'widgets'
-));
+);
 
 # -- Display module configuration page --
-if ($list->setConfigurationFile($core->plugins)) {
+if ($list->setConfigurationFile()) {
 
 	# Get content before page headers
@@ -101,11 +93,9 @@
 
 # -- Execute actions --
-if (!empty($_POST) && empty($_REQUEST['conf']) && $core->auth->isSuperAdmin() && $list->isPathWritable()) {
-	try {
-		$list->executeAction('plugins', $core->plugins, $repository);
-	}
-	catch (Exception $e) {
-		$core->error->add($e->getMessage());
-	}
+try {
+	$list->doActions('plugins');
+}
+catch (Exception $e) {
+	$core->error->add($e->getMessage());
 }
 
@@ -140,4 +130,5 @@
 	echo 
 	'<div class="static-msg">'.__('Following plugins have been installed:').'<ul>';
+
 	foreach ($plugins_install['success'] as $k => $v) {
 		echo 
@@ -145,4 +136,5 @@
 	}
 	echo 
+
 	'</ul></div>';
 }
@@ -150,8 +142,10 @@
 	echo 
 	'<div class="error">'.__('Following plugins have not been installed:').'<ul>';
+
 	foreach ($plugins_install['failure'] as $k => $v) {
 		echo 
 		'<li>'.$k.' ('.$v.')</li>';
 	}
+
 	echo 
 	'</ul></div>';
@@ -162,5 +156,5 @@
 
 	# Updated modules from repo
-	$modules = $repository->get(true);
+	$modules = $list->repository->get(true);
 	if (!empty($modules)) {
 		echo 
@@ -191,7 +185,6 @@
 '<div class="multi-part" id="plugins" title="'.__('Installed plugins').'">';
 
-$modules = $core->plugins->getModules();
+$modules = $list->modules->getModules();
 if (!empty($modules)) {
-
 	echo
 	'<h3>'.__('Activated plugins').'</h3>'.
@@ -209,7 +202,6 @@
 
 # Deactivated modules
-$modules = $core->plugins->getDisabledModules();
+$modules = $list->modules->getDisabledModules();
 if (!empty($modules)) {
-
 	echo
 	'<h3>'.__('Deactivated plugins').'</h3>'.
@@ -233,37 +225,38 @@
 	# New modules from repo
 	$search = $list->getSearchQuery();
-	$modules = $search ? $repository->search($search) : $repository->get();
-
-	echo
-	'<div class="multi-part" id="new" title="'.__('Add plugins from Dotaddict').'">'.
-	'<h3>'.__('Add plugins from Dotaddict repository').'</h3>';
-
-	$list
-		->newList('plugin-new')
-		->setModules($modules)
-		->setPageTab('new')
-		->displaySearchForm()
-		->displayNavMenu()
-		->displayModulesList(
-			/* cols */		array('expander', 'name', 'version', 'desc'),
-			/* actions */	array('install'),
-			/* nav limit */	true
-		);
-
-	echo
-	'<p class="info vertical-separator">'.sprintf(
-		__("Visit %s repository, the resources center for Dotclear."),
-		'<a href="http://dotaddict.org/dc2/plugins">Dotaddict</a>'
-		).
-	'</p>'.
-
-	'</div>';
+	$modules = $search ? $list->repository->search($search) : $list->repository->get();
+
+	if (!empty($search) || !empty($modules)) {
+		echo
+		'<div class="multi-part" id="new" title="'.__('Add plugins from Dotaddict').'">'.
+		'<h3>'.__('Add plugins from Dotaddict repository').'</h3>';
+
+		$list
+			->newList('plugin-new')
+			->setModules($modules)
+			->setPageTab('new')
+			->displaySearchForm()
+			->displayNavMenu()
+			->displayModulesList(
+				/* cols */		array('expander', 'name', 'version', 'desc'),
+				/* actions */	array('install'),
+				/* nav limit */	true
+			);
+
+		echo
+		'<p class="info vertical-separator">'.sprintf(
+			__("Visit %s repository, the resources center for Dotclear."),
+			'<a href="http://dotaddict.org/dc2/plugins">Dotaddict</a>'
+			).
+		'</p>'.
+
+		'</div>';
+	}
 
 	# Add a new plugin
 	echo
-	'<div class="multi-part" id="addplugin" title="'.__('Install or upgrade manually').'">';
-
-	echo '<p>'.__('You can install plugins by uploading or downloading zip files.').'</p>';
-	
+	'<div class="multi-part" id="addplugin" title="'.__('Install or upgrade manually').'">'.
+	'<p>'.__('You can install plugins by uploading or downloading zip files.').'</p>';
+
 	$list->displayManualForm();
 
@@ -282,3 +275,2 @@
 
 dcPage::close();
-?>
Index: admin/services.php
===================================================================
--- admin/services.php	(revision 2174)
+++ admin/services.php	(revision 2215)
@@ -447,8 +447,8 @@
 	{
 		if (empty($get['id'])) {
-				throw new Exception('No module ID');
+			throw new Exception('No module ID');
 		}
 		if (empty($get['list'])) {
-				throw new Exception('No list ID');
+			throw new Exception('No list ID');
 		}
 
@@ -482,5 +482,5 @@
 
 		if (empty($module)) {
-				throw new Exception('Unknow module ID');
+			throw new Exception('Unknow module ID');
 		}
 
@@ -489,5 +489,5 @@
 		$rsp = new xmlTag('module');
 		$rsp->id = $id;
-		
+
 		foreach($module as $k => $v) {
 			$rsp->{$k}((string) $v);
Index: inc/admin/lib.moduleslist.php
===================================================================
--- inc/admin/lib.moduleslist.php	(revision 2195)
+++ inc/admin/lib.moduleslist.php	(revision 2215)
@@ -1,3 +1,14 @@
 <?php
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 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_ADMIN_CONTEXT')) { return; }
 
 class adminModulesList
@@ -5,9 +16,11 @@
 	public $core;
 	public $modules;
-
-	public static  $allow_multi_install;
+	public $repository;
+
+	public static $allow_multi_install = false;
 	public static $distributed_modules = array();
 
 	protected $list_id = 'unknow';
+	protected $data = array();
 
 	protected $config_module = '';
@@ -30,22 +43,17 @@
 	protected $sort_asc = true;
 
-	public function __construct($core, $root, $allow_multi_install=false)
-	{
-		$this->core = $core;
-		self::$allow_multi_install = (boolean) $allow_multi_install;
-		$this->setPathInfo($root);
+	public function __construct(dcModules $modules, $modules_root, $xml_url)
+	{
+		$this->core = $modules->core;
+		$this->modules = $modules;
+		$this->repository = new dcRepository($modules, $xml_url);
+
+		$this->setPathInfo($modules_root);
 		$this->setNavSpecial(__('other'));
-
-		$this->init();
-	}
-
-	protected function init()
-	{
-		return null;
 	}
 
 	public function newList($list_id)
 	{
-		$this->modules = array();
+		$this->data = array();
 		$this->page_tab = '';
 		$this->list_id = $list_id;
@@ -124,5 +132,5 @@
 		$query = $this->getSearchQuery();
 
-		if (empty($this->modules) && $query === null) {
+		if (empty($this->data) && $query === null) {
 			return $this;
 		}
@@ -140,6 +148,6 @@
 			echo 
 			'<p class="message">'.sprintf(
-				__('Found %d result for search "%s":', 'Found %d results for search "%s":', count($this->modules)), 
-				count($this->modules), html::escapeHTML($query)
+				__('Found %d result for search "%s":', 'Found %d results for search "%s":', count($this->data)), 
+				count($this->data), html::escapeHTML($query)
 				).
 			'</p>';
@@ -163,5 +171,5 @@
 	public function displayNavMenu()
 	{
-		if (empty($this->modules) || $this->getSearchQuery() !== null) {
+		if (empty($this->data) || $this->getSearchQuery() !== null) {
 			return $this;
 		}
@@ -169,5 +177,5 @@
 		# Fetch modules required field
 		$indexes = array();
-		foreach ($this->modules as $id => $module) {
+		foreach ($this->data as $id => $module) {
 			if (!isset($module[$this->sort_field])) {
 				continue;
@@ -246,8 +254,8 @@
 	public function setModules($modules)
 	{
-		$this->modules = array();
+		$this->data = array();
 		if (!empty($modules) && is_array($modules)) {
 			foreach($modules as $id => $module) {
-				$this->modules[$id] = self::parseModuleInfo($id, $module);
+				$this->data[$id] = self::parseModuleInfo($id, $module);
 			}
 		}
@@ -257,5 +265,5 @@
 	public function getModules()
 	{
-		return $this->modules;
+		return $this->data;
 	}
 
@@ -297,9 +305,4 @@
 	}
 
-	public static function setDistributedModules($modules)
-	{
-		self::$distributed_modules = $modules;
-	}
-
 	public static function isDistributedModule($module)
 	{
@@ -361,8 +364,8 @@
 		$sort_field = $this->getSortQuery();
 
-		# Sort modules by id
+		# Sort modules by $sort_field (default sname)
 		$modules = $this->getSearchQuery() === null ?
-			self::sortModules($this->modules, $sort_field, $this->sort_asc) :
-			$this->modules;
+			self::sortModules($this->data, $sort_field, $this->sort_asc) :
+			$this->data;
 
 		$count = 0;
@@ -425,10 +428,20 @@
 
 			if (!empty($actions) && $this->core->auth->isSuperAdmin()) {
+				$buttons = $this->getActions($id, $module, $actions);
+
 				echo 
-				'<td class="module-actions nowrap">';
-
-				$this->displayLineActions($id, $module, $actions);
-
-				echo
+				'<td class="module-actions nowrap">'.
+
+				'<form action="'.$this->getPageURL().'" method="post">'.
+				'<div>'.
+				$this->core->formNonce().
+				form::hidden(array('module'), html::escapeHTML($id)).
+				form::hidden(array('tab'), $this->page_tab).
+
+				implode(' ', $buttons).
+
+				'</div>'.
+				'</form>'.
+
 				'</td>';
 			}
@@ -448,65 +461,51 @@
 	}
 
-	protected function displayLineActions($id, $module, $actions, $echo=true)
+	protected function getActions($id, $module, $actions)
 	{
 		$submits = array();
 
-		# Update (from repository)
-		if (in_array('update', $actions) && $this->path_writable) {
-			$submits[] = '<input type="submit" name="update" value="'.__('Update').'" />';
-		}
-
-		# Install (form repository)
-		if (in_array('install', $actions) && $this->path_writable) {
-			$submits[] = '<input type="submit" name="install" value="'.__('Install').'" />';
-		}
-		
-		$tmp = $this->displayOtherLineAction($id, $module, $actions);
-		if (!empty($tmp) && is_array($tmp)) {
-			$submits = array_merge($submits, $tmp);
-		}
-
-		# Activate
-		if (in_array('deactivate', $actions) && $module['root_writable']) {
-			$submits[] = '<input type="submit" name="deactivate" value="'.__('Deactivate').'" class="reset" />';
-		}
-
-		# Deactivate
-		if (in_array('activate', $actions) && $module['root_writable']) {
-			$submits[] = '<input type="submit" name="activate" value="'.__('Activate').'" />';
-		}
-
-		# Delete
-		if (in_array('delete', $actions) && $this->isPathDeletable($module['root'])) {
-			$submits[] = '<input type="submit" class="delete" name="delete" value="'.__('Delete').'" />';
-		}
-
-		# Parse form
-		if (!empty($submits)) {
-			$res = 
-			'<form action="'.$this->getPageURL().'" method="post">'.
-			'<div>'.
-			$this->core->formNonce().
-			form::hidden(array('module'), html::escapeHTML($id)).
-			form::hidden(array('tab'), $this->page_tab).
-			implode(' ', $submits).
-			'</div>'.
-			'</form>';
-
-			if (!$echo) {
-				return $res;
-			}
-			echo $res;
-		}
-	}
-
-	protected function displayOtherLineAction($id, $module, $actions)
-	{
-		return null;
-	}
-
-	public function executeAction($prefix, dcModules $modules, dcRepository $repository)
-	{
-		if (!$this->core->auth->isSuperAdmin() || !$this->isPathWritable()) {
+		# Use loop to keep requested order
+		foreach($actions as $action) {
+			switch($action) {
+
+				# Deactivate
+				case 'activate': if ($module['root_writable']) {
+					$submits[] = 
+					'<input type="submit" name="activate" value="'.__('Activate').'" />';
+				} break;
+
+				# Activate
+				case 'deactivate': if ($module['root_writable']) {
+					$submits[] = 
+					'<input type="submit" name="deactivate" value="'.__('Deactivate').'" class="reset" />';
+				} break;
+
+				# Delete
+				case 'delete': if ($this->isPathDeletable($module['root'])) {
+					$submits[] = 
+					'<input type="submit" class="delete" name="delete" value="'.__('Delete').'" />';
+				} break;
+
+				# Install (from repository)
+				case 'install': if ($this->path_writable) {
+					$submits[] = 
+					'<input type="submit" name="install" value="'.__('Install').'" />';
+				} break;
+
+				# Update (from repository)
+				case 'update': if ($this->path_writable) {
+					$submits[] = 
+					'<input type="submit" name="update" value="'.__('Update').'" />';
+				} break;
+			}
+		}
+
+		return $submits;
+	}
+
+	public function doActions($prefix)
+	{
+		if (empty($_POST) || !empty($_REQUEST['conf']) 
+		|| !$this->core->auth->isSuperAdmin() || !$this->isPathWritable()) {
 			return null;
 		}
@@ -519,5 +518,5 @@
 			if (!empty($_POST['activate'])) {
 
-				$enabled = $modules->getDisabledModules();
+				$enabled = $this->modules->getDisabledModules();
 				if (!isset($enabled[$id])) {
 					throw new Exception(__('No such module.'));
@@ -527,5 +526,5 @@
 				$this->core->callBehavior($prefix.'BeforeActivate', $id);
 
-				$modules->activateModule($id);
+				$this->modules->activateModule($id);
 
 				# --BEHAVIOR-- moduleAfterActivate
@@ -537,9 +536,9 @@
 			elseif (!empty($_POST['deactivate'])) {
 
-				if (!$modules->moduleExists($id)) {
+				if (!$this->modules->moduleExists($id)) {
 					throw new Exception(__('No such module.'));
 				}
 
-				$module = $modules->getModules($id);
+				$module = $this->modules->getModules($id);
 				$module['id'] = $id;
 
@@ -551,5 +550,5 @@
 				$this->core->callBehavior($prefix.'BeforeDeactivate', $module);
 
-				$modules->deactivateModule($id);
+				$this->modules->deactivateModule($id);
 
 				# --BEHAVIOR-- moduleAfterDeactivate
@@ -561,12 +560,12 @@
 			elseif (!empty($_POST['delete'])) {
 
-				$disabled = $modules->getDisabledModules();
+				$disabled = $this->modules->getDisabledModules();
 				if (!isset($disabled[$id])) {
 
-					if (!$modules->moduleExists($id)) {
+					if (!$this->modules->moduleExists($id)) {
 						throw new Exception(__('No such module.'));
 					}
 
-					$module = $modules->getModules($id);
+					$module = $this->modules->getModules($id);
 					$module['id'] = $id;
 
@@ -578,5 +577,5 @@
 					$this->core->callBehavior($prefix.'BeforeDelete', $module);
 
-					$modules->deleteModule($id);
+					$this->modules->deleteModule($id);
 
 					# --BEHAVIOR-- moduleAfterDelete
@@ -584,8 +583,31 @@
 				}
 				else {
-					$modules->deleteModule($id, true);
+					$this->modules->deleteModule($id, true);
 				}
 
 				http::redirect($this->getPageURL('msg=delete'));
+			}
+
+			elseif (!empty($_POST['install'])) {
+
+				$updated = $this->repository->get();
+				if (!isset($updated[$id])) {
+					throw new Exception(__('No such module.'));
+				}
+
+				$module = $updated[$id];
+				$module['id'] = $id;
+
+				$dest = $this->getPath().'/'.basename($module['file']);
+
+				# --BEHAVIOR-- moduleBeforeAdd
+				$this->core->callBehavior($prefix.'BeforeAdd', $module);
+
+				$ret_code = $this->repository->process($module['file'], $dest);
+
+				# --BEHAVIOR-- moduleAfterAdd
+				$this->core->callBehavior($prefix.'AfterAdd', $module);
+
+				http::redirect($this->getPageURL('msg='.($ret_code == 2 ? 'update' : 'install')));
 			}
 
@@ -597,5 +619,5 @@
 				}
 
-				if (!$modules->moduleExists($id)) {
+				if (!$this->modules->moduleExists($id)) {
 					throw new Exception(__('No such module.'));
 				}
@@ -617,5 +639,5 @@
 				$this->core->callBehavior($prefix.'BeforeUpdate', $module);
 
-				$repository->process($module['file'], $dest);
+				$this->repository->process($module['file'], $dest);
 
 				# --BEHAVIOR-- moduleAfterUpdate
@@ -623,27 +645,4 @@
 
 				http::redirect($this->getPageURL('msg=upadte'));
-			}
-
-			elseif (!empty($_POST['install'])) {
-
-				$updated = $repository->get();
-				if (!isset($updated[$id])) {
-					throw new Exception(__('No such module.'));
-				}
-
-				$module = $updated[$id];
-				$module['id'] = $id;
-
-				$dest = $this->getPath().'/'.basename($module['file']);
-
-				# --BEHAVIOR-- moduleBeforeAdd
-				$this->core->callBehavior($prefix.'BeforeAdd', $module);
-
-				$ret_code = $repository->process($module['file'], $dest);
-
-				# --BEHAVIOR-- moduleAfterAdd
-				$this->core->callBehavior($prefix.'AfterAdd', $module);
-
-				http::redirect($this->getPageURL('msg='.($ret_code == 2 ? 'update' : 'install')));
 			}
 		}
@@ -667,5 +666,5 @@
 				$url = urldecode($_POST['pkg_url']);
 				$dest = $this->getPath().'/'.basename($url);
-				$repository->download($url, $dest);
+				$this->repository->download($url, $dest);
 			}
 
@@ -673,5 +672,5 @@
 			$this->core->callBehavior($prefix.'BeforeAdd', null);
 
-			$ret_code = $repository->install($dest);
+			$ret_code = $this->repository->install($dest);
 
 			# --BEHAVIOR-- moduleAfterAdd
@@ -681,14 +680,4 @@
 		}
 
-		return $this->executeOtherAction($prefix, $modules, $repository);
-	}
-
-	/**
-	 * 
-	 * Way for child class to execute their own actions 
-	 * whitout rewriting all standard actions.
-	 */
-	protected function executeOtherAction($prefix, dcModules $modules, dcRepository $repository)
-	{
 		return null;
 	}
@@ -740,5 +729,5 @@
 	 *
 	 */
-	public function setConfigurationFile(dcModules $modules, $id=null)
+	public function setConfigurationFile($id=null)
 	{
 		if (empty($_REQUEST['conf']) || empty($_REQUEST['module']) && !$id) {
@@ -750,10 +739,10 @@
 		}
 
-		if (!$modules->moduleExists($id)) {
+		if (!$this->modules->moduleExists($id)) {
 			$core->error->add(__('Unknow module ID'));
 			return false;
 		}
 
-		$module = $modules->getModules($id);
+		$module = $this->modules->getModules($id);
 		$module = self::parseModuleInfo($id, $module);
 		$file = path::real($module['root'].'/_config.php');
@@ -842,6 +831,6 @@
 		# Sort modules by id
 		$modules = $this->getSearchQuery() === null ?
-			self::sortModules($this->modules, $sort_field, $this->sort_asc) :
-			$this->modules;
+			self::sortModules($this->data, $sort_field, $this->sort_asc) :
+			$this->data;
 
 		$res = '';
@@ -861,10 +850,9 @@
 
 			$current = $this->core->blog->settings->system->theme == $id;
-
-			if (preg_match('#^http(s)?://#', $this->core->blog->settings->system->themes_url)) {
-				$theme_url = http::concatURL($this->core->blog->settings->system->themes_url, '/'.$id);
-			} else {
-				$theme_url = http::concatURL($this->core->blog->url, $this->core->blog->settings->system->themes_url.'/'.$id);
-			}
+			$distrib = self::isDistributedModule($id) ? ' dc-box' : '';
+
+			$theme_url = preg_match('#^http(s)?://#', $this->core->blog->settings->system->themes_url) ?
+				http::concatURL($this->core->blog->settings->system->themes_url, '/'.$id) :
+				http::concatURL($this->core->blog->url, $this->core->blog->settings->system->themes_url.'/'.$id);
 
 			$has_conf = file_exists(path::real($this->core->blog->themes_path.'/'.$id).'/_config.php');
@@ -877,5 +865,5 @@
 
 			$line = 
-			'<div class="box '.($current ? 'medium current-theme' : 'small theme').'">';
+			'<div class="box '.($current ? 'medium current-theme' : 'small theme').$distrib.'">';
 
 			if (in_array('name', $cols)) {
@@ -899,5 +887,6 @@
 
 				$line .= 
-				'<div class="module-sshot"><img src="'.$sshot.'" alt="'.__('screenshot.').'" /></div>';
+				'<div class="module-sshot"><img src="'.$sshot.'" alt="'.
+				sprintf(__('%s screenshot.'), html::escapeHTML($module['name'])).'" /></div>';
 			}
 
@@ -930,4 +919,29 @@
 					'<span class="module-parent-missing">'.sprintf(__('(requires "%s")'),html::escapeHTML($parent)).'</span> ';
 				}
+			}
+
+			if (in_array('version', $cols)) {
+				$line .= 
+				'<span class="module-version">'.sprintf(__('version %s'),html::escapeHTML($module['version'])).'</span> ';
+			}
+
+			$has_details = in_array('details', $cols) && !empty($module['details']);
+			$has_support = in_array('support', $cols) && !empty($module['support']);
+			if ($has_details || $has_support) {
+				$line .=
+				'<span class="mod-more">'.__('Help:').' ';
+
+				if ($has_details) {
+					$line .= 
+					'<a class="module-details" href="'.$module['details'].'">'.__('Details').'</a>';
+				}
+
+				if ($has_support) {
+					$line .= 
+					' - <a class="module-support" href="'.$module['support'].'">'.__('Support').'</a>';
+				}
+
+				$line .=
+				'</span>';
 			}
 
@@ -958,7 +972,16 @@
 
 			# _POST actions
-			if (!empty($actions) && $this->core->auth->isSuperAdmin()) {
+			if (!empty($actions)) {
 				$line .=
-				$this->displayLineActions($id, $module, $actions, false);
+				'<form action="'.$this->getPageURL().'" method="post">'.
+				'<div>'.
+				$this->core->formNonce().
+				form::hidden(array('module'), html::escapeHTML($id)).
+				form::hidden(array('tab'), $this->page_tab).
+
+				implode(' ', $this->getActions($id, $module, $actions)).
+ 
+				'</div>'.
+				'</form>';
 			}
 
@@ -983,39 +1006,44 @@
 	}
 
-	protected function displayOtherLineAction($id, $module, $actions)
+	protected function getActions($id, $module, $actions)
 	{
 		$submits = array();
 
 		$this->core->blog->settings->addNamespace('system');
-		if ($id == $this->core->blog->settings->system->theme) {
-			return null;
-		}
-
-		# Select theme to use on curent blog
-		if (in_array('select', $actions) && $this->path_writable) {
-			$submits[] = '<input type="submit" name="select" value="'.__('Choose').'" />';
-		}
-
-		return $submits;
-	}
-	
-	protected function executeOtherAction($prefix, dcModules $modules, dcRepository $repository)
-	{
-		# Select theme to use on curent blog
-		if (!empty($_POST['module']) && !empty($_POST['select'])) {
-			$id = $_POST['module'];
-
-			if (!$modules->moduleExists($id)) {
-				throw new Exception(__('No such module.'));
-			}
-
-			$this->core->blog->settings->addNamespace('system');
-			$this->core->blog->settings->system->put('theme',$id);
-			$this->core->blog->triggerBlog();
-
-			http::redirect($this->getPageURL('msg=select').'#themes');
-		}
-
-		return null;
+		if ($id != $this->core->blog->settings->system->theme) {
+
+			# Select theme to use on curent blog
+			if (in_array('select', $actions) && $this->path_writable) {
+				$submits[] = '<input type="submit" name="select" value="'.__('Choose').'" />';
+			}
+		}
+
+		return array_merge(
+			$submits,
+			parent::getActions($id, $module, $actions)
+		);
+	}
+
+	public function doActions($prefix)
+	{
+		if (!empty($_POST) && empty($_REQUEST['conf']) && $this->isPathWritable()) {
+
+			# Select theme to use on curent blog
+			if (!empty($_POST['module']) && !empty($_POST['select'])) {
+				$id = $_POST['module'];
+
+				if (!$this->modules->moduleExists($id)) {
+					throw new Exception(__('No such module.'));
+				}
+
+				$this->core->blog->settings->addNamespace('system');
+				$this->core->blog->settings->system->put('theme',$id);
+				$this->core->blog->triggerBlog();
+
+				http::redirect($this->getPageURL('msg=select').'#themes');
+			}
+		}
+
+		return parent::doActions($prefix);
 	}
 }
Index: inc/core/class.dc.repository.php
===================================================================
--- inc/core/class.dc.repository.php	(revision 2214)
+++ inc/core/class.dc.repository.php	(revision 2215)
@@ -44,4 +44,6 @@
 		$this->xml_url = $xml_url;
 		$this->user_agent = sprintf('Dotclear/%s)', DC_VERSION);
+
+		$this->check();
 	}
 
Index: plugins/maintenance/_config.php
===================================================================
--- plugins/maintenance/_config.php	(revision 2182)
+++ plugins/maintenance/_config.php	(revision 2215)
@@ -61,5 +61,5 @@
 
 	echo 
-	'<p>'.__('Manage alert for maintenance task.').'</p>'.
+	'<p>'.__('Setup alert for maintenance task.').'</p>'.
 
 	'<h4 class="pretty-title">'.__('Activation').'</h4>'.
