Index: plugins/maintenance/_admin.php
===================================================================
--- plugins/maintenance/_admin.php	(revision 1940)
+++ plugins/maintenance/_admin.php	(revision 1955)
@@ -43,11 +43,17 @@
 	 * @param	$tasks	<b>arrayObject</b>	Array of tasks to register
 	 * @param	$groups	<b>arrayObject</b>	Array of groups to register
+	 * @param	$tabs	<b>arrayObject</b>	Array of tabs to register
 	 */
-	 public static function register($core, $tasks, $groups)
+	 public static function register($core, $tasks, $groups, $tabs)
 	{
+		$tabs['maintenance'] = __('Servicing');
+		$tabs['backup'] = __('Backup');
+
 		$groups['optimize'] = __('Optimize');
 		$groups['index'] = __('Count and index');
 		$groups['purge'] = __('Purge');
 		$groups['other'] = __('Other');
+		$groups['zipblog'] = __('Compressed file for current blog');
+		$groups['zipfull'] = __('Compressed file for all blogs');
 
 		$tasks[] = 'dcMaintenanceCache';
@@ -57,4 +63,6 @@
 		$tasks[] = 'dcMaintenanceLogs';
 		$tasks[] = 'dcMaintenanceVacuum';
+		$tasks[] = 'dcMaintenanceZipmedia';
+		$tasks[] = 'dcMaintenanceZiptheme';
 	}
 
Index: plugins/maintenance/_prepend.php
===================================================================
--- plugins/maintenance/_prepend.php	(revision 1925)
+++ plugins/maintenance/_prepend.php	(revision 1955)
@@ -24,4 +24,6 @@
 $__autoload['dcMaintenanceLogs'] = dirname(__FILE__).'/inc/tasks/class.dc.maintenance.logs.php';
 $__autoload['dcMaintenanceVacuum'] = dirname(__FILE__).'/inc/tasks/class.dc.maintenance.vacuum.php';
+$__autoload['dcMaintenanceZipmedia'] = dirname(__FILE__).'/inc/tasks/class.dc.maintenance.zipmedia.php';
+$__autoload['dcMaintenanceZiptheme'] = dirname(__FILE__).'/inc/tasks/class.dc.maintenance.ziptheme.php';
 
 $this->core->rest->addFunction('dcMaintenanceStep', array('dcMaintenanceRest', 'step'));
Index: plugins/maintenance/inc/class.dc.maintenance.php
===================================================================
--- plugins/maintenance/inc/class.dc.maintenance.php	(revision 1940)
+++ plugins/maintenance/inc/class.dc.maintenance.php	(revision 1955)
@@ -27,4 +27,5 @@
 	private $core;
 	private $tasks = array();
+	private $tabs = array();
 	private $groups = array();
 
@@ -41,10 +42,11 @@
 
 		$tasks = new ArrayObject();
+		$tabs = new ArrayObject();
 		$groups = new ArrayObject();
 
 		# --BEHAVIOR-- dcMaintenanceRegister
-		$core->callBehavior('dcMaintenanceRegister', $core, $tasks, $groups);
-
-		$this->init($tasks, $groups);
+		$core->callBehavior('dcMaintenanceRegister', $core, $tasks, $groups, $tabs);
+
+		$this->init($tasks, $groups, $tabs);
 	}
 
@@ -54,6 +56,7 @@
 	 * @param	tasks	<b>arrayObject</b>	Array of task to register
 	 * @param	groups	<b>arrayObject</b>	Array of groups to add
-	 */
-	public function init($tasks, $groups)
+	 * @param	tabs	<b>arrayObject</b>	Array of tabs to add
+	 */
+	public function init($tasks, $groups, $tabs)
 	{
 		$this->tasks = $this->groups = array();
@@ -79,4 +82,30 @@
 			$this->groups[(string) $id] = (string) $name;
 		}
+
+		foreach($tabs as $id => $name)
+		{
+			$this->tabs[(string) $id] = (string) $name;
+		}
+	}
+
+	/**
+	 * Get a tab name.
+	 *
+	 * @param	id	<b>string</b> Tab ID
+	 * @return	<b>mixed</b> tab name or null if not exists
+	 */
+	public function getTab($id)
+	{
+		return array_key_exists($id, $this->tabs) ? $this->tabs[$id] : null;
+	}
+
+	/**
+	 * Get tabs.
+	 *
+	 * @return	<b>array</b> Array of tabs ID and name
+	 */
+	public function getTabs()
+	{
+		return $this->tabs;
 	}
 
Index: plugins/maintenance/inc/class.dc.maintenance.task.php
===================================================================
--- plugins/maintenance/inc/class.dc.maintenance.task.php	(revision 1940)
+++ plugins/maintenance/inc/class.dc.maintenance.task.php	(revision 1955)
@@ -28,4 +28,5 @@
 	protected $id;
 	protected $name;
+	protected $tab = 'maintenance';
 	protected $group = 'other';
 
@@ -115,4 +116,14 @@
 
 	/**
+	 * Get task tab.
+	 *
+	 * @return	<b>mixed</b>	Task tab ID or null
+	 */
+	public function tab()
+	{
+		return $this->tab;
+	}
+
+	/**
 	 * Get task group.
 	 *
@@ -211,3 +222,16 @@
 		return null;
 	}
+
+	/**
+	 * Log task execution.
+	 *
+	 * Sometimes we need to log task execution 
+	 * direct from task itself.
+	 *
+	 */
+	protected function log()
+	{
+		$maintenance = new dcMaintenance($this->core);
+		$maintenance->setLog($this->id);
+	}
 }
Index: plugins/maintenance/inc/tasks/class.dc.maintenance.zipmedia.php
===================================================================
--- plugins/maintenance/inc/tasks/class.dc.maintenance.zipmedia.php	(revision 1955)
+++ plugins/maintenance/inc/tasks/class.dc.maintenance.zipmedia.php	(revision 1955)
@@ -0,0 +1,48 @@
+<?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_RC_PATH')) { return; }
+
+class dcMaintenanceZipmedia extends dcMaintenanceTask
+{
+	protected $tab = 'backup';
+	protected $group = 'zipblog';
+
+	protected function init()
+	{
+		$this->task = __('Download media folder of current blog');
+	}
+
+	public function execute()
+	{
+		// Instance media
+		$this->core->media = new dcMedia($this->core);
+		$this->core->media->chdir(null);
+		$this->core->media->getDir();
+
+		// Create zip
+		@set_time_limit(300);
+		$fp = fopen('php://output', 'wb');
+		$zip = new fileZip($fp);
+		$zip->addExclusion('#(^|/).(.*?)_(m|s|sq|t).jpg$#');
+		$zip->addDirectory($this->core->media->root.'/', '', true);
+
+		// Log task execution here as we sent file and stop script
+		$this->log();
+
+		// Send zip
+		header('Content-Disposition: attachment;filename=media.zip');
+		header('Content-Type: application/x-zip');
+		$zip->write();
+		unset($zip);
+		exit(1);
+	}
+}
Index: plugins/maintenance/inc/tasks/class.dc.maintenance.ziptheme.php
===================================================================
--- plugins/maintenance/inc/tasks/class.dc.maintenance.ziptheme.php	(revision 1955)
+++ plugins/maintenance/inc/tasks/class.dc.maintenance.ziptheme.php	(revision 1955)
@@ -0,0 +1,51 @@
+<?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_RC_PATH')) { return; }
+
+class dcMaintenanceZiptheme extends dcMaintenanceTask
+{
+	protected $tab = 'backup';
+	protected $group = 'zipblog';
+
+	protected function init()
+	{
+		$this->task = __('Download active theme of current blog');
+	}
+
+	public function execute()
+	{
+		// Get theme path
+		$path = $this->core->blog->themes_path;
+		$theme =$this->core->blog->settings->system->theme;
+		$dir = path::real($path.'/'.$theme);
+		if (empty($path) || empty($theme) || !is_dir($dir)) {
+			return false;
+		}
+
+		// Create zip
+		@set_time_limit(300);
+		$fp = fopen('php://output', 'wb');
+		$zip = new fileZip($fp);
+		$zip->addExclusion('#(^|/).(.*?)_(m|s|sq|t).jpg$#');
+		$zip->addDirectory($dir.'/', '', true);
+
+		// Log task execution here as we sent file and stop script
+		$this->log();
+
+		// Send zip
+		header('Content-Disposition: attachment;filename=theme-'.$theme.'.zip');
+		header('Content-Type: application/x-zip');
+		$zip->write();
+		unset($zip);
+		exit(1);
+	}
+}
Index: plugins/maintenance/index.php
===================================================================
--- plugins/maintenance/index.php	(revision 1940)
+++ plugins/maintenance/index.php	(revision 1955)
@@ -70,5 +70,5 @@
 dcPage::jsPageTabs($tab);
 
-if ($task) {
+if (0){//$task) {
 	echo 
 	'<script type="text/javascript">'."\n".
@@ -137,46 +137,55 @@
 	// Simple task (with only a button to start it)
 
-	echo 
-	'<div id="maintenance" class="multi-part" title="'.__('Maintenance').'">'.
-	'<h3>'.__('Maintenance').'</h3>'.
-	'<form action="'.$p_url.'" method="post">';
-
-	foreach($maintenance->getGroups($core) as $g_id => $g_name)
+	foreach($maintenance->getTabs() as $tab_id => $tab_name)
 	{
-		$res = '';
-		foreach($maintenance->getTasks($core) as $t)
+		$res_group = '';
+		foreach($maintenance->getGroups($core) as $group_id => $group_name)
 		{
-			if ($t->group() != $g_id) {
-				continue;
+			$res_task = '';
+			foreach($maintenance->getTasks($core) as $t)
+			{
+				if ($t->group() != $group_id || $t->tab() != $tab_id) {
+					continue;
+				}
+
+				$res_task .=  
+				'<p>'.form::radio(array('task', $t->id()), $t->id()).' '.
+				'<label class="classic" for="'.$t->id().'">'.
+				html::escapeHTML($t->task()).'</label>';
+
+				if (array_key_exists($t->id(), $expired)) {
+					$res_task .= 
+					' <span class="clear form-note warn">'.sprintf(
+						__('Last execution of this task was on %s. You should execute it again.'),
+						dt::dt2str(__('%Y-%m-%d %H:%M'), $expired[$t->id()])
+					).'</span>';
+				}
+
+				$res_task .= '</p>';
 			}
 
-			$res .=  
-			'<p>'.form::radio(array('task', $t->id()), $t->id()).' '.
-			'<label class="classic" for="'.$t->id().'">'.
-			html::escapeHTML($t->task()).'</label>';
-
-			if (array_key_exists($t->id(), $expired)) {
-				$res .= 
-				' <span class="clear form-note warn">'.sprintf(
-					__('Last execution of this task was on %s. You should execute it again.'),
-					dt::dt2str(__('%Y-%m-%d %H:%M'), $expired[$t->id()])
-				).'</span>';
+			if (!empty($res_task)) {
+				$res_group .= 
+				'<div class="fieldset">'.
+				'<h4 id="'.$group_id.'">'.$group_name.'</h4>'.
+				$res_task.
+				'</div>';
 			}
-
-			$res .= '</p>';
-		}
-
-		if (!empty($res)) {
-			echo '<div class="fieldset"><h4 id="'.$g_id.'">'.$g_name.'</h4>'.$res.'</div>';
-		}
-	}
-
-	echo 
-	'<p><input type="submit" value="'.__('Execute task').'" /> '.
-	form::hidden(array('tab'), 'maintenance').
-	$core->formNonce().'</p>'.
-	'<p class="form-note info">'.__('This may take a very long time').'.</p>'.
-	'</form>'.
-	'</div>';
+		}
+
+		if (!empty($res_group)) {
+			echo 
+			'<div id="'.$tab_id.'" class="multi-part" title="'.$tab_name.'">'.
+			'<h3>'.$tab_name.'</h3>'.
+			'<form action="'.$p_url.'" method="post">'.
+			$res_group.
+			'<p><input type="submit" value="'.__('Execute task').'" /> '.
+			form::hidden(array('tab'), $tab_id).
+			$core->formNonce().'</p>'.
+			'<p class="form-note info">'.__('This may take a very long time').'.</p>'.
+			'</form>'.
+			'</div>';
+		}
+	}
 
 	// Advanced tasks (that required a tab)
